diff --git a/lib/rules/no-restricted-exports.js b/lib/rules/no-restricted-exports.js index d99e8928209..55a26284681 100644 --- a/lib/rules/no-restricted-exports.js +++ b/lib/rules/no-restricted-exports.js @@ -35,19 +35,51 @@ module.exports = { type: "string" }, uniqueItems: true + }, + restrictDefaultExports: { + type: "object", + properties: { + + // Allow/Disallow `export default foo; export default 42; export default function foo() {}` format + direct: { + type: "boolean" + }, + + // Allow/Disallow `export { foo as default };` format + named: { + type: "boolean" + }, + + // Allow/Disallow `export { default } from "mod"; export { default as default } from "mod";` format + defaultFrom: { + type: "boolean" + }, + + // Allow/Disallow `export { foo as default } from "mod";` format + namedFrom: { + type: "boolean" + }, + + // Allow/Disallow `export * as default from "mod"`; format + namespaceFrom: { + type: "boolean" + } + } } }, additionalProperties: false }], messages: { - restrictedNamed: "'{{name}}' is restricted from being used as an exported name." + restrictedNamed: "'{{name}}' is restricted from being used as an exported name.", + restrictedDefault: "Exporting the 'default' value is restricted." } }, create(context) { const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports); + const restrictDefaultExports = context.options[0] && !restrictedNames.has("default") && context.options[0].restrictDefaultExports; /** * Checks and reports given exported name. @@ -63,6 +95,11 @@ module.exports = { messageId: "restrictedNamed", data: { name } }); + } else if (name === "default" && restrictDefaultExports && restrictDefaultExports.named) { + context.report({ + node, + messageId: "restrictedDefault" + }); } } @@ -73,6 +110,15 @@ module.exports = { } }, + ExportDefaultDeclaration(node) { + if (restrictDefaultExports && restrictDefaultExports.direct) { + context.report({ + node, + messageId: "restrictedDefault" + }); + } + }, + ExportNamedDeclaration(node) { const declaration = node.declaration; diff --git a/tests/lib/rules/no-restricted-exports.js b/tests/lib/rules/no-restricted-exports.js index 631fd6f02fa..4fb1c8f272d 100644 --- a/tests/lib/rules/no-restricted-exports.js +++ b/tests/lib/rules/no-restricted-exports.js @@ -107,7 +107,16 @@ ruleTester.run("no-restricted-exports", rule, { { code: "export default 1;", options: [{ restrictedNamedExports: ["default"] }] }, // "default" does not disallow re-exporting a renamed default export from another module - { code: "export { default as a } from 'foo';", options: [{ restrictedNamedExports: ["default"] }] } + { code: "export { default as a } from 'foo';", options: [{ restrictedNamedExports: ["default"] }] }, + + // restrictDefaultExports.direct option + { code: "export default foo;", options: [{ restrictDefaultExports: { direct: false } }] }, + { code: "export default 42;", options: [{ restrictDefaultExports: { direct: false } }] }, + { code: "export default function foo() {}", options: [{ restrictDefaultExports: { direct: false } }] }, + { code: "export default foo;", options: [{ restrictedNamedExports: ["default"], restrictDefaultExports: { direct: true } }] }, + + // restrictDefaultExports.named option + { code: "const foo = 123;\nexport { foo as default };", options: [{ restrictDefaultExports: { named: false } }] } ], invalid: [ @@ -519,6 +528,47 @@ ruleTester.run("no-restricted-exports", rule, { code: "export { default } from 'foo';", options: [{ restrictedNamedExports: ["default"] }], errors: [{ messageId: "restrictedNamed", data: { name: "default" }, type: "Identifier", column: 10 }] + }, + + // restrictDefaultExports.direct option + { + code: "export default foo;", + options: [{ restrictDefaultExports: { direct: true } }], + errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }] + }, + { + code: "export default 42;", + options: [{ restrictDefaultExports: { direct: true } }], + errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }] + }, + { + code: "export default function foo() {};", + options: [{ restrictDefaultExports: { direct: true } }], + errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }] + }, + { + code: "export default foo;", + options: [{ restrictedNamedExports: ["bar"], restrictDefaultExports: { direct: true } }], + errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }] + }, + + // restrictDefaultExports.named option + { + code: "const foo = 123;\nexport { foo as default };", + options: [{ restrictDefaultExports: { named: true } }], + errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 2, column: 17 }] + }, + + // restrictedNamedExports should take priority over restrictDefaultExports.named + { + code: "const foo = 123;\nexport { foo as default };", + options: [{ restrictedNamedExports: ["default"], restrictDefaultExports: { named: false } }], + errors: [{ messageId: "restrictedNamed", type: "Identifier", line: 2, column: 17 }] + }, + { + code: "const foo = 123;\nexport { foo as default };", + options: [{ restrictedNamedExports: ["default"], restrictDefaultExports: { named: true } }], + errors: [{ messageId: "restrictedNamed", type: "Identifier", line: 2, column: 17 }] } ] });