Source-Mapped Diagnostics
When the C++ has a problem compiling, Cuttlefish translates the error back to the line of TypeScript that caused it — so you don’t have to read generated code. It keeps a behind-the-scenes map (a “source map”) that links each piece of generated C++ to the TypeScript it came from, and uses it to point you straight at your own code.
Source Maps
Every transpilation generates a .thcppmap.json file alongside the C++ output. This maps generated C++ line/column ranges to TypeScript source locations.
Source Map Structure
{
"version": 1,
"generatedFilePath": "out/sketch.ino",
"sourceFilePath": "src/sketch.ts",
"entries": [
{
"generatedStartLine": 42,
"generatedStartColumn": 5,
"generatedEndLine": 42,
"generatedEndColumn": 20,
"tsSpan": {
"start": { "line": 15, "column": 0 },
"end": { "line": 15, "column": 25 }
},
"nodeKind": "CallExpression",
"symbolName": "readAnalog"
}
]
}Each entry contains:
- Generated range — the C++ line and column span in the output file
- TypeScript span — the originating TypeScript source location
- Node kind — a label describing what kind of code this came from (for context)
- Symbol name — the function, variable, or class involved
⚙️ Advanced details — how errors get matched to your code
Node kinds. The nodeKind field uses your code’s structure to describe each entry, with values such as CallExpression (a function call), Identifier (a name), or PropertyAccess (a .property access). These come from Cuttlefish’s internal representation of your TypeScript.
Scoring algorithm. When mapping a C++ error location, the transpiler scores each entry by how tightly it encloses the error position. Entries with the smallest span (most precise match) win. If no entry directly encloses the error, the nearest entry by line distance is used as a fallback.
The map-error Command
Manually map a C++ error to TypeScript:
cuttlefish map-error out/sketch.ino.thcppmap.json
--line 42
--column 10
--message "error: 'readAnalog' was not declared in this scope"Output:
C++ error at out/sketch.ino:42:10
→ src/sketch.ts:15:8 (CallExpression: readAnalog)
error: 'readAnalog' was not declared in this scopeYou can pass either the .thcppmap.json file directly, or the generated C++ file (the .thcppmap.json suffix is appended automatically).
Automatic Error Mapping
When using --compile, C++ compiler errors are automatically mapped back to TypeScript:
cuttlefish build --compileThe transpiler:
- Invokes the C++ compiler (e.g.,
arduino-cli compile) - Captures stderr output with error locations
- For each error, looks up the source map to find the TypeScript span
- Reports the TypeScript location alongside the C++ error
This means you see:
src/sketch.ts:15:8 - error: 'readAnalog' was not declared in this scope
(C++ location: out/sketch.ino:42:10)Instead of having to manually correlate C++ line numbers with your TypeScript source.
The --diagnostics Flag
Generate a full diagnostics report:
cuttlefish build --diagnosticsProduces two files in the output directory:
diagnostics.md — Human-Readable Report
A markdown report with:
- Execution flow — call graph with Mermaid diagram
- GPIO pin usage — table of pins with their modes (INPUT, OUTPUT, PWM, etc.)
- Peripheral allocation — which I2C, SPI, UART, ADC, PWM, and timer instances are active
- Pin usage summary — total pins, used pins, unused pins
- Heap estimate — SRAM consumption for global variables and stack allocations
- Async task analysis — detected async tasks and their intervals
- Build timing — breakdown of time spent in each transpile phase
diagnostics.json — Machine-Readable Report
Everything from the markdown report, plus:
- All transpile diagnostics with full metadata (severity, code, hint)
- Source map entries
- Board details (MCU, architecture, flash/SRAM sizes, clock speed)
- Profiler timing data
⚙️ Advanced details — extra graph fields in diagnostics.json
The JSON report also carries these structural fields:
- Full call graph as JSON (nodes and referenced-by relationships) — which functions call which
- Module dependency graph — the import edges between files
- Tree-shaking report (Cuttlefish removing unused code) — the list of symbols that were dropped because nothing used them
Diagnostics Report Contents
Metadata
{
"metadata": {
"timestamp": "2024-01-15T10:30:00.000Z",
"sourceFile": "sketch.ts",
"target": "avr",
"board": "@typecad/board-arduino-uno",
"framework": "@typecad/framework-arduino",
"buildTarget": "arduino:avr:uno",
"outputFile": "sketch.ino",
"boardDetails": {
"mcu": "ATmega328P",
"architecture": "avr",
"flashKb": 32,
"sramKb": 2,
"clockSpeedMhz": 16
}
}
}Pin Usage
GPIO Pin Usage:
Pin | Number | Mode
D13 | 13 | OUTPUT
A0 | 14 | INPUT (ADC)
D3 | 3 | OUTPUT (PWM)
Summary: 20 total, 3 used, 17 unusedPeripheral Allocation
Peripherals:
I2C0 — active (A4/SDA, A5/SCL)
SPI0 — active (D11/MOSI, D12/MISO, D13/SCK, D10/SS)
ADC — channel 0 (A0)
PWM — D3 (Timer2)Heap Estimate
The report estimates SRAM consumption based on:
- Global variable sizes
- Stack buffer allocations (from template literals, string operations)
- Array sizes
- Bus buffer sizes (Serial RX/TX)
On AVR boards with limited RAM (2KB on Arduino Uno), this helps catch memory overflows before flashing.
Execution Flow
The call graph shows which functions call which:
Entry points: setup, loop
setup → I2C0.begin, D13.asOutput
loop → sensor.readAnalog, led.toggle, delay
ISR handlers: none
Async tasks: noneBuild Timing
The phase names below are Cuttlefish’s build steps: parse reads your TypeScript, ir-build builds Cuttlefish’s internal representation, validation checks for problems, tree-shaking removes unused code, emit writes the C++, and compile runs the C++ compiler.
{
"buildTiming": {
"phases": {
"parse": 45,
"ir-build": 120,
"validation": 30,
"tree-shaking": 15,
"emit": 80,
"compile": 3200
},
"totalMs": 3490
}
}Source Map Resolution for Sketches
When a sketch is flattened (multiple files merged into one .ino), the source map resolver searches for the correct map file:
- Tries the explicitly provided map path
- Looks for
{sketchName}.thcppmap.jsonin the sketch directory - Looks for
example.thcppmap.json(common for example sketches) - Falls back to any
.thcppmap.jsonfile in the directory
This ensures error mapping works even with complex build layouts.
On This Page