@typecad/cuttlefish 1.0.0-alpha.3 → 1.0.0-alpha.7

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 (123) hide show
  1. package/README.md +4 -4
  2. package/dist/api/shared/display-adapter.d.ts +2 -1
  3. package/dist/api/shared/display-adapter.js +8 -1
  4. package/dist/api/shared/display-adapters/sdl.js +9 -2
  5. package/dist/api/shared/display-profile.d.ts +20 -3
  6. package/dist/api/shared/display-profile.js +21 -6
  7. package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
  8. package/dist/api/shared/framework-manifest-registry.js +25 -0
  9. package/dist/api/shared/framework-manifest.d.ts +462 -0
  10. package/dist/api/shared/framework-manifest.js +149 -0
  11. package/dist/api/shared/glcdfont.d.ts +12 -0
  12. package/dist/api/shared/glcdfont.js +124 -0
  13. package/dist/api/shared/graphics-strategy.d.ts +28 -0
  14. package/dist/api/shared/hal-op-ir.d.ts +427 -1
  15. package/dist/api/shared/hal-op-ir.js +95 -1
  16. package/dist/api/shared/index.d.ts +11 -1
  17. package/dist/api/shared/index.js +14 -0
  18. package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
  19. package/dist/api/shared/native-display-op-resolver.js +64 -0
  20. package/dist/api/shared/platform-strategy.d.ts +9 -0
  21. package/dist/api/shared/promise-runtime.js +78 -0
  22. package/dist/api/shared/types.d.ts +8 -0
  23. package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
  24. package/dist/api/shared/validate-framework-manifest.js +417 -0
  25. package/dist/cli-utils.d.ts +1 -0
  26. package/dist/cli-utils.js +3 -1
  27. package/dist/cli.js +175 -4
  28. package/dist/config-loader.js +20 -1
  29. package/dist/config-schema.d.ts +36 -36
  30. package/dist/create/board-spec.d.ts +4 -4
  31. package/dist/create/index.d.ts +1 -1
  32. package/dist/create/index.js +1 -1
  33. package/dist/create/init-scaffold.d.ts +3 -0
  34. package/dist/create/init-scaffold.js +74 -2
  35. package/dist/create/init-templates.d.ts +4 -0
  36. package/dist/create/init-templates.js +217 -17
  37. package/dist/create/init-wizard.js +20 -1
  38. package/dist/emit/cpp-emitter.js +4 -3
  39. package/dist/emit/emitters/emitter-context.d.ts +5 -0
  40. package/dist/emit/emitters/function-emitter-impl.js +69 -59
  41. package/dist/emit/emitters/output-finalizer.d.ts +6 -0
  42. package/dist/emit/emitters/output-finalizer.js +21 -11
  43. package/dist/emit/emitters/setup.js +155 -0
  44. package/dist/emit/emitters/top-level-prep.js +2 -0
  45. package/dist/emit/emitters/ui-emitter.js +23 -8
  46. package/dist/emit/expression-renderer.js +10 -1
  47. package/dist/emit/snprintf-helpers.js +8 -0
  48. package/dist/emit/statement-renderer.js +13 -0
  49. package/dist/emit/utils/async-state-machine.js +185 -116
  50. package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
  51. package/dist/emit/utils/hal-op-cpp-type.js +40 -0
  52. package/dist/ir/adc-range-validation.js +26 -25
  53. package/dist/ir/build-ir.js +5 -1
  54. package/dist/ir/expression-to-ir.js +57 -6
  55. package/dist/ir/feature-registry.js +7 -25
  56. package/dist/ir/hal/hal-emitter.d.ts +5 -2
  57. package/dist/ir/hal/hal-emitter.js +40 -12
  58. package/dist/ir/hal/hal-parser.d.ts +6 -0
  59. package/dist/ir/hal/hal-parser.js +74 -0
  60. package/dist/ir/hal/hal-plugins.js +571 -0
  61. package/dist/ir/identifier-collector.js +18 -0
  62. package/dist/ir/interrupt-analysis.js +8 -3
  63. package/dist/ir/memory-budget-validation.js +1 -0
  64. package/dist/ir/network-validation.d.ts +4 -0
  65. package/dist/ir/network-validation.js +184 -0
  66. package/dist/ir/ownership-analysis.js +33 -1
  67. package/dist/ir/peripheral-ownership.js +5 -0
  68. package/dist/ir/peripheral-validation.d.ts +1 -1
  69. package/dist/ir/peripheral-validation.js +6 -3
  70. package/dist/ir/pin-alias-conflict.d.ts +1 -1
  71. package/dist/ir/pin-alias-conflict.js +2 -1
  72. package/dist/ir/pin-capability-validation.js +34 -32
  73. package/dist/ir/pin-mode-validation.js +5 -0
  74. package/dist/ir/pin-safety.d.ts +1 -1
  75. package/dist/ir/pin-safety.js +2 -1
  76. package/dist/ir/program-analysis.d.ts +39 -0
  77. package/dist/ir/program-analysis.js +192 -0
  78. package/dist/ir/pulldown-validation.d.ts +1 -1
  79. package/dist/ir/pulldown-validation.js +2 -1
  80. package/dist/ir/pwm-timer-sharing.d.ts +1 -1
  81. package/dist/ir/pwm-timer-sharing.js +2 -1
  82. package/dist/ir/resource-analysis.js +2 -0
  83. package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
  84. package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
  85. package/dist/ir/timing-validation.d.ts +6 -1
  86. package/dist/ir/timing-validation.js +51 -12
  87. package/dist/ir/transformers/expressions.js +58 -0
  88. package/dist/ir/transformers/hal-emit-helpers.js +1 -1
  89. package/dist/ir/transformers/variables.js +86 -19
  90. package/dist/ir/try-catch-validation.js +2 -0
  91. package/dist/ir/type-resolution.js +2 -2
  92. package/dist/ir/unit-suspicion-validation.js +9 -7
  93. package/dist/ir/validation-orchestrator.js +9 -7
  94. package/dist/libdef/c-to-decl.d.ts +27 -0
  95. package/dist/libdef/c-to-decl.js +397 -0
  96. package/dist/libdef/component-decls.d.ts +2 -0
  97. package/dist/libdef/component-decls.js +6 -0
  98. package/dist/libdef/component-discovery.d.ts +43 -0
  99. package/dist/libdef/component-discovery.js +83 -0
  100. package/dist/libdef/cpp-to-decl.d.ts +9 -0
  101. package/dist/libdef/cpp-to-decl.js +72 -0
  102. package/dist/libdef/idf-discovery.d.ts +7 -0
  103. package/dist/libdef/idf-discovery.js +59 -0
  104. package/dist/libdef/registry.js +5 -2
  105. package/dist/licenses.d.ts +185 -0
  106. package/dist/licenses.js +963 -0
  107. package/dist/lint-cache.d.ts +59 -0
  108. package/dist/lint-cache.js +257 -0
  109. package/dist/orchestrator/graph-builder.js +6 -2
  110. package/dist/stores/display-profile-store.d.ts +1 -0
  111. package/dist/stores/display-profile-store.js +1 -0
  112. package/dist/testing.d.ts +4 -2
  113. package/dist/testing.js +4 -2
  114. package/dist/transpile.d.ts +3 -0
  115. package/dist/transpile.js +78 -32
  116. package/dist/types.d.ts +5 -1
  117. package/dist/ui-hook.d.ts +17 -1
  118. package/dist/utils/cli.js +71 -1
  119. package/dist/utils/fs.d.ts +13 -0
  120. package/dist/utils/fs.js +50 -0
  121. package/package.json +9 -4
  122. package/dist/ir/heap-array-validation.d.ts +0 -24
  123. package/dist/ir/heap-array-validation.js +0 -29
package/dist/ui-hook.d.ts CHANGED
@@ -58,7 +58,23 @@ export interface TranspilerUIHook {
58
58
  lowerOnMount(htmlPath: string, opts: LowerOptions): LoweredUI;
59
59
  resolveColor(input: string, format: "rgb565" | "rgb666" | "rgb888" | "mono"): number;
60
60
  resolveColorInternal(input: string, format: "rgb565" | "rgb666" | "rgb888" | "mono"): number;
61
- emitRuntimeHeader(): string;
61
+ /**
62
+ * Emits ONLY the CuttlefishGFX class definition (the shared GFX base for
63
+ * native display paths). Called separately from emitRuntimeHeader so the
64
+ * class can be emitted BEFORE display adapter declarations that
65
+ * instantiate CuttlefishGFX by value. Returns "" when active is false
66
+ * (Arduino path).
67
+ */
68
+ emitCuttlefishGfx(active: boolean): string;
69
+ /**
70
+ * Options controlling runtime-header emission.
71
+ * - nativeDisplayActive: when true, emit the shared CuttlefishGFX class
72
+ * (used by native display adapters on AVR/ESP32). Arduino paths pass
73
+ * false (default) and use Adafruit_GFX directly.
74
+ */
75
+ emitRuntimeHeader(opts?: {
76
+ nativeDisplayActive?: boolean;
77
+ }): string;
62
78
  splitUiFile(src: string): UiFileParts;
63
79
  generateProjectUITypeDeclarations(projectRoot: string): {
64
80
  written: string[];
package/dist/utils/cli.js CHANGED
@@ -17,6 +17,8 @@ export function printHelp() {
17
17
  console.log(` cuttlefish board add <spec.jsonc> [--force] Generate board + MCU packages from a chip spec`);
18
18
  console.log(` cuttlefish gen-decls <input.cpp|--all <directory>>`);
19
19
  console.log(` cuttlefish map-error <mapFile> [options]`);
20
+ console.log(` cuttlefish doctor Check that arduino-cli is installed and the board's core is present`);
21
+ console.log(` cuttlefish licenses [--all] [--strict] Scan this project's Arduino libraries for SPDX licenses (--all: every installed library)`);
20
22
  console.log();
21
23
  console.log(chalk.gray(`Transpilation is always performed first. Use --compile, --upload, and`));
22
24
  console.log(chalk.gray(`--monitor to chain operations after transpilation.`));
@@ -337,6 +339,48 @@ export function parseCommandLine(argv) {
337
339
  port: port ? String(port) : undefined,
338
340
  };
339
341
  }
342
+ // doctor subcommand — verify arduino-cli + board core presence
343
+ if (firstArg === "doctor") {
344
+ return {
345
+ command: "doctor",
346
+ // The remaining pipeline fields are unused by doctor; fill with safe
347
+ // defaults, the same way the preview branch does.
348
+ inputFile: undefined,
349
+ emitMode: "split",
350
+ target: "generic",
351
+ outDir: undefined,
352
+ emitMaps: true,
353
+ noTranspile: false,
354
+ compile: false,
355
+ upload: false,
356
+ monitor: false,
357
+ watch: false,
358
+ baud: 9600,
359
+ platformContext: {},
360
+ };
361
+ }
362
+ // licenses subcommand — scan installed Arduino libraries for SPDX licenses
363
+ if (firstArg === "licenses") {
364
+ return {
365
+ command: "licenses",
366
+ strict: argv.includes("--strict"),
367
+ all: argv.includes("--all"),
368
+ // The remaining pipeline fields are unused by licenses; fill with safe
369
+ // defaults, the same way the doctor branch does.
370
+ inputFile: undefined,
371
+ emitMode: "split",
372
+ target: "generic",
373
+ outDir: undefined,
374
+ emitMaps: true,
375
+ noTranspile: false,
376
+ compile: false,
377
+ upload: false,
378
+ monitor: false,
379
+ watch: false,
380
+ baud: 9600,
381
+ platformContext: {},
382
+ };
383
+ }
340
384
  // Named subcommands
341
385
  if (firstArg === "gen-libdefs" || firstArg === "gen-decls" || firstArg === "map-error") {
342
386
  const command = firstArg;
@@ -387,12 +431,16 @@ export function parseCommandLine(argv) {
387
431
  // gen-decls - generate .d.ts from C++ files
388
432
  if (command === "gen-decls") {
389
433
  const allFlag = argv.includes("--all");
434
+ const componentsFlag = argv.includes("--components");
435
+ if (allFlag && componentsFlag) {
436
+ throw new Error("gen-decls: --components and --all are mutually exclusive. Use one or the other.");
437
+ }
390
438
  // The positional path may sit at argv[3] or argv[4] depending on whether
391
439
  // --all precedes or follows it. Scan argv starting after the subcommand
392
440
  // name (argv[2]) for the first token that is not a flag and not a known
393
441
  // flag's value. This mirrors the default-pipeline approach of "first
394
442
  // non-flag token wins".
395
- const booleanFlags = new Set(["--all"]);
443
+ const booleanFlags = new Set(["--all", "--components"]);
396
444
  const valueFlags = new Set([
397
445
  "--emit", "--target", "--outDir", "--out-dir", "--emit-maps", "--build-target",
398
446
  ]);
@@ -413,6 +461,28 @@ export function parseCommandLine(argv) {
413
461
  inputPath = tok;
414
462
  break;
415
463
  }
464
+ // --components mode: scan managed_components/ + components/ declared in
465
+ // cuttlefish.config.ts. Falls back to cwd when no path is given.
466
+ if (componentsFlag) {
467
+ const componentsDir = inputPath || process.cwd();
468
+ return {
469
+ command: "gen-decls",
470
+ inputFile: undefined,
471
+ emitMode,
472
+ target,
473
+ outDir: outDir ? path.resolve(process.cwd(), outDir) : undefined,
474
+ emitMaps,
475
+ noTranspile: false,
476
+ compile: false,
477
+ upload: false,
478
+ monitor: false,
479
+ watch: false,
480
+ baud: 9600,
481
+ platformContext,
482
+ scanDir: undefined,
483
+ componentsDir: path.resolve(process.cwd(), componentsDir),
484
+ };
485
+ }
416
486
  if (!inputPath && !allFlag) {
417
487
  throw new Error("Missing input C++ file path. Use: gen-decls <file.cpp> or gen-decls --all <directory>");
418
488
  }
@@ -2,3 +2,16 @@ export declare function ensureDir(dirPath: string): void;
2
2
  export declare function readText(filePath: string): string;
3
3
  export declare function writeText(filePath: string, content: string): void;
4
4
  export declare function listFiles(dirPath: string, extension: string): string[];
5
+ /**
6
+ * Recursive variant of {@link listFiles}. Walks `dirPath` depth-first and
7
+ * returns every file (in every subdirectory) whose name ends with `extension`.
8
+ *
9
+ * Used by {@link loadLibraryDefinitions} so libdefs under nested cache dirs
10
+ * like `.cuttlefish/component-decls/<component>/` are discovered. Purely
11
+ * additive vs. the non-recursive `listFiles` — single-level layouts keep
12
+ * working, nested layouts now also work.
13
+ *
14
+ * Returns absolute paths. Unreadable directories are silently skipped
15
+ * (matches `listFiles`'s not-exist behavior for non-existent roots).
16
+ */
17
+ export declare function listFilesRecursive(dirPath: string, extension: string): string[];
package/dist/utils/fs.js CHANGED
@@ -10,6 +10,15 @@ export function readText(filePath) {
10
10
  }
11
11
  export function writeText(filePath, content) {
12
12
  ensureDir(path.dirname(filePath));
13
+ // Skip writing when content is identical — preserves mtime so downstream
14
+ // build tools (idf.py/ninja, arduino-cli, make) can skip recompilation.
15
+ try {
16
+ if (fs.readFileSync(filePath, "utf8") === content)
17
+ return;
18
+ }
19
+ catch {
20
+ // File doesn't exist yet — fall through to write.
21
+ }
13
22
  fs.writeFileSync(filePath, content, "utf8");
14
23
  }
15
24
  export function listFiles(dirPath, extension) {
@@ -21,3 +30,44 @@ export function listFiles(dirPath, extension) {
21
30
  .filter((name) => name.toLowerCase().endsWith(extension.toLowerCase()))
22
31
  .map((name) => path.join(dirPath, name));
23
32
  }
33
+ /**
34
+ * Recursive variant of {@link listFiles}. Walks `dirPath` depth-first and
35
+ * returns every file (in every subdirectory) whose name ends with `extension`.
36
+ *
37
+ * Used by {@link loadLibraryDefinitions} so libdefs under nested cache dirs
38
+ * like `.cuttlefish/component-decls/<component>/` are discovered. Purely
39
+ * additive vs. the non-recursive `listFiles` — single-level layouts keep
40
+ * working, nested layouts now also work.
41
+ *
42
+ * Returns absolute paths. Unreadable directories are silently skipped
43
+ * (matches `listFiles`'s not-exist behavior for non-existent roots).
44
+ */
45
+ export function listFilesRecursive(dirPath, extension) {
46
+ if (!fs.existsSync(dirPath)) {
47
+ return [];
48
+ }
49
+ const ext = extension.toLowerCase();
50
+ const out = [];
51
+ const stack = [dirPath];
52
+ while (stack.length > 0) {
53
+ const cur = stack.pop();
54
+ let entries;
55
+ try {
56
+ entries = fs.readdirSync(cur, { withFileTypes: true });
57
+ }
58
+ catch {
59
+ // Permission error / race / etc. Skip this subtree.
60
+ continue;
61
+ }
62
+ for (const entry of entries) {
63
+ const full = path.join(cur, entry.name);
64
+ if (entry.isDirectory()) {
65
+ stack.push(full);
66
+ }
67
+ else if (entry.isFile() && entry.name.toLowerCase().endsWith(ext)) {
68
+ out.push(full);
69
+ }
70
+ }
71
+ }
72
+ return out;
73
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/cuttlefish",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.7",
4
4
  "description": "TypeScript to C++ transpiler — native, Arduino, and bare-metal targets",
5
5
  "type": "module",
6
6
  "main": "./dist/transpile.js",
@@ -49,6 +49,10 @@
49
49
  "types": "./dist/emit/route-hal-op.d.ts",
50
50
  "default": "./dist/emit/route-hal-op.js"
51
51
  },
52
+ "./lib/component-decls": {
53
+ "types": "./dist/libdef/component-decls.d.ts",
54
+ "default": "./dist/libdef/component-decls.js"
55
+ },
52
56
  "./ir/transformers/ui-lowering": {
53
57
  "types": "./dist/ir/transformers/ui-lowering.d.ts",
54
58
  "default": "./dist/ir/transformers/ui-lowering.js"
@@ -80,10 +84,11 @@
80
84
  "dependencies": {
81
85
  "chalk": "^4.1.2",
82
86
  "typescript": "^5.7.3",
83
- "zod": "^3.24.0"
87
+ "zod": "^3.24.0",
88
+ "@typecad/arduino-cli": "1.0.0-alpha.7"
84
89
  },
85
90
  "peerDependencies": {
86
- "@typecad/ui": "1.0.0-alpha.3"
91
+ "@typecad/ui": "1.0.0-alpha.7"
87
92
  },
88
93
  "peerDependenciesMeta": {
89
94
  "@typecad/ui": {
@@ -91,7 +96,7 @@
91
96
  }
92
97
  },
93
98
  "optionalDependencies": {
94
- "@typecad/framework-native": "1.0.0-alpha.3"
99
+ "@typecad/framework-native": "1.0.0-alpha.7"
95
100
  },
96
101
  "devDependencies": {
97
102
  "@types/node": "^22.10.7"
@@ -1,24 +0,0 @@
1
- import type { Diagnostic } from '../types.js';
2
- import type { BoardConstants } from './board-resolver.js';
3
- import type { StatementIR } from '../api/index.js';
4
- import type { PlatformStrategy } from '../api/shared/index.js';
5
- /**
6
- * @deprecated Heap allocation is now validated at emit time by the platform
7
- * strategy's `profileDiagnostics` (see framework-arduino `collectHeapAllocationDiagnostics`).
8
- * This build-time stub returns no diagnostics. Kept to preserve the
9
- * `validation-orchestrator.ts` import; remove that call site when convenient.
10
- */
11
- export declare function validateHeapArrayUsage(_program: {
12
- topLevelStatements: StatementIR[];
13
- functions: Array<{
14
- statements: StatementIR[];
15
- }>;
16
- classes: Array<{
17
- methods: Array<{
18
- statements: StatementIR[];
19
- }>;
20
- constructor?: {
21
- statements: StatementIR[];
22
- };
23
- }>;
24
- }, _boardConstants: BoardConstants | undefined, _strategy?: PlatformStrategy): Diagnostic[];
@@ -1,29 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Heap Allocation Validator (retired — moved to the emit-time profile gate)
3
- //
4
- // Heap allocation via `new` on no-heap architectures (AVR, etc.) is now
5
- // rejected by the Arduino strategy's `profileDiagnostics`
6
- // (`framework-arduino/src/strategy.ts` `collectHeapAllocationDiagnostics`).
7
- //
8
- // WHY THE MOVE: this build-time validator keyed off `boardConstants.architecture`,
9
- // which is only populated when an MCU/board `import` is present. Programs with
10
- // no such import silently bypassed it — so demo #33's `new Accumulator()`
11
- // passed while a HAL-importing demo's `new Blinker()` failed, for the same
12
- // source pattern. The profile-time gate derives `arch` from the FQBN
13
- // (`frameworkData.buildTarget`), so it fires regardless of import structure
14
- // (demo #34 Finding A). It also keys off the `newClassName` marker a user-class
15
- // `new` tags its raw IR node with (set in `expression-to-ir.ts`), making
16
- // detection structural rather than textual.
17
- //
18
- // The export is kept (returns `[]`) so `validation-orchestrator.ts`'s import
19
- // stays valid; the real work happens at emit time.
20
- // ---------------------------------------------------------------------------
21
- /**
22
- * @deprecated Heap allocation is now validated at emit time by the platform
23
- * strategy's `profileDiagnostics` (see framework-arduino `collectHeapAllocationDiagnostics`).
24
- * This build-time stub returns no diagnostics. Kept to preserve the
25
- * `validation-orchestrator.ts` import; remove that call site when convenient.
26
- */
27
- export function validateHeapArrayUsage(_program, _boardConstants, _strategy) {
28
- return [];
29
- }