@craft-ts/dev-tools 0.7.0-beta.13 → 0.7.0-beta.15

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.
Files changed (89) hide show
  1. package/README.md +64 -10
  2. package/package.json +8 -2
  3. package/src/bin/agent-selector.d.ts +22 -0
  4. package/src/bin/agent-selector.js +100 -0
  5. package/src/bin/agent-selector.js.map +1 -0
  6. package/src/bin/craft-graph.js +74 -8
  7. package/src/bin/craft-graph.js.map +1 -1
  8. package/src/bin/craft.d.ts +23 -0
  9. package/src/bin/craft.js +245 -28
  10. package/src/bin/craft.js.map +1 -1
  11. package/src/eslint-rules/anchor-has-href.cjs +37 -3
  12. package/src/eslint-rules/craft-computed-name-match.cjs +26 -5
  13. package/src/eslint-rules/craft-name-match-utils.cjs +18 -9
  14. package/src/eslint-rules/hyperscript-walk.cjs +3 -3
  15. package/src/eslint-rules/index.cjs +46 -1
  16. package/src/eslint-rules/no-auth-token-in-local-storage.cjs +17 -0
  17. package/src/eslint-rules/no-craft-computed-side-effects.cjs +12 -5
  18. package/src/eslint-rules/no-craft-service-component-same-file.cjs +138 -0
  19. package/src/eslint-rules/no-effect-import-in-frontend.cjs +52 -0
  20. package/src/eslint-rules/no-effect-in-params.cjs +31 -1
  21. package/src/eslint-rules/no-explicit-effect-type.cjs +137 -0
  22. package/src/eslint-rules/no-free-has.cjs +47 -0
  23. package/src/eslint-rules/no-heading-level-skip.cjs +6 -6
  24. package/src/eslint-rules/no-raw-class.cjs +76 -0
  25. package/src/eslint-rules/no-raw-css-value.cjs +163 -0
  26. package/src/eslint-rules/no-raw-user-url.cjs +114 -0
  27. package/src/eslint-rules/no-trust-forwarded-headers.cjs +43 -0
  28. package/src/eslint-rules/no-unsafe-html.cjs +93 -0
  29. package/src/eslint-rules/no-unsafe-transfer-state.cjs +54 -0
  30. package/src/eslint-rules/prefer-craft-template-blocks.cjs +8 -8
  31. package/src/eslint-rules/prefer-direct-yieldable-callback.cjs +57 -14
  32. package/src/eslint-rules/prefer-inline-effect-insertion.cjs +263 -0
  33. package/src/eslint-rules/prefer-inline-route-providers.cjs +138 -0
  34. package/src/eslint-rules/recommended-config.cjs +6 -0
  35. package/src/eslint-rules/require-reactive-template-bindings.cjs +8 -8
  36. package/src/eslint-rules/require-route-security-policy.cjs +87 -0
  37. package/src/eslint-rules/require-server-function-timeout.cjs +39 -0
  38. package/src/eslint-rules/security-config.cjs +14 -0
  39. package/src/eslint-rules/security-rule-utils.cjs +21 -0
  40. package/src/eslint-rules/style-file-boundary.cjs +75 -0
  41. package/src/eslint-rules/sync-effect-body.cjs +343 -0
  42. package/src/index.d.ts +4 -0
  43. package/src/index.js +4 -0
  44. package/src/index.js.map +1 -1
  45. package/src/scripts/architecture-graph.js +8 -2
  46. package/src/scripts/architecture-graph.js.map +1 -1
  47. package/src/scripts/create/create-project.d.ts +71 -1
  48. package/src/scripts/create/create-project.js +1937 -176
  49. package/src/scripts/create/create-project.js.map +1 -1
  50. package/src/scripts/data-flow-graph.d.ts +1 -1
  51. package/src/scripts/effect-dependency-graph.d.ts +1 -1
  52. package/src/scripts/security-check.d.ts +30 -0
  53. package/src/scripts/security-check.js +223 -0
  54. package/src/scripts/security-check.js.map +1 -0
  55. package/src/scripts/style-architecture.d.ts +56 -0
  56. package/src/scripts/style-architecture.js +142 -0
  57. package/src/scripts/style-architecture.js.map +1 -0
  58. package/src/scripts/style-graph.d.ts +99 -0
  59. package/src/scripts/style-graph.js +179 -0
  60. package/src/scripts/style-graph.js.map +1 -0
  61. package/src/scripts/style-report.d.ts +55 -0
  62. package/src/scripts/style-report.js +67 -0
  63. package/src/scripts/style-report.js.map +1 -0
  64. package/src/scripts/template/migrate-template.js +1 -1
  65. package/src/scripts/template/migrate-template.js.map +1 -1
  66. package/src/scripts/angular-brand-codemod.ts +0 -3985
  67. package/src/scripts/architecture/migrate-architecture.ts +0 -653
  68. package/src/scripts/architecture-graph.ts +0 -3136
  69. package/src/scripts/components/migrate-components.ts +0 -227
  70. package/src/scripts/components/migration-diagnostic.ts +0 -8
  71. package/src/scripts/create/create-project.ts +0 -849
  72. package/src/scripts/data-flow-graph.ts +0 -240
  73. package/src/scripts/dependency-graph.ts +0 -5908
  74. package/src/scripts/effect-dependency-graph.ts +0 -630
  75. package/src/scripts/migrate.ts +0 -162
  76. package/src/scripts/migration-workspace.ts +0 -93
  77. package/src/scripts/primitives/migrate-named-primitives.ts +0 -627
  78. package/src/scripts/primitives/migrate-primitive-generators.ts +0 -410
  79. package/src/scripts/primitives/migrate-primitives.ts +0 -655
  80. package/src/scripts/primitives/migrate-yieldable-reactive-reads.ts +0 -499
  81. package/src/scripts/primitives/migration-diagnostic.ts +0 -15
  82. package/src/scripts/routes/migrate-routes.ts +0 -895
  83. package/src/scripts/routes/migration-diagnostic.ts +0 -25
  84. package/src/scripts/routes/route-command.ts +0 -1807
  85. package/src/scripts/routes/verify-routes.ts +0 -1511
  86. package/src/scripts/services/config.ts +0 -60
  87. package/src/scripts/services/migrate-services.ts +0 -1348
  88. package/src/scripts/services/migration-diagnostic.ts +0 -28
  89. package/src/scripts/template/migrate-template.ts +0 -418
package/README.md CHANGED
@@ -15,20 +15,67 @@ For coding agents, also install
15
15
 
16
16
  ## Create a project
17
17
 
18
- Create a framework-independent CraftTS application from scratch. The command
19
- asks for the Effect v4 choice first in interactive mode because it changes the
20
- dependencies, generated API boundary, and agent skills:
18
+ Create a framework-independent CraftTS application from scratch. Runtime axes,
19
+ i18n, design-system, typed-CSS, server-function, workspace and reference
20
+ choices are normalized into one effective configuration:
21
21
 
22
22
  ```bash
23
- npx craft create my-app
24
- npx craft create my-app --effect=v4 --agents=codex,cursor,cloud-code
25
- npx craft create my-app --effect=none --agents=none
23
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app
24
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app --effect=v4 --agents=codex,cursor,gemini
25
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app --effect=none --agents=none
26
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app --effect=none --i18n=none --design-system=none --no-typed-css
27
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app --frontend-runtime=effect --backend-runtime=effect --i18n=strict
28
+ npx --yes --package @craft-ts/dev-tools@beta craft create my-app --frontend-runtime=plain --backend-runtime=effect
29
+ npx --yes --package @craft-ts/dev-tools@beta craft create apps/my-app --workspace=nx --references=craft-ts --reference-mode=context
30
+ npx --yes --package @craft-ts/dev-tools@beta craft create apps/my-app --references=craft-ts --reference-mode=source
26
31
  ```
27
32
 
33
+ In a terminal, creation is interactive by default. The frontend and backend
34
+ runtimes are selected independently, so `plain` frontend + `effect` backend is
35
+ available for server functions. The prompts also cover i18n locales, the
36
+ workspace, CraftTS/EffectTS source references, and their resolution
37
+ mode. All closed configuration values use keyboard menus: `↑`/`↓` to move
38
+ and `Enter` to confirm; locales and agent integrations additionally use
39
+ `Space` for multi-selection. Codex is selected by default. Pass
40
+ `--yes` after `create` to disable all prompts, or pass
41
+ `--agents=codex,cursor` / `--agents=none` for scripted agent selection.
42
+
43
+ In interactive mode, reference sources are cloned by default; answer `n` to
44
+ opt out. In non-interactive mode, request them explicitly with
45
+ `--references=craft-ts` or `--references=all`.
46
+
47
+ New standalone projects are initialized with Git (without an initial commit)
48
+ and receive a `.gitignore` covering `node_modules/`, build outputs, test
49
+ reports, and local references. If the destination is already inside another
50
+ Git repository, no nested repository is created.
51
+
52
+ Canonical options include `--frontend-runtime=plain|effect`,
53
+ `--backend-runtime=none|promise|effect`, `--effect-scope=none|frontend|backend|both`,
54
+ `--i18n=strict|loose|none`, `--design-system=basic|none`,
55
+ `--typed-css`/`--no-typed-css`, `--workspace=standalone|nx`, and
56
+ `--references=none|craft-ts|all` with `--reference-mode=context|local|source`.
57
+ `--effect=v4|none`, `--locales` and `--default-locale` remain compatible aliases.
58
+ `--json` includes the complete effective configuration.
59
+
60
+ With references enabled, `.references/manifest.json` records the requested ref
61
+ and resolved SHA. `context` keeps npm dependencies portable; `local` is for
62
+ build artifacts from the checked-out references. `source` keeps the scoped
63
+ `@craft-ts/...` imports but resolves them directly to the cloned CraftTS source
64
+ through TypeScript paths and Vite aliases; the CraftTS clone itself does not
65
+ get a `node_modules`. Refresh clones with
66
+ `npm run update:references` (or the generated `update:craft-ts`/
67
+ `update:effect-ts` scripts).
68
+
69
+ `local` builds CraftTS with its Nx library targets and builds the MCP/log
70
+ workspaces individually; CraftTS has no root `npm run build` script.
71
+
28
72
  The starter includes a routed page, a typed API call, flat-config ESLint, unit
29
- tests, a graph-wide `architecture/` suite, Playwright E2E tests, and README
30
- commands for every quality gate. `codex`, `cursor`, `claude-code`, and the
31
- `cloud-code`/`gemini` aliases install the corresponding project instructions.
73
+ tests, a graph-wide `architecture/` suite, Playwright E2E tests, development
74
+ logs forwarded to a local JSONL server, `.mcp.json` for Craft/log/page MCP
75
+ servers, a browser type-check indicator, and a GitHub Actions workflow with an
76
+ explicit `npm run typecheck` gate. `codex`, `cursor`, `claude-code`, and the
77
+ `gemini` (with `cloud-code` kept as a compatibility alias) installs the
78
+ corresponding Gemini project instructions.
32
79
 
33
80
  ## Project configuration
34
81
 
@@ -137,7 +184,14 @@ The rules cover, among other things:
137
184
  - yieldable reads, writes, methods, and resource triggers;
138
185
  - transport access through `CraftHttpClient`;
139
186
  - typed route loading, dependency proofs, and exception handling;
140
- - pure computed values, browser boundaries, and accessibility contracts.
187
+ - pure computed values, browser boundaries, and accessibility contracts;
188
+ - the security preset, included in `recommended` and `effect`: unchecked DOM
189
+ URLs, raw HTML, dynamic code, implicit SSR transfer, server functions
190
+ without limits or explicit per-function error exposure, forwarded headers, and
191
+ authentication material in browser storage.
192
+
193
+ Apply the preset alone — on a library or a tooling folder that does not take
194
+ `recommended` — with `craftRules.configs.security`.
141
195
 
142
196
  Run `eslint --fix` after changing generated dependency aliases or route
143
197
  metadata. Keep the generated aliases and proofs in the source file so the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craft-ts/dev-tools",
3
- "version": "0.7.0-beta.13",
3
+ "version": "0.7.0-beta.15",
4
4
  "description": "Development tools for craft-ts: ESLint configs, ESLint rules, and codemods",
5
5
  "author": "Romain Geffrault",
6
6
  "license": "MIT",
@@ -24,6 +24,10 @@
24
24
  "types": "./src/eslint-rules/index.d.cts",
25
25
  "default": "./src/eslint-rules/index.cjs"
26
26
  },
27
+ "./style-report": {
28
+ "types": "./src/scripts/style-report.d.ts",
29
+ "default": "./src/scripts/style-report.js"
30
+ },
27
31
  "./template-migration": {
28
32
  "types": "./src/template-migration.d.ts",
29
33
  "default": "./src/template-migration.js"
@@ -60,6 +64,8 @@
60
64
  "files": [
61
65
  "generators.json",
62
66
  "src/**/*",
67
+ "!src/**/*.ts",
68
+ "src/**/*.d.ts",
63
69
  "README.md",
64
70
  "!src/**/*.spec.ts",
65
71
  "!src/**/*.spec.js",
@@ -74,7 +80,7 @@
74
80
  "tslib": "^2.3.0",
75
81
  "ts-morph": "^24.0.0",
76
82
  "ts-node": "^10.9.2",
77
- "typescript": "6.0.3"
83
+ "typescript": "7.0.2"
78
84
  },
79
85
  "peerDependencies": {
80
86
  "@angular-eslint/eslint-plugin": ">=21.0.0",
@@ -0,0 +1,22 @@
1
+ import type { CreateAgent } from '../scripts/create/create-project.js';
2
+ export declare const CREATE_AGENT_OPTIONS: readonly {
3
+ readonly value: CreateAgent;
4
+ readonly label: string;
5
+ }[];
6
+ export type InteractiveOption<Value extends string> = {
7
+ readonly value: Value;
8
+ readonly label: string;
9
+ };
10
+ export type AgentSelectorInput = NodeJS.ReadStream & {
11
+ setRawMode(mode: boolean): NodeJS.ReadStream;
12
+ };
13
+ type AgentSelectorOutput = Pick<NodeJS.WriteStream, 'write'>;
14
+ export declare function selectOptionInteractively<Value extends string>(options: readonly InteractiveOption<Value>[], title: string, initialValue: Value, input?: AgentSelectorInput, output?: AgentSelectorOutput): Promise<Value>;
15
+ export declare function selectOptionsInteractively<Value extends string>(options: readonly InteractiveOption<Value>[], title: string, initialSelection: readonly Value[], input?: AgentSelectorInput, output?: AgentSelectorOutput, minimumSelection?: number): Promise<readonly Value[]>;
16
+ /**
17
+ * Let a user select the integrations for which project skills are generated.
18
+ * The input is deliberately kept injectable so the keyboard state machine can
19
+ * be exercised without spawning a terminal in tests.
20
+ */
21
+ export declare function selectAgentsInteractively(input?: AgentSelectorInput, output?: AgentSelectorOutput, initialSelection?: readonly CreateAgent[]): Promise<readonly CreateAgent[]>;
22
+ export {};
@@ -0,0 +1,100 @@
1
+ import { emitKeypressEvents } from 'node:readline';
2
+ export const CREATE_AGENT_OPTIONS = [
3
+ { value: 'codex', label: 'Codex' },
4
+ { value: 'cursor', label: 'Cursor' },
5
+ { value: 'claude-code', label: 'Claude Code' },
6
+ { value: 'cloud-code', label: 'Gemini CLI' },
7
+ ];
8
+ function selectValuesInteractively(options, title, initialSelection, multiple, input, output, minimumSelection = 0) {
9
+ const selected = new Set(initialSelection);
10
+ let cursor = Math.max(0, options.findIndex((option) => selected.has(option.value)));
11
+ let rendered = false;
12
+ const render = () => {
13
+ if (rendered)
14
+ output.write(`\u001b[${options.length + 1}A`);
15
+ output.write(`${title}\n`);
16
+ for (const [index, option] of options.entries()) {
17
+ const pointer = index === cursor ? '❯' : ' ';
18
+ const marker = multiple ? `${selected.has(option.value) ? '[x]' : '[ ]'} ` : '';
19
+ output.write(`${pointer} ${marker}${option.label}\n`);
20
+ }
21
+ rendered = true;
22
+ };
23
+ return new Promise((resolve, reject) => {
24
+ const wasRaw = input.isRaw ?? false;
25
+ const finish = (result) => {
26
+ input.removeListener('keypress', onKeypress);
27
+ input.setRawMode(wasRaw);
28
+ input.pause();
29
+ output.write('\n');
30
+ resolve(result);
31
+ };
32
+ const cancel = () => {
33
+ input.removeListener('keypress', onKeypress);
34
+ input.setRawMode(wasRaw);
35
+ input.pause();
36
+ output.write('\n');
37
+ reject(new Error('Interactive selection cancelled.'));
38
+ };
39
+ const onKeypress = (_input, key) => {
40
+ if (key.ctrl && key.name === 'c') {
41
+ cancel();
42
+ return;
43
+ }
44
+ if (key.name === 'up') {
45
+ cursor = (cursor - 1 + options.length) % options.length;
46
+ render();
47
+ return;
48
+ }
49
+ if (key.name === 'down') {
50
+ cursor = (cursor + 1) % options.length;
51
+ render();
52
+ return;
53
+ }
54
+ if (multiple && key.name === 'space') {
55
+ const value = options[cursor].value;
56
+ if (selected.has(value)) {
57
+ if (selected.size > minimumSelection)
58
+ selected.delete(value);
59
+ }
60
+ else
61
+ selected.add(value);
62
+ render();
63
+ return;
64
+ }
65
+ if (key.name === 'return' || key.name === 'enter') {
66
+ finish(multiple
67
+ ? options.map((option) => option.value).filter((value) => selected.has(value))
68
+ : [options[cursor].value]);
69
+ }
70
+ };
71
+ try {
72
+ emitKeypressEvents(input);
73
+ input.setRawMode(true);
74
+ input.setEncoding('utf8');
75
+ input.resume();
76
+ input.on('keypress', onKeypress);
77
+ render();
78
+ }
79
+ catch (error) {
80
+ cancel();
81
+ reject(error);
82
+ }
83
+ });
84
+ }
85
+ export function selectOptionInteractively(options, title, initialValue, input = process.stdin, output = process.stdout) {
86
+ return selectValuesInteractively(options, title, [initialValue], false, input, output)
87
+ .then(([value]) => value);
88
+ }
89
+ export function selectOptionsInteractively(options, title, initialSelection, input = process.stdin, output = process.stdout, minimumSelection = 0) {
90
+ return selectValuesInteractively(options, title, initialSelection, true, input, output, minimumSelection);
91
+ }
92
+ /**
93
+ * Let a user select the integrations for which project skills are generated.
94
+ * The input is deliberately kept injectable so the keyboard state machine can
95
+ * be exercised without spawning a terminal in tests.
96
+ */
97
+ export function selectAgentsInteractively(input = process.stdin, output = process.stdout, initialSelection = ['codex']) {
98
+ return selectOptionsInteractively(CREATE_AGENT_OPTIONS, 'Select agent skills (↑/↓ move, Space toggle, Enter confirm):', initialSelection, input, output);
99
+ }
100
+ //# sourceMappingURL=agent-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-selector.js","sourceRoot":"","sources":["../../../../../libs/dev-tools/src/bin/agent-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAInD,MAAM,CAAC,MAAM,oBAAoB,GAG3B;IACJ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAClC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACpC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9C,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;CAC7C,CAAC;AAoBF,SAAS,yBAAyB,CAChC,OAA4C,EAC5C,KAAa,EACb,gBAAkC,EAClC,QAAiB,EACjB,KAAoB,EACpB,MAA2B,EAC3B,gBAAgB,GAAG,CAAC;IAEpB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAQ,gBAAgB,CAAC,CAAC;IAClD,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpF,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,IAAI,QAAQ;YAAE,MAAM,CAAC,KAAK,CAAC,UAAU,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,MAAM,OAAO,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;QACxD,CAAC;QACD,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,IAAI,OAAO,CAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;QACpC,MAAM,MAAM,GAAG,CAAC,MAAwB,EAAQ,EAAE;YAChD,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC7C,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACzB,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC7C,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACzB,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnB,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;QACF,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,GAAQ,EAAQ,EAAE;YACpD,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjC,MAAM,EAAE,CAAC;gBACT,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;gBACxD,MAAM,EAAE,CAAC;gBACT,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACxB,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;gBACvC,MAAM,EAAE,CAAC;gBACT,OAAO;YACT,CAAC;YACD,IAAI,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;gBACpC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACxB,IAAI,QAAQ,CAAC,IAAI,GAAG,gBAAgB;wBAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC/D,CAAC;;oBACI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACzB,MAAM,EAAE,CAAC;gBACT,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAClD,MAAM,CACJ,QAAQ;oBACN,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAC9E,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAC5B,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,CAAC;YACH,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC1B,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACvB,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,EAAE,CAAC;YACf,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACjC,MAAM,EAAE,CAAC;QACX,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,CAAC;YACT,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,OAA4C,EAC5C,KAAa,EACb,YAAmB,EACnB,QAA4B,OAAO,CAAC,KAA2B,EAC/D,SAA8B,OAAO,CAAC,MAAM;IAE5C,OAAO,yBAAyB,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC;SACnF,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,OAA4C,EAC5C,KAAa,EACb,gBAAkC,EAClC,QAA4B,OAAO,CAAC,KAA2B,EAC/D,SAA8B,OAAO,CAAC,MAAM,EAC5C,gBAAgB,GAAG,CAAC;IAEpB,OAAO,yBAAyB,CAC9B,OAAO,EACP,KAAK,EACL,gBAAgB,EAChB,IAAI,EACJ,KAAK,EACL,MAAM,EACN,gBAAgB,CACjB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAA4B,OAAO,CAAC,KAA2B,EAC/D,SAA8B,OAAO,CAAC,MAAM,EAC5C,mBAA2C,CAAC,OAAO,CAAC;IAEpD,OAAO,0BAA0B,CAC/B,oBAAoB,EACpB,8DAA8D,EAC9D,gBAAgB,EAChB,KAAK,EACL,MAAM,CACP,CAAC;AACJ,CAAC"}
@@ -1,5 +1,56 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
2
3
  import { writeDependencyGraph, } from '../scripts/dependency-graph.js';
4
+ import { styleDebt, styleImpact, styleMatrix, } from '../scripts/style-report.js';
5
+ const DEFAULT_STYLE_DUMP = 'tmp/craft-style-graph.json';
6
+ /**
7
+ * The style questions answer from the dump alone.
8
+ *
9
+ * They deliberately do **not** build the TypeScript program: the whole point of
10
+ * asking "what does this token change affect?" is to answer it in the time it
11
+ * takes to decide whether to run the visual suite. A question that costs a full
12
+ * typecheck gets asked once and then never again.
13
+ */
14
+ function runStyleQuery(argv) {
15
+ const impacted = [];
16
+ let dumpPath = DEFAULT_STYLE_DUMP;
17
+ let mode;
18
+ for (let index = 0; index < argv.length; index += 1) {
19
+ switch (argv[index]) {
20
+ case '--impacted':
21
+ mode = 'impacted';
22
+ impacted.push(argv[++index]);
23
+ break;
24
+ case '--style-matrix':
25
+ mode = 'matrix';
26
+ break;
27
+ case '--style-debt':
28
+ mode = 'debt';
29
+ break;
30
+ case '--style-dump':
31
+ dumpPath = argv[++index];
32
+ break;
33
+ default:
34
+ break;
35
+ }
36
+ }
37
+ if (!mode)
38
+ return false;
39
+ let dump;
40
+ try {
41
+ dump = JSON.parse(readFileSync(dumpPath, 'utf8'));
42
+ }
43
+ catch {
44
+ throw new Error(`craft-graph: no style dump at '${dumpPath}'. It is written by the build plugin — give craftStyle({ dumpPath }) a path, run a build, or point at it with --style-dump.`);
45
+ }
46
+ const report = mode === 'impacted'
47
+ ? styleImpact(dump, impacted)
48
+ : mode === 'matrix'
49
+ ? styleMatrix(dump)
50
+ : styleDebt(dump);
51
+ console.log(JSON.stringify(report, null, 2));
52
+ return true;
53
+ }
3
54
  function parseArgs(argv) {
4
55
  const options = {
5
56
  rootDir: process.cwd(),
@@ -34,6 +85,9 @@ function parseArgs(argv) {
34
85
  case '--include':
35
86
  options.include = [...(options.include ?? []), argv[++index]];
36
87
  break;
88
+ case '--style-dump':
89
+ index += 1;
90
+ break;
37
91
  case '--help':
38
92
  case '-h':
39
93
  printHelp();
@@ -59,14 +113,26 @@ Options:
59
113
  json/both/all also write a .architecture.ts catalog.
60
114
  html creates one self-contained visualizer file.
61
115
  --include <text> Restrict analysis to source paths containing text.
116
+
117
+ Style queries, answered from the emitted dump without building the program:
118
+ --impacted <--x> Sheet classes a change to that custom property
119
+ can be seen in. Repeatable. Falls back to "all"
120
+ — and says so — for a name the graph does not know.
121
+ --style-matrix What the application costs to capture.
122
+ --style-debt Escape hatches, unmet obligations, dangling
123
+ variables, and the components nobody styles.
124
+ --style-dump <path> Defaults to ${DEFAULT_STYLE_DUMP}.
62
125
  `);
63
126
  }
64
- writeDependencyGraph(parseArgs(process.argv.slice(2)))
65
- .then((graph) => {
66
- console.log(`Craft graph written: ${graph.nodes.length} nodes, ${graph.edges.length} edges.`);
67
- })
68
- .catch((error) => {
69
- console.error(error instanceof Error ? error.message : error);
70
- process.exitCode = 1;
71
- });
127
+ const argv = process.argv.slice(2);
128
+ if (!runStyleQuery(argv)) {
129
+ writeDependencyGraph(parseArgs(argv))
130
+ .then((graph) => {
131
+ console.log(`Craft graph written: ${graph.nodes.length} nodes, ${graph.edges.length} edges.`);
132
+ })
133
+ .catch((error) => {
134
+ console.error(error instanceof Error ? error.message : error);
135
+ process.exitCode = 1;
136
+ });
137
+ }
72
138
  //# sourceMappingURL=craft-graph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"craft-graph.js","sourceRoot":"","sources":["../../../../../libs/dev-tools/src/bin/craft-graph.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,oBAAoB,GAErB,MAAM,gCAAgC,CAAC;AAExC,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,OAAO,GAAgC;QAC3C,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;QACtB,UAAU,EAAE,wBAAwB;QACpC,MAAM,EAAE,MAAM;KACf,CAAC;IACF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,WAAW,CAAC;YACjB,KAAK,YAAY;gBACf,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACzC,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBAChC,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACnC,MAAM;YACR,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBAC7B,IACE,MAAM,KAAK,MAAM;oBACjB,MAAM,KAAK,SAAS;oBACpB,MAAM,KAAK,MAAM;oBACjB,MAAM,KAAK,MAAM;oBACjB,MAAM,KAAK,KAAK,EAChB,CAAC;oBACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBACzE,CAAC;gBACD,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,WAAW;gBACd,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC9D,MAAM;YACR,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,SAAS,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,MAAM;YACR;gBACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAab,CAAC,CAAC;AACH,CAAC;AAED,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;KACnD,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;IACd,OAAO,CAAC,GAAG,CACT,wBAAwB,KAAK,CAAC,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,KAAK,CAAC,MAAM,SAAS,CACjF,CAAC;AACJ,CAAC,CAAC;KACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"craft-graph.js","sourceRoot":"","sources":["../../../../../libs/dev-tools/src/bin/craft-graph.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,25 @@
1
1
  #!/usr/bin/env node
2
+ type CreateArgs = {
3
+ directory?: string;
4
+ effect?: string;
5
+ frontendRuntime?: 'plain' | 'effect';
6
+ backendRuntime?: 'none' | 'promise' | 'effect';
7
+ effectScope?: 'none' | 'frontend' | 'backend' | 'both';
8
+ agents?: string;
9
+ locales?: string;
10
+ defaultLocale?: string;
11
+ i18n?: 'strict' | 'loose' | 'none';
12
+ designSystem?: 'basic' | 'none';
13
+ typedCss?: boolean;
14
+ workspace?: 'standalone' | 'nx';
15
+ references?: 'none' | 'craft-ts' | 'all';
16
+ referenceMode?: 'context' | 'local' | 'source';
17
+ craftTsRef?: string;
18
+ effectTsRef?: string;
19
+ cloneCraftTs?: boolean;
20
+ cloneEffectTs?: boolean;
21
+ flags: Set<string>;
22
+ help: boolean;
23
+ };
24
+ export declare function parseCreateArgs(argv: string[]): CreateArgs;
2
25
  export {};