@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
|
@@ -3,6 +3,7 @@ import { dirname, relative } from "node:path";
|
|
|
3
3
|
import { resolveRelative } from "./imports.js";
|
|
4
4
|
import { exportedNamesOf, landingsOf, namesATierFolder, rootOf } from "./landing.js";
|
|
5
5
|
import { propertyNameOf } from "./nodes.js";
|
|
6
|
+
import { destructuredNamesOf, withoutTypes } from "./objects.js";
|
|
6
7
|
import { fileOf, normalise } from "./paths.js";
|
|
7
8
|
import { featureOf, inTier, tierOf } from "./tiers.js";
|
|
8
9
|
import { onImportSource } from "./visitors.js";
|
|
@@ -13,7 +14,6 @@ var classify = (path, source = path) => ({
|
|
|
13
14
|
source,
|
|
14
15
|
tier: tierOf(path)
|
|
15
16
|
});
|
|
16
|
-
var FORBIDDEN = "forbidden";
|
|
17
17
|
var placeAndSource = (target, importer) => ({
|
|
18
18
|
file: importer.file,
|
|
19
19
|
source: target.source
|
|
@@ -51,7 +51,7 @@ var targetsOf = (filename, importer, source, taken) => {
|
|
|
51
51
|
var directionRule = (declaration) => {
|
|
52
52
|
const {
|
|
53
53
|
data = placeAndSource,
|
|
54
|
-
messageId =
|
|
54
|
+
messageId = "forbidden",
|
|
55
55
|
optionsFrom,
|
|
56
56
|
scope,
|
|
57
57
|
typeOnly = "skip"
|
|
@@ -89,7 +89,8 @@ var directionRule = (declaration) => {
|
|
|
89
89
|
reachedThrough.set(local, reached);
|
|
90
90
|
namespaces.push({ node, reached, source });
|
|
91
91
|
}, { typeOnly });
|
|
92
|
-
const
|
|
92
|
+
const destructured = new WeakMap;
|
|
93
|
+
const whole = onImportSource((source, node) => judge(source, node, destructured.get(node) ?? WHOLE), { typeOnly });
|
|
93
94
|
return {
|
|
94
95
|
CallExpression: whole.CallExpression,
|
|
95
96
|
ExportAllDeclaration: whole.ExportAllDeclaration,
|
|
@@ -103,6 +104,13 @@ var directionRule = (declaration) => {
|
|
|
103
104
|
MemberExpression(node) {
|
|
104
105
|
reach(node.object, propertyNameOf(node));
|
|
105
106
|
},
|
|
107
|
+
VariableDeclarator(node) {
|
|
108
|
+
const names = destructuredNamesOf(node.id);
|
|
109
|
+
const init = withoutTypes(node.init);
|
|
110
|
+
const call = init?.type === "AwaitExpression" ? withoutTypes(init.argument) : init;
|
|
111
|
+
if (names !== null && call !== undefined)
|
|
112
|
+
destructured.set(call, names);
|
|
113
|
+
},
|
|
106
114
|
"Program:exit"() {
|
|
107
115
|
for (const { node, reached, source } of namespaces) {
|
|
108
116
|
judge(source, node, reached.size === 0 ? WHOLE : [...reached]);
|
|
@@ -111,6 +119,7 @@ var directionRule = (declaration) => {
|
|
|
111
119
|
};
|
|
112
120
|
},
|
|
113
121
|
fixShape: declaration.fixShape,
|
|
122
|
+
...declaration.probe === undefined ? {} : { probe: declaration.probe },
|
|
114
123
|
meta: {
|
|
115
124
|
docs: { description: declaration.description },
|
|
116
125
|
messages: declaration.messages,
|
|
@@ -1,26 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A package's doors, read off its own `package.json` `exports`: each subpath, and the names the
|
|
3
|
-
* file behind it exports — the map `subpath-over-barrel` needs, which one consumer kept by hand.
|
|
4
|
-
*
|
|
5
|
-
* Read with the same regexes three rules already read a re-export shim with, never a parser: a
|
|
6
|
-
* door's entry is `export … from` lines and declarations, and `export *` is followed inside the
|
|
7
|
-
* package to a small fixed depth. A door written as a pattern (`./icons/*`) names no file to read
|
|
8
|
-
* and is left out; a name two doors both export is placed under neither, because the rule could
|
|
9
|
-
* not tell a reader which one to open.
|
|
10
|
-
*/
|
|
11
1
|
export type Doors = {
|
|
12
2
|
name: string;
|
|
13
|
-
|
|
3
|
+
homes: Map<string, string>;
|
|
14
4
|
};
|
|
15
|
-
/** The doors a manifest declares, each with the names behind it. */
|
|
16
5
|
export declare const doorsOf: (manifestPath: string) => Doors | undefined;
|
|
17
|
-
/**
|
|
18
|
-
* Where a bare specifier resolves from a file: the nearest `node_modules/<name>/package.json`
|
|
19
|
-
* walking up. `own` says whether it is the repo's: linked in from outside any `node_modules` (a
|
|
20
|
-
* workspace link — pnpm links a dependency too, but into its store's `node_modules/<name>`) or
|
|
21
|
-
* private (npm refuses to publish one, so under `node_modules` it is the repo's).
|
|
22
|
-
*/
|
|
23
6
|
export declare const resolvePackage: (from: string, name: string) => {
|
|
24
7
|
manifest: string;
|
|
25
8
|
own: boolean;
|
|
26
9
|
} | undefined;
|
|
10
|
+
export declare const nodeModulesAbove: (from: string) => boolean;
|
package/dist/rules/lib/doors.js
CHANGED
|
@@ -1,48 +1,55 @@
|
|
|
1
1
|
// src/rules/lib/doors.ts
|
|
2
|
-
import { existsSync, lstatSync,
|
|
2
|
+
import { existsSync, lstatSync, readdirSync, realpathSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
import { exportedNamesOf } from "./landing.js";
|
|
5
|
+
import { conditionTargetOf, fileFor, readManifest, recordOf } from "./module-text.js";
|
|
6
|
+
import { workspaceMemberNamed } from "./workspace-members.js";
|
|
7
|
+
var LISTED_FILES = 4000;
|
|
8
|
+
var filesBelow = (dir, budget) => {
|
|
9
|
+
let entries;
|
|
10
|
+
try {
|
|
11
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
12
|
+
} catch {
|
|
12
13
|
return [];
|
|
13
|
-
const names = [...table.declared, ...table.reexports.keys()];
|
|
14
|
-
for (const star of table.stars) {
|
|
15
|
-
const next = fileFor(file, star);
|
|
16
|
-
if (next !== undefined)
|
|
17
|
-
names.push(...exportsOf(next, seen, depth + 1));
|
|
18
14
|
}
|
|
19
|
-
return
|
|
15
|
+
return entries.flatMap((entry) => {
|
|
16
|
+
if (budget.left <= 0 || entry.name === "node_modules")
|
|
17
|
+
return [];
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
return filesBelow(join(dir, entry.name), budget).map((one) => `${entry.name}/${one}`);
|
|
20
|
+
}
|
|
21
|
+
budget.left -= 1;
|
|
22
|
+
return [entry.name];
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var expanded = (dir, key, target) => {
|
|
26
|
+
const star = target.indexOf("*");
|
|
27
|
+
const before = target.slice(0, star);
|
|
28
|
+
const suffix = target.slice(star + 1);
|
|
29
|
+
const folder = before.slice(0, before.lastIndexOf("/") + 1);
|
|
30
|
+
const stem = before.slice(folder.length);
|
|
31
|
+
return filesBelow(join(dir, folder), { left: LISTED_FILES }).flatMap((relative) => {
|
|
32
|
+
if (!relative.startsWith(stem) || !relative.endsWith(suffix))
|
|
33
|
+
return [];
|
|
34
|
+
const matched = relative.slice(stem.length, relative.length - suffix.length);
|
|
35
|
+
return matched === "" ? [] : [[key.replace("*", matched).slice(2), `${folder}${relative}`]];
|
|
36
|
+
});
|
|
20
37
|
};
|
|
21
38
|
var doorsOf = (manifestPath) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} catch {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (typeof manifest.name !== "string")
|
|
29
|
-
return;
|
|
30
|
-
if (typeof manifest.exports !== "object" || manifest.exports === null)
|
|
39
|
+
const manifest = readManifest(manifestPath);
|
|
40
|
+
const exported = recordOf(manifest?.exports);
|
|
41
|
+
if (typeof manifest?.name !== "string" || exported === undefined)
|
|
31
42
|
return;
|
|
32
43
|
const dir = dirname(manifestPath);
|
|
33
44
|
const placed = new Map;
|
|
34
45
|
const contested = new Set;
|
|
35
|
-
|
|
36
|
-
if (key === "." || !key.startsWith("./") || key.includes("*"))
|
|
37
|
-
continue;
|
|
38
|
-
const target = conditionTargetOf(value);
|
|
39
|
-
if (target === undefined)
|
|
40
|
-
continue;
|
|
46
|
+
const place = (door, target) => {
|
|
41
47
|
const entry = fileFor(join(dir, "package.json"), target);
|
|
42
48
|
if (entry === undefined)
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
49
|
+
return;
|
|
50
|
+
for (const name of exportedNamesOf(entry)) {
|
|
51
|
+
if (name === "default")
|
|
52
|
+
continue;
|
|
46
53
|
if (contested.has(name))
|
|
47
54
|
continue;
|
|
48
55
|
const already = placed.get(name);
|
|
@@ -53,10 +60,25 @@ var doorsOf = (manifestPath) => {
|
|
|
53
60
|
}
|
|
54
61
|
placed.set(name, door);
|
|
55
62
|
}
|
|
63
|
+
};
|
|
64
|
+
for (const [key, value] of Object.entries(exported)) {
|
|
65
|
+
if (key === "." || !key.startsWith("./"))
|
|
66
|
+
continue;
|
|
67
|
+
const target = conditionTargetOf(value);
|
|
68
|
+
if (target === undefined)
|
|
69
|
+
continue;
|
|
70
|
+
if (key.includes("*")) {
|
|
71
|
+
if (!target.includes("*"))
|
|
72
|
+
continue;
|
|
73
|
+
for (const [door, concrete] of expanded(dir, key, target))
|
|
74
|
+
place(door, concrete);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
place(key.slice(2), target);
|
|
56
78
|
}
|
|
57
79
|
return { homes: placed, name: manifest.name };
|
|
58
80
|
};
|
|
59
|
-
var
|
|
81
|
+
var resolveInNodeModules = (from, name) => {
|
|
60
82
|
let dir = dirname(from);
|
|
61
83
|
for (;; ) {
|
|
62
84
|
const packageDir = join(dir, "node_modules", name);
|
|
@@ -68,13 +90,8 @@ var resolvePackage = (from, name) => {
|
|
|
68
90
|
} catch {
|
|
69
91
|
own = false;
|
|
70
92
|
}
|
|
71
|
-
if (!own)
|
|
72
|
-
|
|
73
|
-
own = JSON.parse(readFileSync(manifest, "utf8")).private === true;
|
|
74
|
-
} catch {
|
|
75
|
-
own = false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
93
|
+
if (!own)
|
|
94
|
+
own = readManifest(manifest)?.private === true;
|
|
78
95
|
return { manifest, own };
|
|
79
96
|
}
|
|
80
97
|
const parent = dirname(dir);
|
|
@@ -83,7 +100,28 @@ var resolvePackage = (from, name) => {
|
|
|
83
100
|
dir = parent;
|
|
84
101
|
}
|
|
85
102
|
};
|
|
103
|
+
var resolvePackage = (from, name) => {
|
|
104
|
+
const found = resolveInNodeModules(from, name);
|
|
105
|
+
if (found?.own === true)
|
|
106
|
+
return found;
|
|
107
|
+
const member = workspaceMemberNamed(from, name);
|
|
108
|
+
if (member === undefined)
|
|
109
|
+
return found;
|
|
110
|
+
return { manifest: found?.manifest ?? member, own: true };
|
|
111
|
+
};
|
|
112
|
+
var nodeModulesAbove = (from) => {
|
|
113
|
+
let dir = dirname(from);
|
|
114
|
+
for (;; ) {
|
|
115
|
+
if (existsSync(join(dir, "node_modules")))
|
|
116
|
+
return true;
|
|
117
|
+
const parent = dirname(dir);
|
|
118
|
+
if (parent === dir)
|
|
119
|
+
return false;
|
|
120
|
+
dir = parent;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
86
123
|
export {
|
|
87
124
|
doorsOf,
|
|
125
|
+
nodeModulesAbove,
|
|
88
126
|
resolvePackage
|
|
89
127
|
};
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { type AnyNode } from './nodes.js';
|
|
2
|
-
/**
|
|
3
|
-
* React's own naming convention: a function called `use<Something>` is a hook.
|
|
4
|
-
*
|
|
5
|
-
* Exported because two other rules test a bare callee identifier against this exact pattern
|
|
6
|
-
* without needing `hookCalledBy`'s member-expression reach — spelling the regex a second and a
|
|
7
|
-
* third time drifted nothing here, but there is no reason to trust that forever.
|
|
8
|
-
*/
|
|
9
2
|
export declare const HOOK_NAME: RegExp;
|
|
10
|
-
|
|
11
|
-
* The hook a call names, spelled as the file spelled it — or null when the call is not a hook.
|
|
12
|
-
*
|
|
13
|
-
* Two stateless-tier rules read a call's callee as a bare identifier and nothing else, so
|
|
14
|
-
* `React.useState(0)` and `hooks.useCart()` held state in a tissue and in a compound under both
|
|
15
|
-
* rules at "error": the hook was there, the name was there, and the rule was looking one node too
|
|
16
|
-
* high. A member call is read here too — the object is whatever the file imported the hook
|
|
17
|
-
* through, and the property is the hook. A computed member (`hooks[name]()`) names nothing this
|
|
18
|
-
* can read and is left alone, as every unreadable shape in this plugin is.
|
|
19
|
-
*/
|
|
3
|
+
export declare const STORE_HOOK_NAME: RegExp;
|
|
20
4
|
export declare const hookCalledBy: (node: AnyNode) => string | null;
|
|
5
|
+
export declare const hookNameOf: (node: AnyNode) => string | null;
|
package/dist/rules/lib/hooks.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
// src/rules/lib/hooks.ts
|
|
2
2
|
import { calleeNameOf, propertyNameOf } from "./nodes.js";
|
|
3
3
|
var HOOK_NAME = /^use[A-Z]/;
|
|
4
|
+
var STORE_HOOK_NAME = /^use\w+Store$/;
|
|
4
5
|
var hookCalledBy = (node) => {
|
|
6
|
+
const name = hookNameOf(node);
|
|
7
|
+
if (name === null || calleeNameOf(node) !== null)
|
|
8
|
+
return name;
|
|
9
|
+
const object = node.callee.object;
|
|
10
|
+
const through = object?.type === "Identifier" && typeof object.name === "string" ? object.name : null;
|
|
11
|
+
return through === null ? name : `${through}.${name}`;
|
|
12
|
+
};
|
|
13
|
+
var hookNameOf = (node) => {
|
|
5
14
|
const bare = calleeNameOf(node);
|
|
6
15
|
if (bare !== null)
|
|
7
16
|
return HOOK_NAME.test(bare) ? bare : null;
|
|
8
17
|
const callee = node.callee;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const property = propertyNameOf(callee);
|
|
12
|
-
if (property === null || !HOOK_NAME.test(property))
|
|
13
|
-
return null;
|
|
14
|
-
const object = callee.object;
|
|
15
|
-
const through = object?.type === "Identifier" && typeof object.name === "string" ? object.name : null;
|
|
16
|
-
return through === null ? property : `${through}.${property}`;
|
|
18
|
+
const property = callee === undefined ? null : propertyNameOf(callee);
|
|
19
|
+
return property !== null && HOOK_NAME.test(property) ? property : null;
|
|
17
20
|
};
|
|
18
21
|
export {
|
|
19
22
|
HOOK_NAME,
|
|
20
|
-
|
|
23
|
+
STORE_HOOK_NAME,
|
|
24
|
+
hookCalledBy,
|
|
25
|
+
hookNameOf
|
|
21
26
|
};
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How a file names another file, read once.
|
|
3
|
-
*
|
|
4
|
-
* Twenty-one rules parsed an import source themselves and each covered a different subset of the
|
|
5
|
-
* five ways it can be written, because each was written by whoever needed one of them that day.
|
|
6
|
-
*/
|
|
7
1
|
export type ModuleNode = {
|
|
8
2
|
arguments?: {
|
|
9
3
|
type?: string;
|
|
@@ -19,34 +13,19 @@ export type ModuleNode = {
|
|
|
19
13
|
type?: string;
|
|
20
14
|
value?: unknown;
|
|
21
15
|
} | null;
|
|
22
|
-
/** What the import brought in, for the rules that judge an import by its names. */
|
|
23
16
|
specifiers?: {
|
|
24
17
|
imported?: {
|
|
25
18
|
name?: string;
|
|
26
19
|
};
|
|
20
|
+
importKind?: string;
|
|
27
21
|
local?: {
|
|
28
22
|
name?: string;
|
|
29
23
|
};
|
|
30
24
|
type?: string;
|
|
31
25
|
}[];
|
|
32
26
|
};
|
|
33
|
-
/**
|
|
34
|
-
* The module a node names, or null when it names none — `export const x = 1` names nothing, a call
|
|
35
|
-
* that is not a `require` names nothing, and `import(`./${name}`)` names something no rule can
|
|
36
|
-
* read. A rule that guessed at the last one would report a finding whose source it cannot print.
|
|
37
|
-
*/
|
|
38
27
|
export declare const sourceOf: (node: ModuleNode) => string | null;
|
|
39
|
-
/** `import type X from`, `import { … } from` graded type, and `export type … from`. */
|
|
40
28
|
export declare const isTypeOnly: (node: ModuleNode) => boolean;
|
|
41
|
-
/** Whether a specifier is relative — walked from the importer, never resolved through an alias. */
|
|
42
29
|
export declare const isRelative: (source: string) => boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Where a relative source lands, as a path — and any other source unchanged.
|
|
45
|
-
*
|
|
46
|
-
* `../../billing/organelles/totals` carries no feature name and no tier name until it is resolved
|
|
47
|
-
* against the file that wrote it. Two rules did that and the rest did not, so the same breach was a
|
|
48
|
-
* finding or not depending on which rule happened to look at it. `@/features/x` is NOT relative: it
|
|
49
|
-
* is an alias the bundler resolves, and joining it to the importer's directory would invent a path
|
|
50
|
-
* that exists nowhere.
|
|
51
|
-
*/
|
|
52
30
|
export declare const resolveRelative: (importer: string, source: string) => string;
|
|
31
|
+
export declare const isR3fImport: (node: ModuleNode) => boolean;
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { literalNamedBy } from "./literal-call.js";
|
|
4
4
|
import { normalise } from "./paths.js";
|
|
5
|
-
var
|
|
5
|
+
var R3F_PACKAGES = new Set(["@react-three/drei", "@react-three/fiber"]);
|
|
6
6
|
var sourceOf = (node) => {
|
|
7
7
|
const source = node.source;
|
|
8
8
|
if (source === undefined || source === null) {
|
|
9
9
|
if (node.callee === undefined)
|
|
10
10
|
return null;
|
|
11
|
-
return literalNamedBy(node,
|
|
11
|
+
return literalNamedBy(node, "require");
|
|
12
12
|
}
|
|
13
13
|
if (source.type !== undefined && source.type !== "Literal")
|
|
14
14
|
return null;
|
|
@@ -17,7 +17,12 @@ var sourceOf = (node) => {
|
|
|
17
17
|
var isTypeOnly = (node) => node.importKind === "type" || node.exportKind === "type";
|
|
18
18
|
var isRelative = (source) => source === "." || source === ".." || source.startsWith("./") || source.startsWith("../");
|
|
19
19
|
var resolveRelative = (importer, source) => isRelative(source) ? path.posix.normalize(path.posix.join(path.posix.dirname(normalise(importer)), source)) : source;
|
|
20
|
+
var isR3fImport = (node) => {
|
|
21
|
+
const source = sourceOf(node);
|
|
22
|
+
return source !== null && R3F_PACKAGES.has(source);
|
|
23
|
+
};
|
|
20
24
|
export {
|
|
25
|
+
isR3fImport,
|
|
21
26
|
isRelative,
|
|
22
27
|
isTypeOnly,
|
|
23
28
|
resolveRelative,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface JsxAttribute {
|
|
2
|
+
name?: {
|
|
3
|
+
name?: string;
|
|
4
|
+
type: string;
|
|
5
|
+
};
|
|
6
|
+
type: string;
|
|
7
|
+
value?: {
|
|
8
|
+
type: string;
|
|
9
|
+
value?: unknown;
|
|
10
|
+
} | null;
|
|
11
|
+
}
|
|
12
|
+
export interface JsxOpeningElement {
|
|
13
|
+
attributes?: JsxAttribute[];
|
|
14
|
+
loc?: unknown;
|
|
15
|
+
name: {
|
|
16
|
+
name?: string;
|
|
17
|
+
type: string;
|
|
18
|
+
};
|
|
19
|
+
type: 'JSXOpeningElement';
|
|
20
|
+
}
|
|
21
|
+
export declare const isCapitalised: (name: string) => boolean;
|
|
22
|
+
export declare const attributeNamed: (node: {
|
|
23
|
+
attributes?: readonly JsxAttribute[];
|
|
24
|
+
}, name: string) => JsxAttribute | undefined;
|
|
25
|
+
export declare const tagNameOf: (node: {
|
|
26
|
+
name?: JsxOpeningElement['name'];
|
|
27
|
+
} | undefined) => string | undefined;
|
|
28
|
+
export declare const meaningfulChildren: <Child extends {
|
|
29
|
+
type: string;
|
|
30
|
+
value?: string;
|
|
31
|
+
}>(children: readonly Child[] | undefined) => Child[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/rules/lib/jsx.ts
|
|
2
|
+
var isCapitalised = (name) => /^[A-Z]/.test(name);
|
|
3
|
+
var attributeNamed = (node, name) => node.attributes?.find((attribute) => attribute?.type === "JSXAttribute" && attribute.name?.type === "JSXIdentifier" && attribute.name.name === name);
|
|
4
|
+
var tagNameOf = (node) => node?.name?.type === "JSXIdentifier" && node.name.name ? node.name.name : undefined;
|
|
5
|
+
var meaningfulChildren = (children) => (children ?? []).filter((child) => child.type !== "JSXText" || (child.value ?? "").trim() !== "");
|
|
6
|
+
export {
|
|
7
|
+
attributeNamed,
|
|
8
|
+
isCapitalised,
|
|
9
|
+
meaningfulChildren,
|
|
10
|
+
tagNameOf
|
|
11
|
+
};
|
|
@@ -1,50 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where an import LANDS, and where the code behind each name it takes LIVES.
|
|
3
|
-
*
|
|
4
|
-
* Two consumer issues were one blindness. A direction rule read the specifier as a string and
|
|
5
|
-
* stopped, so `@/components/organelles` — a bare barrel, which names no file in a tier folder —
|
|
6
|
-
* was invisible (#4), and a one-line `export { CustomCarousel } from '@/kit/organelles/carousel'`
|
|
7
|
-
* sitting in `cells/` laundered an organelle into the cell tier for every rule that looked (#11).
|
|
8
|
-
* The Store adoption that found #4 read 78 → 8 → 5 → 1 as tier fixes landed, which is to say its
|
|
9
|
-
* early numbers measured the rules' blindness as much as the code.
|
|
10
|
-
*
|
|
11
|
-
* So the specifier is resolved on disk: relative to the importer, through the repo's own
|
|
12
|
-
* `package.json` `imports` for a `#` subpath, or through its `tsconfig.json` (or `jsconfig.json`)
|
|
13
|
-
* `paths` — never an alias this plugin knows (LAW 6). The file it lands on is the
|
|
14
|
-
* DOOR. Each name the import takes is then followed through `export … from` and `export *` to the
|
|
15
|
-
* file that declares it, the HOME, to a depth of eight and never twice through one file. A name
|
|
16
|
-
* the door does not export and a bare package are left at the door; a specifier nothing on disk
|
|
17
|
-
* answers lands nowhere, and the rule judges the spelling as before. An import that takes the
|
|
18
|
-
* whole module — a namespace, `export *`, `import()`, `require()` — takes every name the door
|
|
19
|
-
* carries (row 593), narrowed to the members the file reaches when it is a namespace.
|
|
20
|
-
*/
|
|
21
1
|
type Landings = {
|
|
22
|
-
/** The file the specifier resolves to, absolute — or nowhere. */
|
|
23
2
|
door: string | undefined;
|
|
24
|
-
/** Imported name → the absolute file whose code it is; the door when it could not be followed. */
|
|
25
3
|
homes: Map<string, string>;
|
|
26
4
|
};
|
|
27
|
-
/** The absolute file a specifier names from a file, or undefined when nothing on disk answers. */
|
|
28
5
|
export declare const resolveSource: (importer: string, source: string) => string | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* Every name a module exports, its `export *` modules followed to the same depth as a home is. A
|
|
31
|
-
* namespace import, an `export *`, `import()` and `require()` take the whole module (row 593), and
|
|
32
|
-
* "the whole module" is this list — each name then lands where its code lives, as a named import's
|
|
33
|
-
* would.
|
|
34
|
-
*/
|
|
35
6
|
export declare const exportedNamesOf: (file: string) => Set<string>;
|
|
36
7
|
export declare const landingsOf: (importer: string, source: string, names: readonly string[]) => Landings;
|
|
37
|
-
/**
|
|
38
|
-
* Whether a specifier's last segment IS a tier folder — `@/components/organelles`, `../cells`.
|
|
39
|
-
* A folder named `organelles` is the organelles tier whichever alias reaches it, so when nothing
|
|
40
|
-
* on disk answers the spelling is still judged as the folder it names.
|
|
41
|
-
*/
|
|
42
8
|
export declare const namesATierFolder: (source: string) => boolean;
|
|
43
|
-
/**
|
|
44
|
-
* The root a landed path is judged from: the nearest directory above the importer holding a
|
|
45
|
-
* `package.json` or a `tsconfig.json`, else the importer's own. An absolute path would be judged
|
|
46
|
-
* with every directory above the repo in it, and a checkout under `/app/` or `/home/cells/` would
|
|
47
|
-
* make every resolved import a breach.
|
|
48
|
-
*/
|
|
49
9
|
export declare const rootOf: (file: string) => string;
|
|
50
10
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/rules/lib/literal-call.ts
|
|
2
|
+
var TABLE_CALLEES = ["sqliteTable", "pgTable"];
|
|
2
3
|
var literalNamedBy = (node, callee) => {
|
|
3
4
|
if (node.callee.type !== "Identifier" || node.callee.name !== callee)
|
|
4
5
|
return null;
|
|
@@ -6,5 +7,6 @@ var literalNamedBy = (node, callee) => {
|
|
|
6
7
|
return name?.type === "Literal" && typeof name.value === "string" ? name.value : null;
|
|
7
8
|
};
|
|
8
9
|
export {
|
|
10
|
+
TABLE_CALLEES,
|
|
9
11
|
literalNamedBy
|
|
10
12
|
};
|
|
@@ -1,43 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a module's TEXT says it exports, read with regexes and never a parser — the same reading
|
|
3
|
-
* `doors.ts` did for a package's `exports` map, shared now with the landing resolver, because a
|
|
4
|
-
* barrel and a re-export shim are the same shape read for a different question.
|
|
5
|
-
*
|
|
6
|
-
* A table is read once per file per process: `create` runs once per FILE, and the tree does not
|
|
7
|
-
* change under a lint run.
|
|
8
|
-
*/
|
|
9
1
|
type ExportTable = {
|
|
10
|
-
/** Names whose code is HERE: declarations, `export { A as B }` with no `from`, `default`. */
|
|
11
2
|
declared: Set<string>;
|
|
12
|
-
/** Exported name → the name and module it is taken from: `export { A as B } from './x'`. */
|
|
13
3
|
reexports: Map<string, {
|
|
14
4
|
name: string;
|
|
15
5
|
source: string;
|
|
16
6
|
}>;
|
|
17
|
-
/** The modules `export * from` hands through, in order. */
|
|
18
7
|
stars: string[];
|
|
19
8
|
};
|
|
20
9
|
export declare const EXTENSIONS: string[];
|
|
21
|
-
/**
|
|
22
|
-
* Source with its comments blanked to spaces, strings stepped over whole — a glob like `'src/*'`
|
|
23
|
-
* opens no comment and a URL keeps its `//`. Blanked, not cut: the tokens either side of a comment
|
|
24
|
-
* stay apart and every line keeps its number. Every text reader in the plugin reads through it.
|
|
25
|
-
*/
|
|
26
10
|
export declare const stripComments: (source: string) => string;
|
|
27
|
-
/** The file at a base path: itself, with an extension, or its index — or nothing on disk. */
|
|
28
11
|
export declare const fileAt: (base: string) => string | undefined;
|
|
29
|
-
/** A relative module specifier as the file it names, or undefined when nothing on disk answers. */
|
|
30
12
|
export declare const fileFor: (from: string, specifier: string) => string | undefined;
|
|
31
|
-
|
|
13
|
+
export declare const readSource: (file: string) => string | undefined;
|
|
14
|
+
export declare const recordOf: (value: unknown) => Record<string, unknown> | undefined;
|
|
15
|
+
export declare const readManifest: (file: string) => Record<string, unknown> | undefined;
|
|
32
16
|
export declare const exportTableOf: (file: string) => ExportTable | undefined;
|
|
33
|
-
/**
|
|
34
|
-
* The file an `exports` or `imports` value points at, whatever conditions it is wrapped in — a
|
|
35
|
-
* string, an array of alternatives, or a conditions object read in the order a bundler would.
|
|
36
|
-
*/
|
|
37
17
|
export declare const conditionTargetOf: (value: unknown) => string | undefined;
|
|
38
|
-
/**
|
|
39
|
-
* JSON as `tsconfig.json` writes it: comments and trailing commas allowed. `JSON.parse` refuses
|
|
40
|
-
* both, and a reader that stripped `//` blindly would cut `"$schema": "https://…"` in half.
|
|
41
|
-
*/
|
|
42
18
|
export declare const parseLooseJson: (text: string) => unknown;
|
|
43
19
|
export {};
|
|
@@ -49,14 +49,26 @@ var entriesOf = (list) => list.split(",").map((one) => one.trim().replace(/^type
|
|
|
49
49
|
const [taken, exported] = one.split(/\s+as\s+/);
|
|
50
50
|
return { exported: exported ?? taken ?? "", taken: taken ?? "" };
|
|
51
51
|
});
|
|
52
|
-
var
|
|
53
|
-
var readTable = (file) => {
|
|
54
|
-
let source;
|
|
52
|
+
var readSource = (file) => {
|
|
55
53
|
try {
|
|
56
|
-
|
|
54
|
+
return stripComments(readFileSync(file, "utf8"));
|
|
57
55
|
} catch {
|
|
58
56
|
return;
|
|
59
57
|
}
|
|
58
|
+
};
|
|
59
|
+
var recordOf = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : undefined;
|
|
60
|
+
var readManifest = (file) => {
|
|
61
|
+
try {
|
|
62
|
+
return recordOf(JSON.parse(readFileSync(file, "utf8")));
|
|
63
|
+
} catch {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var tables = new Map;
|
|
68
|
+
var readTable = (file) => {
|
|
69
|
+
const source = readSource(file);
|
|
70
|
+
if (source === undefined)
|
|
71
|
+
return;
|
|
60
72
|
const declared = new Set;
|
|
61
73
|
const reexports = new Map;
|
|
62
74
|
const stars = [];
|
|
@@ -119,5 +131,8 @@ export {
|
|
|
119
131
|
fileAt,
|
|
120
132
|
fileFor,
|
|
121
133
|
parseLooseJson,
|
|
134
|
+
readManifest,
|
|
135
|
+
readSource,
|
|
136
|
+
recordOf,
|
|
122
137
|
stripComments
|
|
123
138
|
};
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import { type AnyNode } from './nodes.js';
|
|
2
|
-
/**
|
|
3
|
-
* What a WRITE is, in one place. `mutating-step-declares-retry` asks it of a step's invoke body and
|
|
4
|
-
* `route-no-inline-mutation` asks it of a route handler; two copies of this, spelled slightly
|
|
5
|
-
* differently, is how the two rules would come to disagree about which calls are writes — the same
|
|
6
|
-
* drift `lib/steps.ts` exists to prevent for what a step is.
|
|
7
|
-
*
|
|
8
|
-
* The CRUD names `MedusaService` generates. A framework fact, so a default rather than a blank.
|
|
9
|
-
*/
|
|
10
2
|
export declare const DEFAULT_MUTATION_PREFIXES: string[];
|
|
11
3
|
export declare const mutationPrefixesOf: (rule: string, configured: string[] | undefined) => string[];
|
|
12
|
-
/**
|
|
13
|
-
* `svc.createOrder(…)` — a generated CRUD write, told from `listOrders` by the capital after the
|
|
14
|
-
* prefix, and from `createOrderWorkflow(scope)` by being a METHOD on something. A bare identifier
|
|
15
|
-
* call is the workflow door itself, which is the shape both rules exist to send people towards.
|
|
16
|
-
*/
|
|
17
4
|
export declare const writesWith: (prefixes: readonly string[]) => (node: AnyNode) => boolean;
|
|
18
|
-
/** The method name a write call carries, for a message that points at something. */
|
|
19
5
|
export declare const writeNameOf: (node: AnyNode) => string;
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
export type AnyNode = {
|
|
2
2
|
type?: string;
|
|
3
3
|
} & Record<string, unknown>;
|
|
4
|
-
/**
|
|
5
|
-
* Every node under this one, this one included.
|
|
6
|
-
*
|
|
7
|
-
* A visitor is handed the node it asked for, and some facts live in its BODY — whether a step's
|
|
8
|
-
* invoke function writes anything is the one that made this necessary, and it can be behind an
|
|
9
|
-
* `if`, inside a `try`, or two closures down. A rule that only read the statements directly under
|
|
10
|
-
* the arrow would pass every step that guarded its write. Children are visited in source order.
|
|
11
|
-
*
|
|
12
|
-
* `parent` is skipped: oxlint hands nodes with back-references, and following one walks the whole
|
|
13
|
-
* program from wherever it started.
|
|
14
|
-
*/
|
|
15
4
|
export declare const walkNode: (node: unknown, visit: (node: AnyNode) => void, descends?: (node: AnyNode) => boolean) => void;
|
|
16
|
-
|
|
17
|
-
* Every node under a function's OWN body, stopping at a nested function — a hook called inside a
|
|
18
|
-
* closure this function merely defines belongs to that closure, not to this one. Two rules walked
|
|
19
|
-
* this by hand, one to find a hook call and one to collect `return` statements.
|
|
20
|
-
*/
|
|
5
|
+
export declare const FUNCTION_BOUNDARY_TYPES: Set<string>;
|
|
21
6
|
export declare const walkOwnFunctionBody: (body: unknown, visit: (node: AnyNode) => void) => void;
|
|
22
|
-
/** The name a `MemberExpression`'s non-computed property carries, or null. */
|
|
23
7
|
export declare const propertyNameOf: (node: AnyNode) => string | null;
|
|
24
|
-
/** The name an `Identifier` callee carries, or null — a method call is never one of these. */
|
|
25
8
|
export declare const calleeNameOf: (node: AnyNode) => string | null;
|
package/dist/rules/lib/nodes.js
CHANGED