From b16a4753c111271325f6dced4936bc9da6162138 Mon Sep 17 00:00:00 2001 From: Sebastian Good <2230835+scagood@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:13:24 +0100 Subject: [PATCH] feat(no-process-env): Allow users to exclude specific variables (#345) * fix(no-process-env): Include computed Literals * feat(no-process-env): Allow users to exclude specific variables * docs(no-process-env): Add allowedVariables documentation * Remove comments from test cases --- docs/rules/no-process-env.md | 16 +++++++++ lib/rules/no-process-env.js | 52 ++++++++++++++++++++++++++- tests/lib/rules/no-process-env.js | 59 +++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-process-env.md b/docs/rules/no-process-env.md index bd3c84dc..a57b6a89 100644 --- a/docs/rules/no-process-env.md +++ b/docs/rules/no-process-env.md @@ -30,6 +30,22 @@ if(config.env === "development") { } ``` +### Options + +```json +{ + "rules": { + "n/no-process-env": ["error", { + "allowedVariables": ["NODE_ENV"] + }] + } +} +``` + +#### allowedVariables + +Sometimes you need to allow specific environment variables, this option allows you to exclude specific variables from triggering a linting error. + ## 🔎 Implementation - [Rule source](../../lib/rules/no-process-env.js) diff --git a/lib/rules/no-process-env.js b/lib/rules/no-process-env.js index daec0def..fd7af99f 100644 --- a/lib/rules/no-process-env.js +++ b/lib/rules/no-process-env.js @@ -13,8 +13,26 @@ const querySelector = [ `[computed!=true]`, `[object.name="process"]`, `[property.name="env"]`, + `,`, + `MemberExpression`, + `[computed=true]`, + `[object.name="process"]`, + `[property.value="env"]`, ] +/** + * @param {unknown} node [description] + * @returns {node is import('estree').MemberExpression} + */ +function isMemberExpresion(node) { + return ( + node != null && + typeof node === "object" && + "type" in node && + node.type === "MemberExpression" + ) +} + /** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { @@ -25,16 +43,48 @@ module.exports = { url: "https://github.com/eslint-community/eslint-plugin-n/blob/HEAD/docs/rules/no-process-env.md", }, fixable: null, - schema: [], + schema: [ + { + type: "object", + properties: { + allowedVariables: { + type: "array", + items: { type: "string" }, + }, + }, + additionalProperties: false, + }, + ], messages: { unexpectedProcessEnv: "Unexpected use of process.env.", }, }, create(context) { + const options = context.options[0] ?? {} + /** @type {string[]} */ + const allowedVariables = options.allowedVariables ?? [] return { /** @param {import('estree').MemberExpression} node */ [querySelector.join("")](node) { + if ( + "parent" in node && + isMemberExpresion(node.parent) && + node.parent.property != null + ) { + const child = node.parent.property + if ( + (child.type === "Identifier" && + node.parent.computed === false && + allowedVariables.includes(child.name)) || + (child.type === "Literal" && + typeof child.value === "string" && + node.parent.computed === true && + allowedVariables.includes(child.value)) + ) { + return + } + } context.report({ node, messageId: "unexpectedProcessEnv" }) }, } diff --git a/tests/lib/rules/no-process-env.js b/tests/lib/rules/no-process-env.js index 29ce6a39..25cb986c 100644 --- a/tests/lib/rules/no-process-env.js +++ b/tests/lib/rules/no-process-env.js @@ -13,6 +13,24 @@ new RuleTester().run("no-process-env", rule, { "process[env]", "process.nextTick", "process.execArgv", + + // allowedVariables + { + code: "process.env.NODE_ENV", + options: [{ allowedVariables: ["NODE_ENV"] }], + }, + { + code: "process.env['NODE_ENV']", + options: [{ allowedVariables: ["NODE_ENV"] }], + }, + { + code: "process['env'].NODE_ENV", + options: [{ allowedVariables: ["NODE_ENV"] }], + }, + { + code: "process['env']['NODE_ENV']", + options: [{ allowedVariables: ["NODE_ENV"] }], + }, ], invalid: [ @@ -25,6 +43,15 @@ new RuleTester().run("no-process-env", rule, { }, ], }, + { + code: "process['env']", + errors: [ + { + messageId: "unexpectedProcessEnv", + type: "MemberExpression", + }, + ], + }, { code: "process.env.ENV", errors: [ @@ -43,5 +70,37 @@ new RuleTester().run("no-process-env", rule, { }, ], }, + + // allowedVariables + { + code: "process.env['OTHER_VARIABLE']", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, + { + code: "process.env.OTHER_VARIABLE", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, + { + code: "process['env']['OTHER_VARIABLE']", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, + { + code: "process['env'].OTHER_VARIABLE", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, + { + code: "process.env[NODE_ENV]", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, + { + code: "process['env'][NODE_ENV]", + options: [{ allowedVariables: ["NODE_ENV"] }], + errors: [{ messageId: "unexpectedProcessEnv" }], + }, ], })