@geonosis/oxlint-plugin-biological-architecture 3.0.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 +50 -0
- package/README.md +48 -5
- package/RULES.md +201 -98
- package/corpus/.oxlintrc.json +6 -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/icon-controls/bad-unnamed-icon-button.tsx +8 -0
- package/corpus/icon-controls/good-named-icon-button.tsx +19 -0
- package/corpus/manifest.json +3 -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 -174
- package/dist/presets.d.ts +11 -19
- package/dist/presets.js +89 -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.d.ts +53 -0
- package/dist/rules/icon-control-has-name.js +71 -0
- 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 +3 -1
- 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 +2 -0
- 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 +0 -7
- 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 +2 -25
- 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 +4 -2
- package/dist/rules/tissue-must-compose.js +25 -20
- package/dist/rules/tissue-no-data-props.d.ts +56 -0
- 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 +20 -22
- 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 +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/package.json +2 -2
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/rules/tissue-no-hooks.ts
|
|
2
|
-
import { hookCalledBy } from "./lib/hooks.js";
|
|
2
|
+
import { hookCalledBy, hookNameOf } from "./lib/hooks.js";
|
|
3
|
+
import { sourceOf } from "./lib/imports.js";
|
|
4
|
+
import { optionsBag, STRINGS } from "./lib/schema.js";
|
|
3
5
|
import { tissueEntrypointOf } from "./lib/tissue-entrypoint.js";
|
|
4
6
|
var FORBIDDEN_HOOKS = new Set([
|
|
5
7
|
"useCallback",
|
|
@@ -16,11 +18,14 @@ var tissueNoHooks = {
|
|
|
16
18
|
const { basename: shortName, isEntrypoint } = tissueEntrypointOf(context.filename);
|
|
17
19
|
if (!isEntrypoint)
|
|
18
20
|
return {};
|
|
21
|
+
const reads = new Set((context.options?.[0]?.contextHooks ?? []).filter((one) => !FORBIDDEN_HOOKS.has(one)));
|
|
19
22
|
return {
|
|
20
23
|
CallExpression(node) {
|
|
21
24
|
const name = hookCalledBy(node);
|
|
22
25
|
if (name === null)
|
|
23
26
|
return;
|
|
27
|
+
if (reads.has(hookNameOf(node) ?? ""))
|
|
28
|
+
return;
|
|
24
29
|
context.report({
|
|
25
30
|
data: { file: shortName, hook: name },
|
|
26
31
|
messageId: "called",
|
|
@@ -30,7 +35,7 @@ var tissueNoHooks = {
|
|
|
30
35
|
ImportDeclaration(node) {
|
|
31
36
|
if (node.importKind === "type")
|
|
32
37
|
return;
|
|
33
|
-
if (node
|
|
38
|
+
if (sourceOf(node) !== "react")
|
|
34
39
|
return;
|
|
35
40
|
const specifiers = node.specifiers ?? [];
|
|
36
41
|
for (const spec of specifiers) {
|
|
@@ -52,7 +57,9 @@ var tissueNoHooks = {
|
|
|
52
57
|
},
|
|
53
58
|
fixShape: `A tissue holds no state: no \`useState\`, no \`useEffect\`, and no call to ANY \`use*()\` — including a
|
|
54
59
|
hook defined in \`lib/\` that reads a store behind your back. If you need the hook, the file is a cell:
|
|
55
|
-
move it to \`cells/\`, or push the call into a cell the tissue arranges.
|
|
60
|
+
move it to \`cells/\`, or push the call into a cell the tissue arranges. A hook that only reads the
|
|
61
|
+
framework's context (\`useTranslations\`, \`usePathname\`) is named in \`contextHooks\`, a list that is
|
|
62
|
+
empty until the repo writes it and never excuses \`useState\` and its kin. Private siblings
|
|
56
63
|
(\`.parts.tsx\`, \`.sections.tsx\`) are not the tissue entrypoint and may hold local UI state.`,
|
|
57
64
|
meta: {
|
|
58
65
|
docs: {
|
|
@@ -62,8 +69,19 @@ move it to \`cells/\`, or push the call into a cell the tissue arranges. Private
|
|
|
62
69
|
called: 'Tissue "{{file}}" calls "{{hook}}". A hook call is state, wherever the hook is defined — a rule that only reads imports never sees the state a `lib/` hook reaches through. Move this file to cells/, or push the call into a cell it arranges.',
|
|
63
70
|
forbidden: 'Tissue "{{file}}" imports "{{hook}}" from react. Tissues are pure arrangements of cells and cannot hold state. State lives only at organelle/cell levels. Either push this logic into a cell, or if this file is truly doing cell work, move it to the cells/ tier.'
|
|
64
71
|
},
|
|
65
|
-
schema:
|
|
72
|
+
schema: optionsBag({ contextHooks: STRINGS }),
|
|
66
73
|
type: "problem"
|
|
74
|
+
},
|
|
75
|
+
probe() {
|
|
76
|
+
return {
|
|
77
|
+
path: "src/tissues/geonosis-probe.tsx",
|
|
78
|
+
source: `declare const useGeonosisThing: () => number
|
|
79
|
+
|
|
80
|
+
export function GeonosisProbe() {
|
|
81
|
+
return <div>{useGeonosisThing()}</div>
|
|
82
|
+
}
|
|
83
|
+
`
|
|
84
|
+
};
|
|
67
85
|
}
|
|
68
86
|
};
|
|
69
87
|
var tissue_no_hooks_default = tissueNoHooks;
|
|
@@ -9,6 +9,7 @@ declare const tissueNoOrganelles: {
|
|
|
9
9
|
}) => void;
|
|
10
10
|
}): import('./lib/visitors.js').Visitor;
|
|
11
11
|
fixShape: string;
|
|
12
|
+
probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
|
|
12
13
|
meta: {
|
|
13
14
|
docs: {
|
|
14
15
|
description: string;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
// src/rules/tissue-no-organelles.ts
|
|
2
2
|
import { directionRule } from "./lib/direction-rule.js";
|
|
3
|
+
import { inTier } from "./lib/tiers.js";
|
|
3
4
|
var tissueNoOrganelles = directionRule({
|
|
4
5
|
description: "Tissues cannot directly import organelles. In biology, tissues arrange cells; organelles live INSIDE cells. To reach an organelle from a tissue, go through a cell. This forces tissues to stay at the cell-arrangement level and keeps state encapsulated in the cells that own their organelles.",
|
|
5
6
|
fixShape: `A tissue never imports an organelle. Organelles live INSIDE cells; go through a cell that hosts the
|
|
6
7
|
organelle and let the tissue arrange the cell. Reaching past the cell is how state gets into a layer
|
|
7
8
|
that is supposed to have none.`,
|
|
8
|
-
forbidden: (target) =>
|
|
9
|
+
forbidden: (target) => inTier(target.path, "organelles"),
|
|
9
10
|
messages: {
|
|
10
11
|
forbidden: 'Tissue "{{file}}" cannot import organelle "{{source}}". Tissues arrange cells; organelles live inside cells. Host this organelle inside a cell, then compose the cell from this tissue.'
|
|
11
12
|
},
|
|
13
|
+
probe: () => ({
|
|
14
|
+
path: "src/tissues/geonosis-probe.tsx",
|
|
15
|
+
source: `import { up } from '../organelles/geonosis-up'
|
|
16
|
+
|
|
17
|
+
export const GeonosisProbe = up
|
|
18
|
+
`
|
|
19
|
+
}),
|
|
12
20
|
scope: "tissues"
|
|
13
21
|
});
|
|
14
22
|
var tissue_no_organelles_default = tissueNoOrganelles;
|
|
@@ -9,6 +9,7 @@ declare const tissueNoStores: {
|
|
|
9
9
|
}) => void;
|
|
10
10
|
}): import('./lib/visitors.js').Visitor;
|
|
11
11
|
fixShape: string;
|
|
12
|
+
probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
|
|
12
13
|
meta: {
|
|
13
14
|
docs: {
|
|
14
15
|
description: string;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
// src/rules/tissue-no-stores.ts
|
|
2
2
|
import { directionRule } from "./lib/direction-rule.js";
|
|
3
|
+
import { STORES_FOLDER } from "./lib/tiers.js";
|
|
3
4
|
var tissueNoStores = directionRule({
|
|
4
5
|
description: "Tissues cannot import from stores. Tissues arrange cells but must not directly access state. State lives at organelle and cell levels.",
|
|
5
6
|
fixShape: `A tissue reads no store. State lives at the organelle and cell tiers only — a tissue that needs store
|
|
6
7
|
data is a cell wearing the wrong folder. Move it to \`cells/\`, or have a cell read the store and let
|
|
7
8
|
the tissue arrange that cell.`,
|
|
8
|
-
forbidden: (target) =>
|
|
9
|
+
forbidden: (target) => STORES_FOLDER.test(target.path),
|
|
9
10
|
messages: {
|
|
10
11
|
forbidden: 'Tissue "{{file}}" cannot import from "{{source}}". Tissues arrange cells but must not directly access stores. Push the store read into a constituent cell.'
|
|
11
12
|
},
|
|
13
|
+
probe: () => ({
|
|
14
|
+
path: "src/tissues/geonosis-probe.tsx",
|
|
15
|
+
source: `import { up } from '../stores/geonosis-up'
|
|
16
|
+
|
|
17
|
+
export const GeonosisProbe = up
|
|
18
|
+
`
|
|
19
|
+
}),
|
|
12
20
|
scope: "tissues"
|
|
13
21
|
});
|
|
14
22
|
var tissue_no_stores_default = tissueNoStores;
|
|
@@ -1,31 +1,9 @@
|
|
|
1
|
+
import { type SourceCode } from './lib/comments.js';
|
|
1
2
|
import { type Probe } from './lib/probe.js';
|
|
2
3
|
interface Options {
|
|
3
|
-
/** What a plan id looks like, as a regex source. `\d{3,}` is the NNN a plan file is named for. */
|
|
4
4
|
id?: string;
|
|
5
|
-
/**
|
|
6
|
-
* The words this repo treats as debt markers. Matched case-sensitively, on a word boundary and
|
|
7
|
-
* followed by `(`, `:`, whitespace or the end of the comment — the shapes a marker is written in.
|
|
8
|
-
*/
|
|
9
5
|
markers?: string[];
|
|
10
6
|
}
|
|
11
|
-
type Comment = {
|
|
12
|
-
loc: {
|
|
13
|
-
end: {
|
|
14
|
-
line: number;
|
|
15
|
-
};
|
|
16
|
-
start: {
|
|
17
|
-
line: number;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
type: string;
|
|
21
|
-
value: string;
|
|
22
|
-
};
|
|
23
|
-
type SourceCode = {
|
|
24
|
-
ast?: {
|
|
25
|
-
comments?: Comment[];
|
|
26
|
-
};
|
|
27
|
-
getAllComments?: () => Comment[];
|
|
28
|
-
};
|
|
29
7
|
declare const todoNamesItsPlan: {
|
|
30
8
|
create(context: {
|
|
31
9
|
filename: string;
|
|
@@ -65,11 +43,6 @@ declare const todoNamesItsPlan: {
|
|
|
65
43
|
}[];
|
|
66
44
|
type: 'problem';
|
|
67
45
|
};
|
|
68
|
-
/**
|
|
69
|
-
* The repo's OWN first marker, in a comment, citing nothing. It has to be the configured word:
|
|
70
|
-
* a probe hardcoding one spelling would report the rule as unreachable in every repo that spells
|
|
71
|
-
* its debt with another, which is the whole class of finding probes exist to end.
|
|
72
|
-
*/
|
|
73
46
|
probe(options: readonly unknown[]): Probe;
|
|
74
47
|
};
|
|
75
48
|
export default todoNamesItsPlan;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/rules/todo-names-its-plan.ts
|
|
2
|
+
import { commentsOf } from "./lib/comments.js";
|
|
2
3
|
import { requireOption } from "./lib/options.js";
|
|
4
|
+
import { escapeForRegex } from "./lib/pattern-match.js";
|
|
3
5
|
import { bagOf, firstOf } from "./lib/probe.js";
|
|
4
6
|
import { optionsBag, STRING, STRINGS } from "./lib/schema.js";
|
|
5
7
|
var ID_DEFAULT = String.raw`\d{3,}`;
|
|
6
|
-
var commentsOf = (sourceCode) => sourceCode?.getAllComments?.() ?? sourceCode?.ast?.comments ?? [];
|
|
7
|
-
var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8
8
|
var todoNamesItsPlan = {
|
|
9
9
|
create(context) {
|
|
10
10
|
const { id = ID_DEFAULT, markers = [] } = context.options?.[0] ?? {};
|
|
@@ -3,52 +3,22 @@ import type { AnyNode } from './lib/nodes.js';
|
|
|
3
3
|
import { type Probe } from './lib/probe.js';
|
|
4
4
|
import { type OpeningElement } from './lib/styling.js';
|
|
5
5
|
interface Options {
|
|
6
|
-
/** Paths where a literal is the point — the theme file, the palette, the token layer. */
|
|
7
6
|
allow?: string[];
|
|
8
|
-
/**
|
|
9
|
-
* The modules this rule does not judge, each written out in full — the enumeration a pattern
|
|
10
|
-
* cannot be. A glob grants its exemption to wherever it stops and nobody counts what accumulates
|
|
11
|
-
* on the far side; a list of module names is a number a reader can hold.
|
|
12
|
-
*/
|
|
13
7
|
exemptModules?: string[];
|
|
14
|
-
/** The prefixes a themed custom property starts with. One string or several. */
|
|
15
8
|
tokenPrefix?: string | string[];
|
|
16
9
|
}
|
|
17
10
|
declare const tokensOnlyColors: {
|
|
18
11
|
create(context: RuleContextWithOptions<Options>): {
|
|
19
12
|
JSXOpeningElement?: undefined;
|
|
20
|
-
|
|
21
|
-
* A colour that arrives as a DEFAULT — `({ color = '#090909' })` — is never written in a JSX
|
|
22
|
-
* attribute, so the visitor above cannot see it. It reaches the element through a prop and
|
|
23
|
-
* paints in the brand it was typed for, from the one place nobody looked: seventy-two icons
|
|
24
|
-
* in one kit carried the same hex this way, under this rule, at "error", for its whole life.
|
|
25
|
-
* A default is a value the component CHOOSES, which is exactly what a token is for.
|
|
26
|
-
*
|
|
27
|
-
* A bare word is left alone. `variant = 'primary'` and `size = 'small'` are defaults too, and
|
|
28
|
-
* a rule that read every English word as a colour would be turned off within the week.
|
|
29
|
-
*/
|
|
13
|
+
Property?: undefined;
|
|
30
14
|
AssignmentPattern?: undefined;
|
|
31
15
|
} | {
|
|
32
16
|
JSXOpeningElement(node: OpeningElement): void;
|
|
33
|
-
|
|
34
|
-
* A colour that arrives as a DEFAULT — `({ color = '#090909' })` — is never written in a JSX
|
|
35
|
-
* attribute, so the visitor above cannot see it. It reaches the element through a prop and
|
|
36
|
-
* paints in the brand it was typed for, from the one place nobody looked: seventy-two icons
|
|
37
|
-
* in one kit carried the same hex this way, under this rule, at "error", for its whole life.
|
|
38
|
-
* A default is a value the component CHOOSES, which is exactly what a token is for.
|
|
39
|
-
*
|
|
40
|
-
* A bare word is left alone. `variant = 'primary'` and `size = 'small'` are defaults too, and
|
|
41
|
-
* a rule that read every English word as a colour would be turned off within the week.
|
|
42
|
-
*/
|
|
17
|
+
Property(node: AnyNode): void;
|
|
43
18
|
AssignmentPattern(node: AnyNode): void;
|
|
44
19
|
};
|
|
45
20
|
fixShape: string;
|
|
46
21
|
meta: {
|
|
47
|
-
/**
|
|
48
|
-
* #139: which option grants by PATTERN and which one ENUMERATES. Declared on the rule so the
|
|
49
|
-
* doctor needs no list of its own — a rule that gains a path grant and forgets to say so is a
|
|
50
|
-
* grant nothing counts, which is the defect this pair exists to end.
|
|
51
|
-
*/
|
|
52
22
|
grants: {
|
|
53
23
|
modules: string;
|
|
54
24
|
paths: string;
|
|
@@ -90,11 +60,6 @@ declare const tokensOnlyColors: {
|
|
|
90
60
|
}[];
|
|
91
61
|
type: 'problem';
|
|
92
62
|
};
|
|
93
|
-
/**
|
|
94
|
-
* A named colour in an inline style, which fires under any token prefix — the question is whether
|
|
95
|
-
* the rule RUNS in this repo, and a probe spelled out of the prefix would be defeated by a repo
|
|
96
|
-
* that happened to declare a token of the same name.
|
|
97
|
-
*/
|
|
98
63
|
probe(): Probe;
|
|
99
64
|
};
|
|
100
65
|
export default tokensOnlyColors;
|
|
@@ -6,20 +6,23 @@ import {
|
|
|
6
6
|
isColorShorthand,
|
|
7
7
|
isColorUtility
|
|
8
8
|
} from "./lib/colors.js";
|
|
9
|
-
import { requireOption } from "./lib/options.js";
|
|
10
|
-
import {
|
|
9
|
+
import { DEFAULT_TEST_EXEMPT, requireOption } from "./lib/options.js";
|
|
10
|
+
import { anyOf, isExempt, normalise } from "./lib/paths.js";
|
|
11
11
|
import { optionsBag, STRINGS } from "./lib/schema.js";
|
|
12
12
|
import {
|
|
13
13
|
arbitraryValuesOf,
|
|
14
14
|
classNameOf,
|
|
15
|
+
keyOf,
|
|
15
16
|
localVariablesOf,
|
|
16
17
|
styleEntriesOf,
|
|
18
|
+
styleObjectOf,
|
|
17
19
|
variableOf
|
|
18
20
|
} from "./lib/styling.js";
|
|
19
21
|
var defaultedName = (node) => {
|
|
20
22
|
const left = node.left;
|
|
21
23
|
return left?.type === "Identifier" ? left.name ?? "default" : "default";
|
|
22
24
|
};
|
|
25
|
+
var isNamedOnly = (value) => /^[a-z]+$/i.test(value.trim());
|
|
23
26
|
var tokenOffence = (value, prefixes, local) => {
|
|
24
27
|
const variable = variableOf(value);
|
|
25
28
|
if (variable !== undefined) {
|
|
@@ -31,16 +34,27 @@ var tokenOffence = (value, prefixes, local) => {
|
|
|
31
34
|
};
|
|
32
35
|
var tokensOnlyColors = {
|
|
33
36
|
create(context) {
|
|
34
|
-
const {
|
|
37
|
+
const { tokenPrefix, ...exempt } = context.options?.[0] ?? {};
|
|
35
38
|
const prefixes = [requireOption("tokens-only-colors", tokenPrefix, "tokenPrefix")].flat();
|
|
36
|
-
requireOption("tokens-only-colors", prefixes, "tokenPrefix");
|
|
37
39
|
const filename = normalise(context.filename);
|
|
38
|
-
if (
|
|
39
|
-
return {};
|
|
40
|
-
if (allow.some((path) => filename.includes(path)))
|
|
40
|
+
if (isExempt(filename, exempt))
|
|
41
41
|
return {};
|
|
42
|
+
const readByAnElement = new WeakSet;
|
|
43
|
+
const reportDefault = (node, property, value) => {
|
|
44
|
+
const offence = tokenOffence(value, prefixes, new Set);
|
|
45
|
+
if (offence === undefined || offence === "colorLiteral" && isNamedOnly(value))
|
|
46
|
+
return;
|
|
47
|
+
if (offence === "foreignVariable" && !isColorProperty(property))
|
|
48
|
+
return;
|
|
49
|
+
context.report({ data: { property, value }, messageId: offence, node });
|
|
50
|
+
};
|
|
51
|
+
const isTest = anyOf([...DEFAULT_TEST_EXEMPT, "__fixtures__/", "__visual__/"], filename);
|
|
42
52
|
return {
|
|
43
53
|
JSXOpeningElement(node) {
|
|
54
|
+
const styled = styleObjectOf(node);
|
|
55
|
+
for (const entry of styled?.properties ?? []) {
|
|
56
|
+
readByAnElement.add(entry);
|
|
57
|
+
}
|
|
44
58
|
const report = (messageId, data) => context.report({ data, messageId, node });
|
|
45
59
|
const local = localVariablesOf(node);
|
|
46
60
|
for (const { property, value } of styleEntriesOf(node)) {
|
|
@@ -68,20 +82,22 @@ var tokensOnlyColors = {
|
|
|
68
82
|
}
|
|
69
83
|
}
|
|
70
84
|
},
|
|
85
|
+
Property(node) {
|
|
86
|
+
if (isTest || readByAnElement.has(node))
|
|
87
|
+
return;
|
|
88
|
+
const value = node.value;
|
|
89
|
+
if (value?.type !== "Literal" || typeof value.value !== "string")
|
|
90
|
+
return;
|
|
91
|
+
const name = keyOf(node);
|
|
92
|
+
if (name === undefined)
|
|
93
|
+
return;
|
|
94
|
+
reportDefault(node, name, value.value);
|
|
95
|
+
},
|
|
71
96
|
AssignmentPattern(node) {
|
|
72
97
|
const right = node.right;
|
|
73
98
|
if (right?.type !== "Literal" || typeof right.value !== "string")
|
|
74
99
|
return;
|
|
75
|
-
|
|
76
|
-
if (offence === undefined || offence === "colorLiteral" && isNamedOnly(right.value))
|
|
77
|
-
return;
|
|
78
|
-
if (offence === "foreignVariable" && !isColorProperty(defaultedName(node)))
|
|
79
|
-
return;
|
|
80
|
-
context.report({
|
|
81
|
-
data: { property: defaultedName(node), value: right.value },
|
|
82
|
-
messageId: offence,
|
|
83
|
-
node
|
|
84
|
-
});
|
|
100
|
+
reportDefault(node, defaultedName(node), right.value);
|
|
85
101
|
}
|
|
86
102
|
};
|
|
87
103
|
},
|
|
@@ -122,7 +138,6 @@ exactly like a clean tree.`,
|
|
|
122
138
|
};
|
|
123
139
|
}
|
|
124
140
|
};
|
|
125
|
-
var isNamedOnly = (value) => /^[a-z]+$/i.test(value.trim());
|
|
126
141
|
var tokens_only_colors_default = tokensOnlyColors;
|
|
127
142
|
export {
|
|
128
143
|
tokens_only_colors_default as default
|
|
@@ -2,9 +2,7 @@ import { type RuleContextWithOptions } from './lib/context.js';
|
|
|
2
2
|
import { type AnyNode } from './lib/nodes.js';
|
|
3
3
|
import { type Probe } from './lib/probe.js';
|
|
4
4
|
interface Options {
|
|
5
|
-
/** The call names that read through the query graph. No default: see the note above. */
|
|
6
5
|
queryStepCalls?: string[];
|
|
7
|
-
/** The call names that define a workflow. Default: Medusa's `createWorkflow`. */
|
|
8
6
|
workflowFactories?: string[];
|
|
9
7
|
}
|
|
10
8
|
declare const uniqueQueryStepName: {
|
|
@@ -40,11 +38,6 @@ declare const uniqueQueryStepName: {
|
|
|
40
38
|
}[];
|
|
41
39
|
type: 'problem';
|
|
42
40
|
};
|
|
43
|
-
/**
|
|
44
|
-
* Two query steps in one body, one named and one not — which is one finding rather than two. A
|
|
45
|
-
* body with a single un-named step collides with nothing and is deliberately exempt, so a probe
|
|
46
|
-
* built from one would fire nothing and read as a rule that cannot be exercised.
|
|
47
|
-
*/
|
|
48
41
|
probe(options: readonly unknown[]): Probe;
|
|
49
42
|
};
|
|
50
43
|
export default uniqueQueryStepName;
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
// src/rules/unique-query-step-name.ts
|
|
2
|
-
import {
|
|
2
|
+
import { walkNode } from "./lib/nodes.js";
|
|
3
3
|
import { propertiesOf, stringOf, valueOf } from "./lib/objects.js";
|
|
4
4
|
import { requireOption } from "./lib/options.js";
|
|
5
5
|
import { bagOf, firstOf } from "./lib/probe.js";
|
|
6
6
|
import { optionsBag, STRINGS } from "./lib/schema.js";
|
|
7
|
+
import { DEFAULT_WORKFLOW_FACTORIES, isStepCall, workflowFactoriesOf } from "./lib/steps.js";
|
|
7
8
|
var RULE = "unique-query-step-name";
|
|
8
9
|
var ACCEPTS = "{ queryStepCalls: string[] (required), workflowFactories: string[] }";
|
|
9
|
-
var DEFAULT_WORKFLOW_FACTORIES = ["createWorkflow"];
|
|
10
10
|
var CONFIG = "config";
|
|
11
11
|
var NAME = "name";
|
|
12
12
|
var COLLIDES_FROM = 2;
|
|
13
|
-
var isCallOf = (node, names) => {
|
|
14
|
-
const callee = calleeNameOf(node);
|
|
15
|
-
return callee !== null && names.has(callee);
|
|
16
|
-
};
|
|
17
13
|
var ABSENT = { kind: "absent" };
|
|
18
14
|
var UNREADABLE = { kind: "unreadable" };
|
|
19
15
|
var chainedName = (node, steps) => {
|
|
@@ -26,7 +22,7 @@ var chainedName = (node, steps) => {
|
|
|
26
22
|
if (property?.type !== "Identifier" || property.name !== CONFIG)
|
|
27
23
|
return null;
|
|
28
24
|
const inner = callee.object;
|
|
29
|
-
if (inner === undefined || !
|
|
25
|
+
if (inner === undefined || !isStepCall(inner, steps))
|
|
30
26
|
return null;
|
|
31
27
|
const [first] = node.arguments ?? [];
|
|
32
28
|
const properties = propertiesOf(first);
|
|
@@ -47,18 +43,18 @@ var stepsIn = (body, calls) => {
|
|
|
47
43
|
});
|
|
48
44
|
const steps = [];
|
|
49
45
|
walkNode(body, (node) => {
|
|
50
|
-
if (
|
|
46
|
+
if (isStepCall(node, calls))
|
|
51
47
|
steps.push({ name: names.get(node) ?? ABSENT, node });
|
|
52
48
|
});
|
|
53
49
|
return steps;
|
|
54
50
|
};
|
|
55
51
|
var uniqueQueryStepName = {
|
|
56
52
|
create(context) {
|
|
57
|
-
const factories =
|
|
53
|
+
const factories = workflowFactoriesOf(RULE, context.options?.[0]?.workflowFactories);
|
|
58
54
|
const calls = new Set(requireOption(RULE, context.options?.[0]?.queryStepCalls, "queryStepCalls", ACCEPTS));
|
|
59
55
|
return {
|
|
60
56
|
CallExpression(node) {
|
|
61
|
-
if (!
|
|
57
|
+
if (!isStepCall(node, factories))
|
|
62
58
|
return;
|
|
63
59
|
const steps = stepsIn(node.arguments ?? [], calls);
|
|
64
60
|
if (steps.length < COLLIDES_FROM)
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import { type RuleContextWithOptions } from './lib/context.js';
|
|
2
2
|
import { type Probe } from './lib/probe.js';
|
|
3
3
|
interface Options {
|
|
4
|
-
/** Regex source, tested against the normalised filename: the tree that holds the cell workers. */
|
|
5
4
|
within?: string;
|
|
6
|
-
/** The calls that open a scoped handle — `withCells`, `withConnection`, whatever this repo has. */
|
|
7
5
|
wrapper?: string[];
|
|
8
6
|
}
|
|
7
|
+
interface Callee {
|
|
8
|
+
computed?: boolean;
|
|
9
|
+
name?: string;
|
|
10
|
+
property?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
type?: string;
|
|
13
|
+
};
|
|
14
|
+
type?: string;
|
|
15
|
+
}
|
|
9
16
|
declare const cellHandlesAreScoped: {
|
|
10
17
|
create(context: RuleContextWithOptions<Options>): {
|
|
18
|
+
ExportDefaultDeclaration?: undefined;
|
|
11
19
|
CallExpression?: undefined;
|
|
12
20
|
'Program:exit'?: undefined;
|
|
13
|
-
ExportDefaultDeclaration?: undefined;
|
|
14
21
|
ClassDeclaration?: undefined;
|
|
15
22
|
} | {
|
|
16
23
|
ExportDefaultDeclaration(node: {
|
|
17
24
|
declaration?: unknown;
|
|
18
25
|
}): void;
|
|
19
26
|
CallExpression(node: {
|
|
20
|
-
callee?:
|
|
21
|
-
type?: string;
|
|
22
|
-
name?: string;
|
|
23
|
-
};
|
|
27
|
+
callee?: Callee;
|
|
24
28
|
}): void;
|
|
25
29
|
ClassDeclaration(node: {
|
|
26
30
|
superClass?: {
|
|
@@ -59,7 +63,6 @@ declare const cellHandlesAreScoped: {
|
|
|
59
63
|
}[];
|
|
60
64
|
type: 'problem';
|
|
61
65
|
};
|
|
62
|
-
/** A module handler inside the configured tree that never opens a scope — the smallest breach. */
|
|
63
66
|
probe(options: readonly unknown[]): Probe;
|
|
64
67
|
};
|
|
65
68
|
export default cellHandlesAreScoped;
|
|
@@ -12,6 +12,14 @@ var entrypointMakers = new Set([
|
|
|
12
12
|
"entrypointFor",
|
|
13
13
|
"createWorkflowEntrypoint"
|
|
14
14
|
]);
|
|
15
|
+
var calleeName = (callee) => {
|
|
16
|
+
if (callee?.type === "Identifier")
|
|
17
|
+
return callee.name;
|
|
18
|
+
if (callee?.type === "MemberExpression" && callee.computed !== true) {
|
|
19
|
+
return callee.property?.type === "Identifier" ? callee.property.name : undefined;
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
};
|
|
15
23
|
var cellHandlesAreScoped = {
|
|
16
24
|
create(context) {
|
|
17
25
|
const within = requireOption(RULE, context.options?.[0]?.within, "within", ACCEPTS);
|
|
@@ -33,11 +41,10 @@ var cellHandlesAreScoped = {
|
|
|
33
41
|
handlerNode = node;
|
|
34
42
|
},
|
|
35
43
|
CallExpression(node) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (node.callee.name !== undefined && scopedBy.has(node.callee.name))
|
|
44
|
+
const called = calleeName(node.callee);
|
|
45
|
+
if (called !== undefined && scopedBy.has(called))
|
|
39
46
|
scoped = true;
|
|
40
|
-
if (node.callee.name === "createWorkflowEntrypoint") {
|
|
47
|
+
if (node.callee?.type === "Identifier" && node.callee.name === "createWorkflowEntrypoint") {
|
|
41
48
|
handler = "the workflow entrypoint";
|
|
42
49
|
handlerNode = node;
|
|
43
50
|
}
|
|
@@ -64,7 +71,7 @@ var cellHandlesAreScoped = {
|
|
|
64
71
|
fixShape: `A worker that opens a database-cell handle wraps every invocation in the repo's scope wrapper — the
|
|
65
72
|
module handlers (\`fetch\`, \`queue\`, \`scheduled\`, \`email\`) and the workflow entrypoint alike — so the
|
|
66
73
|
handle is closed when the invocation ends: \`withCells(() => …, (closing) => ctx.waitUntil(closing))\`.
|
|
67
|
-
A handler that declares itself and never calls it opens a pool per call and never closes one. Name
|
|
74
|
+
The call may be a member — \`cellOf(env).withConnection(…)\` — as well as a bare name. A handler that declares itself and never calls it opens a pool per call and never closes one. Name
|
|
68
75
|
the wrapper in \`wrapper\` and the tree the cell workers live in in \`within\`; enabled without either
|
|
69
76
|
the rule reports that once a run and judges nothing.`,
|
|
70
77
|
meta: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type RuleContext } from './lib/context.js';
|
|
2
|
+
import { type Probe } from './lib/probe.js';
|
|
2
3
|
interface CallExpression {
|
|
3
4
|
arguments: {
|
|
4
5
|
callee?: {
|
|
@@ -17,24 +18,12 @@ interface CallExpression {
|
|
|
17
18
|
};
|
|
18
19
|
type: 'CallExpression';
|
|
19
20
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Zustand v5 best practices — single rule enforcing all patterns:
|
|
22
|
-
*
|
|
23
|
-
* 1. REQUIRE SELECTOR: useStore() without args subscribes to entire state.
|
|
24
|
-
* Fix: useStore((s) => s.field) or useStore(useShallow((s) => ({ ... })))
|
|
25
|
-
*
|
|
26
|
-
* 2. SINGLE CALL PER STORE: multiple useStore((s) => s.x) calls create
|
|
27
|
-
* separate subscriptions. Fix: consolidate with useShallow.
|
|
28
|
-
*
|
|
29
|
-
* 3. useShallow BYPASS: calls wrapped in useShallow are always allowed,
|
|
30
|
-
* even if there are multiple (edge case for different selector shapes).
|
|
31
|
-
*/
|
|
32
21
|
declare const zustandV5BestPractices: {
|
|
33
22
|
create(context: RuleContext): {
|
|
34
|
-
ArrowFunctionExpression
|
|
35
|
-
'ArrowFunctionExpression:exit'()
|
|
23
|
+
ArrowFunctionExpression: () => void;
|
|
24
|
+
'ArrowFunctionExpression:exit': () => void;
|
|
36
25
|
CallExpression(node: CallExpression): void;
|
|
37
|
-
FunctionDeclaration
|
|
26
|
+
FunctionDeclaration: () => void;
|
|
38
27
|
ImportDeclaration(node: {
|
|
39
28
|
source: {
|
|
40
29
|
value: string;
|
|
@@ -45,9 +34,9 @@ declare const zustandV5BestPractices: {
|
|
|
45
34
|
};
|
|
46
35
|
}[];
|
|
47
36
|
}): void;
|
|
48
|
-
'FunctionDeclaration:exit'()
|
|
49
|
-
FunctionExpression
|
|
50
|
-
'FunctionExpression:exit'()
|
|
37
|
+
'FunctionDeclaration:exit': () => void;
|
|
38
|
+
FunctionExpression: () => void;
|
|
39
|
+
'FunctionExpression:exit': () => void;
|
|
51
40
|
};
|
|
52
41
|
fixShape: string;
|
|
53
42
|
meta: {
|
|
@@ -61,5 +50,6 @@ declare const zustandV5BestPractices: {
|
|
|
61
50
|
schema: never[];
|
|
62
51
|
type: 'problem';
|
|
63
52
|
};
|
|
53
|
+
probe(): Probe;
|
|
64
54
|
};
|
|
65
55
|
export default zustandV5BestPractices;
|