diff --git a/packages/json/README.md b/packages/json/README.md
index 1b1c9cd0f..8d8b4fc2e 100644
--- a/packages/json/README.md
+++ b/packages/json/README.md
@@ -68,6 +68,12 @@ Default: `null`
A [picomatch pattern](https://github.com/micromatch/picomatch), or array of patterns, which specifies the files in the build the plugin should _ignore_. By default no files are ignored.
+### `extensions`
+
+Type: `Array[...String]`
+Default: `['.json']`
+A list of file extensions to be handled by the plugin. By default, only `.json` files are handled.
+
### `include`
Type: `String` | `Array[...String]`
diff --git a/packages/json/src/index.js b/packages/json/src/index.js
index dcb8f3333..ac597fa4e 100755
--- a/packages/json/src/index.js
+++ b/packages/json/src/index.js
@@ -1,15 +1,19 @@
import { createFilter, dataToEsm } from '@rollup/pluginutils';
+import { extname } from 'path';
export default function json(options = {}) {
const filter = createFilter(options.include, options.exclude);
const indent = 'indent' in options ? options.indent : '\t';
+ const extensions = new Set('extensions' in options ? options.extensions : ['.json']);
return {
name: 'json',
// eslint-disable-next-line no-shadow
transform(code, id) {
- if (id.slice(-5) !== '.json' || !filter(id)) return null;
+ const extension = extname(id);
+
+ if (!extensions.has(extension) || !filter(id)) return null;
try {
const parsed = JSON.parse(code);
diff --git a/packages/json/test/fixtures/custom-file-extension/config.customjson b/packages/json/test/fixtures/custom-file-extension/config.customjson
new file mode 100755
index 000000000..0a6e8769b
--- /dev/null
+++ b/packages/json/test/fixtures/custom-file-extension/config.customjson
@@ -0,0 +1,3 @@
+{
+ "answer": 42
+}
diff --git a/packages/json/test/fixtures/custom-file-extension/main.js b/packages/json/test/fixtures/custom-file-extension/main.js
new file mode 100755
index 000000000..fb5eee1f1
--- /dev/null
+++ b/packages/json/test/fixtures/custom-file-extension/main.js
@@ -0,0 +1,3 @@
+import config from './config.customjson';
+
+t.is(config.answer, 42);
diff --git a/packages/json/test/test.js b/packages/json/test/test.js
index 9aec69089..ba074ea72 100755
--- a/packages/json/test/test.js
+++ b/packages/json/test/test.js
@@ -164,3 +164,24 @@ test('handles empty keys', async (t) => {
'export var b = "c";\nexport default {\n\t"": "a",\n\tb: b\n};\n'
);
});
+
+test('uses extensions option', async (t) => {
+ const bundle = await rollup({
+ input: 'fixtures/custom-file-extension/main.js',
+ plugins: [
+ json({
+ extensions: ['.customjson']
+ })
+ ]
+ });
+ t.plan(1);
+ return testBundle(t, bundle);
+});
+
+test('does not process non-custom extensions', async (t) => {
+ const content = 'some content';
+ const id = 'testfile.json';
+ const plugin = json({ extensions: ['.custom'] });
+ const output = plugin.transform(content, id);
+ t.is(output, null, 'Should return null for files without custom extensions');
+});
diff --git a/packages/json/types/index.d.ts b/packages/json/types/index.d.ts
index 6ef037a23..82ccddb62 100755
--- a/packages/json/types/index.d.ts
+++ b/packages/json/types/index.d.ts
@@ -12,6 +12,11 @@ export interface RollupJsonOptions {
* but you can also specifically exclude files
*/
exclude?: FilterPattern;
+ /**
+ * Specify the file extensions to be parsed as JSON
+ * @default ['.json']
+ */
+ extensions?: string[];
/**
* For tree-shaking, properties will be declared as variables, using
* either `var` or `const`.