@zukhruf/eslint 0.1.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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/authoring/ast.d.ts +10 -0
- package/dist/authoring/ast.d.ts.map +1 -0
- package/dist/authoring/ast.js +22 -0
- package/dist/authoring/ast.js.map +1 -0
- package/dist/authoring/import-ban.d.ts +14 -0
- package/dist/authoring/import-ban.d.ts.map +1 -0
- package/dist/authoring/import-ban.js +32 -0
- package/dist/authoring/import-ban.js.map +1 -0
- package/dist/authoring/path-scope.d.ts +12 -0
- package/dist/authoring/path-scope.d.ts.map +1 -0
- package/dist/authoring/path-scope.js +28 -0
- package/dist/authoring/path-scope.js.map +1 -0
- package/dist/authoring/rule-module.d.ts +14 -0
- package/dist/authoring/rule-module.d.ts.map +1 -0
- package/dist/authoring/rule-module.js +23 -0
- package/dist/authoring/rule-module.js.map +1 -0
- package/dist/authoring/scoped-rule.d.ts +8 -0
- package/dist/authoring/scoped-rule.d.ts.map +1 -0
- package/dist/authoring/scoped-rule.js +12 -0
- package/dist/authoring/scoped-rule.js.map +1 -0
- package/dist/authoring/selector-rule.d.ts +17 -0
- package/dist/authoring/selector-rule.d.ts.map +1 -0
- package/dist/authoring/selector-rule.js +23 -0
- package/dist/authoring/selector-rule.js.map +1 -0
- package/dist/base/config.d.ts +8 -0
- package/dist/base/config.d.ts.map +1 -0
- package/dist/base/config.js +122 -0
- package/dist/base/config.js.map +1 -0
- package/dist/base/options.d.ts +23 -0
- package/dist/base/options.d.ts.map +1 -0
- package/dist/base/options.js +22 -0
- package/dist/base/options.js.map +1 -0
- package/dist/concept.d.ts +16 -0
- package/dist/concept.d.ts.map +1 -0
- package/dist/concept.js +5 -0
- package/dist/concept.js.map +1 -0
- package/dist/diagnostics/config.d.ts +4 -0
- package/dist/diagnostics/config.d.ts.map +1 -0
- package/dist/diagnostics/config.js +25 -0
- package/dist/diagnostics/config.js.map +1 -0
- package/dist/diagnostics/consistent-event-name.d.ts +4 -0
- package/dist/diagnostics/consistent-event-name.d.ts.map +1 -0
- package/dist/diagnostics/consistent-event-name.js +72 -0
- package/dist/diagnostics/consistent-event-name.js.map +1 -0
- package/dist/diagnostics/no-fabricated-fallback.d.ts +4 -0
- package/dist/diagnostics/no-fabricated-fallback.d.ts.map +1 -0
- package/dist/diagnostics/no-fabricated-fallback.js +116 -0
- package/dist/diagnostics/no-fabricated-fallback.js.map +1 -0
- package/dist/diagnostics/no-hardcoded-id-shape.d.ts +4 -0
- package/dist/diagnostics/no-hardcoded-id-shape.d.ts.map +1 -0
- package/dist/diagnostics/no-hardcoded-id-shape.js +73 -0
- package/dist/diagnostics/no-hardcoded-id-shape.js.map +1 -0
- package/dist/environment/config.d.ts +7 -0
- package/dist/environment/config.d.ts.map +1 -0
- package/dist/environment/config.js +28 -0
- package/dist/environment/config.js.map +1 -0
- package/dist/environment/no-default-for-path-env.d.ts +10 -0
- package/dist/environment/no-default-for-path-env.d.ts.map +1 -0
- package/dist/environment/no-default-for-path-env.js +124 -0
- package/dist/environment/no-default-for-path-env.js.map +1 -0
- package/dist/environment/no-single-env-read-wrapper.d.ts +10 -0
- package/dist/environment/no-single-env-read-wrapper.d.ts.map +1 -0
- package/dist/environment/no-single-env-read-wrapper.js +76 -0
- package/dist/environment/no-single-env-read-wrapper.js.map +1 -0
- package/dist/environment/no-undeclared-process-env.d.ts +11 -0
- package/dist/environment/no-undeclared-process-env.d.ts.map +1 -0
- package/dist/environment/no-undeclared-process-env.js +195 -0
- package/dist/environment/no-undeclared-process-env.js.map +1 -0
- package/dist/files.d.ts +16 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +27 -0
- package/dist/files.js.map +1 -0
- package/dist/hono/config.d.ts +3 -0
- package/dist/hono/config.d.ts.map +1 -0
- package/dist/hono/config.js +18 -0
- package/dist/hono/config.js.map +1 -0
- package/dist/hono/no-untyped-empty-json.d.ts +8 -0
- package/dist/hono/no-untyped-empty-json.d.ts.map +1 -0
- package/dist/hono/no-untyped-empty-json.js +14 -0
- package/dist/hono/no-untyped-empty-json.js.map +1 -0
- package/dist/imports/no-deepagents-agent.d.ts +3 -0
- package/dist/imports/no-deepagents-agent.d.ts.map +1 -0
- package/dist/imports/no-deepagents-agent.js +7 -0
- package/dist/imports/no-deepagents-agent.js.map +1 -0
- package/dist/imports/no-playwright-test.d.ts +3 -0
- package/dist/imports/no-playwright-test.d.ts.map +1 -0
- package/dist/imports/no-playwright-test.js +7 -0
- package/dist/imports/no-playwright-test.js.map +1 -0
- package/dist/imports/no-state-managers.d.ts +3 -0
- package/dist/imports/no-state-managers.d.ts.map +1 -0
- package/dist/imports/no-state-managers.js +15 -0
- package/dist/imports/no-state-managers.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/island/island-scope.d.ts +10 -0
- package/dist/island/island-scope.d.ts.map +1 -0
- package/dist/island/island-scope.js +21 -0
- package/dist/island/island-scope.js.map +1 -0
- package/dist/island/no-console.d.ts +9 -0
- package/dist/island/no-console.d.ts.map +1 -0
- package/dist/island/no-console.js +39 -0
- package/dist/island/no-console.js.map +1 -0
- package/dist/island/no-generic-port.d.ts +8 -0
- package/dist/island/no-generic-port.d.ts.map +1 -0
- package/dist/island/no-generic-port.js +14 -0
- package/dist/island/no-generic-port.js.map +1 -0
- package/dist/island/no-process-env.d.ts +3 -0
- package/dist/island/no-process-env.d.ts.map +1 -0
- package/dist/island/no-process-env.js +10 -0
- package/dist/island/no-process-env.js.map +1 -0
- package/dist/island/plugin.d.ts +25 -0
- package/dist/island/plugin.d.ts.map +1 -0
- package/dist/island/plugin.js +67 -0
- package/dist/island/plugin.js.map +1 -0
- package/dist/language/no-enum.d.ts +3 -0
- package/dist/language/no-enum.d.ts.map +1 -0
- package/dist/language/no-enum.js +7 -0
- package/dist/language/no-enum.js.map +1 -0
- package/dist/nx-policy/dependency-policy.d.ts +30 -0
- package/dist/nx-policy/dependency-policy.d.ts.map +1 -0
- package/dist/nx-policy/dependency-policy.js +31 -0
- package/dist/nx-policy/dependency-policy.js.map +1 -0
- package/dist/nx-policy/island-constraint.d.ts +10 -0
- package/dist/nx-policy/island-constraint.d.ts.map +1 -0
- package/dist/nx-policy/island-constraint.js +15 -0
- package/dist/nx-policy/island-constraint.js.map +1 -0
- package/dist/nx-policy/module-boundaries.d.ts +29 -0
- package/dist/nx-policy/module-boundaries.d.ts.map +1 -0
- package/dist/nx-policy/module-boundaries.js +20 -0
- package/dist/nx-policy/module-boundaries.js.map +1 -0
- package/dist/nx-project/config.d.ts +4 -0
- package/dist/nx-project/config.d.ts.map +1 -0
- package/dist/nx-project/config.js +20 -0
- package/dist/nx-project/config.js.map +1 -0
- package/dist/nx-project/no-missing-asset-input.d.ts +9 -0
- package/dist/nx-project/no-missing-asset-input.d.ts.map +1 -0
- package/dist/nx-project/no-missing-asset-input.js +209 -0
- package/dist/nx-project/no-missing-asset-input.js.map +1 -0
- package/dist/nx.d.ts +5 -0
- package/dist/nx.d.ts.map +1 -0
- package/dist/nx.js +5 -0
- package/dist/nx.js.map +1 -0
- package/dist/packaged-app/config.d.ts +4 -0
- package/dist/packaged-app/config.d.ts.map +1 -0
- package/dist/packaged-app/config.js +19 -0
- package/dist/packaged-app/config.js.map +1 -0
- package/dist/packaged-app/no-bare-spawn.d.ts +4 -0
- package/dist/packaged-app/no-bare-spawn.d.ts.map +1 -0
- package/dist/packaged-app/no-bare-spawn.js +175 -0
- package/dist/packaged-app/no-bare-spawn.js.map +1 -0
- package/dist/plugin.d.ts +14 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +48 -0
- package/dist/plugin.js.map +1 -0
- package/dist/pulumi/config.d.ts +3 -0
- package/dist/pulumi/config.d.ts.map +1 -0
- package/dist/pulumi/config.js +17 -0
- package/dist/pulumi/config.js.map +1 -0
- package/dist/pulumi/require-server-replace-guard.d.ts +4 -0
- package/dist/pulumi/require-server-replace-guard.d.ts.map +1 -0
- package/dist/pulumi/require-server-replace-guard.js +120 -0
- package/dist/pulumi/require-server-replace-guard.js.map +1 -0
- package/dist/react/config.d.ts +4 -0
- package/dist/react/config.d.ts.map +1 -0
- package/dist/react/config.js +13 -0
- package/dist/react/config.js.map +1 -0
- package/dist/react/require-combobox-popover-modal.d.ts +10 -0
- package/dist/react/require-combobox-popover-modal.d.ts.map +1 -0
- package/dist/react/require-combobox-popover-modal.js +101 -0
- package/dist/react/require-combobox-popover-modal.js.map +1 -0
- package/dist/react-router/config.d.ts +3 -0
- package/dist/react-router/config.d.ts.map +1 -0
- package/dist/react-router/config.js +34 -0
- package/dist/react-router/config.js.map +1 -0
- package/dist/react-router/no-internal-anchor.d.ts +8 -0
- package/dist/react-router/no-internal-anchor.d.ts.map +1 -0
- package/dist/react-router/no-internal-anchor.js +14 -0
- package/dist/react-router/no-internal-anchor.js.map +1 -0
- package/dist/react-router/no-raw-route-path.d.ts +9 -0
- package/dist/react-router/no-raw-route-path.d.ts.map +1 -0
- package/dist/react-router/no-raw-route-path.js +17 -0
- package/dist/react-router/no-raw-route-path.js.map +1 -0
- package/dist/react-router/require-loader-data-type-argument.d.ts +10 -0
- package/dist/react-router/require-loader-data-type-argument.d.ts.map +1 -0
- package/dist/react-router/require-loader-data-type-argument.js +16 -0
- package/dist/react-router/require-loader-data-type-argument.js.map +1 -0
- package/dist/tailwind/class-name-check.d.ts +12 -0
- package/dist/tailwind/class-name-check.d.ts.map +1 -0
- package/dist/tailwind/class-name-check.js +16 -0
- package/dist/tailwind/class-name-check.js.map +1 -0
- package/dist/tailwind/config.d.ts +3 -0
- package/dist/tailwind/config.d.ts.map +1 -0
- package/dist/tailwind/config.js +18 -0
- package/dist/tailwind/config.js.map +1 -0
- package/dist/tailwind/no-arbitrary-z-index.d.ts +3 -0
- package/dist/tailwind/no-arbitrary-z-index.d.ts.map +1 -0
- package/dist/tailwind/no-arbitrary-z-index.js +7 -0
- package/dist/tailwind/no-arbitrary-z-index.js.map +1 -0
- package/dist/tailwind/no-h-screen.d.ts +3 -0
- package/dist/tailwind/no-h-screen.d.ts.map +1 -0
- package/dist/tailwind/no-h-screen.js +7 -0
- package/dist/tailwind/no-h-screen.js.map +1 -0
- package/dist/tailwind/no-will-change.d.ts +3 -0
- package/dist/tailwind/no-will-change.d.ts.map +1 -0
- package/dist/tailwind/no-will-change.js +7 -0
- package/dist/tailwind/no-will-change.js.map +1 -0
- package/dist/test-files/config.d.ts +3 -0
- package/dist/test-files/config.d.ts.map +1 -0
- package/dist/test-files/config.js +16 -0
- package/dist/test-files/config.js.map +1 -0
- package/dist/test-files/no-test-lifecycle-hooks.d.ts +3 -0
- package/dist/test-files/no-test-lifecycle-hooks.d.ts.map +1 -0
- package/dist/test-files/no-test-lifecycle-hooks.js +9 -0
- package/dist/test-files/no-test-lifecycle-hooks.js.map +1 -0
- package/dist/test-files/require-msw-error-on-unhandled-request.d.ts +10 -0
- package/dist/test-files/require-msw-error-on-unhandled-request.d.ts.map +1 -0
- package/dist/test-files/require-msw-error-on-unhandled-request.js +16 -0
- package/dist/test-files/require-msw-error-on-unhandled-request.js.map +1 -0
- package/dist/workspace/project-manifest.d.ts +14 -0
- package/dist/workspace/project-manifest.d.ts.map +1 -0
- package/dist/workspace/project-manifest.js +45 -0
- package/dist/workspace/project-manifest.js.map +1 -0
- package/dist/workspace/workspace-root.d.ts +12 -0
- package/dist/workspace/workspace-root.d.ts.map +1 -0
- package/dist/workspace/workspace-root.js +46 -0
- package/dist/workspace/workspace-root.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Re-declaring a third-party rule replaces every option the base config gave
|
|
2
|
+
// it: `'functional/no-let': ['error', { ignoreIdentifierPattern }]` drops
|
|
3
|
+
// `allowInFunctions`, and every `let` inside a function becomes an error.
|
|
4
|
+
// These factories return the complete options with the repo's entries
|
|
5
|
+
// appended, so extending a base rule never loses the base's own.
|
|
6
|
+
/** Options for `functional/no-let`: no mutable state at module scope; locals and loop counters stay legal. */
|
|
7
|
+
export function noLet({ ignoreIdentifierPattern = [] } = {}) {
|
|
8
|
+
return { allowInFunctions: true, ignoreIdentifierPattern };
|
|
9
|
+
}
|
|
10
|
+
// node:test's test/it/describe/suite return a Promise the runner owns.
|
|
11
|
+
const NODE_TEST_CALLS = {
|
|
12
|
+
from: 'package',
|
|
13
|
+
package: 'node:test',
|
|
14
|
+
name: ['test', 'it', 'describe', 'suite'],
|
|
15
|
+
};
|
|
16
|
+
/** Options for `@typescript-eslint/no-floating-promises`, with node:test's calls already allowed. */
|
|
17
|
+
export function noFloatingPromises({ allowForKnownSafeCalls = [], } = {}) {
|
|
18
|
+
return {
|
|
19
|
+
allowForKnownSafeCalls: [NODE_TEST_CALLS, ...allowForKnownSafeCalls],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/base/options.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,0EAA0E;AAC1E,0EAA0E;AAC1E,sEAAsE;AACtE,iEAAiE;AAOjE,8GAA8G;AAC9G,MAAM,UAAU,KAAK,CAAC,EAAE,uBAAuB,GAAG,EAAE,KAAmB,EAAE;IACvE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;AAC7D,CAAC;AAaD,uEAAuE;AACvE,MAAM,eAAe,GAAa;IAChC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,WAAW;IACpB,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC;CAC1C,CAAC;AAEF,qGAAqG;AACrG,MAAM,UAAU,kBAAkB,CAAC,EACjC,sBAAsB,GAAG,EAAE,MACE,EAAE;IAC/B,OAAO;QACL,sBAAsB,EAAE,CAAC,eAAe,EAAE,GAAG,sBAAsB,CAAC;KACrE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ESLint, Linter, Rule } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* One concern the package lints (React Router links, Tailwind classes, …): its
|
|
4
|
+
* rules and the config that turns them on. A consumer picks concerns by config
|
|
5
|
+
* name (`extends: ['zukhruf/react-router']`).
|
|
6
|
+
*/
|
|
7
|
+
export interface Concept {
|
|
8
|
+
/** The config's name; consumers extend `zukhruf/<name>`. */
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly rules: Readonly<Record<string, Rule.RuleModule>>;
|
|
11
|
+
/** Builds the config; `plugins` registers this package's plugin. */
|
|
12
|
+
config(plugins: Readonly<Record<string, ESLint.Plugin>>): Linter.Config[];
|
|
13
|
+
}
|
|
14
|
+
/** `severity` for every rule of `rules`, under the plugin's `zukhruf/` prefix. */
|
|
15
|
+
export declare function enable(rules: Readonly<Record<string, Rule.RuleModule>>, severity?: Linter.RuleSeverity): Linter.RulesRecord;
|
|
16
|
+
//# sourceMappingURL=concept.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concept.d.ts","sourceRoot":"","sources":["../src/concept.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1D,oEAAoE;IACpE,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;CAC3E;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CACpB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAChD,QAAQ,GAAE,MAAM,CAAC,YAAsB,GACtC,MAAM,CAAC,WAAW,CAIpB"}
|
package/dist/concept.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** `severity` for every rule of `rules`, under the plugin's `zukhruf/` prefix. */
|
|
2
|
+
export function enable(rules, severity = 'error') {
|
|
3
|
+
return Object.fromEntries(Object.keys(rules).map((name) => [`zukhruf/${name}`, severity]));
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=concept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concept.js","sourceRoot":"","sources":["../src/concept.ts"],"names":[],"mappings":"AAeA,kFAAkF;AAClF,MAAM,UAAU,MAAM,CACpB,KAAgD,EAChD,WAAgC,OAAO;IAEvC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC,CAChE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/diagnostics/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAYrD,gFAAgF;AAChF,eAAO,MAAM,WAAW,EAAE,OAYzB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { enable } from "../concept.js";
|
|
2
|
+
import { SOURCE, TESTS } from "../files.js";
|
|
3
|
+
import consistentEventName from "./consistent-event-name.js";
|
|
4
|
+
import noFabricatedFallback from "./no-fabricated-fallback.js";
|
|
5
|
+
import noHardcodedIdShape from "./no-hardcoded-id-shape.js";
|
|
6
|
+
const rules = {
|
|
7
|
+
'no-fabricated-fallback': noFabricatedFallback,
|
|
8
|
+
'no-hardcoded-id-shape': noHardcodedIdShape,
|
|
9
|
+
'consistent-event-name': consistentEventName,
|
|
10
|
+
};
|
|
11
|
+
/** Code that reports what happened: fallbacks, id matching, log event names. */
|
|
12
|
+
export const diagnostics = {
|
|
13
|
+
name: 'diagnostics',
|
|
14
|
+
rules,
|
|
15
|
+
config: (plugins) => [
|
|
16
|
+
{
|
|
17
|
+
name: 'zukhruf/diagnostics',
|
|
18
|
+
files: SOURCE,
|
|
19
|
+
ignores: TESTS,
|
|
20
|
+
plugins,
|
|
21
|
+
rules: enable(rules),
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/diagnostics/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,oBAAoB,MAAM,6BAA6B,CAAC;AAC/D,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAE5D,MAAM,KAAK,GAAG;IACZ,wBAAwB,EAAE,oBAAoB;IAC9C,uBAAuB,EAAE,kBAAkB;IAC3C,uBAAuB,EAAE,mBAAmB;CAC7C,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,IAAI,EAAE,aAAa;IACnB,KAAK;IACL,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;QACnB;YACE,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,KAAK;YACd,OAAO;YACP,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-event-name.d.ts","sourceRoot":"","sources":["../../src/diagnostics/consistent-event-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAuDnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAyBhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { identifierName, isAstNode, isType, } from "../authoring/ast.js";
|
|
2
|
+
/**
|
|
3
|
+
* Log event names are a query surface, not free text. A codebase that runs two
|
|
4
|
+
* conventions at once, dotted-lowercase in one service and snake_case in
|
|
5
|
+
* another, gives the same failure two names (`chat.run.failed` and
|
|
6
|
+
* `chat_run_failed`), and an alert or dashboard written against one name is
|
|
7
|
+
* blind to the other.
|
|
8
|
+
*
|
|
9
|
+
* Dotted-lowercase wins because it is hierarchical: `dashboard.*` and
|
|
10
|
+
* `*.failed` are prefix filters, and it matches OpenTelemetry's dotted
|
|
11
|
+
* attribute keys.
|
|
12
|
+
*
|
|
13
|
+
* Segments allow internal hyphens (`data-source.staged-file.cleanup.failed`,
|
|
14
|
+
* `auto-update.staged`) because some domains are genuinely two words.
|
|
15
|
+
*/
|
|
16
|
+
const EVENT_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\.[a-z0-9]+(?:-[a-z0-9]+)*)+$/;
|
|
17
|
+
/** `event` written bare or quoted. */
|
|
18
|
+
function isEventKey(node) {
|
|
19
|
+
if (identifierName(node) === 'event')
|
|
20
|
+
return true;
|
|
21
|
+
return isType(node, 'Literal') && node['value'] === 'event';
|
|
22
|
+
}
|
|
23
|
+
function literalString(node) {
|
|
24
|
+
if (!isType(node, 'Literal'))
|
|
25
|
+
return undefined;
|
|
26
|
+
const value = node['value'];
|
|
27
|
+
return typeof value === 'string' ? value : undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Both arms of `cond ? 'a' : 'b'`, so a ternary event name is still checked.
|
|
31
|
+
*
|
|
32
|
+
* Takes `unknown` like the helpers in ast.ts: an ESTree `Expression` has no
|
|
33
|
+
* `parent`, so it is not assignable to `Rule.Node`. For the same reason a
|
|
34
|
+
* ternary's branches cannot be passed to `context.report`, and the report is
|
|
35
|
+
* anchored on the property instead.
|
|
36
|
+
*/
|
|
37
|
+
function candidateValues(node) {
|
|
38
|
+
if (isType(node, 'ConditionalExpression')) {
|
|
39
|
+
const consequent = node['consequent'];
|
|
40
|
+
const alternate = node['alternate'];
|
|
41
|
+
return [consequent, alternate].filter((v) => isAstNode(v));
|
|
42
|
+
}
|
|
43
|
+
return isAstNode(node) ? [node] : [];
|
|
44
|
+
}
|
|
45
|
+
const rule = {
|
|
46
|
+
meta: {
|
|
47
|
+
type: 'problem',
|
|
48
|
+
docs: {
|
|
49
|
+
description: 'Require log event names to be dotted-lowercase, so one failure has one name everywhere it is logged.',
|
|
50
|
+
},
|
|
51
|
+
schema: [],
|
|
52
|
+
messages: {
|
|
53
|
+
badName: "Log event '{{name}}' is not dotted-lowercase. Event names are a query surface: two naming conventions give the same failure two names, and an alert written against one misses the other. Join lowercase segments with '.', e.g. 'dashboard.index.read.failed'.",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
create(context) {
|
|
57
|
+
return {
|
|
58
|
+
Property(node) {
|
|
59
|
+
if (!isEventKey(node.key))
|
|
60
|
+
return;
|
|
61
|
+
for (const candidate of candidateValues(node.value)) {
|
|
62
|
+
const name = literalString(candidate);
|
|
63
|
+
if (name === undefined || EVENT_NAME.test(name))
|
|
64
|
+
continue;
|
|
65
|
+
context.report({ node, messageId: 'badName', data: { name } });
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
export default rule;
|
|
72
|
+
//# sourceMappingURL=consistent-event-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-event-name.js","sourceRoot":"","sources":["../../src/diagnostics/consistent-event-name.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,cAAc,EACd,SAAS,EACT,MAAM,GACP,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;GAaG;AAEH,MAAM,UAAU,GAAG,2DAA2D,CAAC;AAE/E,sCAAsC;AACtC,SAAS,UAAU,CAAC,IAAa;IAC/B,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC;AAC9D,CAAC;AAED,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,IAAa;IACpC,IAAI,MAAM,CAAC,IAAI,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;QACpC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAgB,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,sGAAsG;SACzG;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,OAAO,EACL,iQAAiQ;SACpQ;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,QAAQ,CAAC,IAAI;gBACX,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;oBAAE,OAAO;gBAClC,KAAK,MAAM,SAAS,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpD,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;oBACtC,IAAI,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;wBAAE,SAAS;oBAC1D,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-fabricated-fallback.d.ts","sourceRoot":"","sources":["../../src/diagnostics/no-fabricated-fallback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA2EnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA8ChB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { isRecord, isType, stringsAt } from "../authoring/ast.js";
|
|
2
|
+
import { inRoots, isTestFile } from "../authoring/path-scope.js";
|
|
3
|
+
/**
|
|
4
|
+
* A fallback that invents prose is not a default; it is a claim the code
|
|
5
|
+
* cannot support. `detail ?? 'No diagnostic detail was available.'` reads,
|
|
6
|
+
* downstream, as "we looked and there was nothing", when what actually happened
|
|
7
|
+
* is that a field arrived undefined and nobody asked why. The placeholder is
|
|
8
|
+
* indistinguishable from a real answer, so the bug it hides becomes invisible
|
|
9
|
+
* in exactly the surface built for diagnosing bugs.
|
|
10
|
+
*
|
|
11
|
+
* The shapes this catches pass review easily: `?? 'No diagnostic detail was
|
|
12
|
+
* available.'` on a log field, a `fallback = 'Unknown error'` parameter, and
|
|
13
|
+
* ``error.message || `Request failed ${status}` `` written without checking
|
|
14
|
+
* whether `message` can be empty at all. Each reads as harmless until someone
|
|
15
|
+
* reads it aloud.
|
|
16
|
+
*
|
|
17
|
+
* The rule is deliberately narrow: it fires only on text containing whitespace,
|
|
18
|
+
* because that is what separates a sentence a reader will believe from a machine
|
|
19
|
+
* value. Single tokens (`'production'`, `'utf8'`), identifier-shaped templates
|
|
20
|
+
* (`` `session:${id}` ``) and the empty string are left alone. That last
|
|
21
|
+
* exclusion is measured, not assumed: flagging `''` on a real backend produced
|
|
22
|
+
* dozens of hits and nearly all were boundary coercion (`message.text || ''`
|
|
23
|
+
* before `.trim()`, `match[1] ?? ''`, `sql[i] ?? ''` past the end), which is the
|
|
24
|
+
* identity element for a string operation rather than an invented answer.
|
|
25
|
+
* Narrow beats complete here: a rule that cries wolf gets disabled.
|
|
26
|
+
*/
|
|
27
|
+
function stringLiteralValue(node) {
|
|
28
|
+
return isType(node, 'Literal') && typeof node['value'] === 'string'
|
|
29
|
+
? node['value']
|
|
30
|
+
: undefined;
|
|
31
|
+
}
|
|
32
|
+
/** The literal parts of a template, ignoring whatever `${}` interpolates. */
|
|
33
|
+
function templateText(node) {
|
|
34
|
+
const quasis = node['quasis'];
|
|
35
|
+
if (!Array.isArray(quasis))
|
|
36
|
+
return undefined;
|
|
37
|
+
return quasis
|
|
38
|
+
.map((element) => {
|
|
39
|
+
if (!isRecord(element))
|
|
40
|
+
return '';
|
|
41
|
+
const value = element['value'];
|
|
42
|
+
if (!isRecord(value))
|
|
43
|
+
return '';
|
|
44
|
+
const cooked = value['cooked'];
|
|
45
|
+
return typeof cooked === 'string' ? cooked : '';
|
|
46
|
+
})
|
|
47
|
+
.join('');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Prose is text a reader would mistake for a real answer, and whitespace is
|
|
51
|
+
* what separates it from a machine value. `'Key validation failed'` is a
|
|
52
|
+
* sentence someone will read as a finding; `''`, `'utf8'` and `` `session:${id}` ``
|
|
53
|
+
* are normalization and identifiers. The empty string in particular is just
|
|
54
|
+
* the identity for a string operation, and flagging it drowns this rule in
|
|
55
|
+
* boundary coercions (`message.text || ''` before `.trim()`).
|
|
56
|
+
*/
|
|
57
|
+
function isProse(text, allowed) {
|
|
58
|
+
if (allowed.includes(text))
|
|
59
|
+
return false;
|
|
60
|
+
return /\s/.test(text);
|
|
61
|
+
}
|
|
62
|
+
function isFabricatedProse(node, allowed) {
|
|
63
|
+
const literal = stringLiteralValue(node);
|
|
64
|
+
if (literal !== undefined)
|
|
65
|
+
return isProse(literal, allowed);
|
|
66
|
+
if (!isType(node, 'TemplateLiteral'))
|
|
67
|
+
return false;
|
|
68
|
+
const text = templateText(node);
|
|
69
|
+
return text === undefined ? false : isProse(text, allowed);
|
|
70
|
+
}
|
|
71
|
+
const rule = {
|
|
72
|
+
meta: {
|
|
73
|
+
type: 'problem',
|
|
74
|
+
docs: {
|
|
75
|
+
description: 'Forbid fallbacks that fabricate prose (a sentence, or a template whose literal text has whitespace) for a value the code failed to obtain.',
|
|
76
|
+
},
|
|
77
|
+
schema: [
|
|
78
|
+
{
|
|
79
|
+
type: 'object',
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
properties: {
|
|
82
|
+
allow: { type: 'array', items: { type: 'string' } },
|
|
83
|
+
roots: { type: 'array', items: { type: 'string' } },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
defaultOptions: [{ allow: [], roots: [] }],
|
|
88
|
+
messages: {
|
|
89
|
+
fabricatedFallback: 'This fallback invents text for a value you did not obtain, and downstream cannot tell it from a real one. Cite the line in the producing code where the value can legitimately be absent — if you cannot, the absence is a bug to trace, not a string to paper over. If it genuinely can be absent, let it be absent (omit the key, narrow the type) instead of filling it in.',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
create(context) {
|
|
93
|
+
const filename = context.physicalFilename;
|
|
94
|
+
const roots = stringsAt(context.options[0], 'roots');
|
|
95
|
+
if (isTestFile(filename) || !inRoots(filename, roots))
|
|
96
|
+
return {};
|
|
97
|
+
const allowed = stringsAt(context.options[0], 'allow');
|
|
98
|
+
function check(right, node) {
|
|
99
|
+
if (isFabricatedProse(right, allowed)) {
|
|
100
|
+
context.report({ node, messageId: 'fabricatedFallback' });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
LogicalExpression(node) {
|
|
105
|
+
if (node.operator !== '??' && node.operator !== '||')
|
|
106
|
+
return;
|
|
107
|
+
check(node.right, node);
|
|
108
|
+
},
|
|
109
|
+
AssignmentPattern(node) {
|
|
110
|
+
check(node.right, node);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
export default rule;
|
|
116
|
+
//# sourceMappingURL=no-fabricated-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-fabricated-fallback.js","sourceRoot":"","sources":["../../src/diagnostics/no-fabricated-fallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-hardcoded-id-shape.d.ts","sourceRoot":"","sources":["../../src/diagnostics/no-hardcoded-id-shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA+CnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAkChB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { identifierName, isType } from "../authoring/ast.js";
|
|
2
|
+
/**
|
|
3
|
+
* Entity ids are a schema decision, not a text format. One table declares
|
|
4
|
+
* `id String @id @default(cuid())`, another takes its ids from `randomUUID()`.
|
|
5
|
+
* A regex that hardcodes one of those shapes keeps compiling, keeps passing a
|
|
6
|
+
* test whose fixture uses the matching shape, and silently stops matching the
|
|
7
|
+
* moment the shape changes. A parser that matched a UUID shape against a cuid
|
|
8
|
+
* column never matched in production, while its test stayed green on a UUID
|
|
9
|
+
* fixture.
|
|
10
|
+
*
|
|
11
|
+
* Anchor on the surrounding literal text instead: `/created\s+(\S+)/` cares
|
|
12
|
+
* about the sentence the program prints, which is a contract you own, rather
|
|
13
|
+
* than the id format, which the schema owns.
|
|
14
|
+
*/
|
|
15
|
+
/** `[0-9a-f]{8}-[0-9a-f]{4}` and its case/shorthand variants. */
|
|
16
|
+
const UUID_SHAPE = /\[[^\]]{2,}\]\{8\}-\[[^\]]{2,}\]\{4\}/;
|
|
17
|
+
/** `c[a-z0-9]{24}`, `[a-z0-9]{25}`, `[a-z0-9]{20,32}`: cuid/cuid2 lengths. */
|
|
18
|
+
const CUID_SHAPE = /\[a-z0-9\]\{2\d(?:,\d*)?\}/i;
|
|
19
|
+
function idShapeOf(pattern) {
|
|
20
|
+
if (UUID_SHAPE.test(pattern))
|
|
21
|
+
return 'uuid';
|
|
22
|
+
if (CUID_SHAPE.test(pattern))
|
|
23
|
+
return 'cuid';
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/** `/…/` literals carry `regex`; string and bigint literals do not. */
|
|
27
|
+
function regexPatternOf(node) {
|
|
28
|
+
return 'regex' in node ? node.regex.pattern : undefined;
|
|
29
|
+
}
|
|
30
|
+
/** The string a `new RegExp('…')` / `RegExp('…')` compiles, when it is literal. */
|
|
31
|
+
function regExpSourceArgument(node) {
|
|
32
|
+
if (identifierName(node.callee) !== 'RegExp')
|
|
33
|
+
return undefined;
|
|
34
|
+
const [first] = node.arguments;
|
|
35
|
+
return isType(first, 'Literal') && typeof first['value'] === 'string'
|
|
36
|
+
? first['value']
|
|
37
|
+
: undefined;
|
|
38
|
+
}
|
|
39
|
+
const rule = {
|
|
40
|
+
meta: {
|
|
41
|
+
type: 'problem',
|
|
42
|
+
docs: {
|
|
43
|
+
description: 'Disallow regexes that hardcode an entity-id shape (uuid/cuid); anchor on surrounding text instead.',
|
|
44
|
+
},
|
|
45
|
+
schema: [],
|
|
46
|
+
messages: {
|
|
47
|
+
idShape: 'This regex hardcodes a {{shape}} id shape. Ids are a schema decision (`@default(cuid())` / `randomUUID()`), so a shape change silently stops the match. Anchor on the surrounding literal text (e.g. /created\\s+(\\S+)/) instead.',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
create(context) {
|
|
51
|
+
function report(node, pattern) {
|
|
52
|
+
if (pattern === undefined)
|
|
53
|
+
return;
|
|
54
|
+
const shape = idShapeOf(pattern);
|
|
55
|
+
if (shape) {
|
|
56
|
+
context.report({ node, messageId: 'idShape', data: { shape } });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
Literal(node) {
|
|
61
|
+
report(node, regexPatternOf(node));
|
|
62
|
+
},
|
|
63
|
+
CallExpression(node) {
|
|
64
|
+
report(node, regExpSourceArgument(node));
|
|
65
|
+
},
|
|
66
|
+
NewExpression(node) {
|
|
67
|
+
report(node, regExpSourceArgument(node));
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export default rule;
|
|
73
|
+
//# sourceMappingURL=no-hardcoded-id-shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-hardcoded-id-shape.js","sourceRoot":"","sources":["../../src/diagnostics/no-hardcoded-id-shape.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AAEH,iEAAiE;AACjE,MAAM,UAAU,GAAG,uCAAuC,CAAC;AAE3D,8EAA8E;AAC9E,MAAM,UAAU,GAAG,6BAA6B,CAAC;AAEjD,SAAS,SAAS,CAAC,OAAe;IAChC,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uEAAuE;AACvE,SAAS,cAAc,CAAC,IAAe;IACrC,OAAO,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,mFAAmF;AACnF,SAAS,oBAAoB,CAAC,IAG7B;IACC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;IAC/B,OAAO,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;QACnE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAChB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,oGAAoG;SACvG;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,OAAO,EACL,oOAAoO;SACvO;KACF;IACD,MAAM,CAAC,OAAO;QACZ,SAAS,MAAM,CAAC,IAAe,EAAE,OAA2B;YAC1D,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO;YAClC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YACjC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,CAAC,IAAI;gBACV,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YACrC,CAAC;YACD,cAAc,CAAC,IAAI;gBACjB,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3C,CAAC;YACD,aAAa,CAAC,IAAI;gBAChB,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3C,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Concept } from '../concept.ts';
|
|
2
|
+
/**
|
|
3
|
+
* A service that validates its environment once, in a startup zod schema
|
|
4
|
+
* (`const env = z.object({...})`), and reads it only through declared keys.
|
|
5
|
+
*/
|
|
6
|
+
export declare const env: Concept;
|
|
7
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/environment/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAYrD;;;GAGG;AACH,eAAO,MAAM,GAAG,EAAE,OAYjB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { enable } from "../concept.js";
|
|
2
|
+
import { TESTS, TYPESCRIPT } from "../files.js";
|
|
3
|
+
import noDefaultForPathEnv from "./no-default-for-path-env.js";
|
|
4
|
+
import noSingleEnvReadWrapper from "./no-single-env-read-wrapper.js";
|
|
5
|
+
import noUndeclaredProcessEnv from "./no-undeclared-process-env.js";
|
|
6
|
+
const rules = {
|
|
7
|
+
'no-undeclared-process-env': noUndeclaredProcessEnv,
|
|
8
|
+
'no-single-env-read-wrapper': noSingleEnvReadWrapper,
|
|
9
|
+
'no-default-for-path-env': noDefaultForPathEnv,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A service that validates its environment once, in a startup zod schema
|
|
13
|
+
* (`const env = z.object({...})`), and reads it only through declared keys.
|
|
14
|
+
*/
|
|
15
|
+
export const env = {
|
|
16
|
+
name: 'env',
|
|
17
|
+
rules,
|
|
18
|
+
config: (plugins) => [
|
|
19
|
+
{
|
|
20
|
+
name: 'zukhruf/env',
|
|
21
|
+
files: TYPESCRIPT,
|
|
22
|
+
ignores: TESTS,
|
|
23
|
+
plugins,
|
|
24
|
+
rules: enable(rules),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/environment/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,mBAAmB,MAAM,8BAA8B,CAAC;AAC/D,OAAO,sBAAsB,MAAM,iCAAiC,CAAC;AACrE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AAEpE,MAAM,KAAK,GAAG;IACZ,2BAA2B,EAAE,sBAAsB;IACnD,4BAA4B,EAAE,sBAAsB;IACpD,yBAAyB,EAAE,mBAAmB;CAC/C,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,GAAG,GAAY;IAC1B,IAAI,EAAE,KAAK;IACX,KAAK;IACL,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;QACnB;YACE,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,KAAK;YACd,OAAO;YACP,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* A deployment path (a data directory, a socket) is backed by a volume mount
|
|
4
|
+
* the deployment declares. A code default lets the two drift apart silently:
|
|
5
|
+
* the app writes to a path nothing mounts. Each key listed in `pathEnvKeys`
|
|
6
|
+
* must therefore be a required `z.string()` in the startup schema.
|
|
7
|
+
*/
|
|
8
|
+
declare const rule: Rule.RuleModule;
|
|
9
|
+
export default rule;
|
|
10
|
+
//# sourceMappingURL=no-default-for-path-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-default-for-path-env.d.ts","sourceRoot":"","sources":["../../src/environment/no-default-for-path-env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAmEnC;;;;;GAKG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAmEhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { identifierName, isType, stringsAt, } from "../authoring/ast.js";
|
|
2
|
+
const BANNED_METHODS = [
|
|
3
|
+
'default',
|
|
4
|
+
'optional',
|
|
5
|
+
'transform',
|
|
6
|
+
'catch',
|
|
7
|
+
'nullable',
|
|
8
|
+
];
|
|
9
|
+
const SCHEMA_VARIABLE = 'env';
|
|
10
|
+
// Resolve the object literal of the startup schema, i.e. the `{...}` in
|
|
11
|
+
// `const env = z.object({...})`. Keyed on the `.object(...)` call shape rather
|
|
12
|
+
// than the `z` identifier, so an aliased zod import still resolves.
|
|
13
|
+
function schemaObjectLiteral(init) {
|
|
14
|
+
if (!isType(init, 'CallExpression')) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const callee = init['callee'];
|
|
18
|
+
if (!isType(callee, 'MemberExpression') ||
|
|
19
|
+
identifierName(callee['property']) !== 'object') {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const args = init['arguments'];
|
|
23
|
+
const schema = Array.isArray(args) ? args[0] : undefined;
|
|
24
|
+
return isType(schema, 'ObjectExpression') ? schema : undefined;
|
|
25
|
+
}
|
|
26
|
+
function propertyKeyName(property) {
|
|
27
|
+
if (property['computed'] === true) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const key = property['key'];
|
|
31
|
+
const name = identifierName(key);
|
|
32
|
+
if (name !== undefined) {
|
|
33
|
+
return name;
|
|
34
|
+
}
|
|
35
|
+
if (isType(key, 'Literal') && typeof key['value'] === 'string') {
|
|
36
|
+
return key['value'];
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
function bannedMethodInChain(value) {
|
|
41
|
+
let current = value;
|
|
42
|
+
while (isType(current, 'CallExpression')) {
|
|
43
|
+
const callee = current['callee'];
|
|
44
|
+
if (isType(callee, 'MemberExpression') &&
|
|
45
|
+
BANNED_METHODS.includes(identifierName(callee['property']) ?? '')) {
|
|
46
|
+
return identifierName(callee['property']);
|
|
47
|
+
}
|
|
48
|
+
current = isType(callee, 'MemberExpression') ? callee['object'] : undefined;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A deployment path (a data directory, a socket) is backed by a volume mount
|
|
54
|
+
* the deployment declares. A code default lets the two drift apart silently:
|
|
55
|
+
* the app writes to a path nothing mounts. Each key listed in `pathEnvKeys`
|
|
56
|
+
* must therefore be a required `z.string()` in the startup schema.
|
|
57
|
+
*/
|
|
58
|
+
const rule = {
|
|
59
|
+
meta: {
|
|
60
|
+
type: 'problem',
|
|
61
|
+
docs: {
|
|
62
|
+
description: 'Disallow code defaults/optional/transform on deployment-path env vars in the startup zod schema — the deployment owns the path',
|
|
63
|
+
},
|
|
64
|
+
messages: {
|
|
65
|
+
noDefault: 'Env var "{{key}}" is a deployment path — it must be a required `z.string()` with no `.{{method}}()`. A code default lets the path drift from the volume mount that backs it; the deployment must own and set it explicitly.',
|
|
66
|
+
},
|
|
67
|
+
schema: [
|
|
68
|
+
{
|
|
69
|
+
type: 'object',
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
properties: {
|
|
72
|
+
pathEnvKeys: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
items: { type: 'string' },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
defaultOptions: [{ pathEnvKeys: [] }],
|
|
80
|
+
},
|
|
81
|
+
create(context) {
|
|
82
|
+
const pathEnvKeys = new Set(stringsAt(context.options[0], 'pathEnvKeys'));
|
|
83
|
+
if (pathEnvKeys.size === 0) {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
VariableDeclarator(node) {
|
|
88
|
+
if (!isType(node, 'VariableDeclarator')) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (identifierName(node['id']) !== SCHEMA_VARIABLE) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const schema = schemaObjectLiteral(node['init']);
|
|
95
|
+
if (!schema) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const properties = schema['properties'];
|
|
99
|
+
if (!Array.isArray(properties)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const property of properties) {
|
|
103
|
+
if (!isType(property, 'Property')) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const key = propertyKeyName(property);
|
|
107
|
+
if (!key || !pathEnvKeys.has(key)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const method = bannedMethodInChain(property['value']);
|
|
111
|
+
if (method) {
|
|
112
|
+
context.report({
|
|
113
|
+
node: property,
|
|
114
|
+
messageId: 'noDefault',
|
|
115
|
+
data: { key, method },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
export default rule;
|
|
124
|
+
//# sourceMappingURL=no-default-for-path-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-default-for-path-env.js","sourceRoot":"","sources":["../../src/environment/no-default-for-path-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* An accessor that only returns `process.env.X` (or `process.env.X ?? 'literal'`)
|
|
4
|
+
* hides which variable a call site reads and invites validation to grow there
|
|
5
|
+
* instead of in the startup schema. Async and generator functions change the
|
|
6
|
+
* return type, so inlining them is not equivalent and they are left alone.
|
|
7
|
+
*/
|
|
8
|
+
declare const rule: Rule.RuleModule;
|
|
9
|
+
export default rule;
|
|
10
|
+
//# sourceMappingURL=no-single-env-read-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-single-env-read-wrapper.d.ts","sourceRoot":"","sources":["../../src/environment/no-single-env-read-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAkDnC;;;;;GAKG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAgChB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|