@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,207 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { readText, writeText } from "../utils/fs.js";
|
|
4
|
+
function toSourceMapPath(generatedFilePath) {
|
|
5
|
+
return `${generatedFilePath}.thcppmap.json`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Normalize a file path for comparison across the emitter and g++.
|
|
9
|
+
* g++ on Windows may emit paths that differ from what the emitter wrote:
|
|
10
|
+
* drive-letter casing (C:\ vs c:\), forward vs back slashes, and trailing
|
|
11
|
+
* differences. We normalize separators to "/", lowercase the drive letter
|
|
12
|
+
* only (Windows is case-insensitive but the rest of a path may be
|
|
13
|
+
* significant on POSIX), and resolve relatives.
|
|
14
|
+
*/
|
|
15
|
+
function normalizeFilePath(filePath) {
|
|
16
|
+
let p = path.resolve(filePath);
|
|
17
|
+
// Normalize separators.
|
|
18
|
+
p = p.split(path.sep).join("/");
|
|
19
|
+
// Lowercase the drive letter on Windows ("C:/..." -> "c:/...").
|
|
20
|
+
if (/^[A-Za-z]:\//.test(p)) {
|
|
21
|
+
p = p[0].toLowerCase() + p.slice(1);
|
|
22
|
+
}
|
|
23
|
+
return p;
|
|
24
|
+
}
|
|
25
|
+
export function writeSourceMap(map) {
|
|
26
|
+
const mapPath = toSourceMapPath(map.generatedFilePath);
|
|
27
|
+
writeText(mapPath, JSON.stringify(map, null, 2) + "\n");
|
|
28
|
+
return mapPath;
|
|
29
|
+
}
|
|
30
|
+
export function readSourceMap(mapPath) {
|
|
31
|
+
return JSON.parse(readText(mapPath));
|
|
32
|
+
}
|
|
33
|
+
export function makeGeneratedMap(generatedFilePath, sourceFilePath, entries) {
|
|
34
|
+
return {
|
|
35
|
+
version: 1,
|
|
36
|
+
generatedFilePath,
|
|
37
|
+
sourceFilePath,
|
|
38
|
+
entries,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function scoreEntry(entry, line, column) {
|
|
42
|
+
if (line < entry.generatedStartLine || line > entry.generatedEndLine) {
|
|
43
|
+
return Number.POSITIVE_INFINITY;
|
|
44
|
+
}
|
|
45
|
+
if (line === entry.generatedStartLine && column < entry.generatedStartColumn) {
|
|
46
|
+
return Number.POSITIVE_INFINITY;
|
|
47
|
+
}
|
|
48
|
+
if (line === entry.generatedEndLine && column > entry.generatedEndColumn) {
|
|
49
|
+
return Number.POSITIVE_INFINITY;
|
|
50
|
+
}
|
|
51
|
+
const lineSpan = Math.max(1, entry.generatedEndLine - entry.generatedStartLine + 1);
|
|
52
|
+
const colSpan = Math.max(1, entry.generatedEndColumn - entry.generatedStartColumn + 1);
|
|
53
|
+
return lineSpan * 100000 + colSpan;
|
|
54
|
+
}
|
|
55
|
+
function nearestEntry(entries, line) {
|
|
56
|
+
if (entries.length === 0) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return entries
|
|
60
|
+
.slice()
|
|
61
|
+
.sort((a, b) => {
|
|
62
|
+
const da = Math.min(Math.abs(a.generatedStartLine - line), Math.abs(a.generatedEndLine - line));
|
|
63
|
+
const db = Math.min(Math.abs(b.generatedStartLine - line), Math.abs(b.generatedEndLine - line));
|
|
64
|
+
return da - db;
|
|
65
|
+
})[0];
|
|
66
|
+
}
|
|
67
|
+
export function mapCppLocationToTs(map, cppLine, cppColumn, message, cppFilePath) {
|
|
68
|
+
const scored = map.entries
|
|
69
|
+
.map((entry) => ({ entry, score: scoreEntry(entry, cppLine, cppColumn) }))
|
|
70
|
+
.filter((item) => Number.isFinite(item.score))
|
|
71
|
+
.sort((a, b) => a.score - b.score);
|
|
72
|
+
const best = scored.length > 0 ? scored[0].entry : nearestEntry(map.entries, cppLine);
|
|
73
|
+
return {
|
|
74
|
+
cppFilePath: cppFilePath ?? map.generatedFilePath,
|
|
75
|
+
cppLine,
|
|
76
|
+
cppColumn,
|
|
77
|
+
message,
|
|
78
|
+
mappedTsSpan: best?.tsSpan,
|
|
79
|
+
nodeKind: best?.nodeKind,
|
|
80
|
+
symbolName: best?.symbolName,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function resolveMapPath(mapFileOrGeneratedFile) {
|
|
84
|
+
if (mapFileOrGeneratedFile.endsWith(".thcppmap.json")) {
|
|
85
|
+
return path.resolve(process.cwd(), mapFileOrGeneratedFile);
|
|
86
|
+
}
|
|
87
|
+
return toSourceMapPath(path.resolve(process.cwd(), mapFileOrGeneratedFile));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve source map path for a flattened Arduino sketch
|
|
91
|
+
* When a sketch is flattened, the source map needs to account for merged files
|
|
92
|
+
*/
|
|
93
|
+
export function resolveSourceMapForSketch(sketchPath, originalSourceMapPath) {
|
|
94
|
+
const sketchDir = path.dirname(sketchPath);
|
|
95
|
+
const sketchName = path.basename(sketchPath, path.extname(sketchPath));
|
|
96
|
+
// First try the original source map path
|
|
97
|
+
if (originalSourceMapPath && fs.existsSync(originalSourceMapPath)) {
|
|
98
|
+
return originalSourceMapPath;
|
|
99
|
+
}
|
|
100
|
+
// Try to find source maps for the sketch directory
|
|
101
|
+
const possibleMaps = [
|
|
102
|
+
path.join(sketchDir, `${sketchName}.thcppmap.json`),
|
|
103
|
+
path.join(sketchDir, `${sketchName}.ino.thcppmap.json`),
|
|
104
|
+
path.join(sketchDir, "example.thcppmap.json"), // Common case for example sketches
|
|
105
|
+
];
|
|
106
|
+
for (const mapPath of possibleMaps) {
|
|
107
|
+
if (fs.existsSync(mapPath)) {
|
|
108
|
+
return mapPath;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Look for any .thcppmap.json files in the sketch directory
|
|
112
|
+
try {
|
|
113
|
+
const files = fs.readdirSync(sketchDir);
|
|
114
|
+
const mapFiles = files.filter(f => f.endsWith('.thcppmap.json'));
|
|
115
|
+
if (mapFiles.length > 0) {
|
|
116
|
+
// Return the most recent one
|
|
117
|
+
const latest = mapFiles.sort().pop();
|
|
118
|
+
return path.join(sketchDir, latest);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Ignore readdir errors
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Load every `*.thcppmap.json` in `buildDir` (non-recursive) into an index
|
|
128
|
+
* keyed by the normalized `generatedFilePath`. Returns an empty index if the
|
|
129
|
+
* directory is missing or contains no maps.
|
|
130
|
+
*/
|
|
131
|
+
export function buildSourceMapIndex(buildDir) {
|
|
132
|
+
const index = new Map();
|
|
133
|
+
let files;
|
|
134
|
+
try {
|
|
135
|
+
files = fs.readdirSync(buildDir);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return index;
|
|
139
|
+
}
|
|
140
|
+
for (const file of files) {
|
|
141
|
+
if (!file.endsWith(".thcppmap.json"))
|
|
142
|
+
continue;
|
|
143
|
+
const mapPath = path.join(buildDir, file);
|
|
144
|
+
try {
|
|
145
|
+
const map = JSON.parse(readText(mapPath));
|
|
146
|
+
if (map && map.generatedFilePath) {
|
|
147
|
+
index.set(normalizeFilePath(map.generatedFilePath), map);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Skip unreadable / malformed maps rather than aborting the whole index.
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return index;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Map a g++/compiler error back to its TypeScript source span.
|
|
158
|
+
*
|
|
159
|
+
* Selects the per-file source map whose `generatedFilePath` matches the
|
|
160
|
+
* error's `filePath`, then delegates to `mapCppLocationToTs`. If the exact
|
|
161
|
+
* generated file isn't keyed (e.g. the compiler reported a differently
|
|
162
|
+
* normalized path, or the error came from a header), falls back to a
|
|
163
|
+
* directory-wide search across every loaded map.
|
|
164
|
+
*
|
|
165
|
+
* Returns a `MappedDiagnostic` whose `mappedTsSpan` is `undefined` when no
|
|
166
|
+
* map could resolve the location (the caller should treat that as a raw
|
|
167
|
+
* C++ fallback).
|
|
168
|
+
*/
|
|
169
|
+
export function mapCppErrorToTs(index, error) {
|
|
170
|
+
const normalized = normalizeFilePath(error.filePath);
|
|
171
|
+
// 1. Direct hit on the generated file's own map.
|
|
172
|
+
const direct = index.get(normalized);
|
|
173
|
+
if (direct) {
|
|
174
|
+
return mapCppLocationToTs(direct, error.line, error.column, error.message, error.filePath);
|
|
175
|
+
}
|
|
176
|
+
// 2. Header / alternate-path fallback: search every loaded map. This
|
|
177
|
+
// covers errors reported against a .h (which shares the dir) and any
|
|
178
|
+
// remaining path-normalization drift between the compiler and emitter.
|
|
179
|
+
let best;
|
|
180
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
181
|
+
for (const map of index.values()) {
|
|
182
|
+
// Find the tightest in-range entry across all maps; mapCppLocationToTs
|
|
183
|
+
// always falls back to a nearest match, so we score ourselves to only
|
|
184
|
+
// accept a genuinely in-range candidate.
|
|
185
|
+
const scored = map.entries
|
|
186
|
+
.map((entry) => ({ entry, score: scoreEntry(entry, error.line, error.column) }))
|
|
187
|
+
.filter((item) => Number.isFinite(item.score))
|
|
188
|
+
.sort((a, b) => a.score - b.score);
|
|
189
|
+
if (scored.length === 0)
|
|
190
|
+
continue;
|
|
191
|
+
if (scored[0].score < bestScore) {
|
|
192
|
+
bestScore = scored[0].score;
|
|
193
|
+
best = mapCppLocationToTs(map, error.line, error.column, error.message, error.filePath);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (best)
|
|
197
|
+
return best;
|
|
198
|
+
// 3. Nothing loaded at all — return unmapped so the caller can show the
|
|
199
|
+
// raw C++ location.
|
|
200
|
+
return {
|
|
201
|
+
cppFilePath: error.filePath,
|
|
202
|
+
cppLine: error.line,
|
|
203
|
+
cppColumn: error.column,
|
|
204
|
+
message: error.message,
|
|
205
|
+
mappedTsSpan: undefined,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function tryGenerateLibDecl(modulePath: string, file: string): string | undefined;
|
|
2
|
+
/**
|
|
3
|
+
* Extracts module path from "Cannot find module" error messages.
|
|
4
|
+
* Returns the module path (relative or bare module name), undefined otherwise.
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractMissingModulePath(errorMessage: string): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Attempts to find a .cpp file for a missing module.
|
|
9
|
+
* Checks both direct path and index patterns.
|
|
10
|
+
*/
|
|
11
|
+
export declare function findCppForModule(fromFile: string, modulePath: string): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Auto-generates .d.ts files for C++ modules that are missing declarations.
|
|
14
|
+
* Also tries to generate declarations for framework libraries.
|
|
15
|
+
* Returns list of generated files.
|
|
16
|
+
*/
|
|
17
|
+
export declare function autoGenerateMissingDecls(files: string[], errors: string[]): string[];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { generateDeclFromCpp } from "../libdef/cpp-to-decl.js";
|
|
4
|
+
import { getLoadedFramework, hasLoadedFramework } from "../framework-registry.js";
|
|
5
|
+
export function tryGenerateLibDecl(modulePath, file) {
|
|
6
|
+
try {
|
|
7
|
+
if (hasLoadedFramework()) {
|
|
8
|
+
const { libDeclGenerator } = getLoadedFramework();
|
|
9
|
+
if (libDeclGenerator) {
|
|
10
|
+
return libDeclGenerator(modulePath, file);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// No loaded framework.
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Extracts module path from "Cannot find module" error messages.
|
|
21
|
+
* Returns the module path (relative or bare module name), undefined otherwise.
|
|
22
|
+
*/
|
|
23
|
+
export function extractMissingModulePath(errorMessage) {
|
|
24
|
+
const match = errorMessage.match(/Cannot find module '([^']+)' or its corresponding type declarations/);
|
|
25
|
+
return match ? match[1] : undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Attempts to find a .cpp file for a missing module.
|
|
29
|
+
* Checks both direct path and index patterns.
|
|
30
|
+
*/
|
|
31
|
+
export function findCppForModule(fromFile, modulePath) {
|
|
32
|
+
const basePath = path.resolve(path.dirname(fromFile), modulePath);
|
|
33
|
+
const candidates = [
|
|
34
|
+
`${basePath}.cpp`,
|
|
35
|
+
path.join(basePath, "index.cpp"),
|
|
36
|
+
];
|
|
37
|
+
for (const candidate of candidates) {
|
|
38
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
39
|
+
return candidate;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Auto-generates .d.ts files for C++ modules that are missing declarations.
|
|
46
|
+
* Also tries to generate declarations for framework libraries.
|
|
47
|
+
* Returns list of generated files.
|
|
48
|
+
*/
|
|
49
|
+
export function autoGenerateMissingDecls(files, errors) {
|
|
50
|
+
const generated = [];
|
|
51
|
+
const processedModules = new Set();
|
|
52
|
+
for (const error of errors) {
|
|
53
|
+
const modulePath = extractMissingModulePath(error);
|
|
54
|
+
if (!modulePath || processedModules.has(modulePath)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
processedModules.add(modulePath);
|
|
58
|
+
// Try relative C++ module first
|
|
59
|
+
if (modulePath.startsWith(".")) {
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const cppPath = findCppForModule(file, modulePath);
|
|
62
|
+
if (cppPath) {
|
|
63
|
+
const result = generateDeclFromCpp(cppPath);
|
|
64
|
+
if (result) {
|
|
65
|
+
generated.push(result);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Try framework library for bare module imports
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
const declPath = tryGenerateLibDecl(modulePath, file);
|
|
75
|
+
if (declPath) {
|
|
76
|
+
generated.push(declPath);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return generated;
|
|
83
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TranspileGraphResult } from "../transpile/resolution.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sort files in dependency order using Kahn's algorithm.
|
|
4
|
+
* Dependencies come before dependents so that include ordering is correct
|
|
5
|
+
* (e.g., if A imports B, B appears before A in the result).
|
|
6
|
+
*
|
|
7
|
+
* Falls back to the original order for any files involved in dependency cycles.
|
|
8
|
+
*/
|
|
9
|
+
export declare function topologicalSortFiles(files: string[], dependencies: Map<string, Set<string>>): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Collects all files that need to be transpiled, following both relative and npm imports.
|
|
12
|
+
* Also detects native C++ modules (.d.ts + .cpp pairs).
|
|
13
|
+
* Files are returned in dependency order (dependencies before dependents).
|
|
14
|
+
*
|
|
15
|
+
* @param boardPackage When provided, `@typecad/board` imports resolve to this
|
|
16
|
+
* board package (e.g. `'@typecad/board-arduino-uno'`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function collectTranspileGraph(entryFile: string, boardPackage?: string): TranspileGraphResult;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import { readText } from "../utils/fs.js";
|
|
4
|
+
import { detectNativeCppModule, getNpmPackageInfoForFile, isInNodeModules, resolveImport, isCuttlefishSDKPath, } from "../transpile/resolution.js";
|
|
5
|
+
import { requireUIHook } from "../ui-hook.js";
|
|
6
|
+
/**
|
|
7
|
+
* Sort files in dependency order using Kahn's algorithm.
|
|
8
|
+
* Dependencies come before dependents so that include ordering is correct
|
|
9
|
+
* (e.g., if A imports B, B appears before A in the result).
|
|
10
|
+
*
|
|
11
|
+
* Falls back to the original order for any files involved in dependency cycles.
|
|
12
|
+
*/
|
|
13
|
+
export function topologicalSortFiles(files, dependencies) {
|
|
14
|
+
if (files.length <= 1)
|
|
15
|
+
return [...files];
|
|
16
|
+
const fileSet = new Set(files);
|
|
17
|
+
// Build reverse adjacency list: dep → Set<files that depend on dep>
|
|
18
|
+
const dependents = new Map();
|
|
19
|
+
const inDegree = new Map();
|
|
20
|
+
for (const f of files) {
|
|
21
|
+
dependents.set(f, new Set());
|
|
22
|
+
inDegree.set(f, 0);
|
|
23
|
+
}
|
|
24
|
+
for (const [file, deps] of dependencies) {
|
|
25
|
+
if (!fileSet.has(file))
|
|
26
|
+
continue;
|
|
27
|
+
for (const dep of deps) {
|
|
28
|
+
if (fileSet.has(dep) && dep !== file) {
|
|
29
|
+
dependents.get(dep).add(file);
|
|
30
|
+
inDegree.set(file, (inDegree.get(file) ?? 0) + 1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Kahn's algorithm: start with files that have no in-edges
|
|
35
|
+
const queue = [];
|
|
36
|
+
for (const f of files) {
|
|
37
|
+
if (inDegree.get(f) === 0) {
|
|
38
|
+
queue.push(f);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const sorted = [];
|
|
42
|
+
while (queue.length > 0) {
|
|
43
|
+
const file = queue.shift();
|
|
44
|
+
sorted.push(file);
|
|
45
|
+
for (const dependent of dependents.get(file) ?? []) {
|
|
46
|
+
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
47
|
+
inDegree.set(dependent, newDegree);
|
|
48
|
+
if (newDegree === 0) {
|
|
49
|
+
queue.push(dependent);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// If there are cycles, append remaining files in original order
|
|
54
|
+
if (sorted.length < files.length) {
|
|
55
|
+
const sortedSet = new Set(sorted);
|
|
56
|
+
for (const f of files) {
|
|
57
|
+
if (!sortedSet.has(f))
|
|
58
|
+
sorted.push(f);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return sorted;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Collects all files that need to be transpiled, following both relative and npm imports.
|
|
65
|
+
* Also detects native C++ modules (.d.ts + .cpp pairs).
|
|
66
|
+
* Files are returned in dependency order (dependencies before dependents).
|
|
67
|
+
*
|
|
68
|
+
* @param boardPackage When provided, `@typecad/board` imports resolve to this
|
|
69
|
+
* board package (e.g. `'@typecad/board-arduino-uno'`).
|
|
70
|
+
*/
|
|
71
|
+
export function collectTranspileGraph(entryFile, boardPackage) {
|
|
72
|
+
const ordered = [];
|
|
73
|
+
const pending = [path.resolve(entryFile)];
|
|
74
|
+
const visited = new Set();
|
|
75
|
+
const npmPackages = new Map();
|
|
76
|
+
const nativeModules = new Map();
|
|
77
|
+
const uiModules = new Set();
|
|
78
|
+
// Track dependency edges for topological sorting
|
|
79
|
+
const dependencies = new Map();
|
|
80
|
+
while (pending.length > 0) {
|
|
81
|
+
const filePath = pending.shift();
|
|
82
|
+
if (!filePath || visited.has(filePath)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
visited.add(filePath);
|
|
86
|
+
// Skip TypeCAD SDK files — they are type-level definitions only
|
|
87
|
+
if (isCuttlefishSDKPath(filePath)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
ordered.push(filePath);
|
|
91
|
+
const fileDeps = new Set();
|
|
92
|
+
dependencies.set(filePath, fileDeps);
|
|
93
|
+
const sourceText = readText(filePath);
|
|
94
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
95
|
+
// .ui single-file component: split into script/style/template. The <script>
|
|
96
|
+
// becomes the TS source for graph walking; the template+style are registered
|
|
97
|
+
// as a UI module at a synthetic .ui.html path (so loadUIModuleFromText caches
|
|
98
|
+
// it + the UI registry generates the type declaration under types/). The script's
|
|
99
|
+
// `screen` reference resolves to the in-file template.
|
|
100
|
+
if (extension === ".ui") {
|
|
101
|
+
const ui = requireUIHook();
|
|
102
|
+
const parts = ui.splitUiFile(sourceText);
|
|
103
|
+
// Register the template as a UI module at <file>.ui.html (synthetic path).
|
|
104
|
+
const uiHtmlPath = filePath + ".html";
|
|
105
|
+
ui.loadUIModuleFromText(uiHtmlPath, parts.html, parts.style, filePath);
|
|
106
|
+
uiModules.add(uiHtmlPath);
|
|
107
|
+
// Use the <script> as the TS source for import-graph walking. Inject an
|
|
108
|
+
// implicit `import { screen } from './<base>.ui.html'` so the script can
|
|
109
|
+
// reference `screen` without an explicit import.
|
|
110
|
+
const baseName = path.basename(filePath, ".ui");
|
|
111
|
+
const scriptWithImport = `import { screen } from './${baseName}.ui.html';\n` + parts.script;
|
|
112
|
+
const uiSource = ts.createSourceFile(filePath, scriptWithImport, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
113
|
+
// Walk the script's imports to discover dependencies.
|
|
114
|
+
for (const statement of uiSource.statements) {
|
|
115
|
+
let moduleSpecifier;
|
|
116
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
117
|
+
moduleSpecifier = statement.moduleSpecifier.text;
|
|
118
|
+
}
|
|
119
|
+
else if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
120
|
+
moduleSpecifier = statement.moduleSpecifier.text;
|
|
121
|
+
}
|
|
122
|
+
if (!moduleSpecifier)
|
|
123
|
+
continue;
|
|
124
|
+
if (moduleSpecifier === "@typecad/expect" || moduleSpecifier === "@typecad/ui")
|
|
125
|
+
continue;
|
|
126
|
+
if (moduleSpecifier.startsWith("@typecad/"))
|
|
127
|
+
continue;
|
|
128
|
+
const resolved = resolveImport(filePath, moduleSpecifier, boardPackage);
|
|
129
|
+
if (!resolved)
|
|
130
|
+
continue;
|
|
131
|
+
if (resolved.uiModule)
|
|
132
|
+
continue; // already handled above
|
|
133
|
+
fileDeps.add(resolved.sourcePath);
|
|
134
|
+
if (!visited.has(resolved.sourcePath))
|
|
135
|
+
pending.push(resolved.sourcePath);
|
|
136
|
+
}
|
|
137
|
+
continue; // .ui file itself is not a TS file; the script is inlined at emit
|
|
138
|
+
}
|
|
139
|
+
const source = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, extension === ".tsx" ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
140
|
+
for (const statement of source.statements) {
|
|
141
|
+
let moduleSpecifier;
|
|
142
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
143
|
+
moduleSpecifier = statement.moduleSpecifier.text;
|
|
144
|
+
}
|
|
145
|
+
else if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
146
|
+
moduleSpecifier = statement.moduleSpecifier.text;
|
|
147
|
+
}
|
|
148
|
+
if (!moduleSpecifier) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Check for native C++ module (.d.ts + .cpp pair)
|
|
152
|
+
const nativeModule = detectNativeCppModule(filePath, moduleSpecifier);
|
|
153
|
+
if (nativeModule) {
|
|
154
|
+
nativeModules.set(moduleSpecifier, nativeModule);
|
|
155
|
+
continue; // Don't try to resolve as TypeScript
|
|
156
|
+
}
|
|
157
|
+
// Skip @typecad/expect — it provides type-level stubs only.
|
|
158
|
+
// The AST preprocessor rewrites all expect calls before transpilation.
|
|
159
|
+
if (moduleSpecifier === "@typecad/expect") {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Skip @typecad/ui (and the future @typecad/ui rename) — it provides
|
|
163
|
+
// compile-time authoring stubs only. ui.mount/signal/bind calls are
|
|
164
|
+
// intercepted by tryResolveUICall and lowered to IR; the package itself
|
|
165
|
+
// must NOT be emitted as a C++ module (it would synthesize a bogus
|
|
166
|
+
// _ui_t struct for the `ui` namespace value).
|
|
167
|
+
if (moduleSpecifier === "@typecad/ui" || moduleSpecifier === "@typecad/ui") {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// Skip @typecad/board, @typecad/board-*, @typecad/mcu-*, and
|
|
171
|
+
// @typecad/framework-* — these packages ship src/ for HAL metadata
|
|
172
|
+
// introspection (hal-parser.ts, board-resolver.ts) but their source
|
|
173
|
+
// must NOT be transpiled to C++. The HAL resolver loads class/method
|
|
174
|
+
// metadata from these files separately; emitting them as C++ produces
|
|
175
|
+
// thousands of lines of stub functions (board(), gpioWrite(), etc.)
|
|
176
|
+
// and pulls in unsupported types (Promise, variant, Object.freeze).
|
|
177
|
+
if (moduleSpecifier === "@typecad/board"
|
|
178
|
+
|| moduleSpecifier.startsWith("@typecad/board-")
|
|
179
|
+
|| moduleSpecifier.startsWith("@typecad/mcu-")
|
|
180
|
+
|| moduleSpecifier.startsWith("@typecad/framework-")) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const resolved = resolveImport(filePath, moduleSpecifier, boardPackage);
|
|
184
|
+
// .ui.html modules: load into the UI registry, record the path, and don't
|
|
185
|
+
// push onto `pending` (they are never parsed as TypeScript).
|
|
186
|
+
if (resolved?.uiModule) {
|
|
187
|
+
requireUIHook().loadUIModule(resolved.sourcePath);
|
|
188
|
+
uiModules.add(resolved.sourcePath);
|
|
189
|
+
// Track the dependency edge so topological sort orders the importer
|
|
190
|
+
// after the (virtual) UI module.
|
|
191
|
+
fileDeps.add(resolved.sourcePath);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (resolved) {
|
|
195
|
+
// Track dependency edge for topological sorting
|
|
196
|
+
fileDeps.add(resolved.sourcePath);
|
|
197
|
+
if (!visited.has(resolved.sourcePath)) {
|
|
198
|
+
pending.push(resolved.sourcePath);
|
|
199
|
+
if (resolved.npmPackage) {
|
|
200
|
+
npmPackages.set(resolved.sourcePath, resolved.npmPackage);
|
|
201
|
+
}
|
|
202
|
+
else if (isInNodeModules(resolved.sourcePath)) {
|
|
203
|
+
// If the file is in node_modules but wasn't resolved as an npm package,
|
|
204
|
+
// it was reached via relative import from another npm package file.
|
|
205
|
+
// Create npm package info for it.
|
|
206
|
+
const npmInfo = getNpmPackageInfoForFile(resolved.sourcePath, moduleSpecifier);
|
|
207
|
+
if (npmInfo) {
|
|
208
|
+
npmPackages.set(resolved.sourcePath, npmInfo);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Sort files in dependency order (dependencies before dependents)
|
|
216
|
+
const sorted = topologicalSortFiles(ordered, dependencies);
|
|
217
|
+
return { files: sorted, npmPackages, nativeModules, uiModules };
|
|
218
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { Diagnostic } from "../types.js";
|
|
3
|
+
import { TYPED_ARRAY_NAMES } from "./semantic-facts.js";
|
|
4
|
+
import type { FactStore } from "./semantic-facts.js";
|
|
5
|
+
export type UnknownTypeSeverity = "error" | "warning" | "off";
|
|
6
|
+
export interface VerifierOptions {
|
|
7
|
+
/** Severity for expressions whose canonical type is "unknown".
|
|
8
|
+
* Default "warning" — see module header. */
|
|
9
|
+
unknownTypeSeverity?: UnknownTypeSeverity;
|
|
10
|
+
}
|
|
11
|
+
export interface VerifierResult {
|
|
12
|
+
/** Diagnostics produced by the verifier (may be empty). */
|
|
13
|
+
diagnostics: Diagnostic[];
|
|
14
|
+
/** Counts for measurement/reporting. Use to size the blast radius before
|
|
15
|
+
* flipping unknownTypeSeverity to "error". */
|
|
16
|
+
counts: {
|
|
17
|
+
expressionsVisited: number;
|
|
18
|
+
unknownTypeExpressions: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Verify semantic-fact completeness across user files.
|
|
23
|
+
*
|
|
24
|
+
* Walks every expression, computes its CanonicalType, and emits a diagnostic
|
|
25
|
+
* for each one that resolves to "unknown" (at the configured severity).
|
|
26
|
+
*
|
|
27
|
+
* If `facts` is passed, the walk also POPULATES the store with the computed
|
|
28
|
+
* `type` (CanonicalType) and `cppType` for each expression. This is the single
|
|
29
|
+
* place concrete per-expression type facts are recorded — Phase 3 of the type-
|
|
30
|
+
* resolution consolidation — so gate rules can read them without re-deriving
|
|
31
|
+
* from the ts.TypeChecker, and so a future pipeline reorder can populate the
|
|
32
|
+
* same fields from the ProgramIR SymbolTable instead. See SemanticFacts.cppType.
|
|
33
|
+
*/
|
|
34
|
+
export declare function verifyFacts(program: ts.Program, userFiles: string[], options?: VerifierOptions & {
|
|
35
|
+
facts?: FactStore;
|
|
36
|
+
}): VerifierResult;
|
|
37
|
+
/** Re-export so callers can introspect the typed-array name set if needed. */
|
|
38
|
+
export { TYPED_ARRAY_NAMES };
|