Skip to content

feat: proper line/column tracking in TemplateParseError for better error reporting #2

@coderabbitai

Description

@coderabbitai

Summary

When JSON.parse fails during template compilation in src/template.ts, the thrown TemplateParseError currently hardcodes the offset to 0, losing actual position information.

Additionally, buildTree() in src/tree.ts always throws TemplateParseError(..., 0) when it detects a variable expression in an object key, even though the sentinel encodes the originating expression index — which maps directly to a real source offset.

Motivation

Accurate offsets in TemplateParseError would significantly improve the developer experience by pointing directly to the problematic location in the original template string, rather than always reporting offset 0.

Affected locations

1. compile()JSON.parse catch block (src/template.ts)

  • Parse the native SyntaxError message from JSON.parse using a regex to extract numeric column/position info (e.g. "column X" or "position X" patterns present in V8/SpiderMonkey messages).
  • Map that extracted position back to the original template string, accounting for the sentinel substitutions made during compilation.
  • Fall back to 0 if no numeric position can be extracted from the error message.
  • Consider also tracking line numbers (not just character offsets) in TemplateParseError for multi-line templates.

2. buildTree() — object-key sentinel check (src/tree.ts)

buildTree() currently uses SENTINEL_RE.test(k) and hard-codes 0 as the offset:

if (SENTINEL_RE.test(k)) {
  throw new TemplateParseError(
    'Variable expressions in object keys are not supported',
    0,  // always 0 — real offset is knowable
  );
}

The sentinel encodes the expression index (e.g. \uE000E2\uE000 → index 2), which can be looked up in the exprs array already available at compile time. The fix is to:

  • Thread a readonly number[] of expression offsets into buildTree() (e.g. exprs.map(e => e.offset) passed from compile()).
  • Switch from SENTINEL_RE.test(k) to SENTINEL_RE.exec(k) to capture the match group.
  • Use exprOffsets[Number(match[1])] ?? 0 as the TemplateParseError offset.
  • Propagate exprOffsets into recursive buildTree() calls for arrays and object values.

Context

Requested by

@amery

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions