diff --git a/.eslintignore b/.eslintignore
index 3189ad9a8..957e4a275 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -7,3 +7,7 @@ packages/typescript/test/fixtures/syntax-error
# temporary workaround for eslint bug where package.json is a directory
packages/node-resolve/test/fixtures/package-json-in-path
+
+# temporary workaround for TypeScript as it doesn't support "Arbitrary module namespace identifier names"
+# https://github.com/microsoft/TypeScript/issues/40594
+packages/json/test/fixtures/arbitrary/main.js
diff --git a/packages/json/README.md b/packages/json/README.md
index e98f81fe5..1b1c9cd0f 100644
--- a/packages/json/README.md
+++ b/packages/json/README.md
@@ -75,6 +75,13 @@ Default: `null`
A [picomatch pattern](https://github.com/micromatch/picomatch), or array of patterns, which specifies the files in the build the plugin should operate on. By default all files are targeted.
+### `includeArbitraryNames`
+
+Type: `Boolean`
+Default: `false`
+
+If `true` and `namedExports` is `true`, generates a named export for not a valid identifier properties of the JSON object by leveraging the ["Arbitrary Module Namespace Identifier Names" feature](https://github.com/tc39/ecma262/pull/2154).
+
### `indent`
Type: `String`
diff --git a/packages/json/package.json b/packages/json/package.json
index 47b04a896..986903165 100755
--- a/packages/json/package.json
+++ b/packages/json/package.json
@@ -61,7 +61,7 @@
}
},
"dependencies": {
- "@rollup/pluginutils": "^5.0.1"
+ "@rollup/pluginutils": "^5.1.0"
},
"devDependencies": {
"@rollup/plugin-buble": "^1.0.0",
diff --git a/packages/json/src/index.js b/packages/json/src/index.js
index b61ed2300..dcb8f3333 100755
--- a/packages/json/src/index.js
+++ b/packages/json/src/index.js
@@ -18,6 +18,7 @@ export default function json(options = {}) {
preferConst: options.preferConst,
compact: options.compact,
namedExports: options.namedExports,
+ includeArbitraryNames: options.includeArbitraryNames,
indent
}),
map: { mappings: '' }
diff --git a/packages/json/test/fixtures/arbitrary/foo.json b/packages/json/test/fixtures/arbitrary/foo.json
new file mode 100755
index 000000000..0776ea877
--- /dev/null
+++ b/packages/json/test/fixtures/arbitrary/foo.json
@@ -0,0 +1,3 @@
+{
+ "foo.bar": "baz"
+}
diff --git a/packages/json/test/fixtures/arbitrary/main.js b/packages/json/test/fixtures/arbitrary/main.js
new file mode 100755
index 000000000..75670fae1
--- /dev/null
+++ b/packages/json/test/fixtures/arbitrary/main.js
@@ -0,0 +1,3 @@
+export { 'foo.bar' as bar } from './foo.json';
+
+result = exports; // eslint-disable-line no-undef
diff --git a/packages/json/test/test.js b/packages/json/test/test.js
index 1abbc2377..9aec69089 100755
--- a/packages/json/test/test.js
+++ b/packages/json/test/test.js
@@ -54,6 +54,17 @@ test('generates named exports', async (t) => {
t.is(code.indexOf('this-should-be-excluded'), -1, 'should exclude unused properties');
});
+test('generates named exports including arbitrary names', async (t) => {
+ const bundle = await rollup({
+ input: 'fixtures/arbitrary/main.js',
+ plugins: [json({ includeArbitraryNames: true })]
+ });
+
+ const { result } = await testBundle(t, bundle, { inject: { exports: {} } });
+
+ t.is(result.bar, 'baz');
+});
+
test('resolves extensionless imports in conjunction with the node-resolve plugin', async (t) => {
const bundle = await rollup({
input: 'fixtures/extensionless/main.js',
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dbe85b834..3777d7ee4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -468,8 +468,8 @@ importers:
packages/json:
dependencies:
'@rollup/pluginutils':
- specifier: ^5.0.1
- version: 5.0.1(rollup@4.0.0-24)
+ specifier: ^5.1.0
+ version: 5.1.0(rollup@4.0.0-24)
devDependencies:
'@rollup/plugin-buble':
specifier: ^1.0.0
@@ -2425,6 +2425,21 @@ packages:
rollup: 4.0.0-24
dev: false
+ /@rollup/pluginutils@5.1.0(rollup@4.0.0-24):
+ resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ dependencies:
+ '@types/estree': 1.0.0
+ estree-walker: 2.0.2
+ picomatch: 2.3.1
+ rollup: 4.0.0-24
+ dev: false
+
/@rollup/rollup-android-arm-eabi@4.0.0-24:
resolution: {integrity: sha512-19cF3V1fHfzPzwu0cgZEdWLMdNkqSmKOhidqQv1CkUqAMcb7etA7WLx8YrX5ob31ruI0BYYrUDBunlIuMHHUrg==}
cpu: [arm]