@typecad/cuttlefish 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/api/board-types.d.ts +1 -0
- package/dist/api/board-types.js +4 -0
- package/dist/api/capabilities.d.ts +12 -0
- package/dist/api/capabilities.js +1 -0
- package/dist/api/config.d.ts +120 -0
- package/dist/api/config.js +7 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.js +2 -0
- package/dist/api/schema/builder.d.ts +14 -0
- package/dist/api/schema/builder.js +15 -0
- package/dist/api/schema/index.d.ts +2 -0
- package/dist/api/schema/index.js +1 -0
- package/dist/api/schema/types.d.ts +257 -0
- package/dist/api/schema/types.js +4 -0
- package/dist/api/shared/async-runtime-static.d.ts +8 -0
- package/dist/api/shared/async-runtime-static.js +201 -0
- package/dist/api/shared/async-types.d.ts +42 -0
- package/dist/api/shared/async-types.js +8 -0
- package/dist/api/shared/board-resolver.d.ts +12 -0
- package/dist/api/shared/board-resolver.js +7 -0
- package/dist/api/shared/cpp-type-ir.d.ts +229 -0
- package/dist/api/shared/cpp-type-ir.js +672 -0
- package/dist/api/shared/display-adapter.d.ts +12 -0
- package/dist/api/shared/display-adapter.js +145 -0
- package/dist/api/shared/display-adapters/eink-mono.d.ts +2 -0
- package/dist/api/shared/display-adapters/eink-mono.js +53 -0
- package/dist/api/shared/display-adapters/sdl.d.ts +2 -0
- package/dist/api/shared/display-adapters/sdl.js +452 -0
- package/dist/api/shared/display-adapters/ssd1309.d.ts +2 -0
- package/dist/api/shared/display-adapters/ssd1309.js +136 -0
- package/dist/api/shared/display-adapters/st7796.d.ts +2 -0
- package/dist/api/shared/display-adapters/st7796.js +132 -0
- package/dist/api/shared/display-capabilities.d.ts +45 -0
- package/dist/api/shared/display-capabilities.js +54 -0
- package/dist/api/shared/display-op-ir.d.ts +62 -0
- package/dist/api/shared/display-op-ir.js +19 -0
- package/dist/api/shared/display-profile.d.ts +265 -0
- package/dist/api/shared/display-profile.js +338 -0
- package/dist/api/shared/graphics-strategy.d.ts +29 -0
- package/dist/api/shared/graphics-strategy.js +11 -0
- package/dist/api/shared/hal-op-ir.d.ts +393 -0
- package/dist/api/shared/hal-op-ir.js +18 -0
- package/dist/api/shared/index.d.ts +26 -0
- package/dist/api/shared/index.js +21 -0
- package/dist/api/shared/ir-core.d.ts +363 -0
- package/dist/api/shared/ir-core.js +8 -0
- package/dist/api/shared/ir-declarations.d.ts +201 -0
- package/dist/api/shared/ir-declarations.js +26 -0
- package/dist/api/shared/ir.d.ts +85 -0
- package/dist/api/shared/ir.js +13 -0
- package/dist/api/shared/platform-strategy.d.ts +402 -0
- package/dist/api/shared/platform-strategy.js +14 -0
- package/dist/api/shared/polyfill-helper-registry.d.ts +11 -0
- package/dist/api/shared/polyfill-helper-registry.js +86 -0
- package/dist/api/shared/polyfill-types.d.ts +33 -0
- package/dist/api/shared/polyfill-types.js +76 -0
- package/dist/api/shared/promise-runtime.d.ts +10 -0
- package/dist/api/shared/promise-runtime.js +244 -0
- package/dist/api/shared/snprintf-types.d.ts +29 -0
- package/dist/api/shared/snprintf-types.js +8 -0
- package/dist/api/shared/string-method-registry.d.ts +53 -0
- package/dist/api/shared/string-method-registry.js +168 -0
- package/dist/api/shared/toolchain-types.d.ts +63 -0
- package/dist/api/shared/toolchain-types.js +71 -0
- package/dist/api/shared/types.d.ts +50 -0
- package/dist/api/shared/types.js +6 -0
- package/dist/ast/parse.d.ts +2 -0
- package/dist/ast/parse.js +4 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.js +95 -0
- package/dist/cli-utils.d.ts +37 -0
- package/dist/cli-utils.js +250 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +635 -0
- package/dist/config-loader.d.ts +78 -0
- package/dist/config-loader.js +508 -0
- package/dist/config-schema.d.ts +233 -0
- package/dist/config-schema.js +83 -0
- package/dist/create/board-checklist.d.ts +2 -0
- package/dist/create/board-checklist.js +52 -0
- package/dist/create/board-codegen.d.ts +9 -0
- package/dist/create/board-codegen.js +238 -0
- package/dist/create/board-generators.d.ts +12 -0
- package/dist/create/board-generators.js +652 -0
- package/dist/create/board-spec.d.ts +640 -0
- package/dist/create/board-spec.js +215 -0
- package/dist/create/eslint-rules-template.d.ts +2 -0
- package/dist/create/eslint-rules-template.js +672 -0
- package/dist/create/index.d.ts +11 -0
- package/dist/create/index.js +8 -0
- package/dist/create/init-scaffold.d.ts +27 -0
- package/dist/create/init-scaffold.js +150 -0
- package/dist/create/init-templates.d.ts +24 -0
- package/dist/create/init-templates.js +379 -0
- package/dist/create/init-wizard.d.ts +8 -0
- package/dist/create/init-wizard.js +168 -0
- package/dist/debug/breakpoint-loader.d.ts +24 -0
- package/dist/debug/breakpoint-loader.js +137 -0
- package/dist/debug/index.d.ts +3 -0
- package/dist/debug/index.js +7 -0
- package/dist/debug/preprocessor.d.ts +9 -0
- package/dist/debug/preprocessor.js +214 -0
- package/dist/debug/types.d.ts +32 -0
- package/dist/debug/types.js +6 -0
- package/dist/diagnostics/diagnostics-report.d.ts +51 -0
- package/dist/diagnostics/diagnostics-report.js +333 -0
- package/dist/diagnostics/json-schema.d.ts +138 -0
- package/dist/diagnostics/json-schema.js +27 -0
- package/dist/diagnostics/md-writer.d.ts +10 -0
- package/dist/diagnostics/md-writer.js +336 -0
- package/dist/diagnostics/mermaid-builder.d.ts +65 -0
- package/dist/diagnostics/mermaid-builder.js +681 -0
- package/dist/emit/cpp-emitter.d.ts +6 -0
- package/dist/emit/cpp-emitter.js +48 -0
- package/dist/emit/emitters/class-emitter.d.ts +2 -0
- package/dist/emit/emitters/class-emitter.js +523 -0
- package/dist/emit/emitters/emitter-context.d.ts +174 -0
- package/dist/emit/emitters/emitter-context.js +1 -0
- package/dist/emit/emitters/entrypoint-synthesizer.d.ts +2 -0
- package/dist/emit/emitters/entrypoint-synthesizer.js +175 -0
- package/dist/emit/emitters/function-emitter-impl.d.ts +19 -0
- package/dist/emit/emitters/function-emitter-impl.js +428 -0
- package/dist/emit/emitters/line-appender.d.ts +15 -0
- package/dist/emit/emitters/line-appender.js +344 -0
- package/dist/emit/emitters/namespace-emitter.d.ts +2 -0
- package/dist/emit/emitters/namespace-emitter.js +324 -0
- package/dist/emit/emitters/output-finalizer.d.ts +4 -0
- package/dist/emit/emitters/output-finalizer.js +267 -0
- package/dist/emit/emitters/setup.d.ts +3 -0
- package/dist/emit/emitters/setup.js +851 -0
- package/dist/emit/emitters/top-level-prep.d.ts +2 -0
- package/dist/emit/emitters/top-level-prep.js +706 -0
- package/dist/emit/emitters/type-decl-emitter.d.ts +2 -0
- package/dist/emit/emitters/type-decl-emitter.js +251 -0
- package/dist/emit/emitters/ui-emitter.d.ts +21 -0
- package/dist/emit/emitters/ui-emitter.js +564 -0
- package/dist/emit/enum-emitter.d.ts +1 -0
- package/dist/emit/enum-emitter.js +1 -0
- package/dist/emit/expression-renderer.d.ts +283 -0
- package/dist/emit/expression-renderer.js +1477 -0
- package/dist/emit/native-helpers-emitter.d.ts +11 -0
- package/dist/emit/native-helpers-emitter.js +34 -0
- package/dist/emit/route-hal-op.d.ts +5 -0
- package/dist/emit/route-hal-op.js +13 -0
- package/dist/emit/snprintf-helpers.d.ts +17 -0
- package/dist/emit/snprintf-helpers.js +462 -0
- package/dist/emit/statement-renderer.d.ts +189 -0
- package/dist/emit/statement-renderer.js +948 -0
- package/dist/emit/utils/async-state-machine.d.ts +42 -0
- package/dist/emit/utils/async-state-machine.js +343 -0
- package/dist/emit/utils/comment-helpers.d.ts +20 -0
- package/dist/emit/utils/comment-helpers.js +31 -0
- package/dist/emit/utils/cpp-helpers.d.ts +47 -0
- package/dist/emit/utils/cpp-helpers.js +85 -0
- package/dist/emit/utils/include-resolver.d.ts +58 -0
- package/dist/emit/utils/include-resolver.js +155 -0
- package/dist/emit/utils/index.d.ts +8 -0
- package/dist/emit/utils/index.js +12 -0
- package/dist/emit/utils/type-inference.d.ts +159 -0
- package/dist/emit/utils/type-inference.js +559 -0
- package/dist/eslint-check.d.ts +10 -0
- package/dist/eslint-check.js +102 -0
- package/dist/framework-package.d.ts +10 -0
- package/dist/framework-package.js +58 -0
- package/dist/framework-registry.d.ts +39 -0
- package/dist/framework-registry.js +30 -0
- package/dist/incremental-cache.d.ts +116 -0
- package/dist/incremental-cache.js +335 -0
- package/dist/ir/adc-range-validation.d.ts +11 -0
- package/dist/ir/adc-range-validation.js +250 -0
- package/dist/ir/ast-node-utils.d.ts +8 -0
- package/dist/ir/ast-node-utils.js +32 -0
- package/dist/ir/board-pin-utils.d.ts +13 -0
- package/dist/ir/board-pin-utils.js +65 -0
- package/dist/ir/board-resolver.d.ts +36 -0
- package/dist/ir/board-resolver.js +437 -0
- package/dist/ir/build-ir-state.d.ts +167 -0
- package/dist/ir/build-ir-state.js +306 -0
- package/dist/ir/build-ir.d.ts +2 -0
- package/dist/ir/build-ir.js +808 -0
- package/dist/ir/call-graph.d.ts +35 -0
- package/dist/ir/call-graph.js +194 -0
- package/dist/ir/compile-time-only.d.ts +2 -0
- package/dist/ir/compile-time-only.js +16 -0
- package/dist/ir/declaration-builders.d.ts +9 -0
- package/dist/ir/declaration-builders.js +608 -0
- package/dist/ir/entry-points.d.ts +30 -0
- package/dist/ir/entry-points.js +191 -0
- package/dist/ir/expression-to-ir.d.ts +5 -0
- package/dist/ir/expression-to-ir.js +2249 -0
- package/dist/ir/extract-property-chain.d.ts +10 -0
- package/dist/ir/extract-property-chain.js +30 -0
- package/dist/ir/feature-prescan.d.ts +3 -0
- package/dist/ir/feature-prescan.js +43 -0
- package/dist/ir/feature-registry.d.ts +30 -0
- package/dist/ir/feature-registry.js +816 -0
- package/dist/ir/filter.d.ts +7 -0
- package/dist/ir/filter.js +85 -0
- package/dist/ir/function-builder.d.ts +19 -0
- package/dist/ir/function-builder.js +670 -0
- package/dist/ir/hal/hal-emitter.d.ts +62 -0
- package/dist/ir/hal/hal-emitter.js +735 -0
- package/dist/ir/hal/hal-parser.d.ts +61 -0
- package/dist/ir/hal/hal-parser.js +473 -0
- package/dist/ir/hal/hal-plugins.d.ts +34 -0
- package/dist/ir/hal/hal-plugins.js +706 -0
- package/dist/ir/hal-resolver.d.ts +5 -0
- package/dist/ir/hal-resolver.js +5 -0
- package/dist/ir/heap-analysis.d.ts +8 -0
- package/dist/ir/heap-analysis.js +350 -0
- package/dist/ir/heap-array-validation.d.ts +24 -0
- package/dist/ir/heap-array-validation.js +29 -0
- package/dist/ir/identifier-collector.d.ts +18 -0
- package/dist/ir/identifier-collector.js +439 -0
- package/dist/ir/interrupt-analysis.d.ts +39 -0
- package/dist/ir/interrupt-analysis.js +467 -0
- package/dist/ir/memory-budget-validation.d.ts +10 -0
- package/dist/ir/memory-budget-validation.js +86 -0
- package/dist/ir/namespace-builder.d.ts +7 -0
- package/dist/ir/namespace-builder.js +152 -0
- package/dist/ir/ownership-analysis.d.ts +9 -0
- package/dist/ir/ownership-analysis.js +1207 -0
- package/dist/ir/peripheral-ownership.d.ts +3 -0
- package/dist/ir/peripheral-ownership.js +152 -0
- package/dist/ir/peripheral-symbols.d.ts +7 -0
- package/dist/ir/peripheral-symbols.js +57 -0
- package/dist/ir/peripheral-usage.d.ts +54 -0
- package/dist/ir/peripheral-usage.js +691 -0
- package/dist/ir/peripheral-validation.d.ts +8 -0
- package/dist/ir/peripheral-validation.js +77 -0
- package/dist/ir/pin-alias-conflict.d.ts +4 -0
- package/dist/ir/pin-alias-conflict.js +34 -0
- package/dist/ir/pin-capability-validation.d.ts +6 -0
- package/dist/ir/pin-capability-validation.js +413 -0
- package/dist/ir/pin-mode-validation.d.ts +10 -0
- package/dist/ir/pin-mode-validation.js +301 -0
- package/dist/ir/pin-safety.d.ts +11 -0
- package/dist/ir/pin-safety.js +58 -0
- package/dist/ir/program-analysis.d.ts +44 -0
- package/dist/ir/program-analysis.js +589 -0
- package/dist/ir/pulldown-validation.d.ts +7 -0
- package/dist/ir/pulldown-validation.js +49 -0
- package/dist/ir/pwm-timer-sharing.d.ts +4 -0
- package/dist/ir/pwm-timer-sharing.js +93 -0
- package/dist/ir/reachability.d.ts +68 -0
- package/dist/ir/reachability.js +224 -0
- package/dist/ir/register-decorators.d.ts +6 -0
- package/dist/ir/register-decorators.js +49 -0
- package/dist/ir/render-expr.d.ts +4 -0
- package/dist/ir/render-expr.js +127 -0
- package/dist/ir/resource-analysis.d.ts +19 -0
- package/dist/ir/resource-analysis.js +153 -0
- package/dist/ir/statement-to-ir.d.ts +23 -0
- package/dist/ir/statement-to-ir.js +349 -0
- package/dist/ir/symbol-table.d.ts +68 -0
- package/dist/ir/symbol-table.js +179 -0
- package/dist/ir/symbol-types.d.ts +56 -0
- package/dist/ir/symbol-types.js +107 -0
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +4 -0
- package/dist/ir/timer0-pwm-timing-conflict.js +71 -0
- package/dist/ir/timing-validation.d.ts +7 -0
- package/dist/ir/timing-validation.js +95 -0
- package/dist/ir/transformers/array-methods.d.ts +8 -0
- package/dist/ir/transformers/array-methods.js +493 -0
- package/dist/ir/transformers/call-statement.d.ts +5 -0
- package/dist/ir/transformers/call-statement.js +758 -0
- package/dist/ir/transformers/callback-context-registry.d.ts +20 -0
- package/dist/ir/transformers/callback-context-registry.js +55 -0
- package/dist/ir/transformers/canvas-lowering.d.ts +42 -0
- package/dist/ir/transformers/canvas-lowering.js +249 -0
- package/dist/ir/transformers/control-flow.d.ts +8 -0
- package/dist/ir/transformers/control-flow.js +508 -0
- package/dist/ir/transformers/expressions.d.ts +7 -0
- package/dist/ir/transformers/expressions.js +406 -0
- package/dist/ir/transformers/hal-call-resolver.d.ts +29 -0
- package/dist/ir/transformers/hal-call-resolver.js +274 -0
- package/dist/ir/transformers/hal-emit-helpers.d.ts +14 -0
- package/dist/ir/transformers/hal-emit-helpers.js +63 -0
- package/dist/ir/transformers/namespace-methods.d.ts +20 -0
- package/dist/ir/transformers/namespace-methods.js +110 -0
- package/dist/ir/transformers/register-assignment.d.ts +5 -0
- package/dist/ir/transformers/register-assignment.js +56 -0
- package/dist/ir/transformers/ui-call-resolver.d.ts +149 -0
- package/dist/ir/transformers/ui-call-resolver.js +1136 -0
- package/dist/ir/transformers/ui-callback-lowering.d.ts +62 -0
- package/dist/ir/transformers/ui-callback-lowering.js +623 -0
- package/dist/ir/transformers/ui-mount.d.ts +20 -0
- package/dist/ir/transformers/ui-mount.js +35 -0
- package/dist/ir/transformers/ui-reactive.d.ts +68 -0
- package/dist/ir/transformers/ui-reactive.js +129 -0
- package/dist/ir/transformers/variables.d.ts +14 -0
- package/dist/ir/transformers/variables.js +1045 -0
- package/dist/ir/try-catch-validation.d.ts +26 -0
- package/dist/ir/try-catch-validation.js +128 -0
- package/dist/ir/type-resolution.d.ts +31 -0
- package/dist/ir/type-resolution.js +977 -0
- package/dist/ir/ui-element-auto-wire.d.ts +50 -0
- package/dist/ir/ui-element-auto-wire.js +218 -0
- package/dist/ir/unit-suspicion-validation.d.ts +12 -0
- package/dist/ir/unit-suspicion-validation.js +296 -0
- package/dist/ir/utils/walk-ir.d.ts +6 -0
- package/dist/ir/utils/walk-ir.js +162 -0
- package/dist/ir/validation-orchestrator.d.ts +4 -0
- package/dist/ir/validation-orchestrator.js +45 -0
- package/dist/libdef/base-class-resolver.d.ts +23 -0
- package/dist/libdef/base-class-resolver.js +50 -0
- package/dist/libdef/cpp-to-decl.d.ts +34 -0
- package/dist/libdef/cpp-to-decl.js +584 -0
- package/dist/libdef/header-parser.d.ts +53 -0
- package/dist/libdef/header-parser.js +269 -0
- package/dist/libdef/registry.d.ts +10 -0
- package/dist/libdef/registry.js +142 -0
- package/dist/mapping/peripheral-names.d.ts +23 -0
- package/dist/mapping/peripheral-names.js +63 -0
- package/dist/mapping/source-map.d.ts +46 -0
- package/dist/mapping/source-map.js +207 -0
- package/dist/orchestrator/dts-generator.d.ts +17 -0
- package/dist/orchestrator/dts-generator.js +83 -0
- package/dist/orchestrator/graph-builder.d.ts +18 -0
- package/dist/orchestrator/graph-builder.js +218 -0
- package/dist/orchestrator/semantic-facts-verifier.d.ts +38 -0
- package/dist/orchestrator/semantic-facts-verifier.js +121 -0
- package/dist/orchestrator/semantic-facts.d.ts +141 -0
- package/dist/orchestrator/semantic-facts.js +652 -0
- package/dist/orchestrator/type-checker.d.ts +39 -0
- package/dist/orchestrator/type-checker.js +760 -0
- package/dist/platform/async-runtime.d.ts +8 -0
- package/dist/platform/async-runtime.js +26 -0
- package/dist/platform/generic-strategy.d.ts +101 -0
- package/dist/platform/generic-strategy.js +289 -0
- package/dist/platform/index.d.ts +4 -0
- package/dist/platform/index.js +9 -0
- package/dist/platform/registry.d.ts +21 -0
- package/dist/platform/registry.js +42 -0
- package/dist/platform/toolchain.d.ts +4 -0
- package/dist/platform/toolchain.js +43 -0
- package/dist/preview/client.d.ts +1 -0
- package/dist/preview/client.js +137 -0
- package/dist/preview/server.d.ts +5 -0
- package/dist/preview/server.js +199 -0
- package/dist/profiler/index.d.ts +28 -0
- package/dist/profiler/index.js +28 -0
- package/dist/profiler/profiler.d.ts +95 -0
- package/dist/profiler/profiler.js +338 -0
- package/dist/profiler/types.d.ts +87 -0
- package/dist/profiler/types.js +12 -0
- package/dist/stores/display-profile-store.d.ts +16 -0
- package/dist/stores/display-profile-store.js +48 -0
- package/dist/stores/theme-store.d.ts +13 -0
- package/dist/stores/theme-store.js +30 -0
- package/dist/testing.d.ts +45 -0
- package/dist/testing.js +47 -0
- package/dist/transpile/resolution.d.ts +29 -0
- package/dist/transpile/resolution.js +282 -0
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +722 -0
- package/dist/types.d.ts +217 -0
- package/dist/types.js +1 -0
- package/dist/ui/ui-bridge.d.ts +4 -0
- package/dist/ui/ui-bridge.js +34 -0
- package/dist/ui-hook.d.ts +84 -0
- package/dist/ui-hook.js +45 -0
- package/dist/utils/cli.d.ts +3 -0
- package/dist/utils/cli.js +463 -0
- package/dist/utils/fs.d.ts +4 -0
- package/dist/utils/fs.js +23 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +8 -0
- package/dist/utils/strings.d.ts +35 -0
- package/dist/utils/strings.js +142 -0
- package/dist/utils/ui.d.ts +66 -0
- package/dist/utils/ui.js +149 -0
- package/dist/watch.d.ts +35 -0
- package/dist/watch.js +111 -0
- package/package.json +127 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import * as readline from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { KNOWN_TARGETS } from "./init-scaffold.js";
|
|
5
|
+
function validateProjectName(name) {
|
|
6
|
+
if (!name || name.trim().length === 0) {
|
|
7
|
+
return "Project name cannot be empty.";
|
|
8
|
+
}
|
|
9
|
+
const normalized = name.trim().toLowerCase();
|
|
10
|
+
if (!/^[a-z][a-z0-9-]*$/.test(normalized)) {
|
|
11
|
+
return "Project name must start with a letter and contain only lowercase letters, digits, and hyphens.";
|
|
12
|
+
}
|
|
13
|
+
if (normalized.length > 64) {
|
|
14
|
+
return "Project name must be 64 characters or fewer.";
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
async function promptText(rl, prompt, defaultValue, validate) {
|
|
19
|
+
while (true) {
|
|
20
|
+
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
21
|
+
const answer = await rl.question(`${chalk.cyan("?")} ${prompt}${suffix}: `);
|
|
22
|
+
const value = (answer.trim() || (defaultValue ?? "")).trim();
|
|
23
|
+
if (validate) {
|
|
24
|
+
const error = validate(value);
|
|
25
|
+
if (error) {
|
|
26
|
+
console.log(` ${chalk.red("✗")} ${error}`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function promptSelect(rl, prompt, options) {
|
|
34
|
+
console.log(`${chalk.cyan("?")} ${prompt}:`);
|
|
35
|
+
for (let i = 0; i < options.length; i++) {
|
|
36
|
+
console.log(` ${chalk.dim(`${i + 1})`)} ${options[i].label}`);
|
|
37
|
+
}
|
|
38
|
+
while (true) {
|
|
39
|
+
const answer = await rl.question(` Enter number (1-${options.length}): `);
|
|
40
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
41
|
+
if (idx >= 0 && idx < options.length) {
|
|
42
|
+
return options[idx].value;
|
|
43
|
+
}
|
|
44
|
+
console.log(` ${chalk.red("✗")} Please enter a number between 1 and ${options.length}.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function promptConfirm(rl, prompt, defaultValue) {
|
|
48
|
+
const suffix = defaultValue ? " (Y/n)" : " (y/N)";
|
|
49
|
+
const answer = await rl.question(`${chalk.cyan("?")} ${prompt}${suffix}: `);
|
|
50
|
+
const trimmed = answer.trim().toLowerCase();
|
|
51
|
+
if (trimmed === "")
|
|
52
|
+
return defaultValue;
|
|
53
|
+
return trimmed === "y" || trimmed === "yes";
|
|
54
|
+
}
|
|
55
|
+
export async function runInitWizard(partialOptions) {
|
|
56
|
+
const rl = readline.createInterface({ input, output });
|
|
57
|
+
try {
|
|
58
|
+
console.log();
|
|
59
|
+
console.log(chalk.cyan("⤳ Cuttlefish") + chalk.dim(" — Project Setup"));
|
|
60
|
+
console.log();
|
|
61
|
+
// 1. Project name
|
|
62
|
+
const projectName = partialOptions?.projectName
|
|
63
|
+
?? await promptText(rl, "Project name", "my-project", validateProjectName);
|
|
64
|
+
// 2. Target selection (native first, then embedded boards)
|
|
65
|
+
const targetOptions = KNOWN_TARGETS.map((t) => ({
|
|
66
|
+
label: t.isNative
|
|
67
|
+
? `${t.displayName} (Windows/Linux executable)`
|
|
68
|
+
: `${t.displayName} (${t.architecture.toUpperCase()})`,
|
|
69
|
+
value: t.id,
|
|
70
|
+
}));
|
|
71
|
+
let targetId;
|
|
72
|
+
if (partialOptions?.board) {
|
|
73
|
+
const found = KNOWN_TARGETS.find((t) => t.id === partialOptions.board);
|
|
74
|
+
if (found) {
|
|
75
|
+
targetId = found.id;
|
|
76
|
+
console.log(`${chalk.cyan("?")} Target: ${chalk.white(found.displayName)} (${chalk.dim(partialOptions.board)})`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(` ${chalk.yellow("!")} Target '${chalk.white(partialOptions.board)}' not found.`);
|
|
80
|
+
targetId = await promptSelect(rl, "Target", targetOptions);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
targetId = await promptSelect(rl, "Target", targetOptions);
|
|
85
|
+
}
|
|
86
|
+
const target = KNOWN_TARGETS.find((t) => t.id === targetId);
|
|
87
|
+
// 3. Framework (only for embedded targets)
|
|
88
|
+
let framework = target.framework;
|
|
89
|
+
let frameworkPackage = target.frameworkPackage;
|
|
90
|
+
if (!target.isNative) {
|
|
91
|
+
const frameworkOptions = [
|
|
92
|
+
{ label: "Arduino (digitalWrite, Wire, SPI)", value: 'arduino', pkg: '@typecad/framework-arduino' },
|
|
93
|
+
];
|
|
94
|
+
if (target.architecture === 'avr') {
|
|
95
|
+
frameworkOptions.push({ label: "Bare-metal AVR (PORTB, etc.)", value: 'avr', pkg: '@typecad/framework-avr' });
|
|
96
|
+
}
|
|
97
|
+
if (partialOptions?.framework) {
|
|
98
|
+
const match = frameworkOptions.find(f => f.value === partialOptions.framework);
|
|
99
|
+
framework = match?.value ?? partialOptions.framework;
|
|
100
|
+
frameworkPackage = match?.pkg ?? `@typecad/framework-${partialOptions.framework}`;
|
|
101
|
+
console.log(`${chalk.cyan("?")} Framework: ${chalk.white(framework)}`);
|
|
102
|
+
}
|
|
103
|
+
else if (frameworkOptions.length === 1) {
|
|
104
|
+
framework = frameworkOptions[0].value;
|
|
105
|
+
frameworkPackage = frameworkOptions[0].pkg;
|
|
106
|
+
console.log(`${chalk.cyan("?")} Framework: ${chalk.white(frameworkOptions[0].label)}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const selected = await promptSelect(rl, "Framework", frameworkOptions.map(f => ({ label: f.label, value: f.value })));
|
|
110
|
+
const match = frameworkOptions.find(f => f.value === selected);
|
|
111
|
+
framework = match.value;
|
|
112
|
+
frameworkPackage = match.pkg;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 4. Baud rate (only for embedded)
|
|
116
|
+
let baudRate;
|
|
117
|
+
if (!target.isNative) {
|
|
118
|
+
if (partialOptions?.baud) {
|
|
119
|
+
baudRate = partialOptions.baud;
|
|
120
|
+
console.log(`${chalk.cyan("?")} Serial baud rate: ${chalk.white(baudRate)}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const baudAnswer = await promptText(rl, "Serial baud rate", "9600");
|
|
124
|
+
baudRate = parseInt(baudAnswer, 10);
|
|
125
|
+
if (Number.isNaN(baudRate) || baudRate <= 0) {
|
|
126
|
+
baudRate = 9600;
|
|
127
|
+
console.log(` ${chalk.dim("Using default: 9600")}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// 5. Starter sketch
|
|
132
|
+
let includeSketch;
|
|
133
|
+
if (partialOptions?.noSketch) {
|
|
134
|
+
includeSketch = false;
|
|
135
|
+
console.log(`${chalk.cyan("?")} Create starter sketch: ${chalk.dim("no")}`);
|
|
136
|
+
}
|
|
137
|
+
else if (partialOptions?.noSketch === false) {
|
|
138
|
+
includeSketch = true;
|
|
139
|
+
console.log(`${chalk.cyan("?")} Create starter sketch: ${chalk.green("yes")}`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
includeSketch = await promptConfirm(rl, "Create starter sketch?", true);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
projectName,
|
|
146
|
+
targetId: target.id,
|
|
147
|
+
targetDisplayName: target.displayName,
|
|
148
|
+
isNative: target.isNative,
|
|
149
|
+
architecture: target.architecture,
|
|
150
|
+
boardPackage: target.boardPackage,
|
|
151
|
+
frameworkPackage,
|
|
152
|
+
framework,
|
|
153
|
+
buildTarget: target.buildTarget,
|
|
154
|
+
mcu: target.mcu,
|
|
155
|
+
baudRate,
|
|
156
|
+
includeSketch,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
if (err && typeof err === 'object' && err.code === 'ERR_USE_AFTER_CLOSE') {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
rl.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BreakpointMap, RichBreakpoint } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default directory for TypeCAD debug files.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CUTTLEFISH_DIR = ".cuttlefish";
|
|
6
|
+
/**
|
|
7
|
+
* Default filename for breakpoint data.
|
|
8
|
+
*/
|
|
9
|
+
export declare const BREAKPOINTS_FILE = "breakpoints.json";
|
|
10
|
+
/**
|
|
11
|
+
* Load breakpoints from .cuttlefish/breakpoints.json.
|
|
12
|
+
*
|
|
13
|
+
* @param sourceDir The directory containing the source file (or any directory in the project)
|
|
14
|
+
* @returns BreakpointMap or undefined if no breakpoints file exists
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadBreakpoints(sourceDir: string): BreakpointMap | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Get rich breakpoints for a specific file from the BreakpointMap.
|
|
19
|
+
*
|
|
20
|
+
* @param breakpoints The breakpoint map
|
|
21
|
+
* @param fileName The file path to look up
|
|
22
|
+
* @returns Array of RichBreakpoint objects for the file
|
|
23
|
+
*/
|
|
24
|
+
export declare function getBreakpointsForFile(breakpoints: BreakpointMap, fileName: string): RichBreakpoint[];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/debug — Breakpoint Loader
|
|
3
|
+
//
|
|
4
|
+
// Loads breakpoint data from .cuttlefish/breakpoints.json, which is written
|
|
5
|
+
// by the VS Code extension when users set breakpoints.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
/**
|
|
10
|
+
* Default directory for TypeCAD debug files.
|
|
11
|
+
*/
|
|
12
|
+
export const CUTTLEFISH_DIR = '.cuttlefish';
|
|
13
|
+
/**
|
|
14
|
+
* Default filename for breakpoint data.
|
|
15
|
+
*/
|
|
16
|
+
export const BREAKPOINTS_FILE = 'breakpoints.json';
|
|
17
|
+
/**
|
|
18
|
+
* Find the .cuttlefish directory by walking up from the given directory.
|
|
19
|
+
*/
|
|
20
|
+
function findCuttlefishDir(startDir) {
|
|
21
|
+
let currentDir = path.resolve(startDir);
|
|
22
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
23
|
+
const cuttlefishDir = path.join(currentDir, CUTTLEFISH_DIR);
|
|
24
|
+
if (fs.existsSync(cuttlefishDir) && fs.statSync(cuttlefishDir).isDirectory()) {
|
|
25
|
+
return cuttlefishDir;
|
|
26
|
+
}
|
|
27
|
+
currentDir = path.dirname(currentDir);
|
|
28
|
+
}
|
|
29
|
+
// Check root level
|
|
30
|
+
const rootCuttlefishDir = path.join(currentDir, CUTTLEFISH_DIR);
|
|
31
|
+
if (fs.existsSync(rootCuttlefishDir) && fs.statSync(rootCuttlefishDir).isDirectory()) {
|
|
32
|
+
return rootCuttlefishDir;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load breakpoints from .cuttlefish/breakpoints.json.
|
|
38
|
+
*
|
|
39
|
+
* @param sourceDir The directory containing the source file (or any directory in the project)
|
|
40
|
+
* @returns BreakpointMap or undefined if no breakpoints file exists
|
|
41
|
+
*/
|
|
42
|
+
export function loadBreakpoints(sourceDir) {
|
|
43
|
+
const cuttlefishDir = findCuttlefishDir(sourceDir);
|
|
44
|
+
if (!cuttlefishDir) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const breakpointsPath = path.join(cuttlefishDir, BREAKPOINTS_FILE);
|
|
48
|
+
if (!fs.existsSync(breakpointsPath)) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const content = fs.readFileSync(breakpointsPath, 'utf-8');
|
|
53
|
+
const data = JSON.parse(content);
|
|
54
|
+
// Handle VS Code extension format: { "breakpoints": [...] }
|
|
55
|
+
if (data.breakpoints && Array.isArray(data.breakpoints)) {
|
|
56
|
+
const map = {};
|
|
57
|
+
for (const bp of data.breakpoints) {
|
|
58
|
+
const file = bp.file;
|
|
59
|
+
if (file && bp.line) {
|
|
60
|
+
if (!map[file]) {
|
|
61
|
+
map[file] = [];
|
|
62
|
+
}
|
|
63
|
+
map[file].push({
|
|
64
|
+
file,
|
|
65
|
+
line: bp.line,
|
|
66
|
+
condition: bp.condition,
|
|
67
|
+
logMessage: bp.logMessage,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return map;
|
|
72
|
+
}
|
|
73
|
+
// Handle direct array format: [...]
|
|
74
|
+
if (Array.isArray(data)) {
|
|
75
|
+
const map = {};
|
|
76
|
+
for (const bp of data) {
|
|
77
|
+
const file = bp.file;
|
|
78
|
+
if (file && bp.line) {
|
|
79
|
+
if (!map[file]) {
|
|
80
|
+
map[file] = [];
|
|
81
|
+
}
|
|
82
|
+
map[file].push({
|
|
83
|
+
file,
|
|
84
|
+
line: bp.line,
|
|
85
|
+
condition: bp.condition,
|
|
86
|
+
logMessage: bp.logMessage,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return map;
|
|
91
|
+
}
|
|
92
|
+
// Handle legacy format: { "example.ts": [10, 15] }
|
|
93
|
+
// Convert to rich breakpoint format
|
|
94
|
+
const legacy = data;
|
|
95
|
+
const map = {};
|
|
96
|
+
for (const [file, lines] of Object.entries(legacy)) {
|
|
97
|
+
if (Array.isArray(lines)) {
|
|
98
|
+
map[file] = lines.map(line => ({
|
|
99
|
+
file,
|
|
100
|
+
line: typeof line === 'number' ? line : line.line,
|
|
101
|
+
condition: typeof line === 'object' ? line.condition : undefined,
|
|
102
|
+
logMessage: typeof line === 'object' ? line.logMessage : undefined,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return map;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.warn(`Warning: Failed to parse ${breakpointsPath}: ${error}`);
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get rich breakpoints for a specific file from the BreakpointMap.
|
|
115
|
+
*
|
|
116
|
+
* @param breakpoints The breakpoint map
|
|
117
|
+
* @param fileName The file path to look up
|
|
118
|
+
* @returns Array of RichBreakpoint objects for the file
|
|
119
|
+
*/
|
|
120
|
+
export function getBreakpointsForFile(breakpoints, fileName) {
|
|
121
|
+
// Try exact match first
|
|
122
|
+
if (breakpoints[fileName]) {
|
|
123
|
+
return breakpoints[fileName];
|
|
124
|
+
}
|
|
125
|
+
// Try basename match
|
|
126
|
+
const basename = path.basename(fileName);
|
|
127
|
+
if (breakpoints[basename]) {
|
|
128
|
+
return breakpoints[basename];
|
|
129
|
+
}
|
|
130
|
+
// Try matching against any key that ends with the filename
|
|
131
|
+
for (const key of Object.keys(breakpoints)) {
|
|
132
|
+
if (key.endsWith(basename) || fileName.endsWith(key)) {
|
|
133
|
+
return breakpoints[key];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/debug — Debug Module
|
|
3
|
+
//
|
|
4
|
+
// Provides breakpoint-based debugging for TypeCAD embedded projects.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
export { loadBreakpoints, getBreakpointsForFile, CUTTLEFISH_DIR, BREAKPOINTS_FILE } from './breakpoint-loader.js';
|
|
7
|
+
export { preprocess } from './preprocessor.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BreakpointMap } from './types.js';
|
|
2
|
+
export declare function preprocess(options: {
|
|
3
|
+
/** The source file path (for line number calculation) */
|
|
4
|
+
fileName: string;
|
|
5
|
+
/** The breakpoint map loaded from .cuttlefish/breakpoints.json */
|
|
6
|
+
breakpoints: BreakpointMap;
|
|
7
|
+
/** The source text to transform */
|
|
8
|
+
source: string;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/debug — Debug Preprocessor
|
|
3
|
+
//
|
|
4
|
+
// Transforms TypeScript source by injecting debug code at breakpoint locations.
|
|
5
|
+
// The injected code is generated by the loaded framework's strategy
|
|
6
|
+
// (e.g., Serial.println for Arduino, std::cout for generic targets).
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
import ts from 'typescript';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { getBreakpointsForFile } from './breakpoint-loader.js';
|
|
11
|
+
import { getLoadedFramework, hasLoadedFramework } from '../framework-registry.js';
|
|
12
|
+
import { GenericStrategy } from '../platform/generic-strategy.js';
|
|
13
|
+
function getDebugStrategy() {
|
|
14
|
+
if (hasLoadedFramework()) {
|
|
15
|
+
const { strategy } = getLoadedFramework();
|
|
16
|
+
if (strategy.generateDebugInitCode)
|
|
17
|
+
return strategy;
|
|
18
|
+
}
|
|
19
|
+
// Fall back to the generic strategy's std::cout-based debug output
|
|
20
|
+
return new GenericStrategy();
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Public API
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export function preprocess(options) {
|
|
26
|
+
const { fileName, breakpoints, source } = options;
|
|
27
|
+
const breakpointLines = getBreakpointsForFile(breakpoints, fileName);
|
|
28
|
+
if (breakpointLines.length === 0) {
|
|
29
|
+
return source; // No breakpoints, return unchanged
|
|
30
|
+
}
|
|
31
|
+
const sf = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
32
|
+
const lines = source.split('\n');
|
|
33
|
+
const outputLines = [];
|
|
34
|
+
const relativeFileName = path.basename(fileName);
|
|
35
|
+
// Create a map of line number (0-indexed) to breakpoint
|
|
36
|
+
const breakpointMap = new Map();
|
|
37
|
+
for (const bp of breakpointLines) {
|
|
38
|
+
breakpointMap.set(bp.line - 1, bp);
|
|
39
|
+
}
|
|
40
|
+
// Collect variables in scope at each breakpoint
|
|
41
|
+
const scopeAnalyzer = new ScopeAnalyzer(sf);
|
|
42
|
+
const debugStrategy = getDebugStrategy();
|
|
43
|
+
// Find the first non-import, non-comment line to insert debug init
|
|
44
|
+
let insertIndex = 0;
|
|
45
|
+
for (let i = 0; i < lines.length; i++) {
|
|
46
|
+
const trimmed = lines[i].trim();
|
|
47
|
+
// Skip import statements and comments
|
|
48
|
+
if (trimmed.startsWith('import ') || trimmed.startsWith('//') || trimmed === '') {
|
|
49
|
+
insertIndex = i + 1;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Process each line
|
|
56
|
+
for (let i = 0; i < lines.length; i++) {
|
|
57
|
+
// Insert debug init after imports, before first actual code
|
|
58
|
+
if (i === insertIndex) {
|
|
59
|
+
const initLines = debugStrategy.generateDebugInitCode?.() ?? [];
|
|
60
|
+
outputLines.push(...initLines);
|
|
61
|
+
}
|
|
62
|
+
const lineNum = i; // 0-indexed
|
|
63
|
+
const lineText = lines[i];
|
|
64
|
+
const bp = breakpointMap.get(lineNum);
|
|
65
|
+
if (bp) {
|
|
66
|
+
// Get the original line content (trimmed, for display)
|
|
67
|
+
const displayLine = lineText.trim();
|
|
68
|
+
// Collect variables in scope at this line
|
|
69
|
+
const vars = scopeAnalyzer.getVariablesInScope(lineNum);
|
|
70
|
+
// Inject debug code BEFORE the breakpoint line
|
|
71
|
+
outputLines.push(...generateBreakpointCode(relativeFileName, lineNum + 1, displayLine, vars, bp, debugStrategy));
|
|
72
|
+
}
|
|
73
|
+
// Always include the original line
|
|
74
|
+
outputLines.push(lineText);
|
|
75
|
+
}
|
|
76
|
+
// If all lines were imports/comments, append at end
|
|
77
|
+
if (insertIndex >= lines.length) {
|
|
78
|
+
const initLines = debugStrategy.generateDebugInitCode?.() ?? [];
|
|
79
|
+
outputLines.push(...initLines);
|
|
80
|
+
}
|
|
81
|
+
return outputLines.join('\n');
|
|
82
|
+
}
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Internal — Breakpoint Code Generation
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
/**
|
|
87
|
+
* Generate debug code for a breakpoint.
|
|
88
|
+
* Delegates to the loaded strategy when available.
|
|
89
|
+
*/
|
|
90
|
+
function generateBreakpointCode(fileName, lineNum, originalLine, variables, bp, debugStrategy) {
|
|
91
|
+
// If this is a logpoint (has logMessage), generate log-only code
|
|
92
|
+
if (bp.logMessage) {
|
|
93
|
+
const parts = parseLogMessage(bp.logMessage);
|
|
94
|
+
if (debugStrategy.generateDebugLogpointCode) {
|
|
95
|
+
return debugStrategy.generateDebugLogpointCode({
|
|
96
|
+
fileName, lineNum, parts,
|
|
97
|
+
variables: variables.map(v => ({ name: v.name, isFunction: v.isFunction })),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
// Normalize condition for C++ (convert === to ==, strip semicolons, etc.)
|
|
103
|
+
const normalizedCondition = bp.condition ? normalizeCondition(bp.condition) : undefined;
|
|
104
|
+
if (debugStrategy.generateDebugBreakpointCode) {
|
|
105
|
+
return debugStrategy.generateDebugBreakpointCode({
|
|
106
|
+
fileName, lineNum, originalLine,
|
|
107
|
+
variables: variables.map(v => ({ name: v.name, isFunction: v.isFunction })),
|
|
108
|
+
normalizedCondition,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Internal — Log message parsing
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
function parseLogMessage(message) {
|
|
117
|
+
const parts = [];
|
|
118
|
+
let current = '';
|
|
119
|
+
let i = 0;
|
|
120
|
+
while (i < message.length) {
|
|
121
|
+
if (message[i] === '{') {
|
|
122
|
+
if (current) {
|
|
123
|
+
parts.push({ type: 'text', value: current });
|
|
124
|
+
current = '';
|
|
125
|
+
}
|
|
126
|
+
let varName = '';
|
|
127
|
+
i++;
|
|
128
|
+
while (i < message.length && message[i] !== '}') {
|
|
129
|
+
varName += message[i];
|
|
130
|
+
i++;
|
|
131
|
+
}
|
|
132
|
+
i++;
|
|
133
|
+
parts.push({ type: 'variable', value: varName.trim() });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
current += message[i];
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (current) {
|
|
141
|
+
parts.push({ type: 'text', value: current });
|
|
142
|
+
}
|
|
143
|
+
return parts;
|
|
144
|
+
}
|
|
145
|
+
function normalizeCondition(condition) {
|
|
146
|
+
return condition
|
|
147
|
+
.replace(/;+$/, '')
|
|
148
|
+
.replace(/===/g, '==')
|
|
149
|
+
.replace(/!==/g, '!=')
|
|
150
|
+
.trim();
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Internal — Scope Analysis
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
class ScopeAnalyzer {
|
|
156
|
+
constructor(sf) {
|
|
157
|
+
this.functionVars = new Map();
|
|
158
|
+
this.sf = sf;
|
|
159
|
+
this.analyze();
|
|
160
|
+
}
|
|
161
|
+
getVariablesInScope(line) {
|
|
162
|
+
if (this.functionVars.has(line)) {
|
|
163
|
+
return this.functionVars.get(line);
|
|
164
|
+
}
|
|
165
|
+
return this.functionVars.get(-1) || [];
|
|
166
|
+
}
|
|
167
|
+
analyze() {
|
|
168
|
+
const topLevelVars = [];
|
|
169
|
+
this.collectVariables(this.sf, topLevelVars);
|
|
170
|
+
this.functionVars.set(-1, topLevelVars);
|
|
171
|
+
const visit = (node, currentVars) => {
|
|
172
|
+
if (ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)) {
|
|
173
|
+
const startLine = this.sf.getLineAndCharacterOfPosition(node.getStart()).line;
|
|
174
|
+
const endLine = node.body
|
|
175
|
+
? this.sf.getLineAndCharacterOfPosition(node.body.getEnd()).line
|
|
176
|
+
: startLine;
|
|
177
|
+
const localVars = [...currentVars];
|
|
178
|
+
for (const param of node.parameters) {
|
|
179
|
+
if (ts.isIdentifier(param.name)) {
|
|
180
|
+
localVars.push({ name: param.name.text });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (node.body) {
|
|
184
|
+
this.collectVariables(node.body, localVars);
|
|
185
|
+
}
|
|
186
|
+
for (let line = startLine; line <= endLine; line++) {
|
|
187
|
+
this.functionVars.set(line, localVars);
|
|
188
|
+
}
|
|
189
|
+
return localVars;
|
|
190
|
+
}
|
|
191
|
+
ts.forEachChild(node, child => visit(child, currentVars));
|
|
192
|
+
return currentVars;
|
|
193
|
+
};
|
|
194
|
+
visit(this.sf, topLevelVars);
|
|
195
|
+
}
|
|
196
|
+
collectVariables(node, vars) {
|
|
197
|
+
if (ts.isVariableStatement(node)) {
|
|
198
|
+
for (const decl of node.declarationList.declarations) {
|
|
199
|
+
if (ts.isIdentifier(decl.name)) {
|
|
200
|
+
const isFunction = decl.initializer !== undefined && this.isFunctionExpression(decl.initializer);
|
|
201
|
+
vars.push({ name: decl.name.text, isFunction });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
ts.forEachChild(node, child => {
|
|
206
|
+
if (!ts.isFunctionDeclaration(child) && !ts.isArrowFunction(child) && !ts.isMethodDeclaration(child)) {
|
|
207
|
+
this.collectVariables(child, vars);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
isFunctionExpression(expr) {
|
|
212
|
+
return ts.isArrowFunction(expr) || ts.isFunctionExpression(expr);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A captured variable at a breakpoint.
|
|
3
|
+
*/
|
|
4
|
+
export interface CapturedVariable {
|
|
5
|
+
/** Variable name */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Whether this is a function (cannot print value) */
|
|
8
|
+
isFunction?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A rich breakpoint with optional condition and log message.
|
|
12
|
+
*/
|
|
13
|
+
export interface RichBreakpoint {
|
|
14
|
+
/** Source file path (relative or absolute) */
|
|
15
|
+
file: string;
|
|
16
|
+
/** Line number (1-indexed) */
|
|
17
|
+
line: number;
|
|
18
|
+
/** Optional condition expression (e.g., "counter > 5") */
|
|
19
|
+
condition?: string;
|
|
20
|
+
/** Optional log message with {variable} interpolation (e.g., "counter = {counter}") */
|
|
21
|
+
logMessage?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Map of file paths to arrays of rich breakpoints.
|
|
25
|
+
* Loaded from .cuttlefish/breakpoints.json.
|
|
26
|
+
*/
|
|
27
|
+
export type BreakpointMap = Record<string, RichBreakpoint[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Legacy breakpoint map format (just line numbers).
|
|
30
|
+
* Used for backward compatibility.
|
|
31
|
+
*/
|
|
32
|
+
export type LegacyBreakpointMap = Record<string, number[]>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/debug — Debug Types
|
|
3
|
+
//
|
|
4
|
+
// Type definitions for the TypeCAD debugger breakpoint system.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ProgramIR } from "../api/index.js";
|
|
2
|
+
import type { Diagnostic } from "../types.js";
|
|
3
|
+
import type { DiagnosticsReport } from "./json-schema.js";
|
|
4
|
+
export interface DiagnosticsReportInput {
|
|
5
|
+
/** Entry TypeScript source file path */
|
|
6
|
+
entryFile: string;
|
|
7
|
+
/** Program IR for the entry module (after tree-shaking) */
|
|
8
|
+
program: ProgramIR | null;
|
|
9
|
+
/** All diagnostics collected during transpilation */
|
|
10
|
+
diagnostics: Diagnostic[];
|
|
11
|
+
/** Async task names discovered */
|
|
12
|
+
asyncTaskNames: string[];
|
|
13
|
+
/** Whether timers (millis/micros) are used */
|
|
14
|
+
usesTimers: boolean;
|
|
15
|
+
/** Target architecture (e.g. "avr", "esp32") */
|
|
16
|
+
target: string;
|
|
17
|
+
/** Board package name */
|
|
18
|
+
boardPackage?: string;
|
|
19
|
+
/** Framework package name */
|
|
20
|
+
frameworkPackage?: string;
|
|
21
|
+
/** Build target identifier */
|
|
22
|
+
buildTarget?: string;
|
|
23
|
+
/** Output directory for generated files */
|
|
24
|
+
outDir?: string;
|
|
25
|
+
/** Output file path (relative or absolute) */
|
|
26
|
+
outputFile?: string;
|
|
27
|
+
/** Pre-build compiled modules (for module graph) */
|
|
28
|
+
preBuilt?: Map<string, any>;
|
|
29
|
+
/** Source map entries */
|
|
30
|
+
sourceMaps?: any[];
|
|
31
|
+
/** Profiler timing data */
|
|
32
|
+
profiler?: {
|
|
33
|
+
getTimings?: () => Record<string, number>;
|
|
34
|
+
};
|
|
35
|
+
/** Tree-shaking removed symbols */
|
|
36
|
+
removedSymbols?: string[];
|
|
37
|
+
/** Board pins from board constants */
|
|
38
|
+
boardPins?: Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
aliases: string[];
|
|
41
|
+
number: number;
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the complete DiagnosticsReport from transpile pipeline data.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildDiagnosticsReport(input: DiagnosticsReportInput): DiagnosticsReport;
|
|
48
|
+
/**
|
|
49
|
+
* Write diagnostics.md to the output directory.
|
|
50
|
+
*/
|
|
51
|
+
export declare function writeDiagnosticsReport(report: DiagnosticsReport, program: ProgramIR | null, outDir: string): void;
|