@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,47 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one place a filename becomes a path.
|
|
3
|
-
*
|
|
4
|
-
* oxlint hands a rule the name the platform gave it, so on Windows it arrives with backslashes and
|
|
5
|
-
* every pattern in this plugin — which is written with `/` — misses. Thirty-seven rules carried
|
|
6
|
-
* their own copy of the conversion, spelled three different ways, and one of them fixed only the
|
|
7
|
-
* first separator. A single fix to how a path is read had to be found rule by rule; now there is
|
|
8
|
-
* one line to find.
|
|
9
|
-
*/
|
|
10
1
|
export declare const normalise: (filename: string) => string;
|
|
11
|
-
/**
|
|
12
|
-
* The last segment of a path — what a diagnostic calls the file. An empty last segment is not a
|
|
13
|
-
* name, so a path that ends in a separator answers with itself rather than with `""`.
|
|
14
|
-
*/
|
|
15
2
|
export declare const fileOf: (path: string) => string;
|
|
16
|
-
/**
|
|
17
|
-
* Whether a file IS a door a repo named — one grammar for every rule that has doors (#204).
|
|
18
|
-
*
|
|
19
|
-
* A repo writes its time module down once and enables two rules with it. `time-through-the-door`
|
|
20
|
-
* took a REGEX over the filename; `boundary-time-is-primitive` compared a plain path, so the same
|
|
21
|
-
* spelling — `packages/utils/src/time\.ts$`, or the specifier callers import it by — made the
|
|
22
|
-
* second rule report the door's own signatures. All three spellings are accepted here: the exact
|
|
23
|
-
* path, a path the filename ends with (a specifier is one), and a regex over the filename.
|
|
24
|
-
*/
|
|
25
3
|
export declare const isDoor: (filename: string, door: string) => boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Whether a file IS one of an ENUMERATED list of modules — never a pattern.
|
|
28
|
-
*
|
|
29
|
-
* The counterpart to a path grant, and deliberately not `isDoor`: a door accepts a regex, and a
|
|
30
|
-
* regex is exactly the glob whose exemption stops wherever it happens to stop. An entry here names
|
|
31
|
-
* one module, by its full path or by the tail a repo writes it as, so the count of exemptions is a
|
|
32
|
-
* number a reader can hold.
|
|
33
|
-
*/
|
|
34
4
|
export declare const isModule: (filename: string, module: string) => boolean;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* `/__tests__\//` literal. Takes an already-`normalise`d path, the shape every call site already
|
|
40
|
-
* held in a local before testing it.
|
|
41
|
-
*/
|
|
5
|
+
export declare const isExempt: (filename: string, { allow, exemptModules }: {
|
|
6
|
+
allow?: string[];
|
|
7
|
+
exemptModules?: string[];
|
|
8
|
+
}) => boolean;
|
|
42
9
|
export declare const isTestFile: (path: string) => boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Whether a NORMALISED path matches any of a list of regex sources — `dialect-through-the-seam`
|
|
45
|
-
* and `no-d1-transaction` each carried this loop by hand, over the same shape of option.
|
|
46
|
-
*/
|
|
47
10
|
export declare const anyOf: (patterns: readonly string[], path: string) => boolean;
|
|
11
|
+
export declare const matchesAny: (patterns: readonly RegExp[], path: string) => boolean;
|
|
12
|
+
export declare const trimSlashes: (path: string) => string;
|
|
13
|
+
export declare const rootedAt: (filename: string, directory: string) => {
|
|
14
|
+
after: string;
|
|
15
|
+
repoRoot: string;
|
|
16
|
+
} | null;
|
|
17
|
+
export declare const HARNESS_PATHS: string[];
|
|
18
|
+
export declare const ROUTE_FALLBACK_BASENAMES: Set<string>;
|
|
19
|
+
export declare const LAYOUT_BASENAMES: Set<string>;
|
|
20
|
+
export declare const ROUTE_BODY_BASENAMES: Set<string>;
|
|
21
|
+
export declare const ROUTE_BASENAMES: Set<string>;
|
package/dist/rules/lib/paths.js
CHANGED
|
@@ -16,13 +16,46 @@ var isModule = (filename, module) => {
|
|
|
16
16
|
const named = module.replace(/^\.?\//, "");
|
|
17
17
|
return path === named || path.endsWith(`/${named}`);
|
|
18
18
|
};
|
|
19
|
+
var isExempt = (filename, { allow = [], exemptModules = [] }) => exemptModules.some((module) => isModule(filename, module)) || allow.some((path) => filename.includes(path));
|
|
19
20
|
var isTestFile = (path) => /__tests__\//.test(path);
|
|
20
21
|
var anyOf = (patterns, path) => patterns.some((pattern) => new RegExp(pattern).test(path));
|
|
22
|
+
var matchesAny = (patterns, path) => patterns.some((pattern) => pattern.test(path));
|
|
23
|
+
var trimSlashes = (path) => path.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
24
|
+
var rootedAt = (filename, directory) => {
|
|
25
|
+
const marker = `/${directory}/`;
|
|
26
|
+
const at = filename.indexOf(marker);
|
|
27
|
+
return at < 0 ? null : { after: filename.slice(at + marker.length), repoRoot: filename.slice(0, at) };
|
|
28
|
+
};
|
|
29
|
+
var HARNESS_PATHS = [
|
|
30
|
+
String.raw`/__tests__/`,
|
|
31
|
+
String.raw`/scripts/`,
|
|
32
|
+
String.raw`/testing/`,
|
|
33
|
+
String.raw`/seeds/`
|
|
34
|
+
];
|
|
35
|
+
var ROUTE_FALLBACK_BASENAMES = new Set([
|
|
36
|
+
"default.tsx",
|
|
37
|
+
"error.tsx",
|
|
38
|
+
"global-error.tsx",
|
|
39
|
+
"loading.tsx",
|
|
40
|
+
"not-found.tsx"
|
|
41
|
+
]);
|
|
42
|
+
var LAYOUT_BASENAMES = new Set(["layout.tsx", "template.tsx"]);
|
|
43
|
+
var ROUTE_BODY_BASENAMES = new Set([...LAYOUT_BASENAMES, "page.tsx"]);
|
|
44
|
+
var ROUTE_BASENAMES = new Set([...ROUTE_FALLBACK_BASENAMES, ...ROUTE_BODY_BASENAMES]);
|
|
21
45
|
export {
|
|
46
|
+
HARNESS_PATHS,
|
|
47
|
+
LAYOUT_BASENAMES,
|
|
48
|
+
ROUTE_BASENAMES,
|
|
49
|
+
ROUTE_BODY_BASENAMES,
|
|
50
|
+
ROUTE_FALLBACK_BASENAMES,
|
|
22
51
|
anyOf,
|
|
23
52
|
fileOf,
|
|
24
53
|
isDoor,
|
|
54
|
+
isExempt,
|
|
25
55
|
isModule,
|
|
26
56
|
isTestFile,
|
|
27
|
-
|
|
57
|
+
matchesAny,
|
|
58
|
+
normalise,
|
|
59
|
+
rootedAt,
|
|
60
|
+
trimSlashes
|
|
28
61
|
};
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The longest match for a wildcard pattern against a source string — tsc's own rule for
|
|
3
|
-
* `tsconfig.json` `paths`, and the same rule Node uses for `package.json` `imports`. An exact key
|
|
4
|
-
* wins outright; a pattern with one `*` matches when the source starts with what comes before it
|
|
5
|
-
* and ends with what comes after, and among those the longest fixed (non-star) part wins.
|
|
6
|
-
*
|
|
7
|
-
* `tsconfig-paths.ts` and `package-imports.ts` each carried this loop by hand, spelled identically
|
|
8
|
-
* down to the variable names — one truth about how a wildcard map is searched, read for two
|
|
9
|
-
* different maps. What each caller does with the match (a `paths` entry names several targets and
|
|
10
|
-
* takes `target.replace`; an `imports` value is one target read through `conditionTargetOf` and
|
|
11
|
-
* takes `target.replaceAll`) is NOT unified here, because those two shapes are not the same truth.
|
|
12
|
-
*/
|
|
13
1
|
export declare const longestMatch: <Value>(entries: Iterable<[string, Value]>, source: string) => {
|
|
14
2
|
matched: string;
|
|
15
3
|
value: Value;
|
|
16
4
|
} | undefined;
|
|
5
|
+
export declare const escapeForRegex: (value: string) => string;
|
|
6
|
+
export declare const readableSource: (pattern: string) => string;
|
|
@@ -24,6 +24,10 @@ var longestMatch = (entries, source) => {
|
|
|
24
24
|
}
|
|
25
25
|
return best === undefined ? undefined : { matched: best.matched, value: best.value };
|
|
26
26
|
};
|
|
27
|
+
var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28
|
+
var readableSource = (pattern) => pattern.replaceAll("\\", "").replace(/\$$/, "");
|
|
27
29
|
export {
|
|
28
|
-
|
|
30
|
+
escapeForRegex,
|
|
31
|
+
longestMatch,
|
|
32
|
+
readableSource
|
|
29
33
|
};
|
|
@@ -1,55 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The file a rule says MUST fire it, given the options it was handed.
|
|
3
|
-
*
|
|
4
|
-
* `requireOption` closed one hole: an enabled rule with no option reports that, once a run,
|
|
5
|
-
* instead of reading as a clean tree. It leaves the next one open. A rule CONFIGURED with a repo's own
|
|
6
|
-
* vocabulary — its own brand, `packages/workflows/src/`, `@repo/db` — cannot be exercised by a corpus
|
|
7
|
-
* that ships fixtures saying `acme` and `corpus/workflows/`, so "fires nowhere" is what an
|
|
8
|
-
* adoption's doctor reports about a rule the repo is enforcing perfectly well. Both consumers filed
|
|
9
|
-
* exactly that on 2026-08-30, and both were right about the fact and wrong about whose defect it is.
|
|
10
|
-
*
|
|
11
|
-
* A probe is the answer the rule itself can give: hand it the options and it writes the smallest
|
|
12
|
-
* source that must fire it under THOSE options, at a path that lands where it looks. It is a claim,
|
|
13
|
-
* so it is tested through the real binary — a probe that does not fire is a rule that cannot be
|
|
14
|
-
* exercised, and the honest thing then is to say so rather than to widen the probe until it does.
|
|
15
|
-
*/
|
|
16
1
|
export type Probe = {
|
|
17
|
-
/** Repo-root-relative, `/`-separated. It must satisfy every PATH option the rule reads. */
|
|
18
2
|
path: string;
|
|
19
3
|
source: string;
|
|
20
4
|
};
|
|
21
|
-
/**
|
|
22
|
-
* A probe that needs a TREE rather than a file.
|
|
23
|
-
*
|
|
24
|
-
* A rule that reads a sibling off disk — a registry, a schema's twin — cannot be exercised by one
|
|
25
|
-
* file however right its source is: `no-unregistered-plugin-dir` returns silently when the registry
|
|
26
|
-
* its options name is not there, so the single-file probe fired nothing and every consumer
|
|
27
|
-
* enforcing the rule over a real registry read as a permanent FAIL. The answer is not a widened
|
|
28
|
-
* probe, which would be the rule claiming evidence it does not have; it is a probe that may declare
|
|
29
|
-
* the sibling too, and a reader that mounts all of them.
|
|
30
|
-
*/
|
|
31
5
|
export type ProbeTree = {
|
|
32
6
|
files: readonly Probe[];
|
|
33
7
|
};
|
|
34
8
|
export type ProbeFn = (options: readonly unknown[]) => Probe | ProbeTree;
|
|
35
|
-
/** The files a probe declares, whichever of the two forms it answered in. */
|
|
36
9
|
export declare const filesOf: (answer: Probe | ProbeTree) => readonly Probe[];
|
|
37
|
-
/** The bag a rule reads its keyed options out of, whatever the caller passed. */
|
|
38
10
|
export declare const bagOf: <Options>(options: readonly unknown[]) => Partial<Options>;
|
|
39
|
-
/**
|
|
40
|
-
* The first configured value, or the first default. A probe reads the option the same way `create`
|
|
41
|
-
* does, defaults included — otherwise a repo keeping a default would get a probe built for a value
|
|
42
|
-
* its rule is not using, which fires nowhere and blames the repo for it.
|
|
43
|
-
*/
|
|
44
11
|
export declare const firstOf: (configured: readonly string[] | undefined, fallback: readonly string[]) => string;
|
|
45
|
-
/**
|
|
46
|
-
* A path a regex option would match, built back out of the regex.
|
|
47
|
-
*
|
|
48
|
-
* The path options in this plugin are regex SOURCES — `within`, `paths`, `directories`, a layer's
|
|
49
|
-
* `paths` — so a probe cannot be written against them without inverting one. This inverts the
|
|
50
|
-
* subset those options are actually written in: anchors, non-capturing groups, one-segment
|
|
51
|
-
* wildcards and escaped separators. It is deliberately not a general inverse, and it never has to
|
|
52
|
-
* be trusted: the caller tests the result against the pattern it came from and refuses when it
|
|
53
|
-
* does not match, which turns a wrong guess into a sentence rather than into a silent zero.
|
|
54
|
-
*/
|
|
55
12
|
export declare const pathMatching: (pattern: string, leaf: string) => string;
|
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A pure re-export shim (only `export … from`, no component) is a compatibility alias left behind
|
|
3
|
-
* when a component moves to a feature folder — not the tier it sits in. Three rules read this off
|
|
4
|
-
* the file, each with its own copy.
|
|
5
|
-
*/
|
|
6
1
|
export declare function isReexportOnly(file: string): boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Where a shim's code LIVES, when that is not the shim's own tier — or undefined when the file is
|
|
9
|
-
* not a pure re-export shim at all.
|
|
10
|
-
*
|
|
11
|
-
* The three "must" rules exempted every shim outright, and that was #11's hole surviving in three
|
|
12
|
-
* rules the direction rules' fix did not reach (row 594): `cells/laundered.tsx` re-exporting a
|
|
13
|
-
* stateless compound is a cell that holds no state, and `tissues/alias.tsx` re-exporting a compound
|
|
14
|
-
* is a tissue that composes nothing. Each name the shim hands on is followed to the file that
|
|
15
|
-
* declares it, as the direction rules follow it; an `export *` is judged at the module it hands
|
|
16
|
-
* through. A home in the shim's own tier is the alias the exemption was written for and is not
|
|
17
|
-
* named. A re-export nothing on disk answers — a bare package — is not named either: unresolved
|
|
18
|
-
* stays exempt, exactly as before.
|
|
19
|
-
*/
|
|
20
2
|
export declare const launderedHomesOf: (file: string) => string[] | undefined;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Whether a file RENDERS one of the tiers it imports, not merely names it — a gate satisfied by an
|
|
3
|
-
* import nobody renders was not satisfied. `molecule-must-compose` and `tissue-must-compose` both
|
|
4
|
-
* read this off the import list and the JSX tree; each had its own copy of the reader.
|
|
5
|
-
*/
|
|
6
1
|
type ImportSpecifierNode = {
|
|
7
2
|
imported?: {
|
|
8
3
|
name?: string;
|
|
@@ -45,10 +40,7 @@ export type JsxOpeningElementNode = {
|
|
|
45
40
|
};
|
|
46
41
|
type: 'JSXOpeningElement';
|
|
47
42
|
};
|
|
48
|
-
/** The identifier a JSX tag renders under — `<Foo/>`'s own name, or `<NS.Foo/>`'s namespace root. */
|
|
49
43
|
export declare const rootTagNameOf: (name: JsxOpeningElementNode['name'] | undefined) => string | undefined;
|
|
50
|
-
/** The local names an import brings in, added to `into` when its source composes and it is a value. */
|
|
51
44
|
export declare const collectCompositionLocals: (node: CompositionImportNode, isComposition: (source: string) => boolean, into: Set<string>) => void;
|
|
52
|
-
/** Whether any of the imported locals was actually rendered as a JSX tag. */
|
|
53
45
|
export declare const rendersAnyOf: (locals: ReadonlySet<string>, renderedTagNames: ReadonlySet<string>) => boolean;
|
|
54
46
|
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type Override = {
|
|
2
|
+
files: string[];
|
|
3
|
+
rules: Record<string, unknown>;
|
|
4
|
+
};
|
|
5
|
+
type Run = {
|
|
6
|
+
candidates: string[];
|
|
7
|
+
overrides: Override[];
|
|
8
|
+
prefixes: string[];
|
|
9
|
+
root: string;
|
|
10
|
+
rules: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export declare const runOf: ({ argv, cwd }: {
|
|
13
|
+
argv: readonly string[];
|
|
14
|
+
cwd: string;
|
|
15
|
+
}) => Run | null;
|
|
16
|
+
export declare const designatedIn: (run: Run, rule: string, accepts: (file: string, text: string) => boolean) => string | null;
|
|
17
|
+
export declare const designatedFile: (rule: string, salt?: string, accepts?: (file: string, text: string) => boolean) => string | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/rules/lib/run-files.ts
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { closeSync, existsSync, openSync, readFileSync, readSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, join, matchesGlob, relative, resolve } from "node:path";
|
|
5
|
+
import { parseLooseJson } from "./module-text.js";
|
|
6
|
+
var LINTED = /\.(?:[cm]?[jt]sx?)$/;
|
|
7
|
+
var HEAD_BYTES = 4096;
|
|
8
|
+
var SWITCHES_OFF = /\b(?:oxlint|eslint)-disable(?!-(?:next-)?line)\b/;
|
|
9
|
+
var PLUGIN_NAME = "biological-architecture";
|
|
10
|
+
var FLAGS_WITH_VALUE = new Set([
|
|
11
|
+
"-c",
|
|
12
|
+
"--config",
|
|
13
|
+
"-f",
|
|
14
|
+
"--format",
|
|
15
|
+
"--threads",
|
|
16
|
+
"--tsconfig",
|
|
17
|
+
"-D",
|
|
18
|
+
"-W",
|
|
19
|
+
"-A",
|
|
20
|
+
"--deny",
|
|
21
|
+
"--warn",
|
|
22
|
+
"--allow",
|
|
23
|
+
"--max-warnings"
|
|
24
|
+
]);
|
|
25
|
+
var UNKNOWABLE = ["--ignore-path", "--ignore-pattern", "--no-ignore", "--lsp", "--stdin-filepath"];
|
|
26
|
+
var recordOf = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : {};
|
|
27
|
+
var stringsOf = (value) => Array.isArray(value) ? value.filter((one) => typeof one === "string") : [];
|
|
28
|
+
var ignoredBy = (path, patterns) => patterns.some((pattern) => {
|
|
29
|
+
const bare = pattern.replace(/^\.\//, "").replace(/\/$/, "");
|
|
30
|
+
if (!bare.includes("/"))
|
|
31
|
+
return path.split("/").some((segment) => matchesGlob(segment, bare));
|
|
32
|
+
return matchesGlob(path, bare) || matchesGlob(path, `${bare}/**`);
|
|
33
|
+
});
|
|
34
|
+
var looselyMatches = (path, glob) => matchesGlob(path, glob) || matchesGlob(path, `**/${glob}`) || matchesGlob(basename(path), glob);
|
|
35
|
+
var switchedOff = (file) => {
|
|
36
|
+
let handle;
|
|
37
|
+
try {
|
|
38
|
+
handle = openSync(file, "r");
|
|
39
|
+
const buffer = Buffer.alloc(HEAD_BYTES);
|
|
40
|
+
const read = readSync(handle, buffer, 0, HEAD_BYTES, 0);
|
|
41
|
+
return SWITCHES_OFF.test(buffer.subarray(0, read).toString("utf8"));
|
|
42
|
+
} catch {
|
|
43
|
+
return true;
|
|
44
|
+
} finally {
|
|
45
|
+
if (handle !== undefined)
|
|
46
|
+
closeSync(handle);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var prefixesOf = (jsPlugins) => {
|
|
50
|
+
const names = (Array.isArray(jsPlugins) ? jsPlugins : []).flatMap((entry) => {
|
|
51
|
+
if (typeof entry === "string") {
|
|
52
|
+
return entry.includes("oxlint-plugin-biological-architecture") ? [PLUGIN_NAME] : [];
|
|
53
|
+
}
|
|
54
|
+
const { name, specifier } = recordOf(entry);
|
|
55
|
+
return typeof name === "string" && typeof specifier === "string" && specifier.includes("oxlint-plugin-biological-architecture") ? [name] : [];
|
|
56
|
+
});
|
|
57
|
+
return names.length === 0 ? [PLUGIN_NAME] : names;
|
|
58
|
+
};
|
|
59
|
+
var runOf = ({ argv, cwd }) => {
|
|
60
|
+
let config;
|
|
61
|
+
const paths = [];
|
|
62
|
+
for (let at = 0;at < argv.length; at += 1) {
|
|
63
|
+
const word = argv[at] ?? "";
|
|
64
|
+
const name = word.split("=")[0] ?? word;
|
|
65
|
+
if (UNKNOWABLE.includes(name))
|
|
66
|
+
return null;
|
|
67
|
+
if (name === "-c" || name === "--config") {
|
|
68
|
+
config = word.includes("=") ? word.slice(word.indexOf("=") + 1) : argv[at += 1];
|
|
69
|
+
} else if (FLAGS_WITH_VALUE.has(word))
|
|
70
|
+
at += 1;
|
|
71
|
+
else if (!word.startsWith("-"))
|
|
72
|
+
paths.push(word);
|
|
73
|
+
}
|
|
74
|
+
const configPath = config === undefined ? join(cwd, ".oxlintrc.json") : resolve(cwd, config);
|
|
75
|
+
if (!/\.jsonc?$/.test(configPath) || !existsSync(configPath))
|
|
76
|
+
return null;
|
|
77
|
+
const declared = parseLooseJson(readFileSync(configPath, "utf8"));
|
|
78
|
+
const record = recordOf(declared);
|
|
79
|
+
const patterns = stringsOf(record["ignorePatterns"]);
|
|
80
|
+
if (patterns.some((one) => one.startsWith("!")))
|
|
81
|
+
return null;
|
|
82
|
+
const listed = spawnSync("git", ["ls-files", "-co", "--exclude-standard", "-z", "--", ...paths.length === 0 ? ["."] : paths], { cwd, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
|
|
83
|
+
if (listed.status !== 0)
|
|
84
|
+
return null;
|
|
85
|
+
const root = dirname(configPath);
|
|
86
|
+
return {
|
|
87
|
+
candidates: listed.stdout.split("\x00").filter((path) => LINTED.test(path)).map((path) => resolve(cwd, path)).filter((path) => existsSync(path) && !ignoredBy(relative(root, path), patterns)).toSorted(),
|
|
88
|
+
overrides: (Array.isArray(record["overrides"]) ? record["overrides"] : []).map((one) => ({
|
|
89
|
+
files: stringsOf(recordOf(one)["files"]),
|
|
90
|
+
rules: recordOf(recordOf(one)["rules"])
|
|
91
|
+
})),
|
|
92
|
+
prefixes: prefixesOf(record["jsPlugins"]),
|
|
93
|
+
root,
|
|
94
|
+
rules: recordOf(record["rules"])
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
var isOff = (level) => {
|
|
98
|
+
const first = Array.isArray(level) ? level[0] : level;
|
|
99
|
+
return first === "off" || first === 0;
|
|
100
|
+
};
|
|
101
|
+
var designatedIn = (run, rule, accepts) => {
|
|
102
|
+
const keys = run.prefixes.map((prefix) => `${prefix}/${rule}`);
|
|
103
|
+
const base = keys.map((key) => run.rules[key]).find((level) => level !== undefined);
|
|
104
|
+
if (isOff(base))
|
|
105
|
+
return null;
|
|
106
|
+
const mentioning = run.overrides.filter((one) => keys.some((key) => (key in one.rules)));
|
|
107
|
+
return run.candidates.find((path) => {
|
|
108
|
+
const here = relative(run.root, path);
|
|
109
|
+
if (mentioning.some((one) => one.files.some((glob) => looselyMatches(here, glob)))) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
if (switchedOff(path))
|
|
113
|
+
return false;
|
|
114
|
+
try {
|
|
115
|
+
return accepts(path, readFileSync(path, "utf8"));
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}) ?? null;
|
|
120
|
+
};
|
|
121
|
+
var HOST = /[\\/]oxlint[\\/]bin[\\/]oxlint(?:\.\w+)?$/;
|
|
122
|
+
var run;
|
|
123
|
+
var designated = new Map;
|
|
124
|
+
var designatedFile = (rule, salt = "", accepts = () => true) => {
|
|
125
|
+
if (run === undefined) {
|
|
126
|
+
const [, script = "", ...argv] = process.argv;
|
|
127
|
+
try {
|
|
128
|
+
run = HOST.test(script) ? runOf({ argv, cwd: process.cwd() }) : null;
|
|
129
|
+
} catch {
|
|
130
|
+
run = null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (run === null)
|
|
134
|
+
return null;
|
|
135
|
+
const key = `${rule}\x00${salt}`;
|
|
136
|
+
if (!designated.has(key))
|
|
137
|
+
designated.set(key, designatedIn(run, rule, accepts));
|
|
138
|
+
return designated.get(key) ?? null;
|
|
139
|
+
};
|
|
140
|
+
export {
|
|
141
|
+
designatedFile,
|
|
142
|
+
designatedIn,
|
|
143
|
+
runOf
|
|
144
|
+
};
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Which features may be reached ACROSS feature boundaries is one repo's layout, so it is an
|
|
3
|
-
* option — `organelle-dependency` and `cell-no-cross-feature-organelles` draw the same boundary
|
|
4
|
-
* from two sides, on the same option, with the same default: the one name every feature-sliced
|
|
5
|
-
* repo agrees on.
|
|
6
|
-
*/
|
|
7
1
|
export type SharedFeaturesOptions = {
|
|
8
2
|
sharedFeatures?: string[];
|
|
9
3
|
};
|
|
10
|
-
/** The JSON schema for `{ sharedFeatures?: string[] }`, read by both rules that take it. */
|
|
11
4
|
export declare const SHARED_FEATURES_SCHEMA: {
|
|
12
5
|
additionalProperties: boolean;
|
|
13
6
|
properties: {
|
|
@@ -20,5 +13,4 @@ export declare const SHARED_FEATURES_SCHEMA: {
|
|
|
20
13
|
};
|
|
21
14
|
type: 'object';
|
|
22
15
|
}[];
|
|
23
|
-
/** Whether `importedFeature` is a DIFFERENT feature the options have not named as shared. */
|
|
24
16
|
export declare const crossesFeatureBoundary: (importedFeature: string | undefined, ownFeature: string | undefined, options: SharedFeaturesOptions) => boolean;
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
// src/rules/lib/shared-features.ts
|
|
2
|
+
import { optionsBag, STRINGS } from "./schema.js";
|
|
2
3
|
var DEFAULT_SHARED_FEATURES = ["shared"];
|
|
3
|
-
var SHARED_FEATURES_SCHEMA =
|
|
4
|
-
{
|
|
5
|
-
additionalProperties: false,
|
|
6
|
-
properties: {
|
|
7
|
-
sharedFeatures: { items: { type: "string" }, type: "array" }
|
|
8
|
-
},
|
|
9
|
-
type: "object"
|
|
10
|
-
}
|
|
11
|
-
];
|
|
4
|
+
var SHARED_FEATURES_SCHEMA = optionsBag({ sharedFeatures: STRINGS });
|
|
12
5
|
var crossesFeatureBoundary = (importedFeature, ownFeature, options) => importedFeature !== undefined && importedFeature !== ownFeature && !new Set(options.sharedFeatures ?? DEFAULT_SHARED_FEATURES).has(importedFeature);
|
|
13
6
|
export {
|
|
14
7
|
SHARED_FEATURES_SCHEMA,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const FORM_SOURCES: Set<string>;
|
|
2
|
+
export declare const FORM_CONTEXT_IMPORT_PATTERN: RegExp;
|
|
3
|
+
export declare const isProvidersSource: (source: string) => boolean;
|
|
4
|
+
export interface StateSources {
|
|
5
|
+
forms: Set<string>;
|
|
6
|
+
stores: Set<string>;
|
|
7
|
+
}
|
|
8
|
+
export declare const stateSourcesOf: (file: string, seen?: Set<string>) => StateSources;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/rules/lib/state-sources.ts
|
|
2
|
+
import { STORE_HOOK_NAME } from "./hooks.js";
|
|
3
|
+
import { isRelative } from "./imports.js";
|
|
4
|
+
import { fileFor, readSource } from "./module-text.js";
|
|
5
|
+
import { inTier } from "./tiers.js";
|
|
6
|
+
var FORM_SOURCES = new Set(["react-hook-form"]);
|
|
7
|
+
var FORM_CONTEXT_IMPORT_PATTERN = /FormContext$/;
|
|
8
|
+
var isProvidersSource = (source) => /(?:^|\/)providers(?:\/|$)/.test(source);
|
|
9
|
+
var IMPORT = /\bimport\s+(type\s+)?([^'";]*?)\s*from\s*['"]([^'"]+)['"]/g;
|
|
10
|
+
var STORE_CALL = /(?<!function\s)\b(use\w+Store)\s*\(/g;
|
|
11
|
+
var DEPTH = 4;
|
|
12
|
+
var localsOf = (clause) => {
|
|
13
|
+
const named = /\{([^}]*)\}/.exec(clause)?.[1] ?? "";
|
|
14
|
+
const bare = clause.replace(/\{[^}]*\}/, "").replaceAll(",", " ").trim();
|
|
15
|
+
const fromBare = /^[A-Za-z_$][\w$]*$/.test(bare) ? [bare] : [];
|
|
16
|
+
const fromNamed = named.split(",").map((one) => one.trim()).filter((one) => one !== "" && !one.startsWith("type ")).map((one) => one.split(/\s+as\s+/).at(-1) ?? "");
|
|
17
|
+
return [...fromBare, ...fromNamed].filter((one) => one !== "");
|
|
18
|
+
};
|
|
19
|
+
var importsOf = (text) => [...text.matchAll(IMPORT)].flatMap((found) => found[1] === undefined ? [{ locals: localsOf(found[2] ?? ""), source: found[3] ?? "" }] : []);
|
|
20
|
+
var isCalled = (text, name) => new RegExp(String.raw`(?<![\w$.])${name.replaceAll("$", String.raw`\$`)}\s*\(`).test(text);
|
|
21
|
+
var gather = (file, seen, depth, into) => {
|
|
22
|
+
if (seen.has(file) || depth > DEPTH)
|
|
23
|
+
return;
|
|
24
|
+
seen.add(file);
|
|
25
|
+
const text = readSource(file);
|
|
26
|
+
if (text === undefined)
|
|
27
|
+
return;
|
|
28
|
+
for (const found of text.matchAll(STORE_CALL)) {
|
|
29
|
+
const name = found[1] ?? "";
|
|
30
|
+
if (STORE_HOOK_NAME.test(name))
|
|
31
|
+
into.stores.add(name);
|
|
32
|
+
}
|
|
33
|
+
for (const one of importsOf(text)) {
|
|
34
|
+
if (FORM_SOURCES.has(one.source))
|
|
35
|
+
into.forms.add(one.source);
|
|
36
|
+
else if (isProvidersSource(one.source) && one.locals.some((local) => FORM_CONTEXT_IMPORT_PATTERN.test(local))) {
|
|
37
|
+
into.forms.add(one.source);
|
|
38
|
+
} else if (isRelative(one.source) && one.locals.some((local) => isCalled(text, local))) {
|
|
39
|
+
const next = fileFor(file, one.source);
|
|
40
|
+
if (next !== undefined && inTier(next, "organelles"))
|
|
41
|
+
gather(next, seen, depth + 1, into);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var stateSourcesOf = (file, seen = new Set) => {
|
|
46
|
+
const into = { forms: new Set, stores: new Set };
|
|
47
|
+
gather(file, seen, 0, into);
|
|
48
|
+
return into;
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
FORM_CONTEXT_IMPORT_PATTERN,
|
|
52
|
+
FORM_SOURCES,
|
|
53
|
+
isProvidersSource,
|
|
54
|
+
stateSourcesOf
|
|
55
|
+
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { type AnyNode } from './nodes.js';
|
|
2
|
+
export declare const DEFAULT_STEP_FACTORIES: string[];
|
|
3
|
+
export declare const DEFAULT_WORKFLOW_FACTORIES: string[];
|
|
4
|
+
export declare const workflowFactoriesOf: (rule: string, configured: string[] | undefined) => Set<string>;
|
|
2
5
|
export declare const stepFactoriesOf: (rule: string, configured: string[] | undefined) => Set<string>;
|
|
3
6
|
export declare const isStepCall: (node: AnyNode, factories: ReadonlySet<string>) => boolean;
|
|
4
7
|
export declare const argumentsOf: (node: AnyNode) => AnyNode[];
|
|
5
|
-
/**
|
|
6
|
-
* The step's config, told apart three ways: a bare string name (a call that can carry no config at
|
|
7
|
-
* all), an object this rule can read, and an object it cannot — a spread, or a variable.
|
|
8
|
-
*/
|
|
9
8
|
export type StepConfig = {
|
|
10
9
|
kind: 'bare';
|
|
11
10
|
} | {
|
|
@@ -15,5 +14,4 @@ export type StepConfig = {
|
|
|
15
14
|
kind: 'unreadable';
|
|
16
15
|
};
|
|
17
16
|
export declare const configOf: (node: AnyNode) => StepConfig;
|
|
18
|
-
/** Whatever names the step in a message: its literal name, its config's `name`, or the factory. */
|
|
19
17
|
export declare const stepNameOf: (node: AnyNode, config: StepConfig) => string;
|
package/dist/rules/lib/steps.js
CHANGED
|
@@ -3,6 +3,8 @@ import { calleeNameOf } from "./nodes.js";
|
|
|
3
3
|
import { propertiesOf, stringOf, valueOf } from "./objects.js";
|
|
4
4
|
import { requireOption } from "./options.js";
|
|
5
5
|
var DEFAULT_STEP_FACTORIES = ["createStep"];
|
|
6
|
+
var DEFAULT_WORKFLOW_FACTORIES = ["createWorkflow"];
|
|
7
|
+
var workflowFactoriesOf = (rule, configured) => new Set(requireOption(rule, configured ?? DEFAULT_WORKFLOW_FACTORIES, "workflowFactories"));
|
|
6
8
|
var stepFactoriesOf = (rule, configured) => new Set(requireOption(rule, configured ?? DEFAULT_STEP_FACTORIES, "stepFactories"));
|
|
7
9
|
var isStepCall = (node, factories) => {
|
|
8
10
|
const callee = calleeNameOf(node);
|
|
@@ -29,9 +31,12 @@ var stepNameOf = (node, config) => {
|
|
|
29
31
|
return calleeNameOf(node) ?? "a step";
|
|
30
32
|
};
|
|
31
33
|
export {
|
|
34
|
+
DEFAULT_STEP_FACTORIES,
|
|
35
|
+
DEFAULT_WORKFLOW_FACTORIES,
|
|
32
36
|
argumentsOf,
|
|
33
37
|
configOf,
|
|
34
38
|
isStepCall,
|
|
35
39
|
stepFactoriesOf,
|
|
36
|
-
stepNameOf
|
|
40
|
+
stepNameOf,
|
|
41
|
+
workflowFactoriesOf
|
|
37
42
|
};
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reading the two places a component says what something looks like: `className` and `style`.
|
|
3
|
-
*
|
|
4
|
-
* Both conformance rules need the same three things — the string behind a `className`, the
|
|
5
|
-
* `property: 'literal'` pairs behind a `style` object, and the arbitrary values a Tailwind class
|
|
6
|
-
* carries in brackets — and neither of them needs the other's vocabulary. Written once here so the
|
|
7
|
-
* two cannot disagree about what a className IS, which is the divergence the union of two plugins
|
|
8
|
-
* was cut to end.
|
|
9
|
-
*/
|
|
10
1
|
interface Node {
|
|
11
2
|
type: string;
|
|
12
3
|
}
|
|
@@ -20,46 +11,22 @@ interface Attribute extends Node {
|
|
|
20
11
|
export interface OpeningElement extends Node {
|
|
21
12
|
attributes?: Attribute[];
|
|
22
13
|
}
|
|
23
|
-
/** One `key: 'value'` pair of an inline style object, where both sides were written out. */
|
|
24
14
|
interface StyleEntry {
|
|
25
15
|
property: string;
|
|
26
16
|
value: string;
|
|
27
17
|
}
|
|
28
|
-
/**
|
|
29
|
-
* The literal text of a `className`, or nothing.
|
|
30
|
-
*
|
|
31
|
-
* A className assembled at runtime — `cn(base, isActive && 'x')`, a template with a hole — has no
|
|
32
|
-
* one text, and guessing at one is how a rule reports a line the reader cannot find the value on.
|
|
33
|
-
* Template quasis are joined because their static halves ARE written out, and a hardcoded colour
|
|
34
|
-
* hides in them exactly as well as in a plain string.
|
|
35
|
-
*/
|
|
36
18
|
export declare const classNameOf: (node: OpeningElement) => string | undefined;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
export declare const staticClassNameOf: (node: OpeningElement) => string | undefined;
|
|
20
|
+
export declare const keyOf: (property: {
|
|
21
|
+
computed?: boolean;
|
|
22
|
+
key?: Node & {
|
|
23
|
+
name?: string;
|
|
24
|
+
value?: unknown;
|
|
25
|
+
};
|
|
26
|
+
}) => string | undefined;
|
|
44
27
|
export declare const styleEntriesOf: (node: OpeningElement) => StyleEntry[];
|
|
45
|
-
|
|
46
|
-
* Tailwind arbitrary values, as `[utility, inner]` pairs: `bg-[#fff]` → `['bg', '#fff']`.
|
|
47
|
-
*
|
|
48
|
-
* The utility half is returned because what is inside the brackets only means something with it:
|
|
49
|
-
* `[tan]` is a colour after `text-` and a font after `font-`, and a rule that looked at the inner
|
|
50
|
-
* text alone would have to guess which.
|
|
51
|
-
*/
|
|
28
|
+
export declare const styleObjectOf: (node: OpeningElement) => Node | null;
|
|
52
29
|
export declare const arbitraryValuesOf: (className: string) => [utility: string, inner: string][];
|
|
53
|
-
/**
|
|
54
|
-
* The custom properties the element sets on ITSELF, in its own `style`.
|
|
55
|
-
*
|
|
56
|
-
* A component that writes `style={{ '--pb-text': fromAProp }}` and reads `text-[var(--pb-text)]`
|
|
57
|
-
* back is using a local alias: the variable is declared and consumed on one element and never
|
|
58
|
-
* leaves it. Treating that as a component reaching around the theme reports an accepted convention,
|
|
59
|
-
* which is how a rule earns the reputation that gets it switched off — measured on a consumer's
|
|
60
|
-
* kit, where the pattern appears fifty times.
|
|
61
|
-
*/
|
|
62
30
|
export declare const localVariablesOf: (node: OpeningElement) => Set<string>;
|
|
63
|
-
/** The custom property a `var(--x)` names, or nothing. */
|
|
64
31
|
export declare const variableOf: (value: string) => string | undefined;
|
|
65
32
|
export {};
|