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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +10 -10
  2. package/dist/api/board-types.d.ts +1 -1
  3. package/dist/api/config.d.ts +38 -2
  4. package/dist/api/index.d.ts +1 -1
  5. package/dist/api/schema/types.d.ts +15 -0
  6. package/dist/api/shared/async-runtime-static.d.ts +12 -1
  7. package/dist/api/shared/async-runtime-static.js +69 -24
  8. package/dist/api/shared/async-symbol-detector.d.ts +11 -0
  9. package/dist/api/shared/async-symbol-detector.js +140 -0
  10. package/dist/api/shared/async-types.d.ts +24 -0
  11. package/dist/api/shared/coop-scheduler.d.ts +60 -0
  12. package/dist/api/shared/coop-scheduler.js +149 -0
  13. package/dist/api/shared/display-adapter.d.ts +4 -3
  14. package/dist/api/shared/display-adapter.js +15 -118
  15. package/dist/api/shared/display-adapters/sdl.js +38 -31
  16. package/dist/api/shared/display-profile.d.ts +47 -25
  17. package/dist/api/shared/display-profile.js +31 -164
  18. package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
  19. package/dist/api/shared/framework-manifest-registry.js +27 -0
  20. package/dist/api/shared/framework-manifest.d.ts +595 -0
  21. package/dist/api/shared/framework-manifest.js +193 -0
  22. package/dist/api/shared/glcdfont.d.ts +12 -0
  23. package/dist/api/shared/glcdfont.js +124 -0
  24. package/dist/api/shared/graphics-strategy.d.ts +37 -0
  25. package/dist/api/shared/hal-op-ir.d.ts +764 -1
  26. package/dist/api/shared/hal-op-ir.js +129 -1
  27. package/dist/api/shared/index.d.ts +22 -2
  28. package/dist/api/shared/index.js +26 -1
  29. package/dist/api/shared/ir-core.d.ts +4 -0
  30. package/dist/api/shared/ir-declarations.d.ts +6 -0
  31. package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
  32. package/dist/api/shared/native-display-op-resolver.js +64 -0
  33. package/dist/api/shared/platform-strategy.d.ts +119 -2
  34. package/dist/api/shared/polyfill-helper-registry.js +18 -1
  35. package/dist/api/shared/promise-runtime.d.ts +1 -1
  36. package/dist/api/shared/promise-runtime.js +95 -13
  37. package/dist/api/shared/spdx-licenses.d.ts +139 -0
  38. package/dist/api/shared/spdx-licenses.js +385 -0
  39. package/dist/api/shared/toolchain-types.d.ts +17 -0
  40. package/dist/api/shared/types.d.ts +8 -0
  41. package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
  42. package/dist/api/shared/validate-framework-manifest.js +494 -0
  43. package/dist/api/shared/worker-runtime-polyfill.d.ts +22 -0
  44. package/dist/api/shared/worker-runtime-polyfill.js +34 -0
  45. package/dist/api/shared/worker-runtime.d.ts +69 -0
  46. package/dist/api/shared/worker-runtime.js +163 -0
  47. package/dist/cli-utils.d.ts +1 -0
  48. package/dist/cli-utils.js +3 -1
  49. package/dist/cli.js +249 -32
  50. package/dist/config-loader.d.ts +7 -2
  51. package/dist/config-loader.js +23 -3
  52. package/dist/config-schema.d.ts +112 -70
  53. package/dist/config-schema.js +14 -0
  54. package/dist/contract/board-generator.d.ts +17 -0
  55. package/dist/contract/board-generator.js +57 -0
  56. package/dist/contract/contract-parser.d.ts +217 -0
  57. package/dist/contract/contract-parser.js +224 -0
  58. package/dist/contract/index.d.ts +22 -0
  59. package/dist/contract/index.js +68 -0
  60. package/dist/create/board-codegen.js +4 -4
  61. package/dist/create/board-generators.js +4 -5
  62. package/dist/create/board-spec.d.ts +72 -75
  63. package/dist/create/board-spec.js +0 -1
  64. package/dist/create/framework-catalog.d.ts +64 -0
  65. package/dist/create/framework-catalog.js +136 -0
  66. package/dist/create/index.d.ts +5 -1
  67. package/dist/create/index.js +3 -1
  68. package/dist/create/init-scaffold.d.ts +12 -3
  69. package/dist/create/init-scaffold.js +49 -14
  70. package/dist/create/init-templates.d.ts +4 -0
  71. package/dist/create/init-templates.js +271 -17
  72. package/dist/create/init-wizard.js +41 -27
  73. package/dist/create/install-deps.d.ts +32 -0
  74. package/dist/create/install-deps.js +46 -0
  75. package/dist/debug/preprocessor.js +178 -39
  76. package/dist/debug/types.d.ts +23 -0
  77. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  78. package/dist/diagnostics/mermaid-builder.js +34 -24
  79. package/dist/emit/compliance/arxml-writer.d.ts +11 -0
  80. package/dist/emit/compliance/arxml-writer.js +34 -0
  81. package/dist/emit/compliance/compliance-context.d.ts +57 -0
  82. package/dist/emit/compliance/compliance-context.js +113 -0
  83. package/dist/emit/compliance/deviation-ledger.d.ts +27 -0
  84. package/dist/emit/compliance/deviation-ledger.js +47 -0
  85. package/dist/emit/compliance/deviation-writer.d.ts +30 -0
  86. package/dist/emit/compliance/deviation-writer.js +37 -0
  87. package/dist/emit/compliance/index.d.ts +7 -0
  88. package/dist/emit/compliance/index.js +6 -0
  89. package/dist/emit/compliance/rule-engine.d.ts +13 -0
  90. package/dist/emit/compliance/rule-engine.js +101 -0
  91. package/dist/emit/compliance/rules.d.ts +16 -0
  92. package/dist/emit/compliance/rules.js +191 -0
  93. package/dist/emit/compliance/types.d.ts +59 -0
  94. package/dist/emit/compliance/types.js +8 -0
  95. package/dist/emit/cpp-emitter.js +4 -3
  96. package/dist/emit/emitters/class-emitter.js +6 -1
  97. package/dist/emit/emitters/emitter-context.d.ts +28 -1
  98. package/dist/emit/emitters/function-emitter-impl.js +153 -53
  99. package/dist/emit/emitters/line-appender.js +19 -0
  100. package/dist/emit/emitters/line-marker.d.ts +38 -0
  101. package/dist/emit/emitters/line-marker.js +39 -0
  102. package/dist/emit/emitters/output-finalizer.d.ts +6 -0
  103. package/dist/emit/emitters/output-finalizer.js +101 -12
  104. package/dist/emit/emitters/setup.d.ts +17 -0
  105. package/dist/emit/emitters/setup.js +372 -30
  106. package/dist/emit/emitters/top-level-prep.js +8 -0
  107. package/dist/emit/emitters/type-decl-emitter.js +28 -3
  108. package/dist/emit/emitters/ui-emitter.js +33 -9
  109. package/dist/emit/expression-renderer.d.ts +1 -1
  110. package/dist/emit/expression-renderer.js +91 -6
  111. package/dist/emit/route-hal-op.js +18 -5
  112. package/dist/emit/snprintf-helpers.js +15 -4
  113. package/dist/emit/statement-renderer.d.ts +10 -0
  114. package/dist/emit/statement-renderer.js +34 -5
  115. package/dist/emit/utils/async-state-machine.js +221 -125
  116. package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
  117. package/dist/emit/utils/hal-op-cpp-type.js +40 -0
  118. package/dist/framework-package.js +2 -0
  119. package/dist/framework-registry.d.ts +17 -0
  120. package/dist/install/framework-catalog.d.ts +53 -0
  121. package/dist/install/framework-catalog.js +107 -0
  122. package/dist/install/handle-install.d.ts +35 -0
  123. package/dist/install/handle-install.js +177 -0
  124. package/dist/install/index.d.ts +4 -0
  125. package/dist/install/index.js +3 -0
  126. package/dist/ir/adc-range-validation.js +40 -26
  127. package/dist/ir/build-ir-state.d.ts +1 -0
  128. package/dist/ir/build-ir-state.js +14 -0
  129. package/dist/ir/build-ir.js +9 -5
  130. package/dist/ir/call-graph.js +16 -0
  131. package/dist/ir/expression-to-ir.js +207 -6
  132. package/dist/ir/feature-registry.js +7 -25
  133. package/dist/ir/function-builder.js +22 -0
  134. package/dist/ir/hal/hal-emitter.d.ts +5 -2
  135. package/dist/ir/hal/hal-emitter.js +50 -18
  136. package/dist/ir/hal/hal-parser.d.ts +6 -0
  137. package/dist/ir/hal/hal-parser.js +81 -0
  138. package/dist/ir/hal/hal-plugins.js +733 -1
  139. package/dist/ir/identifier-collector.js +35 -0
  140. package/dist/ir/interrupt-analysis.d.ts +5 -1
  141. package/dist/ir/interrupt-analysis.js +16 -19
  142. package/dist/ir/memory-budget-validation.js +1 -0
  143. package/dist/ir/network-validation.d.ts +4 -0
  144. package/dist/ir/network-validation.js +184 -0
  145. package/dist/ir/ownership-analysis.js +39 -1
  146. package/dist/ir/peripheral-ownership.js +5 -0
  147. package/dist/ir/peripheral-validation.d.ts +1 -1
  148. package/dist/ir/peripheral-validation.js +6 -3
  149. package/dist/ir/pin-alias-conflict.d.ts +1 -1
  150. package/dist/ir/pin-alias-conflict.js +2 -1
  151. package/dist/ir/pin-capability-validation.js +71 -32
  152. package/dist/ir/pin-mode-validation.d.ts +2 -2
  153. package/dist/ir/pin-mode-validation.js +54 -18
  154. package/dist/ir/pin-safety.d.ts +1 -1
  155. package/dist/ir/pin-safety.js +2 -1
  156. package/dist/ir/program-analysis.d.ts +81 -0
  157. package/dist/ir/program-analysis.js +429 -0
  158. package/dist/ir/pulldown-validation.d.ts +1 -1
  159. package/dist/ir/pulldown-validation.js +2 -1
  160. package/dist/ir/pwm-timer-sharing.d.ts +1 -1
  161. package/dist/ir/pwm-timer-sharing.js +2 -1
  162. package/dist/ir/render-expr.js +11 -0
  163. package/dist/ir/resource-analysis.js +2 -0
  164. package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
  165. package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
  166. package/dist/ir/timing-validation.d.ts +6 -1
  167. package/dist/ir/timing-validation.js +61 -13
  168. package/dist/ir/transformers/call-statement.js +105 -0
  169. package/dist/ir/transformers/expressions.js +62 -0
  170. package/dist/ir/transformers/hal-call-resolver.js +21 -0
  171. package/dist/ir/transformers/hal-emit-helpers.js +1 -1
  172. package/dist/ir/transformers/namespace-methods.js +17 -12
  173. package/dist/ir/transformers/ui-reactive.js +2 -2
  174. package/dist/ir/transformers/variables.js +137 -19
  175. package/dist/ir/try-catch-validation.js +2 -0
  176. package/dist/ir/type-resolution.js +20 -2
  177. package/dist/ir/ui-element-auto-wire.js +7 -5
  178. package/dist/ir/unit-suspicion-validation.js +9 -7
  179. package/dist/ir/utils/map-statements.d.ts +4 -0
  180. package/dist/ir/utils/map-statements.js +79 -0
  181. package/dist/ir/validation-orchestrator.js +15 -8
  182. package/dist/ir/worker-analysis.d.ts +10 -0
  183. package/dist/ir/worker-analysis.js +261 -0
  184. package/dist/libdef/c-to-decl.d.ts +27 -0
  185. package/dist/libdef/c-to-decl.js +397 -0
  186. package/dist/libdef/component-decls.d.ts +2 -0
  187. package/dist/libdef/component-decls.js +6 -0
  188. package/dist/libdef/component-discovery.d.ts +43 -0
  189. package/dist/libdef/component-discovery.js +83 -0
  190. package/dist/libdef/cpp-to-decl.d.ts +9 -0
  191. package/dist/libdef/cpp-to-decl.js +72 -0
  192. package/dist/libdef/registry.js +5 -2
  193. package/dist/lint-cache.d.ts +59 -0
  194. package/dist/lint-cache.js +257 -0
  195. package/dist/orchestrator/graph-builder.js +14 -9
  196. package/dist/platform/coop-scheduler-runtime.d.ts +19 -0
  197. package/dist/platform/coop-scheduler-runtime.js +41 -0
  198. package/dist/platform/generic-strategy.d.ts +15 -3
  199. package/dist/platform/generic-strategy.js +49 -4
  200. package/dist/safety/safety-bridge.d.ts +11 -0
  201. package/dist/safety/safety-bridge.js +48 -0
  202. package/dist/safety/sidecar-bridge.d.ts +5 -0
  203. package/dist/safety/sidecar-bridge.js +22 -0
  204. package/dist/safety-hook.d.ts +79 -0
  205. package/dist/safety-hook.js +35 -0
  206. package/dist/testing.d.ts +8 -2
  207. package/dist/testing.js +9 -2
  208. package/dist/transpile.d.ts +3 -0
  209. package/dist/transpile.js +191 -49
  210. package/dist/types.d.ts +22 -3
  211. package/dist/ui-hook.d.ts +17 -3
  212. package/dist/utils/cli.js +123 -2
  213. package/dist/utils/fs.d.ts +13 -0
  214. package/dist/utils/fs.js +50 -0
  215. package/dist/utils/ui.js +3 -1
  216. package/package.json +23 -3
  217. package/dist/api/shared/display-adapters/eink-mono.d.ts +0 -2
  218. package/dist/api/shared/display-adapters/eink-mono.js +0 -53
  219. package/dist/api/shared/display-adapters/ssd1309.d.ts +0 -2
  220. package/dist/api/shared/display-adapters/ssd1309.js +0 -136
  221. package/dist/api/shared/display-adapters/st7796.d.ts +0 -2
  222. package/dist/api/shared/display-adapters/st7796.js +0 -132
  223. package/dist/ir/heap-array-validation.d.ts +0 -24
  224. package/dist/ir/heap-array-validation.js +0 -29
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Append-only store of deviations recorded during emit. Dedupes identical
3
+ * (ruleId, file, line) entries; supports region deviations via openRegion /
4
+ * closeRegion. The ledger is the single source of truth that the sidecar
5
+ * registry is rendered from.
6
+ */
7
+ export class DeviationLedger {
8
+ constructor() {
9
+ this.entries = [];
10
+ this.openRegionEntry = null;
11
+ }
12
+ record(input) {
13
+ if (this.openRegionEntry) {
14
+ throw new Error(`Cannot record single-line deviation for ${input.ruleId} while a region is open for ${this.openRegionEntry.ruleId}.`);
15
+ }
16
+ const endLine = input.line;
17
+ this.append({ ...input, endLine, reviewStatus: "auto-generated" });
18
+ }
19
+ openRegion(input) {
20
+ if (this.openRegionEntry) {
21
+ throw new Error(`Cannot open deviation region for ${input.ruleId}: a region is already open for ${this.openRegionEntry.ruleId}.`);
22
+ }
23
+ this.openRegionEntry = { ...input };
24
+ }
25
+ closeRegion(endLine) {
26
+ if (!this.openRegionEntry) {
27
+ throw new Error("Cannot close a deviation region: no open deviation region.");
28
+ }
29
+ if (endLine < this.openRegionEntry.line) {
30
+ throw new Error(`closeRegion endLine ${endLine} is before the region start line ${this.openRegionEntry.line}.`);
31
+ }
32
+ this.append({ ...this.openRegionEntry, endLine, reviewStatus: "auto-generated" });
33
+ this.openRegionEntry = null;
34
+ }
35
+ all() {
36
+ return this.entries;
37
+ }
38
+ /** Used by the self-check to verify every ledger entry has a matching inline comment. */
39
+ hasEntry(file, line, ruleId) {
40
+ return this.entries.some((e) => e.file === file && line >= e.line && line <= e.endLine && e.ruleId === ruleId);
41
+ }
42
+ append(entry) {
43
+ const dup = this.entries.some((e) => e.ruleId === entry.ruleId && e.file === entry.file && e.line === entry.line);
44
+ if (!dup)
45
+ this.entries.push(entry);
46
+ }
47
+ }
@@ -0,0 +1,30 @@
1
+ import type { ComplianceContext } from "./compliance-context.js";
2
+ import type { Deviation } from "./types.js";
3
+ export interface RegistryJson {
4
+ schemaVersion: string;
5
+ standard: string;
6
+ tool: string;
7
+ toolVersion: string;
8
+ generatedAt: string;
9
+ emittedArtifact: string;
10
+ ruleSubset: {
11
+ id: string;
12
+ category: string;
13
+ }[];
14
+ summary: {
15
+ totalDeviations: number;
16
+ byRule: Record<string, number>;
17
+ };
18
+ deviations: Array<Deviation & {
19
+ /** C++ location of the deviation, mirroring the diagnostic messages. */
20
+ cpp?: {
21
+ file: string;
22
+ line: number;
23
+ };
24
+ }>;
25
+ }
26
+ /**
27
+ * Renders the ledger as the sidecar registry JSON. Pure function — does
28
+ * not touch the filesystem; the caller (finalizeOutput) writes the string.
29
+ */
30
+ export declare function renderRegistryJson(ctx: ComplianceContext, emittedArtifact: string, toolVersion: string): string;
@@ -0,0 +1,37 @@
1
+ import { RULES } from "./rules.js";
2
+ /**
3
+ * Renders the ledger as the sidecar registry JSON. Pure function — does
4
+ * not touch the filesystem; the caller (finalizeOutput) writes the string.
5
+ */
6
+ export function renderRegistryJson(ctx, emittedArtifact, toolVersion) {
7
+ const deviations = [...ctx.ledger().all()];
8
+ const byRule = {};
9
+ for (const d of deviations) {
10
+ byRule[d.ruleId] = (byRule[d.ruleId] ?? 0) + 1;
11
+ }
12
+ // Derive the C++ artifact name for the cpp field. For header deviations,
13
+ // the artifact is the .h file (derived from the source artifact name).
14
+ const sourceArtifact = emittedArtifact;
15
+ const headerArtifact = emittedArtifact.replace(/\.\w+$/, ".h");
16
+ const payload = {
17
+ schemaVersion: "1.0.0",
18
+ standard: "AUTOSAR C++14",
19
+ tool: "cuttlefish",
20
+ toolVersion,
21
+ generatedAt: new Date().toISOString(),
22
+ emittedArtifact,
23
+ ruleSubset: RULES.filter((r) => r.enabled).map((r) => ({ id: r.id, category: r.category })),
24
+ summary: {
25
+ totalDeviations: deviations.length,
26
+ byRule,
27
+ },
28
+ deviations: deviations.map((d) => ({
29
+ ...d,
30
+ cpp: {
31
+ file: d.file === "header" ? headerArtifact : sourceArtifact,
32
+ line: d.line,
33
+ },
34
+ })),
35
+ };
36
+ return JSON.stringify(payload, null, 2);
37
+ }
@@ -0,0 +1,7 @@
1
+ export { ComplianceContext } from "./compliance-context.js";
2
+ export { DeviationLedger } from "./deviation-ledger.js";
3
+ export { runSelfCheck } from "./rule-engine.js";
4
+ export { renderRegistryJson } from "./deviation-writer.js";
5
+ export { renderArxml } from "./arxml-writer.js";
6
+ export { RULES, getRule, rulesByCategory } from "./rules.js";
7
+ export type { ComplianceMode, RuleEntry, RuleSeverity, RuleCategory, Deviation, DeviationKind, SelfCheckFinding, } from "./types.js";
@@ -0,0 +1,6 @@
1
+ export { ComplianceContext } from "./compliance-context.js";
2
+ export { DeviationLedger } from "./deviation-ledger.js";
3
+ export { runSelfCheck } from "./rule-engine.js";
4
+ export { renderRegistryJson } from "./deviation-writer.js";
5
+ export { renderArxml } from "./arxml-writer.js";
6
+ export { RULES, getRule, rulesByCategory } from "./rules.js";
@@ -0,0 +1,13 @@
1
+ import type { ComplianceContext } from "./compliance-context.js";
2
+ import type { SelfCheckFinding } from "./types.js";
3
+ /**
4
+ * Final self-check pass, run inside finalizeOutput after all renderers
5
+ * have pushed lines. Walks the emitted text once and reports:
6
+ * - unrecorded-violation: a banned construct with no matching deviation comment
7
+ * - orphan-deviation: a ledger entry with no matching inline comment
8
+ *
9
+ * Two layers: renderers are the primary enforcement (Pattern 1 picks the
10
+ * compliant spelling by construction); this is the secondary net. Neither
11
+ * is expected to be perfect alone.
12
+ */
13
+ export declare function runSelfCheck(ctx: ComplianceContext, sourceLines: readonly string[], headerLines: readonly string[]): SelfCheckFinding[];
@@ -0,0 +1,101 @@
1
+ import { RULES } from "./rules.js";
2
+ const DEVIATION_COMMENT = /\/\/\s*AUTOSAR\s+Deviation\s+([A-Z]\d[\d-]*[A-Z\d, ]*)/i;
3
+ /**
4
+ * Final self-check pass, run inside finalizeOutput after all renderers
5
+ * have pushed lines. Walks the emitted text once and reports:
6
+ * - unrecorded-violation: a banned construct with no matching deviation comment
7
+ * - orphan-deviation: a ledger entry with no matching inline comment
8
+ *
9
+ * Two layers: renderers are the primary enforcement (Pattern 1 picks the
10
+ * compliant spelling by construction); this is the secondary net. Neither
11
+ * is expected to be perfect alone.
12
+ */
13
+ export function runSelfCheck(ctx, sourceLines, headerLines) {
14
+ if (!ctx.isEnabled())
15
+ return [];
16
+ const findings = [];
17
+ // Pass 1: detect banned constructs in source and header lines.
18
+ for (const file of ["source", "header"]) {
19
+ const lines = file === "source" ? sourceLines : headerLines;
20
+ for (let i = 0; i < lines.length; i++) {
21
+ const lineNo = i + 1;
22
+ const line = lines[i];
23
+ // Strip trailing // comments and skip full comment lines before
24
+ // running detect regexes — rules shouldn't match words in prose.
25
+ // Preserve deviation comments (checked separately below).
26
+ const deviationCommentMatch = line.match(DEVIATION_COMMENT);
27
+ const codePart = line.replace(/\s*\/\/(?!.*AUTOSAR Deviation).*$/, "");
28
+ const isFullComment = /^\s*(\/\/|\/\*|\*)/.test(line);
29
+ const detectTarget = isFullComment ? "" : codePart;
30
+ // Extract any deviation ruleIds already present on this line.
31
+ const commentedIds = new Set();
32
+ if (deviationCommentMatch) {
33
+ for (const id of deviationCommentMatch[1].split(",").map((s) => s.trim())) {
34
+ commentedIds.add(id);
35
+ }
36
+ }
37
+ for (const rule of RULES) {
38
+ if (!rule.detect)
39
+ continue;
40
+ if (!rule.enabled)
41
+ continue;
42
+ if (rule.exempt && rule.exempt.test(detectTarget))
43
+ continue;
44
+ if (!rule.detect.test(detectTarget))
45
+ continue;
46
+ // Check knownPatterns: if this match falls under a known unavoidable
47
+ // pattern, record a deviation and suppress the finding.
48
+ if (rule.knownPatterns) {
49
+ const known = rule.knownPatterns.find((kp) => kp.detect.test(detectTarget));
50
+ if (known) {
51
+ ctx.recordKnownDeviation(rule.id, known.justification, lineNo, file, line.trim(), {
52
+ tsFile: "",
53
+ tsLine: 0,
54
+ kind: known.kind,
55
+ });
56
+ continue;
57
+ }
58
+ }
59
+ // Match found. Is it covered by an inline comment or a ledger entry?
60
+ const covered = commentedIds.has(rule.id) || ctx.ledger().hasEntry(file, lineNo, rule.id);
61
+ if (!covered) {
62
+ findings.push({
63
+ ruleId: rule.id,
64
+ severity: rule.severity,
65
+ line: lineNo,
66
+ file,
67
+ snippet: line.trim(),
68
+ kind: "unrecorded-violation",
69
+ });
70
+ }
71
+ }
72
+ }
73
+ }
74
+ // Pass 2: orphan-deviation detection. For every ledger entry, confirm an
75
+ // inline comment exists at the recorded opening line in the right file.
76
+ // Skip entries from rules that have knownPatterns — those are intentionally
77
+ // inline-comment-less deviations (the emitted text is pre-baked shim strings
78
+ // that can't carry inline comments; the deviation lives in the sidecar only).
79
+ const rulesWithKnownPatterns = new Set(RULES.filter((r) => r.knownPatterns).map((r) => r.id));
80
+ for (const dev of ctx.ledger().all()) {
81
+ if (rulesWithKnownPatterns.has(dev.ruleId))
82
+ continue;
83
+ const lines = dev.file === "source" ? sourceLines : headerLines;
84
+ const openingLine = lines[dev.line - 1] ?? "";
85
+ const commentMatch = openingLine.match(DEVIATION_COMMENT);
86
+ const coversThis = commentMatch &&
87
+ commentMatch[1].split(",").map((s) => s.trim()).includes(dev.ruleId);
88
+ if (!coversThis) {
89
+ // Opening line must carry the comment.
90
+ findings.push({
91
+ ruleId: dev.ruleId,
92
+ severity: "required",
93
+ line: dev.line,
94
+ file: dev.file,
95
+ snippet: openingLine.trim(),
96
+ kind: "orphan-deviation",
97
+ });
98
+ }
99
+ }
100
+ return findings;
101
+ }
@@ -0,0 +1,16 @@
1
+ import type { RuleEntry } from "./types.js";
2
+ /**
3
+ * Curated AUTOSAR C++14 rule subset enforced by the cuttlefish compliance
4
+ * module. ~50 rules: 39 [C] (enforce-by-construction) and 11 [D] (deviation).
5
+ *
6
+ * Detection regexes are deliberately conservative: prefer false-negatives
7
+ * over false-positives, because a false positive aborts builds in strict
8
+ * mode. The renderer is the primary enforcement; the self-check is the
9
+ * secondary net.
10
+ *
11
+ * See docs/superpowers/specs/2026-07-26-autosar-compliance-design.md §
12
+ * "Curated rule subset".
13
+ */
14
+ export declare const RULES: readonly RuleEntry[];
15
+ export declare function getRule(id: string): RuleEntry | undefined;
16
+ export declare function rulesByCategory(category: "C" | "D"): readonly RuleEntry[];
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Curated AUTOSAR C++14 rule subset enforced by the cuttlefish compliance
3
+ * module. ~50 rules: 39 [C] (enforce-by-construction) and 11 [D] (deviation).
4
+ *
5
+ * Detection regexes are deliberately conservative: prefer false-negatives
6
+ * over false-positives, because a false positive aborts builds in strict
7
+ * mode. The renderer is the primary enforcement; the self-check is the
8
+ * secondary net.
9
+ *
10
+ * See docs/superpowers/specs/2026-07-26-autosar-compliance-design.md §
11
+ * "Curated rule subset".
12
+ */
13
+ export const RULES = [
14
+ // ── A. Preprocessor & macros ──────────────────────────────────────────
15
+ { id: "A16-0-1", title: "No #include of unused header", severity: "required", category: "C", enabled: true },
16
+ { id: "A16-0-3", title: "No #include inside namespace", severity: "required", category: "C",
17
+ detect: /^\s*namespace\s+\w+\s*\{[^}]*#include/m, enabled: true },
18
+ { id: "A16-0-4", title: "No #define inside another #define", severity: "required", category: "C", enabled: true },
19
+ { id: "A16-0-5", title: "Header file path unambiguous", severity: "required", category: "C", enabled: true },
20
+ { id: "A16-0-8", title: "#include not used for textual inclusion of code", severity: "required", category: "D", enabled: true },
21
+ { id: "A16-7-1", title: "Header guards via #pragma once", severity: "required", category: "C",
22
+ detect: /#ifndef\s+\w+_H\s*$/,
23
+ exempt: /#pragma once/,
24
+ enabled: true },
25
+ // ── B. Type safety & conversions ──────────────────────────────────────
26
+ { id: "M5-0-3", title: "Implicit narrowing conversion forbidden", severity: "required", category: "C", enabled: true },
27
+ { id: "M5-0-7", title: "C-style cast shall not be used", severity: "required", category: "C",
28
+ detect: /(^|[^:\w.])\(\s*(?:uint\d+_t|int\d+_t|int|char|double|float|bool|size_t|long|short|unsigned\s+\w+)\s*\)\s*[a-zA-Z_(]/,
29
+ exempt: /static_cast|dynamic_cast|reinterpret_cast|const_cast/,
30
+ enabled: true },
31
+ { id: "M5-0-10", title: "No reinterpret_cast", severity: "required", category: "D",
32
+ detect: /reinterpret_cast</, enabled: true,
33
+ knownPatterns: [
34
+ {
35
+ // freeHeap() on AVR exposes no numeric API — avr-libc publishes the
36
+ // heap boundary as the linker symbols __heap_start (int) and __brkval
37
+ // (int*). Computing the free byte count requires subtracting two
38
+ // addresses, which is only expressible as a pointer→integer cast.
39
+ // This is the canonical AUTOSAR category-D "unavoidable platform
40
+ // constraint" deviation. ESP32 uses ESP.getFreeHeap() and needs no
41
+ // cast; this pattern matches only the AVR idiom.
42
+ detect: /reinterpret_cast<size_t>\(&(v|__heap_start)\)|reinterpret_cast<size_t>\(__brkval\)/,
43
+ justification: "AVR freeHeap() measures the gap between the stack and heap via the avr-libc __heap_start/__brkval linker symbols; pointer-to-integer conversion is the only way to compute a byte distance between two addresses on a target with no numeric free-heap API.",
44
+ kind: "polyfill",
45
+ },
46
+ ],
47
+ },
48
+ { id: "M5-2-8", title: "No pointer arithmetic out of bounds", severity: "required", category: "C", enabled: true },
49
+ { id: "A5-2-2", title: "No static_cast downcast of polymorphic type", severity: "required", category: "C", enabled: true },
50
+ { id: "M5-3-2", title: "No bitwise ops on signed narrow types", severity: "required", category: "C", enabled: true,
51
+ knownPatterns: [
52
+ {
53
+ detect: /<<\s*8|>>\s*\d/,
54
+ justification: "Display color packing (RGB565/RGB888) requires bitwise shifts on narrow types; restructuring would change pixel layout.",
55
+ kind: "ts-literal",
56
+ },
57
+ ],
58
+ },
59
+ { id: "A5-3-2", title: "No bitwise assignment on signed narrow types", severity: "required", category: "C", enabled: true },
60
+ { id: "A7-1-1", title: "const on objects that are not modified", severity: "required", category: "C", enabled: true },
61
+ { id: "A7-1-5", title: "auto only for function returns, non-fundamental types, generic lambdas, trailing return types", severity: "required", category: "C",
62
+ detect: /\bauto\b/, enabled: true,
63
+ knownPatterns: [
64
+ {
65
+ // A7-1-5 permits auto for: (1) function call return types,
66
+ // (2) non-fundamental type initializers, (3) generic lambda params,
67
+ // (4) trailing return type syntax. The self-check can't distinguish
68
+ // these from first principles, so we record a deviation for every
69
+ // auto usage. The renderer separately avoids auto for fundamental
70
+ // types (numbers) under --autosar by substituting int32_t/float/etc.
71
+ detect: /\bauto\b/,
72
+ justification: "auto is used for function return types (case 1) and non-fundamental types (case 2) as permitted by A7-1-5; fundamental-type auto is substituted to explicit fixed-width types by the renderer.",
73
+ kind: "other",
74
+ },
75
+ ],
76
+ },
77
+ { id: "A7-1-6", title: "No typedef outside a function -> use using alias", severity: "required", category: "C",
78
+ detect: /\btypedef\b/, exempt: /\busing\b/, enabled: true,
79
+ knownPatterns: [
80
+ {
81
+ detect: /\btypedef\b/,
82
+ justification: "ESP32 BLE/WiFi callback APIs and async runtimes require C-style function-pointer typedefs for framework interop.",
83
+ kind: "freestanding-function",
84
+ },
85
+ ],
86
+ },
87
+ { id: "A7-2-1", title: "Enumerators use scoped enums (enum class)", severity: "required", category: "C",
88
+ detect: /\benum\s+(?!class\b|struct\b)\w+/, enabled: true,
89
+ knownPatterns: [
90
+ {
91
+ detect: /\benum\s+(?:UINodeKind|UIProperty)\b/,
92
+ justification: "UI runtime internal enums (UINodeKind, UIProperty) use unscoped form for C ABI compatibility; converting to enum class would require updating 58 references across the runtime header.",
93
+ kind: "other",
94
+ },
95
+ ],
96
+ },
97
+ // ── C. Memory & objects ───────────────────────────────────────────────
98
+ { id: "A18-0-1", title: "<cstring> over C headers", severity: "required", category: "C",
99
+ detect: /#include\s+<string\.h>/, enabled: true },
100
+ { id: "A18-5-8", title: "No new/delete on plain objects", severity: "required", category: "D",
101
+ detect: /\bnew\s+(?:[A-Z_]|\()|\bdelete\s+(?:\w+\s*\[|\w)/, enabled: true,
102
+ knownPatterns: [
103
+ {
104
+ detect: /\bnew\s+\(|new\s+\(std::nothrow\)|new\s+\(ps_malloc|new\s+(?:Cuttlefish|GFX|Sdl)/,
105
+ justification: "UI runtime allocates canvas buffers and draw-order arrays on the heap via new/new(std::nothrow); no stack alternative exists for dynamic-size buffers on embedded targets.",
106
+ kind: "raw-array",
107
+ },
108
+ {
109
+ detect: /\bdelete\s+\w/,
110
+ justification: "UI runtime frees heap-allocated canvas buffers via delete; matches the new(std::nothrow) allocation.",
111
+ kind: "raw-array",
112
+ },
113
+ ],
114
+ },
115
+ { id: "A18-5-10", title: "No malloc/calloc/realloc", severity: "required", category: "C",
116
+ detect: /\b(malloc|calloc|realloc)\s*\(/, enabled: true,
117
+ knownPatterns: [
118
+ {
119
+ // Offscreen canvas allocation (CuttlefishCanvas16/CuttlefishCanvasMono
120
+ // object + pixel buffer). On targets built with
121
+ // CONFIG_REQUIRES_FULL_LIBCPP but without CONFIG_CPP_EXCEPTIONS (e.g.
122
+ // Zephyr ESP32 display builds), C++ `operator new` throws
123
+ // std::bad_alloc on OOM, and the `new (std::nothrow)` wrapper's
124
+ // internal catch cannot unwind without the EH runtime — it falls
125
+ // through to std::terminate → abort on the first allocation failure.
126
+ // malloc returns NULL on OOM with no exception path, which the
127
+ // runtime's existing canvas-null-checks degrade gracefully. This is
128
+ // the canonical category-C "platform library constraint" deviation:
129
+ // the alternative (operator new) is the very thing that crashes. The
130
+ // object is placement-constructed on the malloc'd memory and freed via
131
+ // an explicit dtor + free, so the vtable/lifetime are correct.
132
+ detect: /malloc\s*\(/,
133
+ justification: "Canvas object/buffer allocation on full-libcpp-without-exceptions targets; malloc avoids the operator-new std::bad_alloc → std::terminate → abort path. OOM returns NULL and the runtime degrades gracefully.",
134
+ kind: "ts-literal",
135
+ },
136
+ ],
137
+ },
138
+ { id: "A27-0-4", title: "No function returning std::move of local", severity: "required", category: "C",
139
+ detect: /return\s+std::move\s*\(/, enabled: true },
140
+ { id: "M5-2-9", title: "No copy of volatile std::atomic", severity: "required", category: "C", enabled: true },
141
+ // ── D. Functions & interfaces ─────────────────────────────────────────
142
+ { id: "A8-4-2", title: "Forward-declare parameters before use", severity: "required", category: "C", enabled: true },
143
+ { id: "A8-4-10", title: "Single return per function", severity: "advisory", category: "D", enabled: true },
144
+ { id: "M3-2-1", title: "All static-storage objects const-initialized", severity: "required", category: "D", enabled: true },
145
+ { id: "M3-2-3", title: "No aggregate inits the compiler can't order statically", severity: "required", category: "C", enabled: true },
146
+ { id: "M3-2-4", title: "No non-trivial init at static storage", severity: "required", category: "D", enabled: true },
147
+ { id: "A3-1-1", title: "final on leaf classes", severity: "required", category: "C", enabled: true },
148
+ { id: "A3-1-5", title: "All virtual methods have override or final", severity: "required", category: "C", enabled: true },
149
+ { id: "A10-3-1", title: "No function hiding in derived classes", severity: "required", category: "C", enabled: true },
150
+ { id: "A8-4-7", title: "One definition of an inline function", severity: "required", category: "C", enabled: true },
151
+ // ── E. Control flow & exceptions ──────────────────────────────────────
152
+ { id: "A5-1-1", title: "No recursion", severity: "required", category: "C", enabled: true },
153
+ { id: "A15-0-2", title: "noexcept on functions that can't throw", severity: "advisory", category: "C", enabled: true,
154
+ knownPatterns: [
155
+ {
156
+ detect: /\bnoexcept\b/,
157
+ justification: "noexcept annotation requires whole-function throw analysis (Phase 5); recorded as advisory deviation until then.",
158
+ kind: "other",
159
+ },
160
+ ],
161
+ },
162
+ { id: "A15-5-1", title: "Destructors must not throw", severity: "required", category: "C", enabled: true },
163
+ { id: "M15-1-3", title: "No throw expressions; no try/catch", severity: "required", category: "D",
164
+ detect: /\bthrow\b|\btry\s*\{|\bcatch\s*\(/, enabled: true },
165
+ { id: "A7-5-1", title: "[[fallthrough]] required where switch falls through", severity: "required", category: "C", enabled: true },
166
+ { id: "M6-2-1", title: "switch must have default", severity: "required", category: "C", enabled: true },
167
+ { id: "M6-4-3", title: "for condition guarded against finite iteration", severity: "required", category: "C", enabled: true },
168
+ { id: "A6-5-1", title: "for/while have single loop variable", severity: "required", category: "C", enabled: true },
169
+ // ── F. Literal & style ────────────────────────────────────────────────
170
+ { id: "A2-10-5", title: "Identifier reuse across scopes limited", severity: "advisory", category: "C", enabled: true },
171
+ { id: "A2-13-1", title: "Only hex literals are bitwise", severity: "required", category: "D", enabled: true },
172
+ { id: "A3-9-1", title: "Fixed-width integers (uint32_t not unsigned int)", severity: "required", category: "C", enabled: true },
173
+ { id: "M4-5-1", title: "No magic numbers; named constants", severity: "advisory", category: "D", enabled: true },
174
+ { id: "A18-1-1", title: "C-style arrays -> std::array", severity: "required", category: "D", enabled: true },
175
+ { id: "A8-4-4", title: "No goto", severity: "required", category: "C",
176
+ detect: /\bgoto\s+\w+;/, enabled: true },
177
+ { id: "A7-1-2", title: "No register keyword", severity: "required", category: "C",
178
+ detect: /(?<![A-Za-z0-9_])register\s+(?:int|char|short|long|unsigned|float|double|bool|void|uint\d+_t|int\d+_t|size_t|auto)/, enabled: true },
179
+ // ── G. Source organization ────────────────────────────────────────────
180
+ { id: "A3-3-2", title: "No unreachable code", severity: "required", category: "C", enabled: true },
181
+ { id: "A0-1-1", title: "No unused variables/functions", severity: "required", category: "C", enabled: true },
182
+ { id: "A2-11-1", title: "No identifier is simultaneously typedef and another entity", severity: "required", category: "C", enabled: true },
183
+ { id: "M0-1-2", title: "No value-convertible dead code", severity: "required", category: "C", enabled: true },
184
+ { id: "A7-3-1", title: "No public/protected mutable non-static members", severity: "required", category: "D", enabled: true },
185
+ ];
186
+ export function getRule(id) {
187
+ return RULES.find((r) => r.id === id);
188
+ }
189
+ export function rulesByCategory(category) {
190
+ return RULES.filter((r) => r.category === category);
191
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Shared types for the AUTOSAR C++14 compliance module.
3
+ * See docs/superpowers/specs/2026-07-26-autosar-compliance-design.md.
4
+ */
5
+ export type ComplianceMode = "off" | "warn" | "strict";
6
+ export type RuleSeverity = "required" | "advisory";
7
+ export type RuleCategory = "C" | "D";
8
+ export type DeviationKind = "hal-instance" | "lowered-exception" | "ts-literal" | "polyfill" | "freestanding-function" | "raw-array" | "other";
9
+ /** A single AUTOSAR C++14 rule entry in the curated subset. */
10
+ export interface RuleEntry {
11
+ id: string;
12
+ title: string;
13
+ severity: RuleSeverity;
14
+ category: RuleCategory;
15
+ /** Anchored regex that detects the banned construct in emitted text. Optional: absence means rule is enforced structurally only. */
16
+ detect?: RegExp;
17
+ /** Regex that, if matched on the same line, suppresses the detect match (e.g. the `static_cast` spelling for M5-0-7). */
18
+ exempt?: RegExp;
19
+ /** Per-rule kill switch. When false, the rule is loaded but neither renderer-gated nor self-checked. */
20
+ enabled: boolean;
21
+ /**
22
+ * Known unavoidable patterns for this rule. When the self-check detects a
23
+ * match for a knownPattern, it records a deviation (instead of flagging an
24
+ * unrecorded-violation) and suppresses the diagnostic. Used for rules whose
25
+ * violations are structural and can't be eliminated (e.g. function-pointer
26
+ * typedefs in ESP32 callbacks, signed bitwise in display color math).
27
+ */
28
+ knownPatterns?: Array<{
29
+ detect: RegExp;
30
+ justification: string;
31
+ kind: DeviationKind;
32
+ }>;
33
+ }
34
+ /** One recorded deviation, accumulated during emit. */
35
+ export interface Deviation {
36
+ ruleId: string;
37
+ file: "source" | "header";
38
+ line: number;
39
+ endLine: number;
40
+ snippet: string;
41
+ justification: string;
42
+ reviewStatus: "auto-generated" | "accepted";
43
+ /** Traceability back to the originating TypeScript. Populated from the source-map. */
44
+ source?: {
45
+ tsFile: string;
46
+ tsLine: number;
47
+ kind: DeviationKind;
48
+ };
49
+ }
50
+ /** A finding from the post-emit self-check pass. */
51
+ export interface SelfCheckFinding {
52
+ ruleId: string;
53
+ severity: RuleSeverity;
54
+ line: number;
55
+ file: "source" | "header";
56
+ snippet: string;
57
+ kind: "unrecorded-violation" | "orphan-deviation";
58
+ }
59
+ export declare const COMPLIANCE_TYPES_MODULE = true;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared types for the AUTOSAR C++14 compliance module.
3
+ * See docs/superpowers/specs/2026-07-26-autosar-compliance-design.md.
4
+ */
5
+ // Tagged sentinel export so `import * as` resolves to a non-empty namespace
6
+ // even though every other export here is a type. This lets the types.test.ts
7
+ // runtime-import check actually verify the module is present.
8
+ export const COMPLIANCE_TYPES_MODULE = true;
@@ -1,5 +1,5 @@
1
1
  import { buildEmitterContext } from "./emitters/setup.js";
2
- import { emitPreamble } from "./emitters/output-finalizer.js";
2
+ import { emitPreamble, emitAsyncTaskClasses, finalizeOutput } from "./emitters/output-finalizer.js";
3
3
  import { runTopLevelPreprocessing } from "./emitters/top-level-prep.js";
4
4
  import { synthesizeEntrypoints } from "./emitters/entrypoint-synthesizer.js";
5
5
  import { emitTypeDeclarations } from "./emitters/type-decl-emitter.js";
@@ -7,7 +7,6 @@ import { emitNamespaces } from "./emitters/namespace-emitter.js";
7
7
  import { emitClasses } from "./emitters/class-emitter.js";
8
8
  import { emitPostClassDeclarations, emitCallbackFunctions, emitFunctions, emitFunctionForwardDeclarations } from "./emitters/function-emitter-impl.js";
9
9
  import { emitUIRuntime } from "./emitters/ui-emitter.js";
10
- import { finalizeOutput } from "./emitters/output-finalizer.js";
11
10
  const globalEnumNames = new Set();
12
11
  const globalLargeEnumNames = new Set();
13
12
  export function registerAllEnumNames(enums) {
@@ -21,7 +20,7 @@ export function registerAllEnumNames(enums) {
21
20
  export function emitCpp(program, options) {
22
21
  // 1. Build shared emitter context (strategy, renderers, analysis, etc.)
23
22
  const ctx = buildEmitterContext(program, options);
24
- // 2. Emit preamble (includes, polyfills, async task classes, shims)
23
+ // 2. Emit preamble (includes, polyfills, shims) — async task classes deferred
25
24
  emitPreamble(ctx);
26
25
  // 2.5. Emit UI runtime (header structs + static tables) — entry file only,
27
26
  // when a UI is mounted. File-scope, must precede any function using it.
@@ -32,6 +31,8 @@ export function emitCpp(program, options) {
32
31
  synthesizeEntrypoints(ctx);
33
32
  // 5. Emit type declarations (enums, type aliases, interfaces, top-level constants)
34
33
  emitTypeDeclarations(ctx);
34
+ // 5.5. Async state machines — after globals so WIFI_SSID etc. are in scope
35
+ emitAsyncTaskClasses(ctx);
35
36
  // 6. Emit namespaces
36
37
  emitNamespaces(ctx);
37
38
  // 6.5. Emit function forward declarations (split mode — must precede class definitions)
@@ -221,7 +221,12 @@ export function emitClasses(ctx) {
221
221
  if (classDef.typeParameters && classDef.typeParameters.length > 0) {
222
222
  appendSourceLine(ctx, `template<typename ${classDef.typeParameters.join(", typename ")}>`);
223
223
  }
224
- appendSourceLine(ctx, `class ${classDef.name}${inheritanceClause} {`);
224
+ // A3-1-1: stamp `final` on leaf classes (nothing inherits from them).
225
+ // baseClassesNeeded holds every class name that appears as an
226
+ // extendsClass somewhere in the program. Disabled when autosar is off.
227
+ const isLeaf = !baseClassesNeeded.has(classDef.name);
228
+ const finalKw = ctx.compliance.isEnabled() && isLeaf ? " final" : "";
229
+ appendSourceLine(ctx, `class ${classDef.name}${inheritanceClause}${finalKw} {`);
225
230
  }
226
231
  const publicFields = classDef.fields.filter(f => f.visibility === "public");
227
232
  const privateFields = classDef.fields.filter(f => f.visibility === "private");
@@ -4,10 +4,11 @@ import type { ProgramAnalysisResult } from "../../ir/program-analysis.js";
4
4
  import type { EmissionScopeState } from "../snprintf-helpers.js";
5
5
  import type { ExpressionRenderer } from "../expression-renderer.js";
6
6
  import type { StatementRenderer } from "../statement-renderer.js";
7
- import type { Diagnostic, EmitMode, SourceMapEntry, SourceSpan } from "../../types.js";
7
+ import type { Diagnostic, EmitMode, ComplianceMode, SourceMapEntry, SourceSpan } from "../../types.js";
8
8
  import type { ResolvedNpmPackage } from "../../transpile/resolution.js";
9
9
  import type { BoardConstants } from "../../ir/board-resolver.js";
10
10
  import type { LibraryDefinition } from "../../types.js";
11
+ import type { ComplianceContext } from "../compliance/compliance-context.js";
11
12
  /** Options controlling C++ emission. */
12
13
  export interface EmitterOptions {
13
14
  outDir: string;
@@ -35,6 +36,12 @@ export interface EmitterOptions {
35
36
  crossModuleEnumNames?: Set<string>;
36
37
  crossModuleStringEnumNames?: Set<string>;
37
38
  crossModuleVariableTypes?: Map<string, string>;
39
+ /** AUTOSAR C++14 compliance mode. Default 'off' — feature is opt-in. */
40
+ autosar?: ComplianceMode;
41
+ /** Tool version, written into the sidecar deviation registry. */
42
+ toolVersion?: string;
43
+ /** When true (and autosar is warn/strict), also write the .autosar-deviations.arxml sidecar. */
44
+ autosarArxml?: boolean;
38
45
  }
39
46
  export interface MappedFunction {
40
47
  name: string;
@@ -56,6 +63,11 @@ export interface CallbackFunction {
56
63
  params: string[];
57
64
  statements: StatementIR[];
58
65
  debounceMs?: number;
66
+ /**
67
+ * True for GPIO / hardware ISR callbacks only. WiFi event handlers, timers,
68
+ * and setInterval use the same hoist path but must NOT get IRAM_ATTR.
69
+ */
70
+ isInterruptHandler?: boolean;
59
71
  /**
60
72
  * Return type of the synthesized free function. Defaults to "void" (the
61
73
  * historical ISR/HAL-callback case). Populated from a hoisted lambda's
@@ -141,6 +153,20 @@ export interface EmitterContext {
141
153
  headerLines: string[];
142
154
  sourceMapEntries: SourceMapEntry[];
143
155
  headerMapEntries: SourceMapEntry[];
156
+ /**
157
+ * Active debug mode. When 'gdb', appendSourceLine emits `#line` markers
158
+ * before lines whose TS source span transitions. 'printf' = no markers.
159
+ * Resolved once from strategy.debugMode(buildTarget) during setup.
160
+ */
161
+ debugMode: 'gdb' | 'printf';
162
+ /**
163
+ * The {filePath, line} of the most recently emitted linemarker, or null if
164
+ * none yet. Used by appendSourceLine for transition detection.
165
+ */
166
+ lastEmittedSource: {
167
+ filePath: string;
168
+ line: number;
169
+ } | null;
144
170
  cArrayVarNames: Set<string>;
145
171
  fnCArrayVarNames: Map<string, Set<string>>;
146
172
  globalPointerVarTypes: Map<string, string>;
@@ -171,4 +197,5 @@ export interface EmitterContext {
171
197
  interfaceNamespaceMap: Map<string, string>;
172
198
  /** Map of interface name to its field types (e.g., "Task" -> Map("id" -> "std::string", "title" -> "std::string")) */
173
199
  interfaceFieldTypes: Map<string, Map<string, string>>;
200
+ compliance: ComplianceContext;
174
201
  }