@intentic/sandbox-contract 1.176.3 → 1.209.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/README.md +65 -0
- package/dist/agent-catalog.d.ts +15 -2
- package/dist/agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog.js +50 -1
- package/dist/agent-catalog.js.map +1 -1
- package/dist/agent-run-model.d.ts +3 -0
- package/dist/agent-run-model.d.ts.map +1 -0
- package/dist/agent-run-model.js +10 -0
- package/dist/agent-run-model.js.map +1 -0
- package/dist/capability-env.d.ts +2 -0
- package/dist/capability-env.d.ts.map +1 -0
- package/dist/capability-env.js +2 -0
- package/dist/capability-env.js.map +1 -0
- package/dist/chores/chores.d.ts +9 -0
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +257 -18
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/digest.js +0 -0
- package/dist/chores/digest.js.map +1 -1
- package/dist/chores/extension-update.d.ts +9 -0
- package/dist/chores/extension-update.d.ts.map +1 -0
- package/dist/chores/extension-update.js +15 -0
- package/dist/chores/extension-update.js.map +1 -0
- package/dist/chores/fix-deps.d.ts +10 -0
- package/dist/chores/fix-deps.d.ts.map +1 -0
- package/dist/chores/fix-deps.js +18 -0
- package/dist/chores/fix-deps.js.map +1 -0
- package/dist/chores/index.d.ts +7 -2
- package/dist/chores/index.d.ts.map +1 -1
- package/dist/chores/index.js +4 -1
- package/dist/chores/index.js.map +1 -1
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js +127 -3
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/stack.d.ts +27 -0
- package/dist/chores/stack.d.ts.map +1 -0
- package/dist/chores/stack.js +121 -0
- package/dist/chores/stack.js.map +1 -0
- package/dist/chores/verdict.d.ts +2 -1
- package/dist/chores/verdict.d.ts.map +1 -1
- package/dist/chores/verdict.js +53 -6
- package/dist/chores/verdict.js.map +1 -1
- package/dist/contract-lock.d.ts +3 -0
- package/dist/contract-lock.d.ts.map +1 -0
- package/dist/contract-lock.js +35 -0
- package/dist/contract-lock.js.map +1 -0
- package/dist/contracts/activity.contract.d.ts +10 -0
- package/dist/contracts/activity.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +230 -20
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +2 -1
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +847 -1
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +3 -1
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts +89 -0
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +3 -1
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +108 -32
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +5 -1
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts +43 -0
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.d.ts +5 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.js +2 -2
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/claude.contract.d.ts +3 -14
- package/dist/contracts/claude.contract.d.ts.map +1 -1
- package/dist/contracts/claude.contract.js +2 -3
- package/dist/contracts/claude.contract.js.map +1 -1
- package/dist/contracts/drafts.contract.d.ts +4 -0
- package/dist/contracts/drafts.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +28 -12
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +9 -0
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +399 -69
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js +15 -1
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts +209 -11
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +12 -2
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/grok.contract.d.ts +0 -13
- package/dist/contracts/grok.contract.d.ts.map +1 -1
- package/dist/contracts/grok.contract.js +1 -2
- package/dist/contracts/grok.contract.js.map +1 -1
- package/dist/contracts/host.contract.d.ts +39 -0
- package/dist/contracts/host.contract.d.ts.map +1 -1
- package/dist/contracts/host.contract.js +3 -2
- package/dist/contracts/host.contract.js.map +1 -1
- package/dist/contracts/loops.contract.d.ts +343 -0
- package/dist/contracts/loops.contract.d.ts.map +1 -0
- package/dist/contracts/loops.contract.js +11 -0
- package/dist/contracts/loops.contract.js.map +1 -0
- package/dist/contracts/panels.contract.d.ts +6 -0
- package/dist/contracts/panels.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.d.ts +112 -0
- package/dist/contracts/personas.contract.d.ts.map +1 -0
- package/dist/contracts/personas.contract.js +13 -0
- package/dist/contracts/personas.contract.js.map +1 -0
- package/dist/contracts/ports.contract.d.ts +1 -0
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.d.ts +1 -0
- package/dist/contracts/prepush.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.js.map +1 -1
- package/dist/contracts/{codex.contract.d.ts → providers.contract.d.ts} +11 -3
- package/dist/contracts/providers.contract.d.ts.map +1 -0
- package/dist/contracts/providers.contract.js +6 -0
- package/dist/contracts/providers.contract.js.map +1 -0
- package/dist/contracts/public.contract.d.ts +24 -0
- package/dist/contracts/public.contract.d.ts.map +1 -0
- package/dist/contracts/public.contract.js +8 -0
- package/dist/contracts/public.contract.js.map +1 -0
- package/dist/contracts/push.contract.d.ts +3 -3
- package/dist/contracts/secrets.contract.d.ts +9 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +16 -1
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.js +1 -1
- package/dist/contracts/sessions.contract.js.map +1 -1
- package/dist/contracts/settings.contract.d.ts +352 -58
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +2 -1
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/share.contract.d.ts +55 -0
- package/dist/contracts/share.contract.d.ts.map +1 -0
- package/dist/contracts/share.contract.js +9 -0
- package/dist/contracts/share.contract.js.map +1 -0
- package/dist/contracts/skills.contract.d.ts +41 -0
- package/dist/contracts/skills.contract.d.ts.map +1 -0
- package/dist/contracts/skills.contract.js +9 -0
- package/dist/contracts/skills.contract.js.map +1 -0
- package/dist/contracts/system.contract.d.ts +204 -8
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +10 -2
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/workflows.contract.d.ts +575 -0
- package/dist/contracts/workflows.contract.d.ts.map +1 -0
- package/dist/contracts/workflows.contract.js +13 -0
- package/dist/contracts/workflows.contract.js.map +1 -0
- package/dist/contracts/workspace.contract.d.ts +18 -4
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +6 -3
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/conversation-ids.d.ts +2 -0
- package/dist/conversation-ids.d.ts.map +1 -0
- package/dist/conversation-ids.js +113 -0
- package/dist/conversation-ids.js.map +1 -0
- package/dist/events.d.ts +523 -17
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +106 -13
- package/dist/events.js.map +1 -1
- package/dist/history-state.d.ts.map +1 -1
- package/dist/history-state.js +10 -0
- package/dist/history-state.js.map +1 -1
- package/dist/hostnames.d.ts +4 -0
- package/dist/hostnames.d.ts.map +1 -1
- package/dist/hostnames.js +7 -2
- package/dist/hostnames.js.map +1 -1
- package/dist/index.d.ts +3791 -478
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -17
- package/dist/index.js.map +1 -1
- package/dist/listener-protocol.d.ts +77 -0
- package/dist/listener-protocol.d.ts.map +1 -0
- package/dist/listener-protocol.js +33 -0
- package/dist/listener-protocol.js.map +1 -0
- package/dist/model-order.d.ts +1 -0
- package/dist/model-order.d.ts.map +1 -1
- package/dist/model-order.js +16 -0
- package/dist/model-order.js.map +1 -1
- package/dist/output-fields.d.ts +30 -0
- package/dist/output-fields.d.ts.map +1 -0
- package/dist/output-fields.js +57 -0
- package/dist/output-fields.js.map +1 -0
- package/dist/path-refs.d.ts.map +1 -1
- package/dist/path-refs.js.map +1 -1
- package/dist/publish-drafts.d.ts +7 -0
- package/dist/publish-drafts.d.ts.map +1 -0
- package/dist/publish-drafts.js +20 -0
- package/dist/publish-drafts.js.map +1 -0
- package/dist/quick-model.d.ts +2 -1
- package/dist/quick-model.d.ts.map +1 -1
- package/dist/quick-model.js +18 -14
- package/dist/quick-model.js.map +1 -1
- package/dist/routes.d.ts +3 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +63 -0
- package/dist/routes.js.map +1 -1
- package/dist/runtime-state.d.ts +33 -0
- package/dist/runtime-state.d.ts.map +1 -0
- package/dist/runtime-state.js +14 -0
- package/dist/runtime-state.js.map +1 -0
- package/dist/schemas.d.ts +4886 -851
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +993 -192
- package/dist/schemas.js.map +1 -1
- package/dist/search-globs.d.ts +6 -0
- package/dist/search-globs.d.ts.map +1 -0
- package/dist/search-globs.js +39 -0
- package/dist/search-globs.js.map +1 -0
- package/dist/share-paths.d.ts +8 -0
- package/dist/share-paths.d.ts.map +1 -0
- package/dist/share-paths.js +21 -0
- package/dist/share-paths.js.map +1 -0
- package/dist/title.d.ts.map +1 -1
- package/dist/title.js +1 -1
- package/dist/title.js.map +1 -1
- package/dist/tunnel-ids.d.ts +1 -0
- package/dist/tunnel-ids.d.ts.map +1 -1
- package/dist/tunnel-ids.js +1 -0
- package/dist/tunnel-ids.js.map +1 -1
- package/dist/versions.d.ts +4 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +15 -0
- package/dist/versions.js.map +1 -0
- package/dist/workflow-faults.d.ts +4 -0
- package/dist/workflow-faults.d.ts.map +1 -0
- package/dist/workflow-faults.js +115 -0
- package/dist/workflow-faults.js.map +1 -0
- package/dist/workspace-state.d.ts +280 -1
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +163 -21
- package/dist/workspace-state.js.map +1 -1
- package/package.json +30 -6
- package/src/agent-catalog.test.ts +147 -7
- package/src/agent-catalog.ts +233 -21
- package/src/agent-run-model.test.ts +60 -0
- package/src/agent-run-model.ts +51 -0
- package/src/capability-env.ts +10 -0
- package/src/capability-ledger.test.ts +110 -0
- package/src/chores/chores.test.ts +32 -0
- package/src/chores/chores.ts +456 -32
- package/src/chores/digest.ts +0 -0
- package/src/chores/extension-update.ts +37 -0
- package/src/chores/fix-deps.ts +40 -0
- package/src/chores/index.ts +7 -2
- package/src/chores/probes.test.ts +155 -3
- package/src/chores/probes.ts +200 -4
- package/src/chores/stack.test.ts +126 -0
- package/src/chores/stack.ts +244 -0
- package/src/chores/verdict.test.ts +357 -19
- package/src/chores/verdict.ts +95 -21
- package/src/contract-lock.test.ts +17 -0
- package/src/contract-lock.ts +66 -0
- package/src/contracts/agent.contract.ts +6 -0
- package/src/contracts/agents.contract.ts +12 -0
- package/src/contracts/automations.contract.ts +17 -1
- package/src/contracts/capabilities.contract.ts +22 -0
- package/src/contracts/ci.contract.ts +10 -2
- package/src/contracts/claude.contract.ts +8 -4
- package/src/contracts/endpoints.contract.ts +21 -0
- package/src/contracts/extensions.contract.ts +42 -0
- package/src/contracts/git.contract.ts +33 -6
- package/src/contracts/grok.contract.ts +4 -3
- package/src/contracts/host.contract.ts +13 -2
- package/src/contracts/loops.contract.ts +62 -0
- package/src/contracts/personas.contract.ts +56 -0
- package/src/contracts/prepush.contract.ts +4 -3
- package/src/contracts/providers.contract.ts +23 -0
- package/src/contracts/public.contract.ts +14 -0
- package/src/contracts/sessions.contract.ts +5 -1
- package/src/contracts/settings.contract.ts +5 -0
- package/src/contracts/share.contract.ts +20 -0
- package/src/contracts/skills.contract.ts +24 -0
- package/src/contracts/system.contract.ts +27 -3
- package/src/contracts/workflows.contract.ts +78 -0
- package/src/contracts/workspace.contract.ts +10 -2
- package/src/conversation-ids.test.ts +25 -0
- package/src/conversation-ids.ts +160 -0
- package/src/events.test.ts +20 -1
- package/src/events.ts +404 -43
- package/src/history-state.ts +30 -1
- package/src/hostnames.ts +20 -6
- package/src/index.ts +58 -17
- package/src/listener-protocol.ts +96 -0
- package/src/model-order.test.ts +32 -1
- package/src/model-order.ts +56 -3
- package/src/output-fields.ts +111 -0
- package/src/path-refs.test.ts +4 -4
- package/src/path-refs.ts +5 -5
- package/src/publish-drafts.ts +59 -0
- package/src/quick-model.test.ts +70 -27
- package/src/quick-model.ts +76 -40
- package/src/routes.test.ts +91 -3
- package/src/routes.ts +135 -0
- package/src/runtime-state.test.ts +45 -0
- package/src/runtime-state.ts +124 -0
- package/src/schemas.test.ts +16 -29
- package/src/schemas.ts +3475 -552
- package/src/search-globs.test.ts +46 -0
- package/src/search-globs.ts +76 -0
- package/src/share-paths.test.ts +48 -0
- package/src/share-paths.ts +68 -0
- package/src/state-portability.ts +8 -8
- package/src/title.test.ts +20 -1
- package/src/title.ts +12 -3
- package/src/tunnel-ids.ts +15 -1
- package/src/versions.test.ts +39 -0
- package/src/versions.ts +48 -0
- package/src/workflow-faults.test.ts +127 -0
- package/src/workflow-faults.ts +188 -0
- package/src/workspace-state.test.ts +169 -15
- package/src/workspace-state.ts +427 -35
- package/dist/contracts/codex.contract.d.ts.map +0 -1
- package/dist/contracts/codex.contract.js +0 -6
- package/dist/contracts/codex.contract.js.map +0 -1
- package/dist/contracts/gemini.contract.d.ts +0 -16
- package/dist/contracts/gemini.contract.d.ts.map +0 -1
- package/dist/contracts/gemini.contract.js +0 -6
- package/dist/contracts/gemini.contract.js.map +0 -1
- package/dist/contracts/kimi.contract.d.ts +0 -16
- package/dist/contracts/kimi.contract.d.ts.map +0 -1
- package/dist/contracts/kimi.contract.js +0 -6
- package/dist/contracts/kimi.contract.js.map +0 -1
- package/dist/contracts/komodo.contract.d.ts +0 -125
- package/dist/contracts/komodo.contract.d.ts.map +0 -1
- package/dist/contracts/komodo.contract.js +0 -14
- package/dist/contracts/komodo.contract.js.map +0 -1
- package/dist/contracts/memory.contract.d.ts +0 -34
- package/dist/contracts/memory.contract.d.ts.map +0 -1
- package/dist/contracts/memory.contract.js +0 -9
- package/dist/contracts/memory.contract.js.map +0 -1
- package/src/contracts/codex.contract.ts +0 -10
- package/src/contracts/gemini.contract.ts +0 -11
- package/src/contracts/kimi.contract.ts +0 -9
- package/src/contracts/komodo.contract.ts +0 -36
- package/src/contracts/memory.contract.ts +0 -13
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/* WHAT THIS REPOSITORY IS BUILT WITH, and the patterns that follow from it — the table the UI chores are written
|
|
2
|
+
* against, kept apart from both the probe that runs it and the chores that read it.
|
|
3
|
+
*
|
|
4
|
+
* It sits in the middle on purpose. probes.ts composes ONE ripgrep sweep out of the rules below, and chores.ts
|
|
5
|
+
* turns the counts that come back into findings and prose. Put the rules in either of those and the other one
|
|
6
|
+
* grows a copy: the probe would hard-code patterns the chore has to describe in words, or the chore would restate
|
|
7
|
+
* globs the probe already walked. Both copies would then be free to disagree about what a component is.
|
|
8
|
+
*
|
|
9
|
+
* NOTHING HERE IS A VERDICT. A framework is a set of dependency names, an idiom is a regex and the name of what
|
|
10
|
+
* replaced it. Which of those amount to work worth doing is the chore book's judgement, made in chores.ts against
|
|
11
|
+
* the same three rules everything else there obeys.
|
|
12
|
+
*
|
|
13
|
+
* THE PATTERNS ARE RIPGREP'S DIALECT, and they carry two constraints that are not obvious from reading them:
|
|
14
|
+
*
|
|
15
|
+
* No literal apostrophe, ever. The scan command wraps each pattern in shell single quotes, so a `'` inside one
|
|
16
|
+
* would end the quoting and hand the rest of the regex to the shell. Match quotes as `[\x22\x27]` instead —
|
|
17
|
+
* Rust's regex crate reads those escapes, and the shell never sees a quote character at all. stack.test.ts
|
|
18
|
+
* enforces this, because the failure is a probe that dies at three in the morning in someone else's workspace
|
|
19
|
+
* rather than anything a reader would notice here.
|
|
20
|
+
*
|
|
21
|
+
* No lookaround. Rust's regex crate has none, and reaching for ripgrep's PCRE2 mode to get it would make the
|
|
22
|
+
* sweep depend on how the box's ripgrep was compiled. A rule that seems to need it is usually asking a question
|
|
23
|
+
* about the FILE rather than about a line — see `absent` below, which is what that question actually is. */
|
|
24
|
+
|
|
25
|
+
export interface UiFramework {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
// The dependency names that mean "this repository is built with it". Any one of them is enough.
|
|
29
|
+
readonly packages: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* The three the maintenance surface knows how to say something specific about. Deliberately not "every framework
|
|
33
|
+
* with a npm package": a framework earns a row here by having idiom rules underneath it, and a table entry with
|
|
34
|
+
* no rules would let a chore announce it recognised Svelte and then have nothing to report. */
|
|
35
|
+
export const UI_FRAMEWORKS: readonly UiFramework[] = [
|
|
36
|
+
{ id: `react`, label: `React`, packages: [`react`] },
|
|
37
|
+
{ id: `vue`, label: `Vue`, packages: [`vue`] },
|
|
38
|
+
{ id: `angular`, label: `Angular`, packages: [`@angular/core`] },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Tailwind is not in the table above because it is not a UI framework and does not own any idiom rules — it is a
|
|
42
|
+
// styling system that any of the three can be wearing, and it gates exactly one chore.
|
|
43
|
+
export const TAILWIND_PACKAGES: readonly string[] = [`tailwindcss`];
|
|
44
|
+
|
|
45
|
+
export const frameworksOf = (deps: readonly string[]): UiFramework[] =>
|
|
46
|
+
UI_FRAMEWORKS.filter((framework) => framework.packages.some((name) => deps.includes(name)));
|
|
47
|
+
|
|
48
|
+
export const usesTailwind = (deps: readonly string[]): boolean => TAILWIND_PACKAGES.some((name) => deps.includes(name));
|
|
49
|
+
|
|
50
|
+
/* Directories a UI scan must never walk, spelled out rather than left to the repository's .gitignore. ripgrep
|
|
51
|
+
* does honour .gitignore, and relying on that is how a repo whose build output is not ignored gets its own
|
|
52
|
+
* minified bundle reported back to it as a thousand hard-coded colours. Tests, specs and stories are excluded for
|
|
53
|
+
* a different reason: they are component-shaped files that are not components, and counting them would put a
|
|
54
|
+
* fixture at the top of every finding. */
|
|
55
|
+
export const SCAN_IGNORES: readonly string[] = [
|
|
56
|
+
`!**/node_modules/**`,
|
|
57
|
+
`!**/dist/**`,
|
|
58
|
+
`!**/build/**`,
|
|
59
|
+
`!**/.next/**`,
|
|
60
|
+
`!**/out/**`,
|
|
61
|
+
`!**/coverage/**`,
|
|
62
|
+
`!**/vendor/**`,
|
|
63
|
+
`!**/generated/**`,
|
|
64
|
+
`!**/*.{test,spec,stories}.*`,
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// What counts as a component file, across all three frameworks at once. The sweep cannot vary by repository — a
|
|
68
|
+
// probe's command is a fixed string — so it asks for all of them and a Vue-only repo simply has no `.tsx` files.
|
|
69
|
+
export const COMPONENT_GLOBS: readonly string[] = [`*.vue`, `*.tsx`, `*.jsx`, `*.component.ts`];
|
|
70
|
+
|
|
71
|
+
// Where a Tailwind class can appear. Wider than COMPONENT_GLOBS because a class list lives in markup as often as
|
|
72
|
+
// in a component — an Angular template and a plain .html page both style with the same utilities.
|
|
73
|
+
export const MARKUP_GLOBS: readonly string[] = [`*.vue`, `*.tsx`, `*.jsx`, `*.html`, `*.svelte`, `*.astro`];
|
|
74
|
+
|
|
75
|
+
/* THE DESIGN SYSTEM BYPASS. Not "any arbitrary value" — `grid-cols-[1fr_auto]` and `w-[calc(100%-2rem)]` are
|
|
76
|
+
* Tailwind working as designed, and a chore that counted them would be objecting to the feature rather than to
|
|
77
|
+
* anything wrong. What this matches is the two arbitrary values that route around a decision the theme already
|
|
78
|
+
* made: a colour that is not in the palette, and a pixel size that is not on the spacing or type scale.
|
|
79
|
+
*
|
|
80
|
+
* The leading `-` is load-bearing. It anchors the match to a utility prefix (`bg-`, `text-`, `w-`), so a bare
|
|
81
|
+
* `[...]` in ordinary prose or an array index cannot be mistaken for a class. */
|
|
82
|
+
export const BYPASS_PATTERN = `-\\[(#[0-9a-fA-F]{3,8}|(rgb|hsl)a?\\(|[0-9]+(\\.[0-9]+)?px)`;
|
|
83
|
+
|
|
84
|
+
export interface IdiomRule {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
// Which framework's migration this belongs to, so a finding can be grouped under the thing that moved on.
|
|
87
|
+
readonly framework: string;
|
|
88
|
+
// What the repository still has, named as the reader would name it.
|
|
89
|
+
readonly label: string;
|
|
90
|
+
// What replaced it. Carried so the prompt can say where to go rather than only what to leave — an agent told
|
|
91
|
+
// "you still use NgModule" and nothing else will pick a destination, and it may not pick this one.
|
|
92
|
+
readonly replacement: string;
|
|
93
|
+
readonly pattern: string;
|
|
94
|
+
readonly globs: readonly string[];
|
|
95
|
+
/* THE IDIOM IS THE PATTERN BEING MISSING, not present — `pattern` names the NEW way, and the file is on the
|
|
96
|
+
* old one precisely because the new one does not appear in it anywhere. The sweep spells this
|
|
97
|
+
* `--files-without-match`.
|
|
98
|
+
*
|
|
99
|
+
* This exists because the alternative got it wrong in a way that is worth remembering. "A Vue file not using
|
|
100
|
+
* <script setup>" was first written as a lookahead over `<script`, which matches per LINE: a migrated
|
|
101
|
+
* component with a second plain `<script>` block for defineOptions, or one that merely mentions `<script` in
|
|
102
|
+
* a comment, both read as un-migrated. It reported five files in an application whose 167 SFCs are every one
|
|
103
|
+
* of them migrated. The question was never "is there a line like this" — it is "does this file contain the
|
|
104
|
+
* new idiom at all", which is one flag rather than a cleverer regex, and it costs no PCRE2.
|
|
105
|
+
*
|
|
106
|
+
* The globs carry more weight on an absent rule than on a normal one, and narrowly is the only safe way to
|
|
107
|
+
* write them: the population is every file they match, so `*.ts` on an absent rule reports the entire
|
|
108
|
+
* repository. Keep them to the file type the migration is actually about. */
|
|
109
|
+
readonly absent?: true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* THE IDIOMS THEIR OWN MAINTAINERS HAVE MOVED ON FROM. Every rule here names something the framework's own
|
|
113
|
+
* documentation now steers people away from, and every one of them still works — which is exactly why they
|
|
114
|
+
* accumulate, and why no editor and no linter will bring them up unprompted.
|
|
115
|
+
*
|
|
116
|
+
* High confidence over coverage. Each pattern is one a reader can check by eye against a file, and the ones that
|
|
117
|
+
* would need real parsing to get right are left out rather than approximated: a rule that is wrong a third of the
|
|
118
|
+
* time trains people to stop reading the row it appears in. */
|
|
119
|
+
export const IDIOM_RULES: readonly IdiomRule[] = [
|
|
120
|
+
{
|
|
121
|
+
id: `react-class-component`,
|
|
122
|
+
framework: `react`,
|
|
123
|
+
label: `class components`,
|
|
124
|
+
replacement: `function components with hooks`,
|
|
125
|
+
pattern: `extends\\s+(React\\.)?(Pure)?Component\\b`,
|
|
126
|
+
globs: [`*.tsx`, `*.jsx`],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: `react-legacy-render`,
|
|
130
|
+
framework: `react`,
|
|
131
|
+
label: `the legacy ReactDOM.render entry point`,
|
|
132
|
+
replacement: `createRoot from react-dom/client`,
|
|
133
|
+
pattern: `ReactDOM\\.render\\(`,
|
|
134
|
+
globs: [`*.tsx`, `*.jsx`, `*.ts`, `*.js`],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: `react-unsafe-lifecycle`,
|
|
138
|
+
framework: `react`,
|
|
139
|
+
// Named as what they are rather than by the UNSAFE_ prefix: a reader who has never renamed one would not
|
|
140
|
+
// recognise "UNSAFE_componentWillMount" as describing their own file.
|
|
141
|
+
label: `the pre-16.3 lifecycle methods`,
|
|
142
|
+
replacement: `effects, or the UNSAFE_ prefixed names if the behaviour is genuinely wanted`,
|
|
143
|
+
pattern: `\\bcomponentWill(Mount|ReceiveProps|Update)\\b`,
|
|
144
|
+
globs: [`*.tsx`, `*.jsx`],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: `react-prop-types`,
|
|
148
|
+
framework: `react`,
|
|
149
|
+
label: `runtime prop-types`,
|
|
150
|
+
replacement: `the component's own TypeScript props type`,
|
|
151
|
+
pattern: `from\\s+[\\x22\\x27]prop-types[\\x22\\x27]`,
|
|
152
|
+
globs: [`*.tsx`, `*.jsx`],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: `vue-options-api`,
|
|
156
|
+
framework: `vue`,
|
|
157
|
+
label: `the Options API`,
|
|
158
|
+
replacement: `<script setup> with the Composition API`,
|
|
159
|
+
// The new idiom, inverted by `absent` below — an SFC that never opens a `<script setup>` tag is still on
|
|
160
|
+
// the old one. A file with no script block at all is swept up too, and that is the honest reading: it has
|
|
161
|
+
// not been migrated because there was nothing there to migrate.
|
|
162
|
+
pattern: `<script[^>]*\\bsetup\\b`,
|
|
163
|
+
globs: [`*.vue`],
|
|
164
|
+
absent: true,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: `vue-2-lifecycle`,
|
|
168
|
+
framework: `vue`,
|
|
169
|
+
label: `the Vue 2 teardown hooks`,
|
|
170
|
+
replacement: `beforeUnmount and unmounted`,
|
|
171
|
+
pattern: `\\b(beforeDestroy|destroyed)\\s*[(:]`,
|
|
172
|
+
globs: [`*.vue`, `*.ts`, `*.js`],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: `vue-global-api`,
|
|
176
|
+
framework: `vue`,
|
|
177
|
+
label: `the Vue 2 global constructor`,
|
|
178
|
+
replacement: `createApp and defineComponent`,
|
|
179
|
+
pattern: `\\b(new\\s+Vue\\(|Vue\\.extend\\()`,
|
|
180
|
+
globs: [`*.vue`, `*.ts`, `*.js`],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: `angular-ngmodule`,
|
|
184
|
+
framework: `angular`,
|
|
185
|
+
label: `NgModule declarations`,
|
|
186
|
+
replacement: `standalone components`,
|
|
187
|
+
pattern: `@NgModule\\(`,
|
|
188
|
+
globs: [`*.ts`],
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: `angular-structural-directives`,
|
|
192
|
+
framework: `angular`,
|
|
193
|
+
label: `the structural directives`,
|
|
194
|
+
replacement: `the built-in control flow blocks`,
|
|
195
|
+
pattern: `\\*ng(If|For|Switch)\\b`,
|
|
196
|
+
globs: [`*.html`, `*.ts`],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: `angular-module-providers`,
|
|
200
|
+
framework: `angular`,
|
|
201
|
+
label: `the module-based providers`,
|
|
202
|
+
replacement: `the provide* functions in the application config`,
|
|
203
|
+
pattern: `\\b(HttpClientModule|BrowserAnimationsModule|RouterModule\\.forRoot)\\b`,
|
|
204
|
+
globs: [`*.ts`],
|
|
205
|
+
},
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
export const idiomRule = (id: string): IdiomRule | undefined => IDIOM_RULES.find((rule) => rule.id === id);
|
|
209
|
+
|
|
210
|
+
/* Two tools naming the same file two ways. The scan reports repo-relative paths because that is what ripgrep
|
|
211
|
+
* prints; jscpd prints whatever it was handed, which for a `.` scan is the same path behind a `./`. Normalising
|
|
212
|
+
* here rather than at each comparison keeps the component-overlap chore from quietly matching nothing because one
|
|
213
|
+
* side had two extra characters. */
|
|
214
|
+
export const normalizePath = (path: string): string => path.replace(/^\.\//, ``);
|
|
215
|
+
|
|
216
|
+
// Below this a stem is too short to have survived the stripping above with its meaning intact — `H1` and `H2`
|
|
217
|
+
// would both reduce to `h` and read as one family of heading components that are not duplicates of anything.
|
|
218
|
+
const MIN_STEM = 3;
|
|
219
|
+
|
|
220
|
+
const QUALIFIER_PREFIX = /^(base|the)/;
|
|
221
|
+
const QUALIFIER_SUFFIX = /(v[0-9]+|new|old|legacy|copy|component|[0-9]+)$/;
|
|
222
|
+
|
|
223
|
+
/* THE NAME TWO COMPONENTS SHARE WHEN THEY ARE THE SAME COMPONENT TWICE — or `undefined` when the file has no
|
|
224
|
+
* name worth comparing.
|
|
225
|
+
*
|
|
226
|
+
* This is a normaliser, not a similarity score, and that is the point: it answers a question the reader can check
|
|
227
|
+
* by eye. `BaseButton.vue` and `ButtonV2.tsx` both reduce to `button`, so a panel claiming they are the same
|
|
228
|
+
* component is making a claim anyone can agree or disagree with in a second. A fuzzy distance would be right more
|
|
229
|
+
* often and checkable never, and an unarguable finding is one nobody can improve.
|
|
230
|
+
*
|
|
231
|
+
* `index` is dropped rather than normalised. Every barrel file in the repository is called it, and a family of
|
|
232
|
+
* forty index files is a finding about the naming convention rather than about any duplication. */
|
|
233
|
+
export const componentStem = (path: string): string | undefined => {
|
|
234
|
+
const file = normalizePath(path).split(`/`).pop() ?? ``;
|
|
235
|
+
// `.component.ts` loses both suffixes, `.vue` loses one — taking everything before the first dot handles both
|
|
236
|
+
// without a table, since a component's name is never the part after a dot.
|
|
237
|
+
const base = (file.split(`.`)[0] ?? ``).toLowerCase().replace(/[^a-z0-9]/g, ``);
|
|
238
|
+
if (base === `` || base === `index`) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
const withoutSuffix = base.replace(QUALIFIER_SUFFIX, ``);
|
|
242
|
+
const stem = (withoutSuffix.length >= MIN_STEM ? withoutSuffix : base).replace(QUALIFIER_PREFIX, ``);
|
|
243
|
+
return stem.length >= MIN_STEM ? stem : base;
|
|
244
|
+
};
|