diff --git a/docs/src/rules/no-restricted-exports.md b/docs/src/rules/no-restricted-exports.md index 44672021a10..446c4fbc337 100644 --- a/docs/src/rules/no-restricted-exports.md +++ b/docs/src/rules/no-restricted-exports.md @@ -17,6 +17,7 @@ By default, this rule doesn't disallow any names. Only the names you specify in This rule has an object option: * `"restrictedNamedExports"` is an array of strings, where each string is a name to be restricted. +* `"restrictedNamedExportsPattern"` is a string representing a regular expression pattern. Named exports matching this pattern will be restricted. This option does not apply to `default` named exports. * `"restrictDefaultExports"` is an object option with boolean properties to restrict certain default export declarations. The option works only if the `restrictedNamedExports` option does not contain the `"default"` value. The following properties are allowed: * `direct`: restricts `export default` declarations. * `named`: restricts `export { foo as default };` declarations. @@ -130,6 +131,38 @@ export default function foo() {} ::: +### restrictedNamedExportsPattern + +Example of **incorrect** code for the `"restrictedNamedExportsPattern"` option: + +::: incorrect + +```js +/*eslint no-restricted-exports: ["error", { + "restrictedNamedExportsPattern": "bar$" +}]*/ + +export const foobar = 1; +``` + +::: + +Example of **correct** code for the `"restrictedNamedExportsPattern"` option: + +::: correct + +```js +/*eslint no-restricted-exports: ["error", { + "restrictedNamedExportsPattern": "bar$" +}]*/ + +export const abc = 1; +``` + +::: + +Note that this option does not apply to `export default` or any `default` named exports. If you want to also restrict `default` exports, use the `restrictDefaultExports` option. + ### restrictDefaultExports This option allows you to restrict certain `default` declarations. The option works only if the `restrictedNamedExports` option does not contain the `"default"` value. This option accepts the following properties: diff --git a/lib/rules/no-restricted-exports.js b/lib/rules/no-restricted-exports.js index a1d54b085fd..8da2f2dfe01 100644 --- a/lib/rules/no-restricted-exports.js +++ b/lib/rules/no-restricted-exports.js @@ -37,7 +37,8 @@ module.exports = { type: "string" }, uniqueItems: true - } + }, + restrictedNamedExportsPattern: { type: "string" } }, additionalProperties: false }, @@ -52,6 +53,7 @@ module.exports = { }, uniqueItems: true }, + restrictedNamedExportsPattern: { type: "string" }, restrictDefaultExports: { type: "object", properties: { @@ -98,6 +100,7 @@ module.exports = { create(context) { const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports); + const restrictedNamePattern = context.options[0] && context.options[0].restrictedNamedExportsPattern; const restrictDefaultExports = context.options[0] && context.options[0].restrictDefaultExports; const sourceCode = context.sourceCode; @@ -109,7 +112,15 @@ module.exports = { function checkExportedName(node) { const name = astUtils.getModuleExportName(node); - if (restrictedNames.has(name)) { + let matchesRestrictedNamePattern = false; + + if (restrictedNamePattern && name !== "default") { + const patternRegex = new RegExp(restrictedNamePattern, "u"); + + matchesRestrictedNamePattern = patternRegex.test(name); + } + + if (matchesRestrictedNamePattern || restrictedNames.has(name)) { context.report({ node, messageId: "restrictedNamed", diff --git a/tests/lib/rules/no-restricted-exports.js b/tests/lib/rules/no-restricted-exports.js index cea7c046694..aab1043fc70 100644 --- a/tests/lib/rules/no-restricted-exports.js +++ b/tests/lib/rules/no-restricted-exports.js @@ -91,6 +91,50 @@ ruleTester.run("no-restricted-exports", rule, { { code: "import a from 'foo';", options: [{ restrictedNamedExports: ["a"] }] }, { code: "import { a } from 'foo';", options: [{ restrictedNamedExports: ["a"] }] }, { code: "import { b as a } from 'foo';", options: [{ restrictedNamedExports: ["a"] }] }, + { + code: "var setSomething; export { setSomething };", + options: [{ restrictedNamedExportsPattern: "^get" }] + }, + { + code: "var foo, bar; export { foo, bar };", + options: [{ restrictedNamedExportsPattern: "^(?!foo)(?!bar).+$" }] + }, + { + code: "var foobar; export default foobar;", + options: [{ restrictedNamedExportsPattern: "bar$" }] + }, + { + code: "var foobar; export default foobar;", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "export default 'default';", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "var foobar; export { foobar as default };", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "var foobar; export { foobar as 'default' };", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "export { default } from 'mod';", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "export { default as default } from 'mod';", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "export { foobar as default } from 'mod';", + options: [{ restrictedNamedExportsPattern: "default" }] + }, + { + code: "export * as default from 'mod';", + options: [{ restrictedNamedExportsPattern: "default" }] + }, // does not check re-export all declarations { code: "export * from 'foo';", options: [{ restrictedNamedExports: ["a"] }] }, @@ -533,6 +577,51 @@ ruleTester.run("no-restricted-exports", rule, { ] }, + // restrictedNamedExportsPattern + { + code: "var getSomething; export { getSomething };", + options: [{ restrictedNamedExportsPattern: "get*" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "getSomething" }, type: "Identifier" } + ] + }, + { + code: "var getSomethingFromUser; export { getSomethingFromUser };", + options: [{ restrictedNamedExportsPattern: "User$" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "getSomethingFromUser" }, type: "Identifier" } + ] + }, + { + code: "var foo, ab, xy; export { foo, ab, xy };", + options: [{ restrictedNamedExportsPattern: "(b|y)$" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "ab" }, type: "Identifier" }, + { messageId: "restrictedNamed", data: { name: "xy" }, type: "Identifier" } + ] + }, + { + code: "var foo; export { foo as ab };", + options: [{ restrictedNamedExportsPattern: "(b|y)$" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "ab" }, type: "Identifier" } + ] + }, + { + code: "var privateUserEmail; export { privateUserEmail };", + options: [{ restrictedNamedExportsPattern: "^privateUser" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "privateUserEmail" }, type: "Identifier" } + ] + }, + { + code: "export const a = 1;", + options: [{ restrictedNamedExportsPattern: "^(?!foo)(?!bar).+$" }], + errors: [ + { messageId: "restrictedNamed", data: { name: "a" }, type: "Identifier" } + ] + }, + // reports "default" in named export declarations (when configured) { code: "var a; export { a as default };",