@geonosis/oxlint-plugin-biological-architecture 3.1.0 → 3.2.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 +44 -0
- package/README.md +48 -5
- package/RULES.md +200 -99
- 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/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 +19 -176
- package/dist/presets.d.ts +11 -19
- package/dist/presets.js +88 -3
- 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 +3 -21
- package/dist/rules/lib/direction-rule.js +12 -3
- package/dist/rules/lib/doors.d.ts +2 -18
- package/dist/rules/lib/doors.js +79 -41
- 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 +2 -52
- package/dist/rules/lib/options.js +44 -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/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/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 +115 -0
- package/dist/rules/list-take-without-order.js +2 -8
- 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 +9 -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 +2 -10
- package/dist/rules/subpath-over-barrel.js +48 -9
- 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 +2 -0
- package/dist/rules/test-no-clock-polling-for-promise-flips.js +18 -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 +5 -3
- 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 +2 -37
- package/dist/rules/tokens-only-colors.js +33 -18
- 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 +12 -9
- 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/package.json +2 -2
|
@@ -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 {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/rules/lib/styling.ts
|
|
2
|
-
|
|
2
|
+
import { attributeNamed } from "./jsx.js";
|
|
3
|
+
var isContainer = (node) => node.type === "JSXExpressionContainer";
|
|
4
|
+
var isTemplate = (node) => node?.type === "TemplateLiteral";
|
|
3
5
|
var classNameOf = (node) => {
|
|
4
6
|
const value = attributeNamed(node, "className")?.value;
|
|
5
7
|
if (value === undefined || value === null)
|
|
@@ -8,11 +10,19 @@ var classNameOf = (node) => {
|
|
|
8
10
|
const literal = value.value;
|
|
9
11
|
return typeof literal === "string" ? literal : undefined;
|
|
10
12
|
}
|
|
11
|
-
if (value
|
|
13
|
+
if (isContainer(value))
|
|
12
14
|
return expressionText(unwrap(value.expression));
|
|
13
|
-
}
|
|
14
15
|
return;
|
|
15
16
|
};
|
|
17
|
+
var staticClassNameOf = (node) => {
|
|
18
|
+
const value = attributeNamed(node, "className")?.value;
|
|
19
|
+
if (value !== undefined && value !== null && isContainer(value)) {
|
|
20
|
+
const expression = unwrap(value.expression);
|
|
21
|
+
if (isTemplate(expression) && (expression.expressions ?? []).length > 0)
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
return classNameOf(node);
|
|
25
|
+
};
|
|
16
26
|
var unwrap = (node) => {
|
|
17
27
|
let current = node ?? null;
|
|
18
28
|
while (current !== null && (current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSNonNullExpression" || current.type === "ParenthesizedExpression")) {
|
|
@@ -55,16 +65,29 @@ var styleEntriesOf = (node) => {
|
|
|
55
65
|
return text === undefined ? [] : [{ property: name, value: text }];
|
|
56
66
|
});
|
|
57
67
|
};
|
|
58
|
-
var
|
|
68
|
+
var styleObjectOf = (node) => {
|
|
59
69
|
const value = attributeNamed(node, "style")?.value;
|
|
60
|
-
if (value
|
|
61
|
-
return
|
|
70
|
+
if (value === undefined || value === null || !isContainer(value))
|
|
71
|
+
return null;
|
|
62
72
|
const expression = unwrap(value.expression);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
return expression?.type === "ObjectExpression" ? expression : null;
|
|
74
|
+
};
|
|
75
|
+
var styleProperties = (node) => styleObjectOf(node)?.properties ?? [];
|
|
76
|
+
var withoutVariants = (token) => {
|
|
77
|
+
let depth = 0;
|
|
78
|
+
let from = 0;
|
|
79
|
+
for (const [at, char] of [...token].entries()) {
|
|
80
|
+
if (char === "[")
|
|
81
|
+
depth += 1;
|
|
82
|
+
else if (char === "]")
|
|
83
|
+
depth -= 1;
|
|
84
|
+
else if (char === ":" && depth === 0)
|
|
85
|
+
from = at + 1;
|
|
86
|
+
}
|
|
87
|
+
return token.slice(from);
|
|
66
88
|
};
|
|
67
|
-
var arbitraryValuesOf = (className) => className.split(/\s+/).flatMap((
|
|
89
|
+
var arbitraryValuesOf = (className) => className.split(/\s+/).flatMap((classToken) => {
|
|
90
|
+
const token = withoutVariants(classToken).replace(/^!|!$/g, "");
|
|
68
91
|
const open = token.indexOf("[");
|
|
69
92
|
const close = token.lastIndexOf("]");
|
|
70
93
|
if (open <= 0 || close <= open)
|
|
@@ -84,7 +107,10 @@ var variableOf = (value) => /^var\(\s*(--[A-Za-z0-9_-]+)/.exec(value.trim())?.[1
|
|
|
84
107
|
export {
|
|
85
108
|
arbitraryValuesOf,
|
|
86
109
|
classNameOf,
|
|
110
|
+
keyOf,
|
|
87
111
|
localVariablesOf,
|
|
112
|
+
staticClassNameOf,
|
|
88
113
|
styleEntriesOf,
|
|
114
|
+
styleObjectOf,
|
|
89
115
|
variableOf
|
|
90
116
|
};
|
|
@@ -1,31 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The tiers, and the one path pattern every rule here tests a filename against.
|
|
3
|
-
*
|
|
4
|
-
* `(?:features/[^/]+/)?<tier>/` is a Medusa storefront's broader form, kept when the two forks were
|
|
5
|
-
* merged: it reaches a flat kit (`packages/ui/src/tissues/…`) as well as a feature-sliced app, and
|
|
6
|
-
* a rule that reaches more files is the stricter rule. The `(?:^|/)` anchor is this file's
|
|
7
|
-
* addition, so `subtissues/` is not read as `tissues/`.
|
|
8
|
-
*/
|
|
9
1
|
export declare const TIERS: readonly ['atoms', 'molecules', 'compounds', 'organelles', 'cells', 'tissues'];
|
|
10
2
|
export type Tier = (typeof TIERS)[number];
|
|
3
|
+
export declare const APP_FOLDER: RegExp;
|
|
4
|
+
export declare const LAYOUTS_FOLDER: RegExp;
|
|
5
|
+
export declare const STORES_FOLDER: RegExp;
|
|
6
|
+
export declare const ABOVE_ATOMS_FOLDER: RegExp;
|
|
7
|
+
export declare const ORGANS_FOLDER: RegExp;
|
|
8
|
+
export declare const COMPONENT_FILE_PATTERN: RegExp;
|
|
9
|
+
export declare const PRIVATE_SIBLING: RegExp;
|
|
10
|
+
export declare const CELL_PRIVATE_SIBLING: RegExp;
|
|
11
11
|
export declare const inTier: (filename: string, tier: Tier) => boolean;
|
|
12
|
-
|
|
12
|
+
export declare const inOrgans: (filename: string) => boolean;
|
|
13
|
+
export declare const folderOf: <Name extends string>(source: string, names: readonly Name[]) => Name | undefined;
|
|
14
|
+
export declare const inTiersAbove: (filename: string, tier: Tier) => boolean;
|
|
13
15
|
export declare const tierOf: (filename: string) => Tier | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* The tier a file sits DIRECTLY in — the folder that is its own parent — or none.
|
|
16
|
-
*
|
|
17
|
-
* `tierOf` answers for anywhere in the path, which is what a rule about IMPORTS wants. A rule about
|
|
18
|
-
* the file's own folder wants the parent and nothing else: `cells/parts/helper.ts` is in `parts/`,
|
|
19
|
-
* and `subtissues/` is not `tissues/` however a regex written without an anchor read it (#5).
|
|
20
|
-
*/
|
|
21
16
|
export declare const tierFolderOf: (filename: string) => Tier | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* The feature a path belongs to, or none — a flat kit (`packages/ui/src/atoms/`) has tiers and no
|
|
24
|
-
* features, and a rule that assumed otherwise simply never fired there.
|
|
25
|
-
*/
|
|
26
17
|
export declare const featureOf: (filename: string) => string | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* A `scope` naming something that is not a tier matches no file, which is the inert rule the
|
|
29
|
-
* option refusal exists to stop — one option along. So it is a config error, and it stops the run.
|
|
30
|
-
*/
|
|
31
18
|
export declare const requireTiers: (rule: string, names: readonly string[]) => Tier[];
|
package/dist/rules/lib/tiers.js
CHANGED
|
@@ -9,7 +9,35 @@ var PATTERNS = {
|
|
|
9
9
|
organelles: /(?:^|\/)(?:features\/[^/]+\/)?organelles\//,
|
|
10
10
|
tissues: /(?:^|\/)(?:features\/[^/]+\/)?tissues\//
|
|
11
11
|
};
|
|
12
|
+
var APP_FOLDER = /(?:^|\/)app\//;
|
|
13
|
+
var LAYOUTS_FOLDER = /(?:^|\/)layouts\//;
|
|
14
|
+
var STORES_FOLDER = /(?:^|\/)stores\//;
|
|
15
|
+
var ABOVE_ATOMS_FOLDER = /(?:^|\/)(molecules|compounds|organelles|cells|layouts)\//;
|
|
16
|
+
var ORGANS_FOLDER = /(?:^|\/)(?:features\/[^/]+\/)?organs\//;
|
|
17
|
+
var COMPONENT_FILE_PATTERN = /(?:^|\/)(?:features\/[^/]+\/)?(compounds|organelles|cells|tissues|organs)\/.+\.tsx$/;
|
|
18
|
+
var SHARED_PRIVATE_SUFFIXES = [
|
|
19
|
+
"parts",
|
|
20
|
+
"sections",
|
|
21
|
+
"summary",
|
|
22
|
+
"layouts",
|
|
23
|
+
"icons",
|
|
24
|
+
"types",
|
|
25
|
+
"sidebar",
|
|
26
|
+
"data",
|
|
27
|
+
"stories",
|
|
28
|
+
"spec",
|
|
29
|
+
"test"
|
|
30
|
+
];
|
|
31
|
+
var privateSiblingOf = (...own) => new RegExp(`\\.(?:${[...SHARED_PRIVATE_SUFFIXES, ...own].join("|")})\\.tsx$`);
|
|
32
|
+
var PRIVATE_SIBLING = privateSiblingOf("hooks", "utils", "context", "store", "config");
|
|
33
|
+
var CELL_PRIVATE_SIBLING = privateSiblingOf("form", "steps");
|
|
12
34
|
var inTier = (filename, tier) => PATTERNS[tier].test(normalise(filename));
|
|
35
|
+
var inOrgans = (filename) => ORGANS_FOLDER.test(normalise(filename));
|
|
36
|
+
var folderOf = (source, names) => {
|
|
37
|
+
const listed = new Set(names);
|
|
38
|
+
return normalise(source).split("/").find((segment) => listed.has(segment));
|
|
39
|
+
};
|
|
40
|
+
var inTiersAbove = (filename, tier) => TIERS.slice(TIERS.indexOf(tier) + 1).some((above) => inTier(filename, above));
|
|
13
41
|
var tierOf = (filename) => TIERS.find((tier) => inTier(filename, tier));
|
|
14
42
|
var tierFolderOf = (filename) => {
|
|
15
43
|
const parent = normalise(filename).split("/").at(-2);
|
|
@@ -17,15 +45,27 @@ var tierFolderOf = (filename) => {
|
|
|
17
45
|
};
|
|
18
46
|
var FEATURE = /(?:^|\/)features\/([^/]+)\//;
|
|
19
47
|
var featureOf = (filename) => FEATURE.exec(normalise(filename))?.[1];
|
|
48
|
+
var isTier = (name) => TIERS.some((tier) => tier === name);
|
|
20
49
|
var requireTiers = (rule, names) => names.map((name) => {
|
|
21
|
-
if (
|
|
50
|
+
if (isTier(name))
|
|
22
51
|
return name;
|
|
23
52
|
throw new Error(`biological-architecture/${rule} is scoped to "${name}", which is not a tier, so that scope can never match a file. The tiers are ${TIERS.join(", ")}.`);
|
|
24
53
|
});
|
|
25
54
|
export {
|
|
55
|
+
ABOVE_ATOMS_FOLDER,
|
|
56
|
+
APP_FOLDER,
|
|
57
|
+
CELL_PRIVATE_SIBLING,
|
|
58
|
+
COMPONENT_FILE_PATTERN,
|
|
59
|
+
LAYOUTS_FOLDER,
|
|
60
|
+
ORGANS_FOLDER,
|
|
61
|
+
PRIVATE_SIBLING,
|
|
62
|
+
STORES_FOLDER,
|
|
26
63
|
TIERS,
|
|
27
64
|
featureOf,
|
|
65
|
+
folderOf,
|
|
66
|
+
inOrgans,
|
|
28
67
|
inTier,
|
|
68
|
+
inTiersAbove,
|
|
29
69
|
requireTiers,
|
|
30
70
|
tierFolderOf,
|
|
31
71
|
tierOf
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
// src/rules/lib/tissue-entrypoint.ts
|
|
2
|
-
import { normalise } from "./paths.js";
|
|
3
|
-
|
|
4
|
-
var PRIVATE_TISSUE_SIBLING = /\.(parts|sections|summary|layouts|icons|types|hooks|utils|context|store|sidebar|data|config|stories|spec|test)\.tsx$/;
|
|
2
|
+
import { fileOf, normalise } from "./paths.js";
|
|
3
|
+
import { inTier, PRIVATE_SIBLING } from "./tiers.js";
|
|
5
4
|
var tissueEntrypointOf = (filename) => {
|
|
6
5
|
const normalized = normalise(filename);
|
|
7
|
-
const basename = normalized
|
|
6
|
+
const basename = fileOf(normalized);
|
|
8
7
|
return {
|
|
9
8
|
basename,
|
|
10
|
-
isEntrypoint:
|
|
9
|
+
isEntrypoint: inTier(normalized, "tissues") && basename.endsWith(".tsx") && basename !== "index.tsx" && !PRIVATE_SIBLING.test(basename)
|
|
11
10
|
};
|
|
12
11
|
};
|
|
13
12
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/rules/lib/tsconfig-paths.ts
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { parseLooseJson } from "./module-text.js";
|
|
4
|
+
import { parseLooseJson, readManifest } from "./module-text.js";
|
|
5
5
|
import { longestMatch } from "./pattern-match.js";
|
|
6
6
|
var CHAIN = 5;
|
|
7
7
|
var configs = new Map;
|
|
@@ -26,12 +26,7 @@ var baseFileOf = (dir, base) => {
|
|
|
26
26
|
return;
|
|
27
27
|
if (rest !== "")
|
|
28
28
|
return withJson(join(packageDir, rest));
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
declared = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8")).tsconfig;
|
|
32
|
-
} catch {
|
|
33
|
-
declared = undefined;
|
|
34
|
-
}
|
|
29
|
+
const declared = readManifest(join(packageDir, "package.json"))?.tsconfig;
|
|
35
30
|
return join(packageDir, typeof declared === "string" ? declared : "tsconfig.json");
|
|
36
31
|
};
|
|
37
32
|
var packageDirAbove = (dir, name) => {
|
|
@@ -77,19 +72,56 @@ var readConfig = (file) => {
|
|
|
77
72
|
}
|
|
78
73
|
return { anchor, paths };
|
|
79
74
|
};
|
|
75
|
+
var GLOB = /[*?{[]/;
|
|
76
|
+
var strings = (value) => Array.isArray(value) ? value.filter((one) => typeof one === "string") : [];
|
|
77
|
+
var referencePathsOf = (references) => (Array.isArray(references) ? references : []).flatMap((one) => {
|
|
78
|
+
if (typeof one !== "object" || one === null || !("path" in one))
|
|
79
|
+
return [];
|
|
80
|
+
return typeof one.path === "string" ? [one.path] : [];
|
|
81
|
+
});
|
|
82
|
+
var includedBy = (file) => {
|
|
83
|
+
const dir = dirname(file);
|
|
84
|
+
const entries = strings(rawOf(file)?.include);
|
|
85
|
+
return entries.length === 0 ? [dir] : entries.map((entry) => {
|
|
86
|
+
const segments = entry.split("/");
|
|
87
|
+
const globAt = segments.findIndex((one) => GLOB.test(one));
|
|
88
|
+
const head = globAt === -1 ? segments : segments.slice(0, globAt);
|
|
89
|
+
const last = head.at(-1);
|
|
90
|
+
const literal = last !== undefined && /\.[a-z]+$/.test(last) ? head.slice(0, -1) : head;
|
|
91
|
+
return resolve(dir, ...literal);
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
var isUnder = (dir, parent) => dir === parent || dir.startsWith(`${parent}/`);
|
|
95
|
+
var referencedConfig = (file, dir) => {
|
|
96
|
+
const refs = rawOf(file)?.references;
|
|
97
|
+
for (const named of referencePathsOf(refs)) {
|
|
98
|
+
const target = resolve(dirname(file), named);
|
|
99
|
+
const config = CONFIG_FILES.map((name) => join(target, name)).find((one) => existsSync(one));
|
|
100
|
+
const project = config ?? (target.endsWith(".json") ? target : withJson(target));
|
|
101
|
+
if (!existsSync(project))
|
|
102
|
+
continue;
|
|
103
|
+
if (!includedBy(project).some((included) => isUnder(dir, included)))
|
|
104
|
+
continue;
|
|
105
|
+
const found = readConfig(project);
|
|
106
|
+
if (found !== null)
|
|
107
|
+
return found;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
80
111
|
var CONFIG_FILES = ["tsconfig.json", "jsconfig.json"];
|
|
112
|
+
var nearestConfigFile = (dir) => {
|
|
113
|
+
const file = CONFIG_FILES.map((name) => join(dir, name)).find((one) => existsSync(one));
|
|
114
|
+
if (file !== undefined)
|
|
115
|
+
return file;
|
|
116
|
+
const parent = dirname(dir);
|
|
117
|
+
return parent === dir ? undefined : nearestConfigFile(parent);
|
|
118
|
+
};
|
|
81
119
|
var configFor = (dir) => {
|
|
82
120
|
const known = configs.get(dir);
|
|
83
121
|
if (known !== undefined)
|
|
84
122
|
return known;
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
if (file !== undefined)
|
|
88
|
-
found = readConfig(file);
|
|
89
|
-
else {
|
|
90
|
-
const parent = dirname(dir);
|
|
91
|
-
found = parent === dir ? null : configFor(parent);
|
|
92
|
-
}
|
|
123
|
+
const file = nearestConfigFile(dir);
|
|
124
|
+
const found = file === undefined ? null : readConfig(file) ?? referencedConfig(file, dir);
|
|
93
125
|
configs.set(dir, found);
|
|
94
126
|
return found;
|
|
95
127
|
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/rules/lib/type-members.ts
|
|
2
|
+
import { readSource } from "./module-text.js";
|
|
3
|
+
var DEPTH = 4;
|
|
4
|
+
var OPENERS = new Set(["(", "[", "{", "<"]);
|
|
5
|
+
var CLOSERS = new Set([")", "]", "}", ">"]);
|
|
6
|
+
var QUOTES = new Set(['"', "'", "`"]);
|
|
7
|
+
var nextOutside = (text, from) => {
|
|
8
|
+
const quote = text[from];
|
|
9
|
+
if (quote === undefined || !QUOTES.has(quote))
|
|
10
|
+
return from;
|
|
11
|
+
let at = from + 1;
|
|
12
|
+
while (at < text.length && text[at] !== quote)
|
|
13
|
+
at += text[at] === "\\" ? 2 : 1;
|
|
14
|
+
return at;
|
|
15
|
+
};
|
|
16
|
+
function* scan(text, from = 0) {
|
|
17
|
+
let depth = 0;
|
|
18
|
+
for (let at = from;at < text.length; at += 1) {
|
|
19
|
+
at = nextOutside(text, at);
|
|
20
|
+
const char = text[at] ?? "";
|
|
21
|
+
const closes = CLOSERS.has(char) && !(char === ">" && text[at - 1] === "=");
|
|
22
|
+
if (OPENERS.has(char))
|
|
23
|
+
depth += 1;
|
|
24
|
+
else if (closes)
|
|
25
|
+
depth -= 1;
|
|
26
|
+
yield { at, char, closes, depth };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var closesAt = (text, open) => {
|
|
30
|
+
for (const { at, closes, depth } of scan(text, open))
|
|
31
|
+
if (closes && depth === 0)
|
|
32
|
+
return at;
|
|
33
|
+
return -1;
|
|
34
|
+
};
|
|
35
|
+
var splitTop = (text, separators) => {
|
|
36
|
+
const parts = [];
|
|
37
|
+
let from = 0;
|
|
38
|
+
for (const { at, char, depth } of scan(text)) {
|
|
39
|
+
if (depth === 0 && separators.has(char)) {
|
|
40
|
+
parts.push(text.slice(from, at));
|
|
41
|
+
from = at + 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
parts.push(text.slice(from));
|
|
45
|
+
return parts.map((one) => one.trim()).filter((one) => one !== "");
|
|
46
|
+
};
|
|
47
|
+
var CONTINUES_BEFORE = /(?:[|&:=,(<]|=>)\s*$/;
|
|
48
|
+
var CONTINUES_AFTER = /^\s*[|&?:.=)]/;
|
|
49
|
+
var membersText = (body) => {
|
|
50
|
+
const members = [];
|
|
51
|
+
let from = 0;
|
|
52
|
+
for (const { at, char, depth } of scan(body)) {
|
|
53
|
+
if (depth !== 0)
|
|
54
|
+
continue;
|
|
55
|
+
if (char === ";" || char === ",") {
|
|
56
|
+
members.push(body.slice(from, at));
|
|
57
|
+
from = at + 1;
|
|
58
|
+
} else if (char === `
|
|
59
|
+
`) {
|
|
60
|
+
const current = body.slice(from, at);
|
|
61
|
+
if (current.trim() !== "" && !CONTINUES_BEFORE.test(current) && !CONTINUES_AFTER.test(body.slice(at + 1))) {
|
|
62
|
+
members.push(current);
|
|
63
|
+
from = at + 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
members.push(body.slice(from));
|
|
68
|
+
return members.map((one) => one.trim()).filter((one) => one !== "");
|
|
69
|
+
};
|
|
70
|
+
var KEY = /^(?:readonly\s+)?(?:(["'])(.*?)\1|([A-Za-z_$][\w$]*))\s*\??\s*(?=[:(<])/;
|
|
71
|
+
var memberOf = (text) => {
|
|
72
|
+
const key = KEY.exec(text);
|
|
73
|
+
if (key === null)
|
|
74
|
+
return;
|
|
75
|
+
const name = key[2] ?? key[3] ?? "";
|
|
76
|
+
const rest = text.slice(key[0].length).trim();
|
|
77
|
+
if (rest.startsWith(":"))
|
|
78
|
+
return { name, type: rest.slice(1).trim() };
|
|
79
|
+
const generics = rest.startsWith("<") ? closesAt(rest, 0) + 1 : 0;
|
|
80
|
+
const open = generics > 0 ? generics : 0;
|
|
81
|
+
if (rest[open] !== "(")
|
|
82
|
+
return;
|
|
83
|
+
const close = closesAt(rest, open);
|
|
84
|
+
if (close === -1)
|
|
85
|
+
return;
|
|
86
|
+
const returned = rest.slice(close + 1).replace(/^\s*:\s*/, "");
|
|
87
|
+
return { name, type: `${rest.slice(0, close + 1)} => ${returned === "" ? "void" : returned}` };
|
|
88
|
+
};
|
|
89
|
+
var parseMembers = (body) => membersText(body).flatMap((one) => memberOf(one) ?? []);
|
|
90
|
+
var escaped = (name) => name.replaceAll("$", String.raw`\$`);
|
|
91
|
+
var bodyAfter = (text, from) => {
|
|
92
|
+
const open = text.indexOf("{", from);
|
|
93
|
+
if (open === -1)
|
|
94
|
+
return;
|
|
95
|
+
const close = closesAt(text, open);
|
|
96
|
+
return close === -1 ? undefined : text.slice(open + 1, close);
|
|
97
|
+
};
|
|
98
|
+
var aliasText = (text, from) => {
|
|
99
|
+
let end = from;
|
|
100
|
+
for (const { at, char, depth } of scan(text, from)) {
|
|
101
|
+
if (depth === 0 && (char === ";" || char === `
|
|
102
|
+
`)) {
|
|
103
|
+
const scanned = text.slice(from, at);
|
|
104
|
+
if (char === ";" || scanned.trim() !== "" && !CONTINUES_BEFORE.test(scanned) && !CONTINUES_AFTER.test(text.slice(at + 1))) {
|
|
105
|
+
end = at;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
end = at + 1;
|
|
110
|
+
}
|
|
111
|
+
return text.slice(from, end);
|
|
112
|
+
};
|
|
113
|
+
var IDENTIFIER_TYPE = /^([A-Za-z_$][\w$]*)(?:<.*>)?$/s;
|
|
114
|
+
var membersIn = (text, name, depth) => {
|
|
115
|
+
if (depth > DEPTH)
|
|
116
|
+
return;
|
|
117
|
+
const interfaced = new RegExp(String.raw`\binterface\s+${escaped(name)}\b`).exec(text);
|
|
118
|
+
if (interfaced !== null) {
|
|
119
|
+
const body = bodyAfter(text, interfaced.index + interfaced[0].length);
|
|
120
|
+
return body === undefined ? undefined : parseMembers(body);
|
|
121
|
+
}
|
|
122
|
+
const aliased = new RegExp(String.raw`\btype\s+${escaped(name)}\b[^=]*=\s*`).exec(text);
|
|
123
|
+
if (aliased === null)
|
|
124
|
+
return;
|
|
125
|
+
const parts = splitTop(aliasText(text, aliased.index + aliased[0].length), new Set(["&"]));
|
|
126
|
+
const found = parts.flatMap((part) => {
|
|
127
|
+
if (part.startsWith("{") && closesAt(part, 0) === part.length - 1) {
|
|
128
|
+
return [parseMembers(part.slice(1, -1))];
|
|
129
|
+
}
|
|
130
|
+
const named = IDENTIFIER_TYPE.exec(part)?.[1];
|
|
131
|
+
const inner = named === undefined ? undefined : membersIn(text, named, depth + 1);
|
|
132
|
+
return inner === undefined ? [] : [inner];
|
|
133
|
+
});
|
|
134
|
+
return found.length === 0 ? undefined : found.flat();
|
|
135
|
+
};
|
|
136
|
+
var membersOfNamedType = (file, name) => {
|
|
137
|
+
const text = readSource(file);
|
|
138
|
+
return text === undefined ? undefined : membersIn(text, name, 0);
|
|
139
|
+
};
|
|
140
|
+
var STATE_REFERENCE = /^(?:React\.)?(?:Dispatch|SetStateAction)\b|^Function$/;
|
|
141
|
+
var UNDECLARED = new Set(["any", "unknown", "object", "{}"]);
|
|
142
|
+
var unwrapped = (type) => {
|
|
143
|
+
let current = type.trim();
|
|
144
|
+
while (current.startsWith("(") && closesAt(current, 0) === current.length - 1) {
|
|
145
|
+
current = current.slice(1, -1).trim();
|
|
146
|
+
}
|
|
147
|
+
return current;
|
|
148
|
+
};
|
|
149
|
+
var isFunctionType = (type) => {
|
|
150
|
+
const from = type.startsWith("<") ? closesAt(type, 0) + 1 : 0;
|
|
151
|
+
if (type[from] !== "(")
|
|
152
|
+
return false;
|
|
153
|
+
const close = closesAt(type, from);
|
|
154
|
+
return close !== -1 && /^\s*=>/.test(type.slice(close + 1));
|
|
155
|
+
};
|
|
156
|
+
var callableOrUndeclared = (type) => {
|
|
157
|
+
const alternatives = splitTop(unwrapped(type), new Set(["|"])).map(unwrapped);
|
|
158
|
+
if (alternatives.some((one) => isFunctionType(one) || STATE_REFERENCE.test(one)))
|
|
159
|
+
return "handler";
|
|
160
|
+
return alternatives.some((one) => UNDECLARED.has(one.replaceAll(/\s+/g, ""))) ? "undeclared" : undefined;
|
|
161
|
+
};
|
|
162
|
+
export {
|
|
163
|
+
callableOrUndeclared,
|
|
164
|
+
membersOfNamedType
|
|
165
|
+
};
|
|
@@ -2,30 +2,8 @@ import { type ModuleNode } from './imports.js';
|
|
|
2
2
|
export type Visitor = Record<string, ((node: never) => void) | undefined>;
|
|
3
3
|
type ImportHandler = (source: string, node: ModuleNode) => void;
|
|
4
4
|
type ImportOptions = {
|
|
5
|
-
/**
|
|
6
|
-
* Whether `import type` and `export type … from` are visited. They are not, by default: a type a
|
|
7
|
-
* bundler erases is not a dependency, and every direction rule here says so. `no-orm-outside-db`
|
|
8
|
-
* is the exception that made this an option — a type borrowed from the ORM is still a line a
|
|
9
|
-
* replacement would have to rewrite, so that rule counts them.
|
|
10
|
-
*/
|
|
11
5
|
typeOnly?: 'skip' | 'visit';
|
|
12
6
|
};
|
|
13
|
-
/**
|
|
14
|
-
* One visitor set for every way a file can name another: `import`, `export … from`, `export * from`,
|
|
15
|
-
* `import()` and `require()`.
|
|
16
|
-
*
|
|
17
|
-
* Eleven rules hand-wrote three of these keys; the ones whose author had met a dynamic import wrote
|
|
18
|
-
* a fourth. Which doors a wall was watched at became an accident of who wrote the rule, and a wall
|
|
19
|
-
* with a door left open is not a wall. The handler takes the source AND the node, because a rule
|
|
20
|
-
* that reports wants the node and a rule like `organelle-single-source` wants its specifiers.
|
|
21
|
-
*/
|
|
22
7
|
export declare const onImportSource: (onSource: ImportHandler, { typeOnly }?: ImportOptions) => Visitor;
|
|
23
|
-
/**
|
|
24
|
-
* Two visitor sets as one, with both handlers run for a node type they both name.
|
|
25
|
-
*
|
|
26
|
-
* A rule that watches imports AND something else — `dialect-through-the-seam` also reads
|
|
27
|
-
* `sql.raw(…)` calls, `organelle-single-source` also counts store hooks — would otherwise have to
|
|
28
|
-
* spread one object over the other, and the spread SILENTLY drops the handler underneath it.
|
|
29
|
-
*/
|
|
30
8
|
export declare const mergeVisitors: (...visitors: Visitor[]) => Visitor;
|
|
31
9
|
export {};
|