@sister.software/oxlint-config 9.2.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/index.d.ts +5 -0
- package/out/index.d.ts.map +1 -1
- package/out/index.js +8 -2
- package/out/index.js.map +1 -1
- package/out/plugin.d.ts.map +1 -1
- package/out/plugin.js +2 -0
- package/out/plugin.js.map +1 -1
- package/out/process-globals-plugin.d.ts +13 -0
- package/out/process-globals-plugin.d.ts.map +1 -0
- package/out/process-globals-plugin.js +48 -0
- package/out/process-globals-plugin.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +14 -1
- package/src/plugin.ts +2 -0
- package/src/process-globals-plugin.ts +68 -0
package/out/index.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export interface OxlintConfigOptions {
|
|
|
25
25
|
padding?: boolean;
|
|
26
26
|
/** Require braces around single-statement work bodies (bare `return` exempt; on by default). */
|
|
27
27
|
braces?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Forbid direct `process.env` / `process.argv` access (off by default). Turn on once the project funnels those reads
|
|
30
|
+
* through blessed helpers, which disable `sister-software/no-process-globals`.
|
|
31
|
+
*/
|
|
32
|
+
restrictProcessGlobals?: boolean;
|
|
28
33
|
/** Override the default ignore patterns. */
|
|
29
34
|
ignorePatterns?: string[];
|
|
30
35
|
/** Extra config deep-merged last; an escape hatch for per-repo tweaks. */
|
package/out/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,cAAc,mBAAmB,CAAA;AAEjC,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElD,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,UAOjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,cAAc,mBAAmB,CAAA;AAEjC,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElD,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,UAOjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAkFlF;AAED,eAAe,kBAAkB,CAAA"}
|
package/out/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export const DefaultIgnorePatterns = [
|
|
|
30
30
|
* @returns A complete oxlint config object (no `extends` required).
|
|
31
31
|
*/
|
|
32
32
|
export function createOxlintConfig(options = {}) {
|
|
33
|
-
const { packageNamespace = "@sister.software", copyrightHolder = "Sister Software", spdxLicenseIdentifier = "UNLICENSED", author = "Teffen Ellis, et al.", react = false, headers = true, padding = true, braces = true, ignorePatterns = DefaultIgnorePatterns, overrides = {}, } = options;
|
|
33
|
+
const { packageNamespace = "@sister.software", copyrightHolder = "Sister Software", spdxLicenseIdentifier = "UNLICENSED", author = "Teffen Ellis, et al.", react = false, headers = true, padding = true, braces = true, restrictProcessGlobals = false, ignorePatterns = DefaultIgnorePatterns, overrides = {}, } = options;
|
|
34
34
|
const plugins = ["typescript", "unicorn", "oxc", ...(react ? ["react"] : [])];
|
|
35
35
|
const rules = {
|
|
36
36
|
// JavaScript
|
|
@@ -76,9 +76,15 @@ export function createOxlintConfig(options = {}) {
|
|
|
76
76
|
// Warning severity: a stylistic nudge (auto-fixable), not a hard CI gate.
|
|
77
77
|
rules["sister-software/require-braces"] = "warn";
|
|
78
78
|
}
|
|
79
|
+
if (restrictProcessGlobals) {
|
|
80
|
+
// Error severity: a governance gate — direct env/argv access should fail the lint.
|
|
81
|
+
rules["sister-software/no-process-globals"] = "error";
|
|
82
|
+
}
|
|
79
83
|
return {
|
|
80
84
|
plugins,
|
|
81
|
-
...(headers || padding || braces
|
|
85
|
+
...(headers || padding || braces || restrictProcessGlobals
|
|
86
|
+
? { jsPlugins: ["@sister.software/oxlint-config/plugin"] }
|
|
87
|
+
: {}),
|
|
82
88
|
categories: { correctness: "error" },
|
|
83
89
|
ignorePatterns,
|
|
84
90
|
rules,
|
package/out/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,cAAc,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/out/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAG/C,QAAA,MAAM,oBAAoB,EAAE,MAQ3B,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
package/out/plugin.js
CHANGED
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
import { bracesRule } from "./braces-plugin.js";
|
|
9
9
|
import { headerRule } from "./headers-plugin.js";
|
|
10
10
|
import { paddingRule } from "./padding-plugin.js";
|
|
11
|
+
import { noProcessGlobalsRule } from "./process-globals-plugin.js";
|
|
11
12
|
const sisterSoftwarePlugin = {
|
|
12
13
|
meta: { name: "sister-software" },
|
|
13
14
|
rules: {
|
|
14
15
|
"require-file-header": headerRule,
|
|
15
16
|
"padding-lines": paddingRule,
|
|
16
17
|
"require-braces": bracesRule,
|
|
18
|
+
"no-process-globals": noProcessGlobalsRule,
|
|
17
19
|
},
|
|
18
20
|
};
|
|
19
21
|
export default sisterSoftwarePlugin;
|
package/out/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAElE,MAAM,oBAAoB,GAAW;IACpC,IAAI,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;IACjC,KAAK,EAAE;QACN,qBAAqB,EAAE,UAAU;QACjC,eAAe,EAAE,WAAW;QAC5B,gBAAgB,EAAE,UAAU;QAC5B,oBAAoB,EAAE,oBAAoB;KAC1C;CACD,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
* @file A no-process-globals rule, authored as an oxlint JS plugin (ESLint v9-compatible API). It
|
|
6
|
+
* forbids direct `process.env` / `process.argv` access so those reads can be funneled through a
|
|
7
|
+
* few blessed helpers; the helper files disable the rule (`sister-software/no-process-globals`).
|
|
8
|
+
* oxlint has no `no-restricted-syntax`, so this is a small dedicated rule instead.
|
|
9
|
+
*/
|
|
10
|
+
import type { Rule } from "./plugin-types.js";
|
|
11
|
+
export declare const noProcessGlobalsRule: Rule;
|
|
12
|
+
export default noProcessGlobalsRule;
|
|
13
|
+
//# sourceMappingURL=process-globals-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-globals-plugin.d.ts","sourceRoot":"","sources":["../src/process-globals-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,mBAAmB,CAAA;AA+BtD,eAAO,MAAM,oBAAoB,EAAE,IAwBlC,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
* @file A no-process-globals rule, authored as an oxlint JS plugin (ESLint v9-compatible API). It
|
|
6
|
+
* forbids direct `process.env` / `process.argv` access so those reads can be funneled through a
|
|
7
|
+
* few blessed helpers; the helper files disable the rule (`sister-software/no-process-globals`).
|
|
8
|
+
* oxlint has no `no-restricted-syntax`, so this is a small dedicated rule instead.
|
|
9
|
+
*/
|
|
10
|
+
/** `process` members that must be reached through a blessed helper, not accessed directly. */
|
|
11
|
+
const RESTRICTED_MEMBERS = new Set(["env", "argv"]);
|
|
12
|
+
/** The accessed member name for `process.env` (identifier) or `process["env"]` (string literal). */
|
|
13
|
+
function accessedMember(node) {
|
|
14
|
+
const property = node.property;
|
|
15
|
+
if (!property)
|
|
16
|
+
return null;
|
|
17
|
+
if (!node.computed && property.type === "Identifier")
|
|
18
|
+
return property.name ?? null;
|
|
19
|
+
if (node.computed && (property.type === "Literal" || property.type === "StringLiteral")) {
|
|
20
|
+
return typeof property.value === "string" ? property.value : null;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
export const noProcessGlobalsRule = {
|
|
25
|
+
meta: {
|
|
26
|
+
name: "no-process-globals",
|
|
27
|
+
type: "problem",
|
|
28
|
+
schema: [{ type: "object", additionalProperties: true }],
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
return {
|
|
32
|
+
MemberExpression(node) {
|
|
33
|
+
const member = node;
|
|
34
|
+
if (member.object?.type !== "Identifier" || member.object.name !== "process")
|
|
35
|
+
return;
|
|
36
|
+
const name = accessedMember(member);
|
|
37
|
+
if (!name || !RESTRICTED_MEMBERS.has(name))
|
|
38
|
+
return;
|
|
39
|
+
context.report({
|
|
40
|
+
node,
|
|
41
|
+
message: `Direct \`process.${name}\` access is restricted — read it through the project's blessed helper (disable \`sister-software/no-process-globals\` there).`,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
export default noProcessGlobalsRule;
|
|
48
|
+
//# sourceMappingURL=process-globals-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-globals-plugin.js","sourceRoot":"","sources":["../src/process-globals-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,8FAA8F;AAC9F,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;AAanD,oGAAoG;AACpG,SAAS,cAAc,CAAC,IAAgB;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;IAE9B,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAE1B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAA;IAElF,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,eAAe,CAAC,EAAE,CAAC;QACzF,OAAO,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAClE,CAAC;IAED,OAAO,IAAI,CAAA;AACZ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACzC,IAAI,EAAE;QACL,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC;KACxD;IACD,MAAM,CAAC,OAAO;QACb,OAAO;YACN,gBAAgB,CAAC,IAAI;gBACpB,MAAM,MAAM,GAAG,IAAkB,CAAA;gBAEjC,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;oBAAE,OAAM;gBAEpF,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;gBAEnC,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,OAAM;gBAElD,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI;oBACJ,OAAO,EAAE,oBAAoB,IAAI,gIAAgI;iBACjK,CAAC,CAAA;YACH,CAAC;SACD,CAAA;IACF,CAAC;CACD,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -30,6 +30,11 @@ export interface OxlintConfigOptions {
|
|
|
30
30
|
padding?: boolean
|
|
31
31
|
/** Require braces around single-statement work bodies (bare `return` exempt; on by default). */
|
|
32
32
|
braces?: boolean
|
|
33
|
+
/**
|
|
34
|
+
* Forbid direct `process.env` / `process.argv` access (off by default). Turn on once the project funnels those reads
|
|
35
|
+
* through blessed helpers, which disable `sister-software/no-process-globals`.
|
|
36
|
+
*/
|
|
37
|
+
restrictProcessGlobals?: boolean
|
|
33
38
|
/** Override the default ignore patterns. */
|
|
34
39
|
ignorePatterns?: string[]
|
|
35
40
|
/** Extra config deep-merged last; an escape hatch for per-repo tweaks. */
|
|
@@ -70,6 +75,7 @@ export function createOxlintConfig(options: OxlintConfigOptions = {}): OxlintCon
|
|
|
70
75
|
headers = true,
|
|
71
76
|
padding = true,
|
|
72
77
|
braces = true,
|
|
78
|
+
restrictProcessGlobals = false,
|
|
73
79
|
ignorePatterns = DefaultIgnorePatterns,
|
|
74
80
|
overrides = {},
|
|
75
81
|
} = options
|
|
@@ -125,9 +131,16 @@ export function createOxlintConfig(options: OxlintConfigOptions = {}): OxlintCon
|
|
|
125
131
|
rules["sister-software/require-braces"] = "warn"
|
|
126
132
|
}
|
|
127
133
|
|
|
134
|
+
if (restrictProcessGlobals) {
|
|
135
|
+
// Error severity: a governance gate — direct env/argv access should fail the lint.
|
|
136
|
+
rules["sister-software/no-process-globals"] = "error"
|
|
137
|
+
}
|
|
138
|
+
|
|
128
139
|
return {
|
|
129
140
|
plugins,
|
|
130
|
-
...(headers || padding || braces
|
|
141
|
+
...(headers || padding || braces || restrictProcessGlobals
|
|
142
|
+
? { jsPlugins: ["@sister.software/oxlint-config/plugin"] }
|
|
143
|
+
: {}),
|
|
131
144
|
categories: { correctness: "error" },
|
|
132
145
|
ignorePatterns,
|
|
133
146
|
rules,
|
package/src/plugin.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { bracesRule } from "./braces-plugin.js"
|
|
|
10
10
|
import { headerRule } from "./headers-plugin.js"
|
|
11
11
|
import { paddingRule } from "./padding-plugin.js"
|
|
12
12
|
import type { Plugin } from "./plugin-types.js"
|
|
13
|
+
import { noProcessGlobalsRule } from "./process-globals-plugin.js"
|
|
13
14
|
|
|
14
15
|
const sisterSoftwarePlugin: Plugin = {
|
|
15
16
|
meta: { name: "sister-software" },
|
|
@@ -17,6 +18,7 @@ const sisterSoftwarePlugin: Plugin = {
|
|
|
17
18
|
"require-file-header": headerRule,
|
|
18
19
|
"padding-lines": paddingRule,
|
|
19
20
|
"require-braces": bracesRule,
|
|
21
|
+
"no-process-globals": noProcessGlobalsRule,
|
|
20
22
|
},
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
* @file A no-process-globals rule, authored as an oxlint JS plugin (ESLint v9-compatible API). It
|
|
6
|
+
* forbids direct `process.env` / `process.argv` access so those reads can be funneled through a
|
|
7
|
+
* few blessed helpers; the helper files disable the rule (`sister-software/no-process-globals`).
|
|
8
|
+
* oxlint has no `no-restricted-syntax`, so this is a small dedicated rule instead.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { AstNode, Rule } from "./plugin-types.js"
|
|
12
|
+
|
|
13
|
+
/** `process` members that must be reached through a blessed helper, not accessed directly. */
|
|
14
|
+
const RESTRICTED_MEMBERS = new Set(["env", "argv"])
|
|
15
|
+
|
|
16
|
+
interface Identifierish extends AstNode {
|
|
17
|
+
name?: string
|
|
18
|
+
value?: unknown
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface MemberNode extends AstNode {
|
|
22
|
+
object?: Identifierish
|
|
23
|
+
property?: Identifierish
|
|
24
|
+
computed?: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The accessed member name for `process.env` (identifier) or `process["env"]` (string literal). */
|
|
28
|
+
function accessedMember(node: MemberNode): string | null {
|
|
29
|
+
const property = node.property
|
|
30
|
+
|
|
31
|
+
if (!property) return null
|
|
32
|
+
|
|
33
|
+
if (!node.computed && property.type === "Identifier") return property.name ?? null
|
|
34
|
+
|
|
35
|
+
if (node.computed && (property.type === "Literal" || property.type === "StringLiteral")) {
|
|
36
|
+
return typeof property.value === "string" ? property.value : null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const noProcessGlobalsRule: Rule = {
|
|
43
|
+
meta: {
|
|
44
|
+
name: "no-process-globals",
|
|
45
|
+
type: "problem",
|
|
46
|
+
schema: [{ type: "object", additionalProperties: true }],
|
|
47
|
+
},
|
|
48
|
+
create(context) {
|
|
49
|
+
return {
|
|
50
|
+
MemberExpression(node) {
|
|
51
|
+
const member = node as MemberNode
|
|
52
|
+
|
|
53
|
+
if (member.object?.type !== "Identifier" || member.object.name !== "process") return
|
|
54
|
+
|
|
55
|
+
const name = accessedMember(member)
|
|
56
|
+
|
|
57
|
+
if (!name || !RESTRICTED_MEMBERS.has(name)) return
|
|
58
|
+
|
|
59
|
+
context.report({
|
|
60
|
+
node,
|
|
61
|
+
message: `Direct \`process.${name}\` access is restricted — read it through the project's blessed helper (disable \`sister-software/no-process-globals\` there).`,
|
|
62
|
+
})
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default noProcessGlobalsRule
|