@typecad/cuttlefish 0.1.0-alpha.2 → 1.0.0-alpha.6

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 (54) hide show
  1. package/README.md +10 -10
  2. package/dist/api/board-types.d.ts +1 -1
  3. package/dist/api/shared/hal-op-ir.d.ts +10 -1
  4. package/dist/api/shared/platform-strategy.d.ts +6 -0
  5. package/dist/api/shared/types.d.ts +8 -0
  6. package/dist/cli-utils.d.ts +1 -0
  7. package/dist/cli-utils.js +3 -1
  8. package/dist/cli.js +75 -0
  9. package/dist/create/index.d.ts +1 -1
  10. package/dist/create/index.js +1 -1
  11. package/dist/create/init-scaffold.js +48 -2
  12. package/dist/create/init-templates.d.ts +2 -0
  13. package/dist/create/init-templates.js +189 -9
  14. package/dist/emit/emitters/setup.js +122 -1
  15. package/dist/ir/adc-range-validation.js +26 -25
  16. package/dist/ir/expression-to-ir.js +43 -6
  17. package/dist/ir/hal/hal-plugins.js +10 -0
  18. package/dist/ir/interrupt-analysis.js +8 -3
  19. package/dist/ir/memory-budget-validation.js +1 -0
  20. package/dist/ir/ownership-analysis.js +19 -0
  21. package/dist/ir/peripheral-ownership.js +5 -0
  22. package/dist/ir/peripheral-validation.d.ts +1 -1
  23. package/dist/ir/peripheral-validation.js +6 -3
  24. package/dist/ir/pin-alias-conflict.d.ts +1 -1
  25. package/dist/ir/pin-alias-conflict.js +2 -1
  26. package/dist/ir/pin-capability-validation.js +34 -32
  27. package/dist/ir/pin-mode-validation.js +5 -0
  28. package/dist/ir/pin-safety.d.ts +1 -1
  29. package/dist/ir/pin-safety.js +2 -1
  30. package/dist/ir/program-analysis.d.ts +16 -0
  31. package/dist/ir/program-analysis.js +113 -0
  32. package/dist/ir/pulldown-validation.d.ts +1 -1
  33. package/dist/ir/pulldown-validation.js +2 -1
  34. package/dist/ir/pwm-timer-sharing.d.ts +1 -1
  35. package/dist/ir/pwm-timer-sharing.js +2 -1
  36. package/dist/ir/resource-analysis.js +2 -0
  37. package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
  38. package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
  39. package/dist/ir/timing-validation.js +1 -0
  40. package/dist/ir/transformers/variables.js +46 -17
  41. package/dist/ir/try-catch-validation.js +2 -0
  42. package/dist/ir/type-resolution.js +2 -2
  43. package/dist/ir/unit-suspicion-validation.js +9 -7
  44. package/dist/ir/validation-orchestrator.js +6 -6
  45. package/dist/licenses.d.ts +185 -0
  46. package/dist/licenses.js +963 -0
  47. package/dist/testing.d.ts +1 -1
  48. package/dist/testing.js +1 -1
  49. package/dist/transpile.js +17 -9
  50. package/dist/types.d.ts +7 -1
  51. package/dist/utils/cli.js +44 -0
  52. package/package.json +5 -4
  53. package/dist/ir/heap-array-validation.d.ts +0 -24
  54. package/dist/ir/heap-array-validation.js +0 -29
package/dist/testing.d.ts CHANGED
@@ -15,7 +15,7 @@ export type { EmitMode, GeneratedOutputs, TargetProfile, PlatformContext } from
15
15
  export { findConfigFile, parseConfigFile, loadCuttlefishConfig, generateVirtualTypeDeclaration, } from "./config-loader.js";
16
16
  export { transpileFile } from "./transpile.js";
17
17
  export { resetUIEngine, __simulateUIAbsentForTest } from "./ui/ui-bridge.js";
18
- export { scaffoldProject, normalizeProjectName, KNOWN_BOARDS, generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateGitignore, generateEslintConfig, runInitWizard, } from "./create/index.js";
18
+ export { scaffoldProject, normalizeProjectName, KNOWN_BOARDS, generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateStarterTest, generateStarterSim, generateGitignore, generateEslintConfig, runInitWizard, } from "./create/index.js";
19
19
  export type { InitProjectOptions } from "./create/index.js";
20
20
  export { scaffoldBoardPackages, parseBoardSpec, safeParseBoardSpec, stripJsonc, } from "./create/index.js";
21
21
  export type { BoardSpec, ScaffoldBoardResult } from "./create/index.js";
package/dist/testing.js CHANGED
@@ -18,7 +18,7 @@ export { transpileFile } from "./transpile.js";
18
18
  // ── UI bridge (optional @typecad/ui) ─────────────────────────────────────────
19
19
  export { resetUIEngine, __simulateUIAbsentForTest } from "./ui/ui-bridge.js";
20
20
  // ── Project scaffolding ──────────────────────────────────────────────────────
21
- export { scaffoldProject, normalizeProjectName, KNOWN_BOARDS, generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateGitignore, generateEslintConfig, runInitWizard, } from "./create/index.js";
21
+ export { scaffoldProject, normalizeProjectName, KNOWN_BOARDS, generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateStarterTest, generateStarterSim, generateGitignore, generateEslintConfig, runInitWizard, } from "./create/index.js";
22
22
  // ── Board codegen (`cuttlefish board add`) ───────────────────────────────────
23
23
  export { scaffoldBoardPackages, parseBoardSpec, safeParseBoardSpec, stripJsonc, } from "./create/index.js";
24
24
  export { BoardGenerators } from "./create/index.js";
package/dist/transpile.js CHANGED
@@ -138,8 +138,9 @@ function formatFatalDiagnostics(entries) {
138
138
  `Transpilation aborted because ${errors.length} unsupported pattern${errors.length === 1 ? "" : "s"} were found.`,
139
139
  ];
140
140
  for (const { filePath, diagnostic } of errors) {
141
- const locationBase = filePath
142
- ? path.relative(process.cwd(), filePath) || filePath
141
+ const resolvedFile = filePath ?? diagnostic.filePath;
142
+ const locationBase = resolvedFile
143
+ ? path.relative(process.cwd(), resolvedFile) || resolvedFile
143
144
  : diagnostic.source ?? "user code";
144
145
  const position = diagnostic.line != null
145
146
  ? `(${diagnostic.line}:${diagnostic.column ?? 1})`
@@ -336,7 +337,7 @@ export async function transpileFile(options) {
336
337
  code: "themeCss-ui-entry-ignored",
337
338
  message: `display.themeCss is ignored for .ui single-file entries; the inline <style> in ${path.basename(options.inputFile)} is the sole CSS source.`,
338
339
  hint: `Move the standalone CSS into the .ui file's <style> block, or change the entry to a .ts file that imports a .ui.html module.`,
339
- source: path.basename(options.inputFile),
340
+ filePath: path.basename(options.inputFile),
340
341
  });
341
342
  }
342
343
  }
@@ -348,7 +349,7 @@ export async function transpileFile(options) {
348
349
  if (hasUIHook()) {
349
350
  for (const mod of requireUIHook().allUIModules()) {
350
351
  for (const d of mod.diagnostics) {
351
- diagnostics.push({ ...d, source: d.source ?? path.basename(mod.htmlPath) });
352
+ diagnostics.push({ ...d, filePath: d.filePath ?? path.basename(mod.htmlPath) });
352
353
  }
353
354
  }
354
355
  }
@@ -466,7 +467,7 @@ export async function transpileFile(options) {
466
467
  if (hasUIHook()) {
467
468
  for (const mod of requireUIHook().allUIModules()) {
468
469
  for (const d of mod.mountDiagnostics) {
469
- diagnostics.push({ ...d, source: d.source ?? path.basename(mod.htmlPath) });
470
+ diagnostics.push({ ...d, filePath: d.filePath ?? path.basename(mod.htmlPath) });
470
471
  }
471
472
  }
472
473
  }
@@ -689,6 +690,7 @@ export async function transpileFile(options) {
689
690
  profiler.endTimer("post:flatten");
690
691
  // Profiler session ends (profiling disabled - no report generation)
691
692
  // ── Generate diagnostics report if enabled ──────────────────────────────
693
+ let diagnosticsReportPath;
692
694
  if (options.diagnostics) {
693
695
  try {
694
696
  const entryPreBuilt = preBuilt.get(entryFile);
@@ -708,17 +710,23 @@ export async function transpileFile(options) {
708
710
  removedSymbols: allRemovedSymbols,
709
711
  });
710
712
  writeDiagnosticsReport(report, entryPreBuilt?.programIR ?? null, outDir);
713
+ diagnosticsReportPath = path.join(outDir, "diagnostics.md");
711
714
  }
712
715
  catch (e) {
713
- // Diagnostics report generation is best-effort; don't fail the build
714
- if (options.debug) {
715
- logDebug(`Diagnostics report generation failed: ${e instanceof Error ? e.message : String(e)}`, true);
716
- }
716
+ // Diagnostics report generation is best-effort; don't fail the build,
717
+ // but surface the failure so the user knows --diagnostics didn't work.
718
+ diagnostics.push({
719
+ severity: "warning",
720
+ message: `Diagnostics report generation failed: ${e instanceof Error ? e.message : String(e)}`,
721
+ code: "diagnostics-report-failed",
722
+ source: "transpile",
723
+ });
717
724
  }
718
725
  }
719
726
  return {
720
727
  ...entryOutputs,
721
728
  diagnostics,
729
+ diagnosticsReportPath,
722
730
  };
723
731
  }
724
732
  export function generateLibraryDefinitions(options) {
package/dist/types.d.ts CHANGED
@@ -114,7 +114,11 @@ export interface LibraryDefinition {
114
114
  variants?: LibraryDefinitionVariant[];
115
115
  }
116
116
  export interface CommandLineOptions {
117
- command: "default" | "build" | "gen-libdefs" | "gen-decls" | "map-error" | "preview";
117
+ command: "default" | "build" | "gen-libdefs" | "gen-decls" | "map-error" | "preview" | "doctor" | "licenses";
118
+ /** For `licenses`: treat unknown/missing licenses as failures (exit 1). */
119
+ strict?: boolean;
120
+ /** For `licenses`: scan all installed libraries (default: this project's only). */
121
+ all?: boolean;
118
122
  inputFile?: string;
119
123
  emitMode: EmitMode;
120
124
  target: TargetProfile;
@@ -181,6 +185,8 @@ export interface GeneratedOutputs {
181
185
  diagnostics: Diagnostic[];
182
186
  asyncTaskNames?: string[];
183
187
  usesTimers?: boolean;
188
+ /** Path to the diagnostics.md report, if --diagnostics was passed. */
189
+ diagnosticsReportPath?: string;
184
190
  }
185
191
  interface CompileErrorEntry {
186
192
  filePath: 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/cuttlefish",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "1.0.0-alpha.6",
4
4
  "description": "TypeScript to C++ transpiler — native, Arduino, and bare-metal targets",
5
5
  "type": "module",
6
6
  "main": "./dist/transpile.js",
@@ -80,10 +80,11 @@
80
80
  "dependencies": {
81
81
  "chalk": "^4.1.2",
82
82
  "typescript": "^5.7.3",
83
- "zod": "^3.24.0"
83
+ "zod": "^3.24.0",
84
+ "@typecad/arduino-cli": "1.0.0-alpha.6"
84
85
  },
85
86
  "peerDependencies": {
86
- "@typecad/ui": "0.1.0-alpha.2"
87
+ "@typecad/ui": "1.0.0-alpha.6"
87
88
  },
88
89
  "peerDependenciesMeta": {
89
90
  "@typecad/ui": {
@@ -91,7 +92,7 @@
91
92
  }
92
93
  },
93
94
  "optionalDependencies": {
94
- "@typecad/framework-native": "0.1.0-alpha.2"
95
+ "@typecad/framework-native": "1.0.0-alpha.6"
95
96
  },
96
97
  "devDependencies": {
97
98
  "@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
- }