@geonosis/oxlint-plugin-biological-architecture 3.1.0 → 3.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/CHANGELOG.md +57 -0
- package/README.md +75 -6
- package/RULES.md +202 -101
- package/corpus/.oxlintrc.json +5 -0
- package/corpus/data/bad-dynamic-orm.ts +5 -0
- package/corpus/data/bad-type-only-orm.ts +3 -0
- package/corpus/e2e/bad-list-response.spec.ts +5 -0
- package/corpus/e2e/bad-timeout.spec.ts +5 -0
- package/corpus/e2e/good-detail-response.spec.ts +5 -0
- package/corpus/e2e/good-state.spec.ts +5 -0
- package/corpus/manifest.json +2 -0
- package/corpus/medusa/queries/bad-silent-cap.ts +11 -0
- package/corpus/medusa/queries/good-paged-through.ts +19 -0
- package/corpus/medusa/queries/integration-tests/any-row.ts +10 -0
- package/corpus/tissues/bad-awaits-data.tsx +8 -0
- package/corpus/tissues/bad-fetches-data.tsx +7 -0
- package/corpus/tissues/good-takes-products.tsx +5 -0
- package/dist/discover-atoms.d.ts +2 -37
- package/dist/discover-atoms.js +1 -104
- package/dist/index.d.ts +3 -12
- package/dist/index.js +21 -176
- package/dist/presets.d.ts +11 -19
- package/dist/presets.js +94 -4
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +172 -0
- package/dist/rules/atom-no-deps.d.ts +1 -0
- package/dist/rules/atom-no-deps.js +10 -11
- package/dist/rules/boundary-time-is-primitive.d.ts +0 -7
- package/dist/rules/cell-must-be-stateful.d.ts +2 -2
- package/dist/rules/cell-must-be-stateful.js +24 -23
- package/dist/rules/cell-must-not-compose-cell.d.ts +1 -0
- package/dist/rules/cell-must-not-compose-cell.js +10 -3
- package/dist/rules/cell-no-cross-feature-organelles.d.ts +1 -0
- package/dist/rules/cell-no-cross-feature-organelles.js +7 -0
- package/dist/rules/cell-no-tissues.d.ts +1 -0
- package/dist/rules/cell-no-tissues.js +11 -7
- package/dist/rules/cells-folder-index-is-barrel.d.ts +12 -10
- package/dist/rules/cells-folder-index-is-barrel.js +66 -34
- package/dist/rules/compound-must-be-stateless.d.ts +2 -0
- package/dist/rules/compound-must-be-stateless.js +24 -26
- package/dist/rules/compound-no-stores.d.ts +1 -0
- package/dist/rules/compound-no-stores.js +12 -10
- package/dist/rules/constants-in-constants-file.d.ts +2 -8
- package/dist/rules/constants-in-constants-file.js +5 -6
- package/dist/rules/dialect-through-the-seam.d.ts +0 -13
- package/dist/rules/durable-body-reads-through-steps.d.ts +0 -14
- package/dist/rules/durable-body-reads-through-steps.js +8 -3
- package/dist/rules/effect-hook-naming.d.ts +9 -11
- package/dist/rules/effect-hook-naming.js +33 -31
- package/dist/rules/emit-declares-attempts.d.ts +0 -17
- package/dist/rules/emit-declares-attempts.js +5 -10
- package/dist/rules/font-roles-only.d.ts +0 -18
- package/dist/rules/font-roles-only.js +19 -22
- package/dist/rules/hermetic-e2e-no-wall-clock-waits.d.ts +53 -0
- package/dist/rules/hermetic-e2e-no-wall-clock-waits.js +100 -0
- package/dist/rules/icon-control-has-name.js +7 -1
- package/dist/rules/layer-walls.d.ts +0 -25
- package/dist/rules/layer-walls.js +7 -13
- package/dist/rules/lib/atom-map.d.ts +24 -0
- package/dist/rules/lib/atom-map.js +16 -0
- package/dist/rules/lib/cells-barrel.d.ts +0 -1
- package/dist/rules/lib/colors.d.ts +0 -19
- package/dist/rules/lib/colors.js +10 -243
- package/dist/rules/lib/comments.d.ts +19 -0
- package/dist/rules/lib/comments.js +5 -0
- package/dist/rules/lib/context.d.ts +0 -10
- package/dist/rules/lib/direction-rule.d.ts +4 -21
- package/dist/rules/lib/direction-rule.js +25 -4
- package/dist/rules/lib/doors.d.ts +2 -18
- package/dist/rules/lib/doors.js +81 -41
- package/dist/rules/lib/fresh.d.ts +5 -0
- package/dist/rules/lib/fresh.js +15 -0
- package/dist/rules/lib/hooks.d.ts +2 -17
- package/dist/rules/lib/hooks.js +14 -9
- package/dist/rules/lib/imports.d.ts +2 -23
- package/dist/rules/lib/imports.js +7 -2
- package/dist/rules/lib/jsx.d.ts +31 -0
- package/dist/rules/lib/jsx.js +11 -0
- package/dist/rules/lib/landing.d.ts +0 -40
- package/dist/rules/lib/literal-call.d.ts +1 -0
- package/dist/rules/lib/literal-call.js +2 -0
- package/dist/rules/lib/module-text.d.ts +3 -27
- package/dist/rules/lib/module-text.js +19 -4
- package/dist/rules/lib/mutations.d.ts +0 -14
- package/dist/rules/lib/nodes.d.ts +1 -18
- package/dist/rules/lib/nodes.js +1 -0
- package/dist/rules/lib/objects.d.ts +2 -11
- package/dist/rules/lib/objects.js +21 -0
- package/dist/rules/lib/options.d.ts +3 -52
- package/dist/rules/lib/options.js +49 -18
- package/dist/rules/lib/package-imports.d.ts +0 -5
- package/dist/rules/lib/package-imports.js +4 -10
- package/dist/rules/lib/paths.d.ts +15 -41
- package/dist/rules/lib/paths.js +34 -1
- package/dist/rules/lib/pattern-match.d.ts +2 -12
- package/dist/rules/lib/pattern-match.js +5 -1
- package/dist/rules/lib/probe.d.ts +0 -43
- package/dist/rules/lib/reexports.d.ts +0 -18
- package/dist/rules/lib/render-tracking.d.ts +0 -8
- package/dist/rules/lib/run-files.d.ts +18 -0
- package/dist/rules/lib/run-files.js +144 -0
- package/dist/rules/lib/shared-features.d.ts +0 -8
- package/dist/rules/lib/shared-features.js +2 -9
- package/dist/rules/lib/state-sources.d.ts +8 -0
- package/dist/rules/lib/state-sources.js +55 -0
- package/dist/rules/lib/steps.d.ts +3 -5
- package/dist/rules/lib/steps.js +6 -1
- package/dist/rules/lib/styling.d.ts +9 -42
- package/dist/rules/lib/styling.js +36 -10
- package/dist/rules/lib/tiers.d.ts +11 -24
- package/dist/rules/lib/tiers.js +41 -1
- package/dist/rules/lib/tissue-entrypoint.d.ts +0 -1
- package/dist/rules/lib/tissue-entrypoint.js +4 -5
- package/dist/rules/lib/token-layer.d.ts +19 -0
- package/dist/rules/lib/token-layer.js +170 -0
- package/dist/rules/lib/tsconfig-paths.d.ts +0 -4
- package/dist/rules/lib/tsconfig-paths.js +47 -15
- package/dist/rules/lib/type-members.d.ts +6 -0
- package/dist/rules/lib/type-members.js +165 -0
- package/dist/rules/lib/visitors.d.ts +0 -22
- package/dist/rules/lib/workspace-members.d.ts +2 -0
- package/dist/rules/lib/workspace-members.js +113 -0
- package/dist/rules/list-take-without-order.d.ts +24 -0
- package/dist/rules/list-take-without-order.js +293 -16
- package/dist/rules/max-comment-density.d.ts +3 -18
- package/dist/rules/max-comment-density.js +3 -3
- package/dist/rules/molecule-atoms-only.d.ts +1 -0
- package/dist/rules/molecule-atoms-only.js +11 -7
- package/dist/rules/molecule-must-compose.d.ts +2 -0
- package/dist/rules/molecule-must-compose.js +17 -21
- package/dist/rules/mutating-step-declares-retry.d.ts +2 -7
- package/dist/rules/mutating-step-declares-retry.js +29 -11
- package/dist/rules/named-when-block.d.ts +0 -2
- package/dist/rules/named-when-block.js +2 -8
- package/dist/rules/next-route-segment-is-thin-delegate.d.ts +4 -19
- package/dist/rules/next-route-segment-is-thin-delegate.js +47 -71
- package/dist/rules/no-brand-names.d.ts +0 -9
- package/dist/rules/no-brand-names.js +1 -1
- package/dist/rules/no-card-shaped-div.d.ts +4 -42
- package/dist/rules/no-card-shaped-div.js +12 -4
- package/dist/rules/no-cross-feature-stores.d.ts +1 -0
- package/dist/rules/no-cross-feature-stores.js +9 -5
- package/dist/rules/no-d1-transaction.d.ts +2 -5
- package/dist/rules/no-d1-transaction.js +7 -0
- package/dist/rules/no-date-string-compare.d.ts +2 -0
- package/dist/rules/no-date-string-compare.js +14 -8
- package/dist/rules/no-duplicate-jsx-patterns.d.ts +3 -1
- package/dist/rules/no-duplicate-jsx-patterns.js +16 -1
- package/dist/rules/no-generic-utility-package.d.ts +48 -2
- package/dist/rules/no-generic-utility-package.js +48 -9
- package/dist/rules/no-hook-in-component-disguise.d.ts +27 -13
- package/dist/rules/no-hook-in-component-disguise.js +38 -30
- package/dist/rules/no-index-count-as-exact.d.ts +0 -3
- package/dist/rules/no-inert-hidden-jsx.d.ts +4 -21
- package/dist/rules/no-inert-hidden-jsx.js +13 -12
- package/dist/rules/no-inline-data-in-jsx.d.ts +2 -0
- package/dist/rules/no-inline-data-in-jsx.js +17 -2
- package/dist/rules/no-invalid-feature-folders.d.ts +2 -0
- package/dist/rules/no-invalid-feature-folders.js +12 -4
- package/dist/rules/no-loader-side-effect-in-index-file.d.ts +2 -9
- package/dist/rules/no-logic-in-component-files.d.ts +6 -5
- package/dist/rules/no-logic-in-component-files.js +52 -31
- package/dist/rules/no-mock-db-in-integration.d.ts +0 -15
- package/dist/rules/no-mock-db-in-integration.js +3 -4
- package/dist/rules/no-orm-outside-db.d.ts +1 -0
- package/dist/rules/no-orm-outside-db.js +10 -7
- package/dist/rules/no-raw-html-atoms.d.ts +3 -22
- package/dist/rules/no-raw-html-atoms.js +5 -17
- package/dist/rules/no-raw-sql-outside-allowed.d.ts +2 -0
- package/dist/rules/no-raw-sql-outside-allowed.js +10 -15
- package/dist/rules/no-react-namespace.d.ts +2 -0
- package/dist/rules/no-react-namespace.js +13 -0
- package/dist/rules/no-renamed-html-props.d.ts +2 -0
- package/dist/rules/no-renamed-html-props.js +11 -2
- package/dist/rules/no-render-prop-reader.d.ts +4 -20
- package/dist/rules/no-render-prop-reader.js +13 -5
- package/dist/rules/no-runtime-dead-affordance.d.ts +3 -26
- package/dist/rules/no-runtime-dead-affordance.js +7 -20
- package/dist/rules/no-swallowed-catch.js +2 -8
- package/dist/rules/no-trivial-wrapper-component.d.ts +4 -19
- package/dist/rules/no-trivial-wrapper-component.js +24 -33
- package/dist/rules/no-ts-in-bio-folders.d.ts +2 -13
- package/dist/rules/no-ts-in-bio-folders.js +9 -7
- package/dist/rules/no-type-definitions-in-components.d.ts +2 -0
- package/dist/rules/no-type-definitions-in-components.js +12 -1
- package/dist/rules/no-unregistered-plugin-dir.d.ts +0 -41
- package/dist/rules/no-unregistered-plugin-dir.js +1 -9
- package/dist/rules/no-void-port.d.ts +2 -4
- package/dist/rules/no-void-port.js +7 -0
- package/dist/rules/organelle-dependency.d.ts +1 -0
- package/dist/rules/organelle-dependency.js +10 -8
- package/dist/rules/organelle-single-source.d.ts +2 -0
- package/dist/rules/organelle-single-source.js +58 -9
- package/dist/rules/plugin-route-namespaced.d.ts +0 -11
- package/dist/rules/plugin-route-namespaced.js +2 -2
- package/dist/rules/queries-require-org-scope.d.ts +0 -3
- package/dist/rules/queries-require-org-scope.js +3 -10
- package/dist/rules/queue-loop-is-the-library.js +3 -2
- package/dist/rules/route-no-inline-mutation.d.ts +1 -25
- package/dist/rules/route-no-inline-mutation.js +2 -7
- package/dist/rules/router-schema-parity.d.ts +0 -9
- package/dist/rules/router-schema-parity.js +5 -9
- package/dist/rules/service-name-not-reserved.d.ts +0 -3
- package/dist/rules/service-name-not-reserved.js +1 -34
- package/dist/rules/ssot-no-inline-facts.js +2 -5
- package/dist/rules/ssot-no-process-env.js +4 -12
- package/dist/rules/step-declares-compensation-or-none.d.ts +2 -1
- package/dist/rules/step-declares-compensation-or-none.js +17 -1
- package/dist/rules/step-opens-its-own-cell.d.ts +3 -26
- package/dist/rules/step-opens-its-own-cell.js +8 -13
- package/dist/rules/store-route-scopes-tenant-data.js +8 -26
- package/dist/rules/subpath-over-barrel.d.ts +3 -10
- package/dist/rules/subpath-over-barrel.js +55 -10
- package/dist/rules/subscriber-declares-id.d.ts +0 -2
- package/dist/rules/subscriber-declares-id.js +2 -8
- package/dist/rules/tables-declare-their-plane.d.ts +0 -2
- package/dist/rules/tables-declare-their-plane.js +4 -10
- package/dist/rules/tenant-tables-carry-org-id.d.ts +1 -4
- package/dist/rules/tenant-tables-carry-org-id.js +5 -12
- package/dist/rules/test-no-clock-polling-for-promise-flips.d.ts +7 -1
- package/dist/rules/test-no-clock-polling-for-promise-flips.js +21 -1
- package/dist/rules/time-through-the-door.d.ts +0 -24
- package/dist/rules/time-through-the-door.js +5 -5
- package/dist/rules/tissue-must-compose.d.ts +4 -2
- package/dist/rules/tissue-must-compose.js +25 -20
- package/dist/rules/tissue-no-data-props.d.ts +57 -1
- package/dist/rules/tissue-no-data-props.js +114 -32
- package/dist/rules/tissue-no-fetch.d.ts +26 -0
- package/dist/rules/tissue-no-fetch.js +57 -0
- package/dist/rules/tissue-no-hooks.d.ts +21 -23
- package/dist/rules/tissue-no-hooks.js +22 -4
- package/dist/rules/tissue-no-organelles.d.ts +1 -0
- package/dist/rules/tissue-no-organelles.js +9 -1
- package/dist/rules/tissue-no-stores.d.ts +1 -0
- package/dist/rules/tissue-no-stores.js +9 -1
- package/dist/rules/todo-names-its-plan.d.ts +1 -28
- package/dist/rules/todo-names-its-plan.js +2 -2
- package/dist/rules/tokens-only-colors.d.ts +8 -46
- package/dist/rules/tokens-only-colors.js +64 -20
- package/dist/rules/unique-query-step-name.d.ts +0 -7
- package/dist/rules/unique-query-step-name.js +6 -10
- package/dist/rules/worker-handles-are-scoped.d.ts +11 -8
- package/dist/rules/worker-handles-are-scoped.js +12 -5
- package/dist/rules/zustand-v5-best-practices.d.ts +8 -18
- package/dist/rules/zustand-v5-best-practices.js +32 -56
- package/dist/timing.d.ts +18 -0
- package/dist/timing.js +75 -0
- package/package.json +2 -2
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { type AnyNode } from './nodes.js';
|
|
2
|
-
/**
|
|
3
|
-
* React's own naming convention: a function called `use<Something>` is a hook.
|
|
4
|
-
*
|
|
5
|
-
* Exported because two other rules test a bare callee identifier against this exact pattern
|
|
6
|
-
* without needing `hookCalledBy`'s member-expression reach — spelling the regex a second and a
|
|
7
|
-
* third time drifted nothing here, but there is no reason to trust that forever.
|
|
8
|
-
*/
|
|
9
2
|
export declare const HOOK_NAME: RegExp;
|
|
10
|
-
|
|
11
|
-
* The hook a call names, spelled as the file spelled it — or null when the call is not a hook.
|
|
12
|
-
*
|
|
13
|
-
* Two stateless-tier rules read a call's callee as a bare identifier and nothing else, so
|
|
14
|
-
* `React.useState(0)` and `hooks.useCart()` held state in a tissue and in a compound under both
|
|
15
|
-
* rules at "error": the hook was there, the name was there, and the rule was looking one node too
|
|
16
|
-
* high. A member call is read here too — the object is whatever the file imported the hook
|
|
17
|
-
* through, and the property is the hook. A computed member (`hooks[name]()`) names nothing this
|
|
18
|
-
* can read and is left alone, as every unreadable shape in this plugin is.
|
|
19
|
-
*/
|
|
3
|
+
export declare const STORE_HOOK_NAME: RegExp;
|
|
20
4
|
export declare const hookCalledBy: (node: AnyNode) => string | null;
|
|
5
|
+
export declare const hookNameOf: (node: AnyNode) => string | null;
|
package/dist/rules/lib/hooks.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
// src/rules/lib/hooks.ts
|
|
2
2
|
import { calleeNameOf, propertyNameOf } from "./nodes.js";
|
|
3
3
|
var HOOK_NAME = /^use[A-Z]/;
|
|
4
|
+
var STORE_HOOK_NAME = /^use\w+Store$/;
|
|
4
5
|
var hookCalledBy = (node) => {
|
|
6
|
+
const name = hookNameOf(node);
|
|
7
|
+
if (name === null || calleeNameOf(node) !== null)
|
|
8
|
+
return name;
|
|
9
|
+
const object = node.callee.object;
|
|
10
|
+
const through = object?.type === "Identifier" && typeof object.name === "string" ? object.name : null;
|
|
11
|
+
return through === null ? name : `${through}.${name}`;
|
|
12
|
+
};
|
|
13
|
+
var hookNameOf = (node) => {
|
|
5
14
|
const bare = calleeNameOf(node);
|
|
6
15
|
if (bare !== null)
|
|
7
16
|
return HOOK_NAME.test(bare) ? bare : null;
|
|
8
17
|
const callee = node.callee;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const property = propertyNameOf(callee);
|
|
12
|
-
if (property === null || !HOOK_NAME.test(property))
|
|
13
|
-
return null;
|
|
14
|
-
const object = callee.object;
|
|
15
|
-
const through = object?.type === "Identifier" && typeof object.name === "string" ? object.name : null;
|
|
16
|
-
return through === null ? property : `${through}.${property}`;
|
|
18
|
+
const property = callee === undefined ? null : propertyNameOf(callee);
|
|
19
|
+
return property !== null && HOOK_NAME.test(property) ? property : null;
|
|
17
20
|
};
|
|
18
21
|
export {
|
|
19
22
|
HOOK_NAME,
|
|
20
|
-
|
|
23
|
+
STORE_HOOK_NAME,
|
|
24
|
+
hookCalledBy,
|
|
25
|
+
hookNameOf
|
|
21
26
|
};
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How a file names another file, read once.
|
|
3
|
-
*
|
|
4
|
-
* Twenty-one rules parsed an import source themselves and each covered a different subset of the
|
|
5
|
-
* five ways it can be written, because each was written by whoever needed one of them that day.
|
|
6
|
-
*/
|
|
7
1
|
export type ModuleNode = {
|
|
8
2
|
arguments?: {
|
|
9
3
|
type?: string;
|
|
@@ -19,34 +13,19 @@ export type ModuleNode = {
|
|
|
19
13
|
type?: string;
|
|
20
14
|
value?: unknown;
|
|
21
15
|
} | null;
|
|
22
|
-
/** What the import brought in, for the rules that judge an import by its names. */
|
|
23
16
|
specifiers?: {
|
|
24
17
|
imported?: {
|
|
25
18
|
name?: string;
|
|
26
19
|
};
|
|
20
|
+
importKind?: string;
|
|
27
21
|
local?: {
|
|
28
22
|
name?: string;
|
|
29
23
|
};
|
|
30
24
|
type?: string;
|
|
31
25
|
}[];
|
|
32
26
|
};
|
|
33
|
-
/**
|
|
34
|
-
* The module a node names, or null when it names none — `export const x = 1` names nothing, a call
|
|
35
|
-
* that is not a `require` names nothing, and `import(`./${name}`)` names something no rule can
|
|
36
|
-
* read. A rule that guessed at the last one would report a finding whose source it cannot print.
|
|
37
|
-
*/
|
|
38
27
|
export declare const sourceOf: (node: ModuleNode) => string | null;
|
|
39
|
-
/** `import type X from`, `import { … } from` graded type, and `export type … from`. */
|
|
40
28
|
export declare const isTypeOnly: (node: ModuleNode) => boolean;
|
|
41
|
-
/** Whether a specifier is relative — walked from the importer, never resolved through an alias. */
|
|
42
29
|
export declare const isRelative: (source: string) => boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Where a relative source lands, as a path — and any other source unchanged.
|
|
45
|
-
*
|
|
46
|
-
* `../../billing/organelles/totals` carries no feature name and no tier name until it is resolved
|
|
47
|
-
* against the file that wrote it. Two rules did that and the rest did not, so the same breach was a
|
|
48
|
-
* finding or not depending on which rule happened to look at it. `@/features/x` is NOT relative: it
|
|
49
|
-
* is an alias the bundler resolves, and joining it to the importer's directory would invent a path
|
|
50
|
-
* that exists nowhere.
|
|
51
|
-
*/
|
|
52
30
|
export declare const resolveRelative: (importer: string, source: string) => string;
|
|
31
|
+
export declare const isR3fImport: (node: ModuleNode) => boolean;
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { literalNamedBy } from "./literal-call.js";
|
|
4
4
|
import { normalise } from "./paths.js";
|
|
5
|
-
var
|
|
5
|
+
var R3F_PACKAGES = new Set(["@react-three/drei", "@react-three/fiber"]);
|
|
6
6
|
var sourceOf = (node) => {
|
|
7
7
|
const source = node.source;
|
|
8
8
|
if (source === undefined || source === null) {
|
|
9
9
|
if (node.callee === undefined)
|
|
10
10
|
return null;
|
|
11
|
-
return literalNamedBy(node,
|
|
11
|
+
return literalNamedBy(node, "require");
|
|
12
12
|
}
|
|
13
13
|
if (source.type !== undefined && source.type !== "Literal")
|
|
14
14
|
return null;
|
|
@@ -17,7 +17,12 @@ var sourceOf = (node) => {
|
|
|
17
17
|
var isTypeOnly = (node) => node.importKind === "type" || node.exportKind === "type";
|
|
18
18
|
var isRelative = (source) => source === "." || source === ".." || source.startsWith("./") || source.startsWith("../");
|
|
19
19
|
var resolveRelative = (importer, source) => isRelative(source) ? path.posix.normalize(path.posix.join(path.posix.dirname(normalise(importer)), source)) : source;
|
|
20
|
+
var isR3fImport = (node) => {
|
|
21
|
+
const source = sourceOf(node);
|
|
22
|
+
return source !== null && R3F_PACKAGES.has(source);
|
|
23
|
+
};
|
|
20
24
|
export {
|
|
25
|
+
isR3fImport,
|
|
21
26
|
isRelative,
|
|
22
27
|
isTypeOnly,
|
|
23
28
|
resolveRelative,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface JsxAttribute {
|
|
2
|
+
name?: {
|
|
3
|
+
name?: string;
|
|
4
|
+
type: string;
|
|
5
|
+
};
|
|
6
|
+
type: string;
|
|
7
|
+
value?: {
|
|
8
|
+
type: string;
|
|
9
|
+
value?: unknown;
|
|
10
|
+
} | null;
|
|
11
|
+
}
|
|
12
|
+
export interface JsxOpeningElement {
|
|
13
|
+
attributes?: JsxAttribute[];
|
|
14
|
+
loc?: unknown;
|
|
15
|
+
name: {
|
|
16
|
+
name?: string;
|
|
17
|
+
type: string;
|
|
18
|
+
};
|
|
19
|
+
type: 'JSXOpeningElement';
|
|
20
|
+
}
|
|
21
|
+
export declare const isCapitalised: (name: string) => boolean;
|
|
22
|
+
export declare const attributeNamed: (node: {
|
|
23
|
+
attributes?: readonly JsxAttribute[];
|
|
24
|
+
}, name: string) => JsxAttribute | undefined;
|
|
25
|
+
export declare const tagNameOf: (node: {
|
|
26
|
+
name?: JsxOpeningElement['name'];
|
|
27
|
+
} | undefined) => string | undefined;
|
|
28
|
+
export declare const meaningfulChildren: <Child extends {
|
|
29
|
+
type: string;
|
|
30
|
+
value?: string;
|
|
31
|
+
}>(children: readonly Child[] | undefined) => Child[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/rules/lib/jsx.ts
|
|
2
|
+
var isCapitalised = (name) => /^[A-Z]/.test(name);
|
|
3
|
+
var attributeNamed = (node, name) => node.attributes?.find((attribute) => attribute?.type === "JSXAttribute" && attribute.name?.type === "JSXIdentifier" && attribute.name.name === name);
|
|
4
|
+
var tagNameOf = (node) => node?.name?.type === "JSXIdentifier" && node.name.name ? node.name.name : undefined;
|
|
5
|
+
var meaningfulChildren = (children) => (children ?? []).filter((child) => child.type !== "JSXText" || (child.value ?? "").trim() !== "");
|
|
6
|
+
export {
|
|
7
|
+
attributeNamed,
|
|
8
|
+
isCapitalised,
|
|
9
|
+
meaningfulChildren,
|
|
10
|
+
tagNameOf
|
|
11
|
+
};
|
|
@@ -1,50 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where an import LANDS, and where the code behind each name it takes LIVES.
|
|
3
|
-
*
|
|
4
|
-
* Two consumer issues were one blindness. A direction rule read the specifier as a string and
|
|
5
|
-
* stopped, so `@/components/organelles` — a bare barrel, which names no file in a tier folder —
|
|
6
|
-
* was invisible (#4), and a one-line `export { CustomCarousel } from '@/kit/organelles/carousel'`
|
|
7
|
-
* sitting in `cells/` laundered an organelle into the cell tier for every rule that looked (#11).
|
|
8
|
-
* The Store adoption that found #4 read 78 → 8 → 5 → 1 as tier fixes landed, which is to say its
|
|
9
|
-
* early numbers measured the rules' blindness as much as the code.
|
|
10
|
-
*
|
|
11
|
-
* So the specifier is resolved on disk: relative to the importer, through the repo's own
|
|
12
|
-
* `package.json` `imports` for a `#` subpath, or through its `tsconfig.json` (or `jsconfig.json`)
|
|
13
|
-
* `paths` — never an alias this plugin knows (LAW 6). The file it lands on is the
|
|
14
|
-
* DOOR. Each name the import takes is then followed through `export … from` and `export *` to the
|
|
15
|
-
* file that declares it, the HOME, to a depth of eight and never twice through one file. A name
|
|
16
|
-
* the door does not export and a bare package are left at the door; a specifier nothing on disk
|
|
17
|
-
* answers lands nowhere, and the rule judges the spelling as before. An import that takes the
|
|
18
|
-
* whole module — a namespace, `export *`, `import()`, `require()` — takes every name the door
|
|
19
|
-
* carries (row 593), narrowed to the members the file reaches when it is a namespace.
|
|
20
|
-
*/
|
|
21
1
|
type Landings = {
|
|
22
|
-
/** The file the specifier resolves to, absolute — or nowhere. */
|
|
23
2
|
door: string | undefined;
|
|
24
|
-
/** Imported name → the absolute file whose code it is; the door when it could not be followed. */
|
|
25
3
|
homes: Map<string, string>;
|
|
26
4
|
};
|
|
27
|
-
/** The absolute file a specifier names from a file, or undefined when nothing on disk answers. */
|
|
28
5
|
export declare const resolveSource: (importer: string, source: string) => string | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* Every name a module exports, its `export *` modules followed to the same depth as a home is. A
|
|
31
|
-
* namespace import, an `export *`, `import()` and `require()` take the whole module (row 593), and
|
|
32
|
-
* "the whole module" is this list — each name then lands where its code lives, as a named import's
|
|
33
|
-
* would.
|
|
34
|
-
*/
|
|
35
6
|
export declare const exportedNamesOf: (file: string) => Set<string>;
|
|
36
7
|
export declare const landingsOf: (importer: string, source: string, names: readonly string[]) => Landings;
|
|
37
|
-
/**
|
|
38
|
-
* Whether a specifier's last segment IS a tier folder — `@/components/organelles`, `../cells`.
|
|
39
|
-
* A folder named `organelles` is the organelles tier whichever alias reaches it, so when nothing
|
|
40
|
-
* on disk answers the spelling is still judged as the folder it names.
|
|
41
|
-
*/
|
|
42
8
|
export declare const namesATierFolder: (source: string) => boolean;
|
|
43
|
-
/**
|
|
44
|
-
* The root a landed path is judged from: the nearest directory above the importer holding a
|
|
45
|
-
* `package.json` or a `tsconfig.json`, else the importer's own. An absolute path would be judged
|
|
46
|
-
* with every directory above the repo in it, and a checkout under `/app/` or `/home/cells/` would
|
|
47
|
-
* make every resolved import a breach.
|
|
48
|
-
*/
|
|
49
9
|
export declare const rootOf: (file: string) => string;
|
|
50
10
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/rules/lib/literal-call.ts
|
|
2
|
+
var TABLE_CALLEES = ["sqliteTable", "pgTable"];
|
|
2
3
|
var literalNamedBy = (node, callee) => {
|
|
3
4
|
if (node.callee.type !== "Identifier" || node.callee.name !== callee)
|
|
4
5
|
return null;
|
|
@@ -6,5 +7,6 @@ var literalNamedBy = (node, callee) => {
|
|
|
6
7
|
return name?.type === "Literal" && typeof name.value === "string" ? name.value : null;
|
|
7
8
|
};
|
|
8
9
|
export {
|
|
10
|
+
TABLE_CALLEES,
|
|
9
11
|
literalNamedBy
|
|
10
12
|
};
|
|
@@ -1,43 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a module's TEXT says it exports, read with regexes and never a parser — the same reading
|
|
3
|
-
* `doors.ts` did for a package's `exports` map, shared now with the landing resolver, because a
|
|
4
|
-
* barrel and a re-export shim are the same shape read for a different question.
|
|
5
|
-
*
|
|
6
|
-
* A table is read once per file per process: `create` runs once per FILE, and the tree does not
|
|
7
|
-
* change under a lint run.
|
|
8
|
-
*/
|
|
9
1
|
type ExportTable = {
|
|
10
|
-
/** Names whose code is HERE: declarations, `export { A as B }` with no `from`, `default`. */
|
|
11
2
|
declared: Set<string>;
|
|
12
|
-
/** Exported name → the name and module it is taken from: `export { A as B } from './x'`. */
|
|
13
3
|
reexports: Map<string, {
|
|
14
4
|
name: string;
|
|
15
5
|
source: string;
|
|
16
6
|
}>;
|
|
17
|
-
/** The modules `export * from` hands through, in order. */
|
|
18
7
|
stars: string[];
|
|
19
8
|
};
|
|
20
9
|
export declare const EXTENSIONS: string[];
|
|
21
|
-
/**
|
|
22
|
-
* Source with its comments blanked to spaces, strings stepped over whole — a glob like `'src/*'`
|
|
23
|
-
* opens no comment and a URL keeps its `//`. Blanked, not cut: the tokens either side of a comment
|
|
24
|
-
* stay apart and every line keeps its number. Every text reader in the plugin reads through it.
|
|
25
|
-
*/
|
|
26
10
|
export declare const stripComments: (source: string) => string;
|
|
27
|
-
/** The file at a base path: itself, with an extension, or its index — or nothing on disk. */
|
|
28
11
|
export declare const fileAt: (base: string) => string | undefined;
|
|
29
|
-
/** A relative module specifier as the file it names, or undefined when nothing on disk answers. */
|
|
30
12
|
export declare const fileFor: (from: string, specifier: string) => string | undefined;
|
|
31
|
-
|
|
13
|
+
export declare const readSource: (file: string) => string | undefined;
|
|
14
|
+
export declare const recordOf: (value: unknown) => Record<string, unknown> | undefined;
|
|
15
|
+
export declare const readManifest: (file: string) => Record<string, unknown> | undefined;
|
|
32
16
|
export declare const exportTableOf: (file: string) => ExportTable | undefined;
|
|
33
|
-
/**
|
|
34
|
-
* The file an `exports` or `imports` value points at, whatever conditions it is wrapped in — a
|
|
35
|
-
* string, an array of alternatives, or a conditions object read in the order a bundler would.
|
|
36
|
-
*/
|
|
37
17
|
export declare const conditionTargetOf: (value: unknown) => string | undefined;
|
|
38
|
-
/**
|
|
39
|
-
* JSON as `tsconfig.json` writes it: comments and trailing commas allowed. `JSON.parse` refuses
|
|
40
|
-
* both, and a reader that stripped `//` blindly would cut `"$schema": "https://…"` in half.
|
|
41
|
-
*/
|
|
42
18
|
export declare const parseLooseJson: (text: string) => unknown;
|
|
43
19
|
export {};
|
|
@@ -49,14 +49,26 @@ var entriesOf = (list) => list.split(",").map((one) => one.trim().replace(/^type
|
|
|
49
49
|
const [taken, exported] = one.split(/\s+as\s+/);
|
|
50
50
|
return { exported: exported ?? taken ?? "", taken: taken ?? "" };
|
|
51
51
|
});
|
|
52
|
-
var
|
|
53
|
-
var readTable = (file) => {
|
|
54
|
-
let source;
|
|
52
|
+
var readSource = (file) => {
|
|
55
53
|
try {
|
|
56
|
-
|
|
54
|
+
return stripComments(readFileSync(file, "utf8"));
|
|
57
55
|
} catch {
|
|
58
56
|
return;
|
|
59
57
|
}
|
|
58
|
+
};
|
|
59
|
+
var recordOf = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : undefined;
|
|
60
|
+
var readManifest = (file) => {
|
|
61
|
+
try {
|
|
62
|
+
return recordOf(JSON.parse(readFileSync(file, "utf8")));
|
|
63
|
+
} catch {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var tables = new Map;
|
|
68
|
+
var readTable = (file) => {
|
|
69
|
+
const source = readSource(file);
|
|
70
|
+
if (source === undefined)
|
|
71
|
+
return;
|
|
60
72
|
const declared = new Set;
|
|
61
73
|
const reexports = new Map;
|
|
62
74
|
const stars = [];
|
|
@@ -119,5 +131,8 @@ export {
|
|
|
119
131
|
fileAt,
|
|
120
132
|
fileFor,
|
|
121
133
|
parseLooseJson,
|
|
134
|
+
readManifest,
|
|
135
|
+
readSource,
|
|
136
|
+
recordOf,
|
|
122
137
|
stripComments
|
|
123
138
|
};
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import { type AnyNode } from './nodes.js';
|
|
2
|
-
/**
|
|
3
|
-
* What a WRITE is, in one place. `mutating-step-declares-retry` asks it of a step's invoke body and
|
|
4
|
-
* `route-no-inline-mutation` asks it of a route handler; two copies of this, spelled slightly
|
|
5
|
-
* differently, is how the two rules would come to disagree about which calls are writes — the same
|
|
6
|
-
* drift `lib/steps.ts` exists to prevent for what a step is.
|
|
7
|
-
*
|
|
8
|
-
* The CRUD names `MedusaService` generates. A framework fact, so a default rather than a blank.
|
|
9
|
-
*/
|
|
10
2
|
export declare const DEFAULT_MUTATION_PREFIXES: string[];
|
|
11
3
|
export declare const mutationPrefixesOf: (rule: string, configured: string[] | undefined) => string[];
|
|
12
|
-
/**
|
|
13
|
-
* `svc.createOrder(…)` — a generated CRUD write, told from `listOrders` by the capital after the
|
|
14
|
-
* prefix, and from `createOrderWorkflow(scope)` by being a METHOD on something. A bare identifier
|
|
15
|
-
* call is the workflow door itself, which is the shape both rules exist to send people towards.
|
|
16
|
-
*/
|
|
17
4
|
export declare const writesWith: (prefixes: readonly string[]) => (node: AnyNode) => boolean;
|
|
18
|
-
/** The method name a write call carries, for a message that points at something. */
|
|
19
5
|
export declare const writeNameOf: (node: AnyNode) => string;
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
export type AnyNode = {
|
|
2
2
|
type?: string;
|
|
3
3
|
} & Record<string, unknown>;
|
|
4
|
-
/**
|
|
5
|
-
* Every node under this one, this one included.
|
|
6
|
-
*
|
|
7
|
-
* A visitor is handed the node it asked for, and some facts live in its BODY — whether a step's
|
|
8
|
-
* invoke function writes anything is the one that made this necessary, and it can be behind an
|
|
9
|
-
* `if`, inside a `try`, or two closures down. A rule that only read the statements directly under
|
|
10
|
-
* the arrow would pass every step that guarded its write. Children are visited in source order.
|
|
11
|
-
*
|
|
12
|
-
* `parent` is skipped: oxlint hands nodes with back-references, and following one walks the whole
|
|
13
|
-
* program from wherever it started.
|
|
14
|
-
*/
|
|
15
4
|
export declare const walkNode: (node: unknown, visit: (node: AnyNode) => void, descends?: (node: AnyNode) => boolean) => void;
|
|
16
|
-
|
|
17
|
-
* Every node under a function's OWN body, stopping at a nested function — a hook called inside a
|
|
18
|
-
* closure this function merely defines belongs to that closure, not to this one. Two rules walked
|
|
19
|
-
* this by hand, one to find a hook call and one to collect `return` statements.
|
|
20
|
-
*/
|
|
5
|
+
export declare const FUNCTION_BOUNDARY_TYPES: Set<string>;
|
|
21
6
|
export declare const walkOwnFunctionBody: (body: unknown, visit: (node: AnyNode) => void) => void;
|
|
22
|
-
/** The name a `MemberExpression`'s non-computed property carries, or null. */
|
|
23
7
|
export declare const propertyNameOf: (node: AnyNode) => string | null;
|
|
24
|
-
/** The name an `Identifier` callee carries, or null — a method call is never one of these. */
|
|
25
8
|
export declare const calleeNameOf: (node: AnyNode) => string | null;
|
package/dist/rules/lib/nodes.js
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import type { AnyNode } from './nodes.js';
|
|
2
|
-
/** The expression under any `as` / `satisfies` — a retyped value is the value it was. */
|
|
3
2
|
export declare const withoutTypes: (node: unknown) => AnyNode | undefined;
|
|
4
|
-
/**
|
|
5
|
-
* The properties of an object literal, or **null when it cannot be read whole**.
|
|
6
|
-
*
|
|
7
|
-
* A spread hides properties, and the posture this plugin already took for `emit-declares-attempts`
|
|
8
|
-
* is the one that holds here too: a rule that guessed at what a spread contains would fire on every
|
|
9
|
-
* repo that factored its configs out, and people would learn to ignore it. Unreadable is not the
|
|
10
|
-
* same as absent, and only one of the two is a finding.
|
|
11
|
-
*/
|
|
12
3
|
export declare const propertiesOf: (node: unknown) => AnyNode[] | null;
|
|
13
|
-
/** The value of the named property, or undefined. `name` and `'name'` are read alike; `[name]` is not. */
|
|
14
4
|
export declare const valueOf: (properties: readonly AnyNode[], name: string) => AnyNode | undefined;
|
|
15
5
|
export declare const hasProperty: (properties: readonly AnyNode[], name: string) => boolean;
|
|
16
|
-
/** The string a node literally is, or null — a constant is a value this cannot read. */
|
|
17
6
|
export declare const stringOf: (node: unknown) => string | null;
|
|
7
|
+
export declare const keyNameOf: (node: AnyNode) => string | null;
|
|
8
|
+
export declare const destructuredNamesOf: (pattern: unknown) => string[] | null;
|
|
@@ -26,8 +26,29 @@ var stringOf = (node) => {
|
|
|
26
26
|
const literal = node;
|
|
27
27
|
return literal?.type === "Literal" && typeof literal.value === "string" ? literal.value : null;
|
|
28
28
|
};
|
|
29
|
+
var keyNameOf = (node) => {
|
|
30
|
+
const key = node.key;
|
|
31
|
+
if (key?.type === "Identifier" && typeof key.name === "string")
|
|
32
|
+
return key.name;
|
|
33
|
+
return stringOf(key);
|
|
34
|
+
};
|
|
35
|
+
var destructuredNamesOf = (pattern) => {
|
|
36
|
+
const at = pattern;
|
|
37
|
+
if (at?.type !== "ObjectPattern")
|
|
38
|
+
return null;
|
|
39
|
+
const names = [];
|
|
40
|
+
for (const one of at.properties ?? []) {
|
|
41
|
+
const name = one.type === "Property" && one.computed !== true ? keyNameOf(one) : null;
|
|
42
|
+
if (name === null)
|
|
43
|
+
return null;
|
|
44
|
+
names.push(name);
|
|
45
|
+
}
|
|
46
|
+
return names;
|
|
47
|
+
};
|
|
29
48
|
export {
|
|
49
|
+
destructuredNamesOf,
|
|
30
50
|
hasProperty,
|
|
51
|
+
keyNameOf,
|
|
31
52
|
propertiesOf,
|
|
32
53
|
stringOf,
|
|
33
54
|
valueOf,
|
|
@@ -1,34 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #199: the rule and the option it REQUIRES, in one fixed position at the front of the finding.
|
|
3
|
-
*
|
|
4
|
-
* The prose after it quotes every option the rule accepts, which is what a consumer with a
|
|
5
|
-
* half-written config needs — and is exactly why a reader matching the option name anywhere in the
|
|
6
|
-
* message cannot tell a required option from a mentioned one. `refuses-bare.bin.test.ts` asserted
|
|
7
|
-
* that way and passed for a release over an entry claiming `engine` for a rule that requires
|
|
8
|
-
* `within`. The doctor and the cli read the pair out of this header and nowhere else.
|
|
9
|
-
*/
|
|
10
1
|
export declare const refusalHeader: (rule: string, option: string) => string;
|
|
11
|
-
/**
|
|
12
|
-
* The signal a rule raises when an option it cannot run without is missing. Carries the pair a
|
|
13
|
-
* reader would otherwise parse back out of the sentence. Caught by `reportingOncePerRun` in the
|
|
14
|
-
* registry; a `create` reached WITHOUT the registry (a unit test on the rule module) sees it thrown,
|
|
15
|
-
* which is the rule saying what it requires, not the plugin's behaviour.
|
|
16
|
-
*/
|
|
17
2
|
export declare class OptionMissing extends Error {
|
|
18
3
|
readonly option: string;
|
|
19
4
|
readonly rule: string;
|
|
20
5
|
constructor(rule: string, option: string, message: string);
|
|
21
6
|
}
|
|
22
|
-
/**
|
|
23
|
-
* A regex-source option in either shape: a bare string is a one-element list.
|
|
24
|
-
*
|
|
25
|
-
* The seven tree options #12 added in one commit shipped as three strings and four lists. A
|
|
26
|
-
* consumer wrote `seam` as a string, oxlint refused the config at options validation, and every
|
|
27
|
-
* rule in it read 0 with exit 1 — a config mistake presenting as a clean zero. One shape rule for
|
|
28
|
-
* all of them, read here and declared by `PATTERNS` below, so the reader never has to know which.
|
|
29
|
-
*/
|
|
30
7
|
export declare const patternsOf: (value: string | readonly string[] | null | undefined) => string[];
|
|
31
|
-
/** The JSON schema for an option `patternsOf` reads: `string | string[]`. */
|
|
32
8
|
export declare const PATTERNS: {
|
|
33
9
|
anyOf: ({
|
|
34
10
|
type: 'string';
|
|
@@ -40,35 +16,10 @@ export declare const PATTERNS: {
|
|
|
40
16
|
type: 'array';
|
|
41
17
|
})[];
|
|
42
18
|
};
|
|
43
|
-
|
|
44
|
-
* #203: a test file is not a door/seam rule's business anywhere, so the default says so — the
|
|
45
|
-
* fallback for an `exempt` option a repo has not configured.
|
|
46
|
-
*
|
|
47
|
-
* `time-through-the-door` 1.4.0 had `__tests__` compiled in; making every path an option (law 6)
|
|
48
|
-
* emptied it, and the reach GREW — a Workers + D1 app's first RC run reported six findings in test
|
|
49
|
-
* files that had never been in scope. Test paths are not consumer vocabulary the way a door is:
|
|
50
|
-
* every repo spells them these three ways, and a repo with a fourth spelling names its own list and
|
|
51
|
-
* replaces this one. `dialect-through-the-seam` held the identical array as its own copy; one now.
|
|
52
|
-
*/
|
|
19
|
+
export declare const DEFAULT_TENANT_KEY = "orgId";
|
|
53
20
|
export declare const DEFAULT_TEST_EXEMPT: string[];
|
|
54
|
-
/**
|
|
55
|
-
* The value, or the requirement raised, naming the rule and the option. Read by the rule, judged
|
|
56
|
-
* here: some of these options are keyed and one is positional, and what they have in common is not
|
|
57
|
-
* their shape but that the rule cannot fire without them.
|
|
58
|
-
*
|
|
59
|
-
* `accepts` is the whole option bag written out — `{ roots: string[], registry: string | string[] }`
|
|
60
|
-
* — appended so the accepted shape comes back WITH the finding. Without it the only way to learn
|
|
61
|
-
* what a rule takes is to read the dist bundle, which is how a consumer whose registry is split
|
|
62
|
-
* reached for a list, was told `should be string`, and could not tell from the refusal whether a
|
|
63
|
-
* list was a shape the rule had or a shape it lacked. Optional, so a rule that has not written its
|
|
64
|
-
* shape down is reported exactly as it always was.
|
|
65
|
-
*
|
|
66
|
-
* #205 is history now: a `requireOptionHere` once waited for a file a tree-scoped rule would judge
|
|
67
|
-
* and named it in the refusal, because a refusal thrown over every package the preset reached was
|
|
68
|
-
* noise a consumer learned to route around. Reported once a run, a refusal has no per-package
|
|
69
|
-
* noise to wait out, and no rule was calling it, so it is gone.
|
|
70
|
-
*/
|
|
71
21
|
export declare const requireOption: <Value>(rule: string, value: Value | null | undefined, option: string, accepts?: string) => Value;
|
|
72
22
|
type Create<Context> = (context: Context) => Record<string, unknown>;
|
|
73
|
-
export declare const
|
|
23
|
+
export declare const onceFor: (key: string, file: string) => boolean;
|
|
24
|
+
export declare const reportingOncePerRun: <Context>(create: Create<Context>, rule?: string) => Create<Context>;
|
|
74
25
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/rules/lib/options.ts
|
|
2
|
-
|
|
2
|
+
import { designatedFile } from "./run-files.js";
|
|
3
3
|
var isMissing = (value) => value === undefined || value === null || value === "" || Array.isArray(value) && value.length === 0;
|
|
4
4
|
var refusalHeader = (rule, option) => `biological-architecture/${rule} requires option \`${option}\`.`;
|
|
5
5
|
|
|
@@ -20,43 +20,74 @@ var PATTERNS = {
|
|
|
20
20
|
{ items: { type: "string" }, type: "array" }
|
|
21
21
|
]
|
|
22
22
|
};
|
|
23
|
+
var DEFAULT_TENANT_KEY = "orgId";
|
|
23
24
|
var DEFAULT_TEST_EXEMPT = ["__tests__/", String.raw`\.test\.`, String.raw`\.spec\.`];
|
|
24
25
|
var requireOption = (rule, value, option, accepts) => {
|
|
25
26
|
if (isMissing(value)) {
|
|
26
|
-
throw new OptionMissing(rule, option, `${refusalHeader(rule, option)} It is enabled but its \`${option}\` option is
|
|
27
|
+
throw new OptionMissing(rule, option, `${refusalHeader(rule, option)} It is enabled but its \`${option}\` option is nothing, so it judges no file — this finding stands in for every file it did not read, once a run. Configure \`${option}\`, or turn the rule off: an enabled rule that judges nothing would otherwise read exactly like a rule that found nothing.${accepts === undefined ? "" : ` It accepts ${accepts}.`}`);
|
|
27
28
|
}
|
|
28
29
|
return value;
|
|
29
30
|
};
|
|
30
31
|
var raisedOver = new Map;
|
|
31
|
-
var
|
|
32
|
+
var filenameOf = (context) => {
|
|
32
33
|
const named = context?.filename;
|
|
33
34
|
return typeof named === "string" ? named : "";
|
|
34
35
|
};
|
|
35
|
-
var
|
|
36
|
+
var badPatternMessage = (rule, error) => `biological-architecture/${rule} threw a SyntaxError — ${error.message}. An option of this rule holds a pattern that is not a regular expression. This finding stands in for every file it could not judge, once a run; fix the pattern, or turn the rule off.`;
|
|
37
|
+
var onceFor = (key, file) => {
|
|
38
|
+
if (file === "")
|
|
39
|
+
return true;
|
|
40
|
+
const designated = designatedFile(key.split("/")[0] ?? key);
|
|
41
|
+
if (designated !== null)
|
|
42
|
+
return file === designated;
|
|
43
|
+
const first = raisedOver.get(key);
|
|
44
|
+
if (first !== undefined && first !== file)
|
|
45
|
+
return false;
|
|
46
|
+
raisedOver.set(key, file);
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
var refusalVisitor = (context, key, finding) => onceFor(key, filenameOf(context)) ? {
|
|
50
|
+
Program(node) {
|
|
51
|
+
context.report({ ...finding, node });
|
|
52
|
+
}
|
|
53
|
+
} : {};
|
|
54
|
+
var reportedAtVisit = (visitor, rule, context) => Object.fromEntries(Object.entries(visitor).map(([name, handler]) => [
|
|
55
|
+
name,
|
|
56
|
+
typeof handler === "function" ? (node) => {
|
|
57
|
+
try {
|
|
58
|
+
handler(node);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (!(error instanceof SyntaxError))
|
|
61
|
+
throw error;
|
|
62
|
+
if (!onceFor(`${rule}/pattern`, filenameOf(context)))
|
|
63
|
+
return;
|
|
64
|
+
context.report({ message: badPatternMessage(rule, error), node });
|
|
65
|
+
}
|
|
66
|
+
} : handler
|
|
67
|
+
]));
|
|
68
|
+
var reportingOncePerRun = (create, rule = "") => (context) => {
|
|
36
69
|
try {
|
|
37
|
-
return create(context);
|
|
70
|
+
return reportedAtVisit(create(context), rule, context);
|
|
38
71
|
} catch (error) {
|
|
72
|
+
if (error instanceof SyntaxError) {
|
|
73
|
+
return refusalVisitor(context, `${rule}/pattern`, {
|
|
74
|
+
message: badPatternMessage(rule, error)
|
|
75
|
+
});
|
|
76
|
+
}
|
|
39
77
|
if (!(error instanceof OptionMissing))
|
|
40
78
|
throw error;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (first !== undefined && first !== file)
|
|
46
|
-
return {};
|
|
47
|
-
raisedOver.set(key, file);
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
Program(node) {
|
|
51
|
-
context.report({ message: error.message, node });
|
|
52
|
-
}
|
|
53
|
-
};
|
|
79
|
+
return refusalVisitor(context, `${error.rule}/${error.option}`, {
|
|
80
|
+
data: { option: error.option, rule: error.rule },
|
|
81
|
+
message: error.message
|
|
82
|
+
});
|
|
54
83
|
}
|
|
55
84
|
};
|
|
56
85
|
export {
|
|
86
|
+
DEFAULT_TENANT_KEY,
|
|
57
87
|
DEFAULT_TEST_EXEMPT,
|
|
58
88
|
OptionMissing,
|
|
59
89
|
PATTERNS,
|
|
90
|
+
onceFor,
|
|
60
91
|
patternsOf,
|
|
61
92
|
refusalHeader,
|
|
62
93
|
reportingOncePerRun,
|
|
@@ -1,6 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The places the manifest says a `#` specifier may be, best match first — as bases without
|
|
3
|
-
* extensions, for the caller to find the file at. A target that is not relative names a package,
|
|
4
|
-
* which is not a file in this repo, and is left out. Empty when no manifest maps it.
|
|
5
|
-
*/
|
|
6
1
|
export declare const importCandidates: (importer: string, source: string) => string[];
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
// src/rules/lib/package-imports.ts
|
|
2
|
-
import { existsSync
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { conditionTargetOf } from "./module-text.js";
|
|
4
|
+
import { conditionTargetOf, readManifest, recordOf } from "./module-text.js";
|
|
5
5
|
import { longestMatch } from "./pattern-match.js";
|
|
6
6
|
var manifests = new Map;
|
|
7
7
|
var readImports = (file) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof parsed.imports !== "object" || parsed.imports === null)
|
|
11
|
-
return null;
|
|
12
|
-
return { dir: dirname(file), imports: parsed.imports };
|
|
13
|
-
} catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
8
|
+
const imports = recordOf(readManifest(file)?.imports);
|
|
9
|
+
return imports === undefined ? null : { dir: dirname(file), imports };
|
|
16
10
|
};
|
|
17
11
|
var importsFor = (dir) => {
|
|
18
12
|
const known = manifests.get(dir);
|