@typecad/cuttlefish 1.0.0-alpha.13 → 1.0.0-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -79
- package/assets/editor-extensions/typecad-debug/README.md +141 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js +347 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js.map +1 -0
- package/assets/editor-extensions/typecad-debug/package.json +76 -0
- package/assets/editor-extensions/typecad-ui/LICENSE +27 -0
- package/assets/editor-extensions/typecad-ui/README.md +52 -0
- package/assets/editor-extensions/typecad-ui/file-icon-dark.png +0 -0
- package/assets/editor-extensions/typecad-ui/file-icon-light.png +0 -0
- package/assets/editor-extensions/typecad-ui/icon.png +0 -0
- package/assets/editor-extensions/typecad-ui/language-configuration.json +43 -0
- package/assets/editor-extensions/typecad-ui/package.json +54 -0
- package/assets/editor-extensions/typecad-ui/snippets/typecad-ui.json +80 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/markdown-ui.json +45 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/typecad-ui.tmLanguage.json +1269 -0
- package/dist/api/config.d.ts +30 -27
- package/dist/api/schema/types.d.ts +20 -3
- package/dist/api/shared/async-runtime-static.d.ts +1 -1
- package/dist/api/shared/async-runtime-static.js +5 -5
- package/dist/api/shared/async-types.d.ts +3 -2
- package/dist/api/shared/board-catalog.d.ts +2 -0
- package/dist/api/shared/board-catalog.js +6 -0
- package/dist/api/shared/board-resolver.d.ts +4 -7
- package/dist/api/shared/board-resolver.js +2 -1
- package/dist/api/shared/coop-scheduler.d.ts +1 -1
- package/dist/api/shared/coop-scheduler.js +1 -1
- package/dist/api/shared/cpp-type-ir.d.ts +1 -1
- package/dist/api/shared/cpp-type-ir.js +1 -1
- package/dist/api/shared/display-profile.d.ts +1 -1
- package/dist/api/shared/display-profile.js +3 -5
- package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
- package/dist/api/shared/framework-manifest-registry.js +0 -1
- package/dist/api/shared/framework-manifest.d.ts +65 -507
- package/dist/api/shared/framework-manifest.js +6 -11
- package/dist/api/shared/hal-op-ir.d.ts +294 -685
- package/dist/api/shared/hal-op-ir.js +31 -65
- package/dist/api/shared/index.d.ts +0 -4
- package/dist/api/shared/index.js +1 -7
- package/dist/api/shared/ir-core.d.ts +6 -0
- package/dist/api/shared/ir-declarations.d.ts +4 -0
- package/dist/api/shared/ir.d.ts +1 -3
- package/dist/api/shared/platform-strategy.d.ts +14 -37
- package/dist/api/shared/polyfill-helper-registry.js +0 -5
- package/dist/api/shared/polyfill-types.js +0 -27
- package/dist/api/shared/promise-runtime.js +3 -3
- package/dist/api/shared/spdx-licenses.d.ts +12 -10
- package/dist/api/shared/spdx-licenses.js +1 -1
- package/dist/api/shared/toolchain-types.d.ts +1 -1
- package/dist/api/shared/toolchain-types.js +3 -3
- package/dist/api/shared/types.d.ts +0 -3
- package/dist/api/shared/validate-framework-manifest.js +13 -33
- package/dist/board-catalog/dts-reader.d.ts +220 -0
- package/dist/board-catalog/dts-reader.js +1052 -0
- package/dist/board-catalog/index.d.ts +11 -0
- package/dist/board-catalog/index.js +12 -0
- package/dist/board-catalog/pinconfig.d.ts +48 -0
- package/dist/board-catalog/pinconfig.js +263 -0
- package/dist/board-catalog/sdk.d.ts +82 -0
- package/dist/board-catalog/sdk.js +180 -0
- package/dist/board-catalog/store.d.ts +196 -0
- package/dist/board-catalog/store.js +363 -0
- package/dist/board-catalog/types.d.ts +233 -0
- package/dist/board-catalog/types.js +7 -0
- package/dist/board-catalog/walker.d.ts +112 -0
- package/dist/board-catalog/walker.js +1101 -0
- package/dist/cli-utils.d.ts +2 -2
- package/dist/cli-utils.js +5 -5
- package/dist/cli.js +227 -244
- package/dist/config-loader.d.ts +14 -19
- package/dist/config-loader.js +242 -78
- package/dist/config-schema.d.ts +19 -227
- package/dist/config-schema.js +9 -8
- package/dist/contract/board-generator.d.ts +4 -4
- package/dist/contract/board-generator.js +16 -5
- package/dist/contract/contract-parser.d.ts +36 -127
- package/dist/contract/contract-parser.js +76 -0
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.js +70 -21
- package/dist/create/active-board-catalog.d.ts +9 -0
- package/dist/create/active-board-catalog.js +94 -0
- package/dist/create/board-catalog.generated.d.ts +96 -0
- package/dist/create/board-catalog.generated.js +128737 -0
- package/dist/create/board-search.d.ts +23 -0
- package/dist/create/board-search.js +88 -0
- package/dist/create/editor-integration.d.ts +32 -0
- package/dist/create/editor-integration.js +257 -0
- package/dist/create/eslint-rules-template.d.ts +2 -2
- package/dist/create/framework-catalog.d.ts +48 -8
- package/dist/create/framework-catalog.js +58 -44
- package/dist/create/index.d.ts +8 -13
- package/dist/create/index.js +5 -9
- package/dist/create/mcu-target.d.ts +39 -0
- package/dist/create/mcu-target.js +80 -0
- package/dist/create/pack-targets.d.ts +19 -0
- package/dist/create/pack-targets.js +56 -0
- package/dist/create/{init-scaffold.d.ts → scaffold.d.ts} +8 -11
- package/dist/create/{init-scaffold.js → scaffold.js} +28 -87
- package/dist/create/templates.d.ts +51 -0
- package/dist/create/{init-templates.js → templates.js} +135 -116
- package/dist/create/wizard.d.ts +19 -0
- package/dist/create/wizard.js +314 -0
- package/dist/debug/preprocessor.d.ts +5 -0
- package/dist/debug/preprocessor.js +31 -7
- package/dist/diagnostics/diagnostics-report.d.ts +1 -1
- package/dist/diagnostics/diagnostics-report.js +3 -11
- package/dist/diagnostics/json-schema.d.ts +1 -1
- package/dist/diagnostics/md-writer.js +2 -2
- package/dist/diagnostics/mermaid-builder.d.ts +1 -1
- package/dist/diagnostics/mermaid-builder.js +1 -1
- package/dist/emit/cpp-emitter.js +4 -1
- package/dist/emit/emitters/class-emitter.js +32 -4
- package/dist/emit/emitters/emitter-context.d.ts +11 -0
- package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
- package/dist/emit/emitters/function-emitter-impl.js +33 -17
- package/dist/emit/emitters/output-finalizer.d.ts +7 -0
- package/dist/emit/emitters/output-finalizer.js +31 -23
- package/dist/emit/emitters/setup.js +147 -63
- package/dist/emit/emitters/top-level-prep.js +1 -1
- package/dist/emit/emitters/type-decl-emitter.js +13 -8
- package/dist/emit/emitters/ui-emitter.js +1 -1
- package/dist/emit/expression-renderer.d.ts +3 -3
- package/dist/emit/expression-renderer.js +17 -7
- package/dist/emit/route-hal-op.js +17 -48
- package/dist/emit/snprintf-helpers.d.ts +1 -3
- package/dist/emit/snprintf-helpers.js +1 -39
- package/dist/emit/statement-renderer.d.ts +0 -4
- package/dist/emit/statement-renderer.js +54 -45
- package/dist/emit/utils/async-state-machine.d.ts +16 -9
- package/dist/emit/utils/async-state-machine.js +56 -54
- package/dist/emit/utils/comment-helpers.d.ts +0 -8
- package/dist/emit/utils/comment-helpers.js +1 -1
- package/dist/emit/utils/cpp-helpers.d.ts +2 -2
- package/dist/emit/utils/cpp-helpers.js +2 -2
- package/dist/emit/utils/hal-op-cpp-type.js +4 -6
- package/dist/emit/utils/index.d.ts +3 -3
- package/dist/emit/utils/index.js +3 -3
- package/dist/emit/utils/type-inference.d.ts +1 -29
- package/dist/emit/utils/type-inference.js +0 -75
- package/dist/framework-package.d.ts +3 -0
- package/dist/framework-package.js +23 -6
- package/dist/framework-registry.d.ts +5 -5
- package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
- package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
- package/dist/frameworks/native/index.d.ts +3 -0
- package/dist/frameworks/native/index.js +15 -0
- package/dist/frameworks/native/native-compile.d.ts +17 -0
- package/dist/frameworks/native/native-compile.js +170 -0
- package/dist/frameworks/native/native-config.d.ts +41 -0
- package/dist/frameworks/native/native-config.js +7 -0
- package/dist/frameworks/native/strategy.d.ts +97 -0
- package/dist/frameworks/native/strategy.js +664 -0
- package/dist/ir/board-resolver.d.ts +18 -23
- package/dist/ir/board-resolver.js +43 -401
- package/dist/ir/build-ir-state.d.ts +3 -0
- package/dist/ir/build-ir-state.js +42 -0
- package/dist/ir/build-ir.d.ts +1 -1
- package/dist/ir/build-ir.js +64 -45
- package/dist/ir/declaration-builders.js +1 -0
- package/dist/ir/expression-to-ir.js +17 -10
- package/dist/ir/hal/hal-emitter.d.ts +0 -2
- package/dist/ir/hal/hal-emitter.js +92 -41
- package/dist/ir/hal/hal-parser.d.ts +5 -5
- package/dist/ir/hal/hal-parser.js +128 -36
- package/dist/ir/hal/hal-plugins.d.ts +0 -1
- package/dist/ir/hal/hal-plugins.js +425 -716
- package/dist/ir/heap-analysis.js +2 -41
- package/dist/ir/identifier-collector.js +32 -20
- package/dist/ir/network-validation.js +7 -11
- package/dist/ir/ownership-analysis.js +75 -13
- package/dist/ir/peripheral-usage.d.ts +8 -2
- package/dist/ir/peripheral-usage.js +78 -149
- package/dist/ir/peripheral-validation.js +23 -3
- package/dist/ir/pin-capability-validation.d.ts +12 -0
- package/dist/ir/pin-capability-validation.js +61 -97
- package/dist/ir/pin-mode-validation.js +5 -5
- package/dist/ir/program-analysis.d.ts +8 -15
- package/dist/ir/program-analysis.js +140 -323
- package/dist/ir/pulldown-validation.js +11 -4
- package/dist/ir/resource-analysis.js +15 -3
- package/dist/ir/statement-to-ir.js +0 -6
- package/dist/ir/timing-validation.js +1 -1
- package/dist/ir/transformers/array-methods.js +11 -5
- package/dist/ir/transformers/call-statement.js +20 -87
- package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
- package/dist/ir/transformers/callback-context-registry.js +8 -16
- package/dist/ir/transformers/control-flow.js +0 -13
- package/dist/ir/transformers/expressions.js +10 -9
- package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
- package/dist/ir/transformers/hal-call-resolver.js +24 -10
- package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
- package/dist/ir/transformers/hal-emit-helpers.js +2 -2
- package/dist/ir/transformers/namespace-methods.js +1 -1
- package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
- package/dist/ir/transformers/ui-callback-lowering.js +0 -24
- package/dist/ir/transformers/variables.js +338 -42
- package/dist/ir/try-catch-validation.js +4 -3
- package/dist/ir/type-resolution.js +15 -4
- package/dist/ir/validation-orchestrator.js +0 -9
- package/dist/libdef/cpp-to-decl.d.ts +0 -9
- package/dist/libdef/cpp-to-decl.js +0 -72
- package/dist/libdef/registry.d.ts +0 -1
- package/dist/libdef/registry.js +1 -24
- package/dist/library/catalog.d.ts +35 -0
- package/dist/library/catalog.js +67 -0
- package/dist/library/cli.d.ts +2 -0
- package/dist/library/cli.js +168 -0
- package/dist/library/init.d.ts +25 -0
- package/dist/library/init.js +397 -0
- package/dist/library/install.d.ts +9 -0
- package/dist/library/install.js +80 -0
- package/dist/library/registry-search.d.ts +34 -0
- package/dist/library/registry-search.js +50 -0
- package/dist/library/validate.d.ts +17 -0
- package/dist/library/validate.js +175 -0
- package/dist/library-packages.d.ts +95 -0
- package/dist/library-packages.js +275 -0
- package/dist/mapping/peripheral-names.js +9 -4
- package/dist/mapping/source-map.d.ts +3 -4
- package/dist/mapping/source-map.js +12 -18
- package/dist/orchestrator/graph-builder.d.ts +3 -3
- package/dist/orchestrator/graph-builder.js +29 -12
- package/dist/orchestrator/type-checker.d.ts +3 -3
- package/dist/orchestrator/type-checker.js +3 -3
- package/dist/platform/async-runtime.js +1 -1
- package/dist/platform/coop-scheduler-runtime.js +2 -2
- package/dist/platform/generic-debug-codegen.d.ts +36 -0
- package/dist/platform/generic-debug-codegen.js +185 -0
- package/dist/platform/generic-strategy.d.ts +3 -4
- package/dist/platform/generic-strategy.js +5 -80
- package/dist/platform/index.js +1 -1
- package/dist/platform/registry.d.ts +2 -2
- package/dist/platform/registry.js +2 -2
- package/dist/preview/client.js +17 -3
- package/dist/safety/asil-decorators.d.ts +32 -0
- package/dist/safety/asil-decorators.js +32 -0
- package/dist/safety/authoring.d.ts +85 -0
- package/dist/safety/authoring.js +61 -0
- package/dist/safety/engine.d.ts +3 -0
- package/dist/safety/engine.js +83 -0
- package/dist/safety/hal/ops.d.ts +48 -0
- package/dist/safety/hal/ops.js +46 -0
- package/dist/safety/iso26262/analyze.d.ts +13 -0
- package/dist/safety/iso26262/analyze.js +29 -0
- package/dist/safety/iso26262/asil.d.ts +10 -0
- package/dist/safety/iso26262/asil.js +22 -0
- package/dist/safety/iso26262/collect.d.ts +14 -0
- package/dist/safety/iso26262/collect.js +137 -0
- package/dist/safety/iso26262/goto-checker.d.ts +10 -0
- package/dist/safety/iso26262/goto-checker.js +72 -0
- package/dist/safety/iso26262/heap-checker.d.ts +7 -0
- package/dist/safety/iso26262/heap-checker.js +57 -0
- package/dist/safety/iso26262/init-checker.d.ts +13 -0
- package/dist/safety/iso26262/init-checker.js +127 -0
- package/dist/safety/iso26262/loop-checker.d.ts +7 -0
- package/dist/safety/iso26262/loop-checker.js +86 -0
- package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
- package/dist/safety/iso26262/recursion-checker.js +134 -0
- package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
- package/dist/safety/iso26262/sidecar-writer.js +13 -0
- package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
- package/dist/safety/passes/pinMode-intercept.js +60 -0
- package/dist/safety/runtime/mode-table.d.ts +5 -0
- package/dist/safety/runtime/mode-table.js +55 -0
- package/dist/safety/runtime/polyfills.d.ts +6 -0
- package/dist/safety/runtime/polyfills.js +12 -0
- package/dist/safety/runtime/result-struct.d.ts +11 -0
- package/dist/safety/runtime/result-struct.js +98 -0
- package/dist/safety/runtime/safe-int.d.ts +33 -0
- package/dist/safety/runtime/safe-int.js +170 -0
- package/dist/safety/runtime/safe-traits.d.ts +4 -0
- package/dist/safety/runtime/safe-traits.js +95 -0
- package/dist/safety/runtime/safe-variable.d.ts +39 -0
- package/dist/safety/runtime/safe-variable.js +226 -0
- package/dist/safety/runtime/vote.d.ts +8 -0
- package/dist/safety/runtime/vote.js +92 -0
- package/dist/safety/runtime/write-verify.d.ts +8 -0
- package/dist/safety/runtime/write-verify.js +71 -0
- package/dist/safety/safe-int-types.d.ts +45 -0
- package/dist/safety/safe-int-types.js +25 -0
- package/dist/safety/safe-variable-types.d.ts +29 -0
- package/dist/safety/safe-variable-types.js +19 -0
- package/dist/safety/safety-bridge.d.ts +5 -6
- package/dist/safety/safety-bridge.js +15 -28
- package/dist/safety/sidecar-bridge.d.ts +1 -3
- package/dist/safety/sidecar-bridge.js +3 -20
- package/dist/safety/specifiers.d.ts +6 -0
- package/dist/safety/specifiers.js +14 -0
- package/dist/safety-hook.d.ts +8 -7
- package/dist/safety-hook.js +12 -13
- package/dist/testing.d.ts +5 -6
- package/dist/testing.js +5 -5
- package/dist/transpile/resolution.d.ts +1 -1
- package/dist/transpile/resolution.js +18 -9
- package/dist/transpile/test-pins.d.ts +18 -0
- package/dist/transpile/test-pins.js +142 -0
- package/dist/transpile.d.ts +1 -2
- package/dist/transpile.js +90 -29
- package/dist/types.d.ts +45 -26
- package/dist/ui-hook.d.ts +1 -1
- package/dist/utils/cli.d.ts +2 -2
- package/dist/utils/cli.js +160 -157
- package/dist/utils/fs.d.ts +3 -4
- package/dist/utils/fs.js +4 -5
- package/dist/utils/strings.d.ts +0 -1
- package/dist/utils/strings.js +0 -8
- package/dist/utils/ui.d.ts +5 -2
- package/dist/utils/ui.js +13 -3
- package/package.json +158 -149
- package/dist/add-preset.d.ts +0 -4
- package/dist/add-preset.js +0 -74
- package/dist/api/shared/async-symbol-detector.d.ts +0 -11
- package/dist/api/shared/async-symbol-detector.js +0 -140
- package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
- package/dist/api/shared/native-display-op-resolver.js +0 -64
- package/dist/create/board-checklist.d.ts +0 -2
- package/dist/create/board-checklist.js +0 -52
- package/dist/create/board-codegen.d.ts +0 -9
- package/dist/create/board-codegen.js +0 -238
- package/dist/create/board-generators.d.ts +0 -12
- package/dist/create/board-generators.js +0 -651
- package/dist/create/board-spec.d.ts +0 -637
- package/dist/create/board-spec.js +0 -214
- package/dist/create/init-templates.d.ts +0 -28
- package/dist/create/init-wizard.d.ts +0 -8
- package/dist/create/init-wizard.js +0 -182
- package/dist/install/framework-catalog.d.ts +0 -53
- package/dist/install/framework-catalog.js +0 -107
- package/dist/install/handle-install.d.ts +0 -35
- package/dist/install/handle-install.js +0 -177
- package/dist/install/index.d.ts +0 -4
- package/dist/install/index.js +0 -3
- package/dist/ir/pin-state-tracking.d.ts +0 -58
- package/dist/ir/pin-state-tracking.js +0 -182
- package/dist/ir/pwm-timer-sharing.d.ts +0 -4
- package/dist/ir/pwm-timer-sharing.js +0 -94
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
- package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
- package/dist/libdef/component-decls.d.ts +0 -2
- package/dist/libdef/component-decls.js +0 -6
- package/dist/libdef/component-discovery.d.ts +0 -43
- package/dist/libdef/component-discovery.js +0 -83
- package/dist/theme-tokens.d.ts +0 -22
- package/dist/theme-tokens.js +0 -172
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
// `cuttlefish install` — installs a chosen @typecad/framework-* package into the
|
|
2
|
-
// current project. The flow asks which board to target first, then narrows the
|
|
3
|
-
// framework choices to those compatible with that board (see framework-catalog).
|
|
4
|
-
// A framework id may be passed directly (`cuttlefish install arduino`) to skip
|
|
5
|
-
// the prompts entirely, which also makes the command usable in CI.
|
|
6
|
-
import * as readline from "node:readline/promises";
|
|
7
|
-
import { stdin as input, stdout as output } from "node:process";
|
|
8
|
-
import { spawnSync } from "node:child_process";
|
|
9
|
-
import chalk from "chalk";
|
|
10
|
-
import { KNOWN_TARGETS } from "../create/index.js";
|
|
11
|
-
import { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
|
|
12
|
-
// ── prompts (mirror the create wizard's style for a consistent UX) ──────────
|
|
13
|
-
async function promptSelect(rl, prompt, options) {
|
|
14
|
-
console.log(`${chalk.cyan("?")} ${prompt}:`);
|
|
15
|
-
for (let i = 0; i < options.length; i++) {
|
|
16
|
-
console.log(` ${chalk.dim(`${i + 1})`)} ${options[i].label}`);
|
|
17
|
-
}
|
|
18
|
-
while (true) {
|
|
19
|
-
const answer = await rl.question(` Enter number (1-${options.length}): `);
|
|
20
|
-
const idx = parseInt(answer.trim(), 10) - 1;
|
|
21
|
-
if (idx >= 0 && idx < options.length) {
|
|
22
|
-
return options[idx].value;
|
|
23
|
-
}
|
|
24
|
-
console.log(` ${chalk.red("✗")} Please enter a number between 1 and ${options.length}.`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
async function selectBoardInteractively(rl) {
|
|
28
|
-
const options = KNOWN_TARGETS.map((t) => ({
|
|
29
|
-
label: t.isNative
|
|
30
|
-
? `${t.displayName} (Windows/Linux executable)`
|
|
31
|
-
: `${t.displayName} (${t.architecture.toUpperCase()})`,
|
|
32
|
-
value: t.id,
|
|
33
|
-
}));
|
|
34
|
-
const selectedId = await promptSelect(rl, "Target board", options);
|
|
35
|
-
return KNOWN_TARGETS.find((t) => t.id === selectedId);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Pick a framework for `target`. When only one framework is compatible with the
|
|
39
|
-
* board it is auto-selected (mirrors the create wizard's single-option path) so
|
|
40
|
-
* the user isn't asked a question with one answer.
|
|
41
|
-
*/
|
|
42
|
-
async function selectFrameworkInteractively(rl, target, compatible) {
|
|
43
|
-
if (compatible.length === 1) {
|
|
44
|
-
const only = compatible[0];
|
|
45
|
-
console.log(`${chalk.cyan("?")} Framework: ${chalk.white(only.label)} ${chalk.dim(`(only option for ${target.id})`)}`);
|
|
46
|
-
return only;
|
|
47
|
-
}
|
|
48
|
-
const selectedId = await promptSelect(rl, "Framework", compatible.map((f) => ({ label: f.label, value: f.id })));
|
|
49
|
-
return compatible.find((f) => f.id === selectedId);
|
|
50
|
-
}
|
|
51
|
-
let testRunner;
|
|
52
|
-
/**
|
|
53
|
-
* FOR TESTS ONLY. Replaces the real spawn-based installer with `runner`.
|
|
54
|
-
* Pass `undefined` to restore the real executor.
|
|
55
|
-
*/
|
|
56
|
-
export function __setInstallRunnerForTest(runner) {
|
|
57
|
-
testRunner = runner;
|
|
58
|
-
}
|
|
59
|
-
function runRealInstall(cmd) {
|
|
60
|
-
// stdio: "inherit" streams the package manager's own output to the terminal
|
|
61
|
-
// (install progress, deprecation warnings, etc.). On failure the user has
|
|
62
|
-
// already seen the details above, so we only need to report the exit code.
|
|
63
|
-
const result = spawnSync(cmd.bin, cmd.args, {
|
|
64
|
-
cwd: cmd.cwd,
|
|
65
|
-
stdio: "inherit",
|
|
66
|
-
});
|
|
67
|
-
if (result.error) {
|
|
68
|
-
const errno = result.error.code;
|
|
69
|
-
return {
|
|
70
|
-
status: null,
|
|
71
|
-
launchError: errno === "ENOENT" ? `'${cmd.bin}' not found on PATH` : String(result.error),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
return { status: result.status };
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Resolve the package manager and run the install for `entry`'s package. In
|
|
78
|
-
* dry-run mode the command is printed but not executed. Throws on launch
|
|
79
|
-
* failure or non-zero exit so the CLI surfaces a clear error.
|
|
80
|
-
*/
|
|
81
|
-
export function installFrameworkPackage(entry, opts) {
|
|
82
|
-
const pm = detectPackageManager(opts.cwd);
|
|
83
|
-
const { bin, args } = buildInstallCommand(pm, entry.packageName);
|
|
84
|
-
if (opts.dryRun) {
|
|
85
|
-
console.log(`${chalk.cyan("$")} ${bin} ${args.join(" ")}`);
|
|
86
|
-
return { pm, bin, args };
|
|
87
|
-
}
|
|
88
|
-
const cmd = { bin, args, cwd: opts.cwd };
|
|
89
|
-
const run = testRunner ?? runRealInstall;
|
|
90
|
-
const result = run(cmd);
|
|
91
|
-
if (result.launchError) {
|
|
92
|
-
throw new Error(`Failed to run '${bin}': ${result.launchError}`);
|
|
93
|
-
}
|
|
94
|
-
if (result.status !== 0) {
|
|
95
|
-
throw new Error(`'${bin} ${args.join(" ")}' exited with code ${result.status}. See the package manager output above for details.`);
|
|
96
|
-
}
|
|
97
|
-
return { pm, bin, args };
|
|
98
|
-
}
|
|
99
|
-
// ── command entry point ─────────────────────────────────────────────────────
|
|
100
|
-
export async function handleInstall(options) {
|
|
101
|
-
const cwd = process.cwd();
|
|
102
|
-
// 1. Resolve which framework to install.
|
|
103
|
-
let entry;
|
|
104
|
-
if (options.framework) {
|
|
105
|
-
const resolved = frameworkCatalogEntry(options.framework);
|
|
106
|
-
if (!resolved) {
|
|
107
|
-
const available = FRAMEWORK_CATALOG.filter((f) => f.installable).map((f) => f.id).join(", ");
|
|
108
|
-
throw new Error(`Unknown framework '${options.framework}'. Available: ${available}`);
|
|
109
|
-
}
|
|
110
|
-
if (!resolved.installable) {
|
|
111
|
-
throw new Error(`Framework '${options.framework}' has no published package yet and cannot be installed.`);
|
|
112
|
-
}
|
|
113
|
-
entry = resolved;
|
|
114
|
-
console.log(`${chalk.cyan("?")} Framework: ${chalk.white(entry.label)}`);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// Resolve the target board. --board skips the board prompt; otherwise the
|
|
118
|
-
// board is chosen interactively (which requires a TTY — handled below).
|
|
119
|
-
let target;
|
|
120
|
-
if (options.board) {
|
|
121
|
-
const found = KNOWN_TARGETS.find((t) => t.id === options.board);
|
|
122
|
-
if (!found) {
|
|
123
|
-
const available = KNOWN_TARGETS.map((t) => t.id).join(", ");
|
|
124
|
-
throw new Error(`Unknown board '${options.board}'. Available: ${available}`);
|
|
125
|
-
}
|
|
126
|
-
target = found;
|
|
127
|
-
console.log(`${chalk.cyan("?")} Board: ${chalk.white(target.displayName)} (${chalk.dim(target.id)})`);
|
|
128
|
-
}
|
|
129
|
-
// Narrow to the frameworks compatible with that board.
|
|
130
|
-
let compatible;
|
|
131
|
-
if (target) {
|
|
132
|
-
compatible = frameworksForTarget(target).filter((f) => f.installable);
|
|
133
|
-
if (compatible.length === 0) {
|
|
134
|
-
throw new Error(`No installable frameworks are compatible with board '${target.id}'.`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (compatible && compatible.length === 1) {
|
|
138
|
-
// Only one framework fits this board — auto-select it (no prompt, so this
|
|
139
|
-
// path also works under CI / non-interactive stdin).
|
|
140
|
-
entry = compatible[0];
|
|
141
|
-
console.log(`${chalk.cyan("?")} Framework: ${chalk.white(entry.label)} ${chalk.dim(`(only option for ${target.id})`)}`);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
// Need to prompt — for the board (if --board wasn't given) and/or for the
|
|
145
|
-
// framework (when 2+ are compatible). Refuse to hang on a readline that
|
|
146
|
-
// can't be answered (e.g. piped stdin under CI).
|
|
147
|
-
if (!process.stdin.isTTY) {
|
|
148
|
-
throw new Error("No framework specified and stdin is not interactive. " +
|
|
149
|
-
"Pass a framework id (e.g. 'cuttlefish install arduino'), " +
|
|
150
|
-
"or a board with a single compatible framework (e.g. '--board arduino-uno').");
|
|
151
|
-
}
|
|
152
|
-
const rl = readline.createInterface({ input, output });
|
|
153
|
-
try {
|
|
154
|
-
if (!target) {
|
|
155
|
-
target = await selectBoardInteractively(rl);
|
|
156
|
-
compatible = frameworksForTarget(target).filter((f) => f.installable);
|
|
157
|
-
if (compatible.length === 0) {
|
|
158
|
-
throw new Error(`No installable frameworks are compatible with board '${target.id}'.`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
entry = await selectFrameworkInteractively(rl, target, compatible);
|
|
162
|
-
}
|
|
163
|
-
finally {
|
|
164
|
-
rl.close();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
// 2. Install it.
|
|
169
|
-
console.log(`\n${chalk.cyan("⤳")} Installing ${chalk.white(entry.packageName)} into ${chalk.dim(cwd)}…`);
|
|
170
|
-
const result = installFrameworkPackage(entry, { cwd, dryRun: options.dryRun });
|
|
171
|
-
if (options.dryRun) {
|
|
172
|
-
console.log(chalk.dim("(dry-run — nothing was installed)"));
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
console.log(`\n${chalk.green("✓")} Installed ${chalk.white(entry.packageName)} via ${result.pm}.`);
|
|
176
|
-
console.log(chalk.dim(`Next: run 'cuttlefish create' and pick ${entry.id}, or set framework: "${entry.packageName}" in cuttlefish.config.ts.`));
|
|
177
|
-
}
|
package/dist/install/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { handleInstall, installFrameworkPackage, __setInstallRunnerForTest } from "./handle-install.js";
|
|
2
|
-
export type { InstallResult } from "./handle-install.js";
|
|
3
|
-
export { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
|
|
4
|
-
export type { FrameworkCatalogEntry, BoardLike, PackageManager, } from "./framework-catalog.js";
|
package/dist/install/index.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// `cuttlefish install` command — install a @typecad/framework-* package.
|
|
2
|
-
export { handleInstall, installFrameworkPackage, __setInstallRunnerForTest } from "./handle-install.js";
|
|
3
|
-
export { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { ProgramIR } from "../api/index.js";
|
|
2
|
-
export type TrackedPinLevel = 'high' | 'low' | 'unknown';
|
|
3
|
-
/** C++ identifier for a pin's shadow state variable. */
|
|
4
|
-
export declare function pinShadowVarName(pin: number): string;
|
|
5
|
-
export declare function resetPinStateTracking(): void;
|
|
6
|
-
/** Record gpio.set_mode — OUTPUT* modes enable tracking, anything else ends it. */
|
|
7
|
-
export declare function notePinSetMode(pin: number, mode: string | null): void;
|
|
8
|
-
/** Record gpio.write — literal values set the level; expressions make it unknown. */
|
|
9
|
-
export declare function notePinWrite(pin: number, literalValue: number | boolean | null): void;
|
|
10
|
-
/** Record gpio.toggle — inverts a known level, keeps unknown as unknown. */
|
|
11
|
-
export declare function notePinToggle(pin: number): void;
|
|
12
|
-
/**
|
|
13
|
-
* Record PWM/tone output — the pin no longer has a digital level, so any
|
|
14
|
-
* tracked level goes unknown (reads must not fold to the pre-PWM literal).
|
|
15
|
-
* A later digital write/toggle restores digital tracking.
|
|
16
|
-
*/
|
|
17
|
-
export declare function notePinAnalogOutput(pin: number): void;
|
|
18
|
-
/**
|
|
19
|
-
* Resolve a read on a pin at the current program point.
|
|
20
|
-
* Returns 'high'/'low' when the level folds to a constant, 'shadow' when a
|
|
21
|
-
* shadow variable must carry it, or null when the pin is not a tracked
|
|
22
|
-
* output pin (unconfigured or input mode → normal hardware read lowering).
|
|
23
|
-
*/
|
|
24
|
-
export declare function resolveTrackedRead(pin: number): 'high' | 'low' | 'shadow' | null;
|
|
25
|
-
/** Whether write/toggle ops on this pin must also update its shadow variable. */
|
|
26
|
-
export declare function isShadowPin(pin: number): boolean;
|
|
27
|
-
/** Consume the shadow declarations owed by this build (pin + initializer).
|
|
28
|
-
* Clears the shadow set: emit reads the updatesShadow flags baked into the
|
|
29
|
-
* ops below, never this module's live state (each file's build resets the
|
|
30
|
-
* tracker, and all files finish building before any emit runs). */
|
|
31
|
-
export declare function takeShadowDeclarations(): {
|
|
32
|
-
pin: number;
|
|
33
|
-
initial: boolean;
|
|
34
|
-
}[];
|
|
35
|
-
/** Mark every gpio.write / gpio.toggle op in the program whose pin has a
|
|
36
|
-
* tracked shadow read, so the emitter appends the shadow-variable update.
|
|
37
|
-
* Runs once at the end of buildProgramIR, after the whole file is lowered —
|
|
38
|
-
* at that point the shadow set is final, so writes that were lowered BEFORE
|
|
39
|
-
* the first shadow read are marked too (their ops are already in the IR).
|
|
40
|
-
* This is what makes emit independent of tracker state across files. */
|
|
41
|
-
export declare function markShadowUpdatingOps(program: ProgramIR): void;
|
|
42
|
-
export type PinLevelSnapshot = Map<number, TrackedPinLevel>;
|
|
43
|
-
export declare function snapshotPinLevels(): PinLevelSnapshot;
|
|
44
|
-
export declare function restorePinLevels(snapshot: PinLevelSnapshot): void;
|
|
45
|
-
/**
|
|
46
|
-
* Merge two branch-end states into the live state: pins that agree keep
|
|
47
|
-
* their level; pins that differ (or exist in only one branch) become
|
|
48
|
-
* unknown. Pass the pre-branch state as one side when there is no else
|
|
49
|
-
* branch, so pins written in the taken branch invalidate.
|
|
50
|
-
*/
|
|
51
|
-
export declare function mergePinLevels(a: PinLevelSnapshot, b: PinLevelSnapshot): void;
|
|
52
|
-
/** Invalidate all known levels (after loop/switch bodies, which may run any
|
|
53
|
-
* number of times). Shadow tracking is unaffected — it is runtime truth. */
|
|
54
|
-
export declare function invalidatePinLevels(): void;
|
|
55
|
-
/** Disable/enable constant folding around function and callback bodies. */
|
|
56
|
-
export declare function setPinFoldingEnabled(enabled: boolean): void;
|
|
57
|
-
/** Whether pin-level constant folding is currently allowed. */
|
|
58
|
-
export declare function isPinFoldingEnabled(): boolean;
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Output Pin State Tracking
|
|
3
|
-
//
|
|
4
|
-
// Tracks the driven level of pins configured as OUTPUT so that
|
|
5
|
-
// OutputPin.read()/isHigh()/isLow() can be answered without a hardware pin
|
|
6
|
-
// read. Reading back an OUTPUT-only pin is not portable (Zephyr's
|
|
7
|
-
// gpio_pin_get reads the input latch, which is undefined for direction-only
|
|
8
|
-
// outputs), so the transpiler instead maintains the state itself:
|
|
9
|
-
//
|
|
10
|
-
// - When the level is statically known at the read site (asOutput(false)
|
|
11
|
-
// followed by literal high/low/write/toggle calls), the read folds to a
|
|
12
|
-
// compile-time constant.
|
|
13
|
-
// - When it is not (runtime-valued writes, loops, branches, function
|
|
14
|
-
// bodies), the read lowers to a shadow variable (`__tc_pin_state_<n>`)
|
|
15
|
-
// that every generated write/toggle on that pin keeps updated.
|
|
16
|
-
//
|
|
17
|
-
// The tracker is updated in program order during IR lowering (the same pass
|
|
18
|
-
// that resolves HAL method bodies), so the state seen at each read site is
|
|
19
|
-
// the state at that point in the source. Control-flow joins and loop bodies
|
|
20
|
-
// conservatively invalidate levels (see control-flow.ts hooks); function and
|
|
21
|
-
// callback bodies disable folding entirely and force the shadow form.
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
import { walkProgramIR, walkExpressions } from "./utils/walk-ir.js";
|
|
24
|
-
/** Pin numbers explicitly configured as OUTPUT via gpio.set_mode. */
|
|
25
|
-
const outputPins = new Set();
|
|
26
|
-
/** Last driven level per output pin, at the current program point. */
|
|
27
|
-
const pinLevels = new Map();
|
|
28
|
-
/** Output pins whose reads lowered to the shadow variable form. */
|
|
29
|
-
const shadowPins = new Set();
|
|
30
|
-
/** Initializer for each shadow variable: the statically-known level at the
|
|
31
|
-
* time the first shadow read was resolved, or `false` when unknown. */
|
|
32
|
-
const shadowInitial = new Map();
|
|
33
|
-
/** Folding is disabled inside function/callback bodies, where the top-level
|
|
34
|
-
* program-point state does not apply at runtime. */
|
|
35
|
-
let foldingEnabled = true;
|
|
36
|
-
/** C++ identifier for a pin's shadow state variable. */
|
|
37
|
-
export function pinShadowVarName(pin) {
|
|
38
|
-
return `__tc_pin_state_${pin}`;
|
|
39
|
-
}
|
|
40
|
-
export function resetPinStateTracking() {
|
|
41
|
-
outputPins.clear();
|
|
42
|
-
pinLevels.clear();
|
|
43
|
-
shadowPins.clear();
|
|
44
|
-
shadowInitial.clear();
|
|
45
|
-
foldingEnabled = true;
|
|
46
|
-
}
|
|
47
|
-
/** Record gpio.set_mode — OUTPUT* modes enable tracking, anything else ends it. */
|
|
48
|
-
export function notePinSetMode(pin, mode) {
|
|
49
|
-
const isOutput = mode !== null && /output/i.test(mode);
|
|
50
|
-
if (isOutput) {
|
|
51
|
-
outputPins.add(pin);
|
|
52
|
-
pinLevels.set(pin, 'unknown');
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
outputPins.delete(pin);
|
|
56
|
-
pinLevels.delete(pin);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/** Record gpio.write — literal values set the level; expressions make it unknown. */
|
|
60
|
-
export function notePinWrite(pin, literalValue) {
|
|
61
|
-
if (!outputPins.has(pin))
|
|
62
|
-
return;
|
|
63
|
-
pinLevels.set(pin, literalValue === null ? 'unknown' : (literalValue ? 'high' : 'low'));
|
|
64
|
-
}
|
|
65
|
-
/** Record gpio.toggle — inverts a known level, keeps unknown as unknown. */
|
|
66
|
-
export function notePinToggle(pin) {
|
|
67
|
-
if (!outputPins.has(pin))
|
|
68
|
-
return;
|
|
69
|
-
const level = pinLevels.get(pin);
|
|
70
|
-
if (level === 'high')
|
|
71
|
-
pinLevels.set(pin, 'low');
|
|
72
|
-
else if (level === 'low')
|
|
73
|
-
pinLevels.set(pin, 'high');
|
|
74
|
-
else
|
|
75
|
-
pinLevels.set(pin, 'unknown');
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Record PWM/tone output — the pin no longer has a digital level, so any
|
|
79
|
-
* tracked level goes unknown (reads must not fold to the pre-PWM literal).
|
|
80
|
-
* A later digital write/toggle restores digital tracking.
|
|
81
|
-
*/
|
|
82
|
-
export function notePinAnalogOutput(pin) {
|
|
83
|
-
if (!outputPins.has(pin))
|
|
84
|
-
return;
|
|
85
|
-
pinLevels.set(pin, 'unknown');
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Resolve a read on a pin at the current program point.
|
|
89
|
-
* Returns 'high'/'low' when the level folds to a constant, 'shadow' when a
|
|
90
|
-
* shadow variable must carry it, or null when the pin is not a tracked
|
|
91
|
-
* output pin (unconfigured or input mode → normal hardware read lowering).
|
|
92
|
-
*/
|
|
93
|
-
export function resolveTrackedRead(pin) {
|
|
94
|
-
if (!outputPins.has(pin))
|
|
95
|
-
return null;
|
|
96
|
-
const level = pinLevels.get(pin);
|
|
97
|
-
if (foldingEnabled && (level === 'high' || level === 'low'))
|
|
98
|
-
return level;
|
|
99
|
-
shadowPins.add(pin);
|
|
100
|
-
if (!shadowInitial.has(pin))
|
|
101
|
-
shadowInitial.set(pin, level === 'high');
|
|
102
|
-
return 'shadow';
|
|
103
|
-
}
|
|
104
|
-
/** Whether write/toggle ops on this pin must also update its shadow variable. */
|
|
105
|
-
export function isShadowPin(pin) {
|
|
106
|
-
return shadowPins.has(pin);
|
|
107
|
-
}
|
|
108
|
-
/** Consume the shadow declarations owed by this build (pin + initializer).
|
|
109
|
-
* Clears the shadow set: emit reads the updatesShadow flags baked into the
|
|
110
|
-
* ops below, never this module's live state (each file's build resets the
|
|
111
|
-
* tracker, and all files finish building before any emit runs). */
|
|
112
|
-
export function takeShadowDeclarations() {
|
|
113
|
-
const decls = [...shadowPins].sort((a, b) => a - b).map(pin => ({
|
|
114
|
-
pin,
|
|
115
|
-
initial: shadowInitial.get(pin) ?? false,
|
|
116
|
-
}));
|
|
117
|
-
shadowPins.clear();
|
|
118
|
-
shadowInitial.clear();
|
|
119
|
-
return decls;
|
|
120
|
-
}
|
|
121
|
-
/** Mark every gpio.write / gpio.toggle op in the program whose pin has a
|
|
122
|
-
* tracked shadow read, so the emitter appends the shadow-variable update.
|
|
123
|
-
* Runs once at the end of buildProgramIR, after the whole file is lowered —
|
|
124
|
-
* at that point the shadow set is final, so writes that were lowered BEFORE
|
|
125
|
-
* the first shadow read are marked too (their ops are already in the IR).
|
|
126
|
-
* This is what makes emit independent of tracker state across files. */
|
|
127
|
-
export function markShadowUpdatingOps(program) {
|
|
128
|
-
if (shadowPins.size === 0)
|
|
129
|
-
return;
|
|
130
|
-
const markOp = (op) => {
|
|
131
|
-
const halOp = op;
|
|
132
|
-
if (!halOp)
|
|
133
|
-
return;
|
|
134
|
-
if ((halOp.operation === "gpio.write" || halOp.operation === "gpio.toggle") && isShadowPin(halOp.pin)) {
|
|
135
|
-
halOp.updatesShadow = true;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
walkProgramIR(program, (stmt) => {
|
|
139
|
-
if (stmt.kind === "hal-op")
|
|
140
|
-
markOp(stmt.operation);
|
|
141
|
-
walkExpressions([stmt], (expr) => {
|
|
142
|
-
if (expr.kind === "hal-expr")
|
|
143
|
-
markOp(expr.operation);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
export function snapshotPinLevels() {
|
|
148
|
-
return new Map(pinLevels);
|
|
149
|
-
}
|
|
150
|
-
export function restorePinLevels(snapshot) {
|
|
151
|
-
pinLevels.clear();
|
|
152
|
-
for (const [pin, level] of snapshot)
|
|
153
|
-
pinLevels.set(pin, level);
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Merge two branch-end states into the live state: pins that agree keep
|
|
157
|
-
* their level; pins that differ (or exist in only one branch) become
|
|
158
|
-
* unknown. Pass the pre-branch state as one side when there is no else
|
|
159
|
-
* branch, so pins written in the taken branch invalidate.
|
|
160
|
-
*/
|
|
161
|
-
export function mergePinLevels(a, b) {
|
|
162
|
-
const pins = new Set([...a.keys(), ...b.keys()]);
|
|
163
|
-
for (const pin of pins) {
|
|
164
|
-
const la = a.get(pin) ?? 'unknown';
|
|
165
|
-
const lb = b.get(pin) ?? 'unknown';
|
|
166
|
-
pinLevels.set(pin, la === lb ? la : 'unknown');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/** Invalidate all known levels (after loop/switch bodies, which may run any
|
|
170
|
-
* number of times). Shadow tracking is unaffected — it is runtime truth. */
|
|
171
|
-
export function invalidatePinLevels() {
|
|
172
|
-
for (const pin of outputPins)
|
|
173
|
-
pinLevels.set(pin, 'unknown');
|
|
174
|
-
}
|
|
175
|
-
/** Disable/enable constant folding around function and callback bodies. */
|
|
176
|
-
export function setPinFoldingEnabled(enabled) {
|
|
177
|
-
foldingEnabled = enabled;
|
|
178
|
-
}
|
|
179
|
-
/** Whether pin-level constant folding is currently allowed. */
|
|
180
|
-
export function isPinFoldingEnabled() {
|
|
181
|
-
return foldingEnabled;
|
|
182
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Diagnostic } from '../types.js';
|
|
2
|
-
import type { BoardConstants } from './board-resolver.js';
|
|
3
|
-
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
4
|
-
export declare function validatePWMTimerSharing(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { findBoardPinByName, formatPinReference } from './board-pin-utils.js';
|
|
2
|
-
function extractTimerId(role, timerField) {
|
|
3
|
-
// Prefer explicit timer field from board definition
|
|
4
|
-
if (timerField) {
|
|
5
|
-
return timerField;
|
|
6
|
-
}
|
|
7
|
-
if (!role) {
|
|
8
|
-
return undefined;
|
|
9
|
-
}
|
|
10
|
-
// Fall back to parsing AVR OC register naming convention
|
|
11
|
-
const match = role.match(/^OC(\d+)[A-Z]?$/i);
|
|
12
|
-
return match ? `timer${match[1]}` : undefined;
|
|
13
|
-
}
|
|
14
|
-
function getPwmTimerPins(boardConstants) {
|
|
15
|
-
if (!boardConstants) {
|
|
16
|
-
return [];
|
|
17
|
-
}
|
|
18
|
-
const pinsByIndex = new Map();
|
|
19
|
-
for (const [key, value] of boardConstants) {
|
|
20
|
-
const nameMatch = key.match(/^pins\.all\.(\d+)\.name$/);
|
|
21
|
-
if (nameMatch && typeof value === 'string') {
|
|
22
|
-
const pinIndex = nameMatch[1];
|
|
23
|
-
const numberValue = boardConstants.get(`pins.all.${pinIndex}.number`);
|
|
24
|
-
const aliasesValue = boardConstants.get(`pins.all.${pinIndex}.aliases`);
|
|
25
|
-
const aliases = typeof aliasesValue === 'string' && aliasesValue.length > 0
|
|
26
|
-
? aliasesValue.split(',').map(entry => entry.trim()).filter(Boolean)
|
|
27
|
-
: [];
|
|
28
|
-
pinsByIndex.set(pinIndex, {
|
|
29
|
-
pinNumber: typeof numberValue === 'number' ? numberValue : Number(pinIndex),
|
|
30
|
-
canonicalName: value,
|
|
31
|
-
aliases,
|
|
32
|
-
timerId: '',
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
for (const [key, value] of boardConstants) {
|
|
37
|
-
const typeMatch = key.match(/^pins\.all\.(\d+)\.functions\.\d+\.type$/);
|
|
38
|
-
if (!typeMatch || value !== 'pwm') {
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const pinIndex = typeMatch[1];
|
|
42
|
-
const roleKey = key.replace(/\.type$/, '.role');
|
|
43
|
-
const timerKey = key.replace(/\.type$/, '.timer');
|
|
44
|
-
const timerId = extractTimerId(boardConstants.get(roleKey), boardConstants.get(timerKey));
|
|
45
|
-
if (!timerId) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const pin = pinsByIndex.get(pinIndex);
|
|
49
|
-
if (pin) {
|
|
50
|
-
pin.timerId = timerId;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return Array.from(pinsByIndex.values()).filter(pin => pin.timerId.length > 0);
|
|
54
|
-
}
|
|
55
|
-
export function validatePWMTimerSharing(usage, boardConstants, filePath) {
|
|
56
|
-
if (usage.pwmPinsUsed.size < 2 || !boardConstants) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
const boardName = boardConstants.get('name');
|
|
60
|
-
const boardLabel = typeof boardName === 'string' && boardName.length > 0
|
|
61
|
-
? ` on ${boardName}`
|
|
62
|
-
: '';
|
|
63
|
-
const pins = getPwmTimerPins(boardConstants);
|
|
64
|
-
const pinsByTimer = new Map();
|
|
65
|
-
for (const pin of pins) {
|
|
66
|
-
if (!usage.pwmPinsUsed.has(pin.pinNumber)) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const group = pinsByTimer.get(pin.timerId) ?? [];
|
|
70
|
-
group.push(pin);
|
|
71
|
-
pinsByTimer.set(pin.timerId, group);
|
|
72
|
-
}
|
|
73
|
-
const diagnostics = [];
|
|
74
|
-
for (const [timerId, timerPins] of pinsByTimer) {
|
|
75
|
-
if (timerPins.length < 2) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const references = timerPins
|
|
79
|
-
.sort((left, right) => left.pinNumber - right.pinNumber)
|
|
80
|
-
.map((pin) => {
|
|
81
|
-
const usedNames = [pin.canonicalName, ...pin.aliases].filter(name => usage.pinsUsed.has(name));
|
|
82
|
-
const preferredName = usedNames[0] ?? pin.canonicalName;
|
|
83
|
-
return formatPinReference(preferredName, findBoardPinByName(pin.canonicalName, boardConstants));
|
|
84
|
-
});
|
|
85
|
-
diagnostics.push({
|
|
86
|
-
severity: 'info',
|
|
87
|
-
code: 'pwm-timer-sharing',
|
|
88
|
-
filePath,
|
|
89
|
-
source: 'pwm-timer-sharing',
|
|
90
|
-
message: `${references.join(', ')} share ${timerId}${boardLabel}. Duty cycle can differ per pin, but timer-wide PWM settings are shared across that group. Prefer pins on different timer groups if you need independent PWM timing behavior.`,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return diagnostics;
|
|
94
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Diagnostic } from '../types.js';
|
|
2
|
-
import type { BoardConstants } from './board-resolver.js';
|
|
3
|
-
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
4
|
-
export declare function validateTimer0PWMTimingConflict(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { findBoardPinByName, formatPinReference } from './board-pin-utils.js';
|
|
2
|
-
function getTimer0PwmPins(boardConstants) {
|
|
3
|
-
if (!boardConstants) {
|
|
4
|
-
return [];
|
|
5
|
-
}
|
|
6
|
-
const pinsByIndex = new Map();
|
|
7
|
-
for (const [key, value] of boardConstants) {
|
|
8
|
-
const match = key.match(/^pins\.all\.(\d+)\.name$/);
|
|
9
|
-
if (!match || typeof value !== 'string') {
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
12
|
-
const pinIndex = match[1];
|
|
13
|
-
const numberValue = boardConstants.get(`pins.all.${pinIndex}.number`);
|
|
14
|
-
const aliasesValue = boardConstants.get(`pins.all.${pinIndex}.aliases`);
|
|
15
|
-
const aliases = typeof aliasesValue === 'string' && aliasesValue.length > 0
|
|
16
|
-
? aliasesValue.split(',').map(entry => entry.trim()).filter(Boolean)
|
|
17
|
-
: [];
|
|
18
|
-
pinsByIndex.set(pinIndex, {
|
|
19
|
-
pinNumber: typeof numberValue === 'number' ? numberValue : Number(pinIndex),
|
|
20
|
-
canonicalName: value,
|
|
21
|
-
aliases,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
const timer0Pins = [];
|
|
25
|
-
for (const [key, value] of boardConstants) {
|
|
26
|
-
// Check for timer field first, fall back to OC register regex
|
|
27
|
-
const timerMatch = key.match(/^pins\.all\.(\d+)\.functions\.(\d+)\.timer$/);
|
|
28
|
-
if (timerMatch && value === 'timer0') {
|
|
29
|
-
const pin = pinsByIndex.get(timerMatch[1]);
|
|
30
|
-
if (pin) {
|
|
31
|
-
timer0Pins.push(pin);
|
|
32
|
-
}
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const match = key.match(/^pins\.all\.(\d+)\.functions\.\d+\.role$/);
|
|
36
|
-
if (!match || typeof value !== 'string' || !/^OC0[A-Z]?$/i.test(value)) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
const pin = pinsByIndex.get(match[1]);
|
|
40
|
-
if (pin && !timer0Pins.some(p => p.pinNumber === pin.pinNumber)) {
|
|
41
|
-
timer0Pins.push(pin);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return timer0Pins;
|
|
45
|
-
}
|
|
46
|
-
export function validateTimer0PWMTimingConflict(usage, boardConstants, filePath) {
|
|
47
|
-
if (!usage.timer0 || usage.pwmPinsUsed.size === 0) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
const timer0Pins = getTimer0PwmPins(boardConstants)
|
|
51
|
-
.filter(pin => usage.pwmPinsUsed.has(pin.pinNumber));
|
|
52
|
-
if (timer0Pins.length === 0) {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
const boardName = boardConstants?.get('name');
|
|
56
|
-
const boardLabel = typeof boardName === 'string' && boardName.length > 0
|
|
57
|
-
? ` on ${boardName}`
|
|
58
|
-
: '';
|
|
59
|
-
const pinReferences = timer0Pins
|
|
60
|
-
.sort((left, right) => left.pinNumber - right.pinNumber)
|
|
61
|
-
.map((pin) => {
|
|
62
|
-
const usedName = [pin.canonicalName, ...pin.aliases].find(name => usage.pinsUsed.has(name)) ?? pin.canonicalName;
|
|
63
|
-
return formatPinReference(usedName, findBoardPinByName(pin.canonicalName, boardConstants));
|
|
64
|
-
});
|
|
65
|
-
return [{
|
|
66
|
-
severity: 'info',
|
|
67
|
-
code: 'timer0-pwm-timing-conflict',
|
|
68
|
-
filePath,
|
|
69
|
-
source: 'timer0-pwm-timing-conflict',
|
|
70
|
-
message: `${pinReferences.join(', ')} use Timer0 PWM${boardLabel}, and your program also relies on Timer0-backed timing APIs such as delay(), millis(), or micros(). This coupling is common on AVR boards, so prefer non-Timer0 PWM pins when you want PWM behavior isolated from core timing.`,
|
|
71
|
-
}];
|
|
72
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// Public barrel for component declaration generation.
|
|
2
|
-
//
|
|
3
|
-
// framework-esp32 imports `generateComponentDeclsForProject` from here so its
|
|
4
|
-
// dependency on cuttlefish is declared through the package exports map rather
|
|
5
|
-
// than a deep relative path. Spec: 2026-07-19-framework-esp32-components-design.md
|
|
6
|
-
export { generateComponentDeclsForProject } from "./cpp-to-decl.js";
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export interface ComponentScanRoots {
|
|
2
|
-
/** Subdirectory names under managed_components/ (e.g. espressif__esp_wifi). */
|
|
3
|
-
managed: string[];
|
|
4
|
-
/** Absolute paths to local component directories. */
|
|
5
|
-
local: string[];
|
|
6
|
-
/**
|
|
7
|
-
* ESP-IDF built-in component names (e.g. esp_wifi). Resolved against
|
|
8
|
-
* `idfRoot/components/<name>/include/` when idfRoot is provided; ignored
|
|
9
|
-
* otherwise (the caller is responsible for passing idfRoot when builtins
|
|
10
|
-
* are present).
|
|
11
|
-
*/
|
|
12
|
-
builtin: string[];
|
|
13
|
-
/** Optional ESP-IDF install root for resolving `builtin` names. */
|
|
14
|
-
idfRoot?: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* A discovered header plus the directory its generated .d.ts should land in.
|
|
18
|
-
*
|
|
19
|
-
* `outputDir` is alongside the header for managed/local components (so the
|
|
20
|
-
* .d.ts lives in the same gitignored component dir, regenerated on each run).
|
|
21
|
-
* For built-in components it's a project-local cache — NEVER write into the
|
|
22
|
-
* IDF install itself.
|
|
23
|
-
*/
|
|
24
|
-
export interface DiscoveredHeader {
|
|
25
|
-
/** Absolute path to the source .h file. */
|
|
26
|
-
path: string;
|
|
27
|
-
/** Absolute directory where the generated .d.ts should be written. */
|
|
28
|
-
outputDir: string;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Find all .h files for the declared components.
|
|
32
|
-
*
|
|
33
|
-
* - managed: scan `managed_components/<name>/include/` (falling back to the
|
|
34
|
-
* component dir if no include/ exists). Populated by `idf.py reconfigure`.
|
|
35
|
-
* - local: scan `<path>/include/` (or `<path>/`).
|
|
36
|
-
* - builtin: scan `<idfRoot>/components/<name>/include/` (IDF ships with these).
|
|
37
|
-
*
|
|
38
|
-
* For builtins the output .d.ts goes to `<projectDir>/.cuttlefish/component-decls/<component>/`
|
|
39
|
-
* — never into `$IDF_PATH/components/`, which would pollute the IDF install.
|
|
40
|
-
*
|
|
41
|
-
* Returned entries are unsorted — the caller decides ordering.
|
|
42
|
-
*/
|
|
43
|
-
export declare function discoverComponentHeaders(projectDir: string, roots: ComponentScanRoots): DiscoveredHeader[];
|