Skip to content

Commit 1a527ee

Browse files
dmealingclaude
andcommitted
refactor(codegen-ts): simplify template-source annotator/renderers (behavior-preserving)
annotate.ts: factor the duplicated escaped/unescaped variable-token construction (implicit-iterator + resolve-and-push) into a single makeVarToken helper. render.ts: factor the repeated styled-span + optional <a href> wrapping across the var/unescaped, section/inverted/close, and partial cases into a single linkSpan helper. Token IR, all rendered bytes, and every golden are byte-identical; codegen-ts suite green at 809/809. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 18928c3 commit 1a527ee

2 files changed

Lines changed: 32 additions & 41 deletions

File tree

server/typescript/packages/codegen-ts/src/generators/template-source-annotate.ts

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ export function annotateTemplate(
132132
return { field, href: fieldHref(field.owner, field.name) };
133133
}
134134

135+
// Build a variable token ({{x}} or {{&x}}/{{{x}}}). The implicit iterator
136+
// `.` is always valid against the current context; any other path resolves
137+
// against the enriched tree (carrying field + href when found).
138+
function makeVarToken(
139+
kind: "var" | "unescaped",
140+
raw: string,
141+
value: string,
142+
stack: ResolveStack<AnnotatePayloadField>,
143+
): TplToken {
144+
if (value === ".") return { kind, raw, path: value, valid: true };
145+
const r = resolveAt(stack, value);
146+
return r
147+
? { kind, raw, path: value, field: r.field, href: r.href, valid: true }
148+
: { kind, raw, path: value, valid: false };
149+
}
150+
135151
function walk(
136152
tokens: Token[],
137153
stack: ResolveStack<AnnotatePayloadField>,
@@ -156,48 +172,15 @@ export function annotateTemplate(
156172
// {{x}} — escaped variable.
157173
const raw = source.slice(start, end);
158174
cursor = end;
159-
if (value === ".") {
160-
// Implicit iterator — always valid, references the current context.
161-
out.push({ kind: "var", raw, path: value, valid: true });
162-
break;
163-
}
164-
const r = resolveAt(stack, value);
165-
out.push(
166-
r
167-
? {
168-
kind: "var",
169-
raw,
170-
path: value,
171-
field: r.field,
172-
href: r.href,
173-
valid: true,
174-
}
175-
: { kind: "var", raw, path: value, valid: false },
176-
);
175+
out.push(makeVarToken("var", raw, value, stack));
177176
break;
178177
}
179178
case "&":
180179
case "{": {
181180
// {{&x}} / {{{x}}} — unescaped variable (mustache.js emits "&" for both).
182181
const raw = source.slice(start, end);
183182
cursor = end;
184-
if (value === ".") {
185-
out.push({ kind: "unescaped", raw, path: value, valid: true });
186-
break;
187-
}
188-
const r = resolveAt(stack, value);
189-
out.push(
190-
r
191-
? {
192-
kind: "unescaped",
193-
raw,
194-
path: value,
195-
field: r.field,
196-
href: r.href,
197-
valid: true,
198-
}
199-
: { kind: "unescaped", raw, path: value, valid: false },
200-
);
183+
out.push(makeVarToken("unescaped", raw, value, stack));
201184
break;
202185
}
203186
case "#":

server/typescript/packages/codegen-ts/src/generators/template-source-render.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ function styledSpan(style: string, inner: string): string {
141141
return `<span style="${style}">${inner}</span>`;
142142
}
143143

144+
/** A styled span for a token kind, wrapped in a clickable `<a href>` when the
145+
* token resolved to a link (else the bare span). The raw text is HTML-escaped. */
146+
function linkSpan(
147+
style: string,
148+
raw: string,
149+
href: string | undefined,
150+
): string {
151+
const span = styledSpan(style, escapeHtml(raw));
152+
return href ? `<a href="${escapeHtml(href)}">${span}</a>` : span;
153+
}
154+
144155
/**
145156
* The collapsed <details> "Linked view": a <pre> reproducing the template where
146157
* each token is an inline-styled <span> (color by kind) and each resolved
@@ -159,22 +170,19 @@ export function renderRichLinkedHtml(tokens: TplToken[]): string {
159170
}
160171
case "var":
161172
case "unescaped": {
162-
const span = styledSpan(STYLE_VAR, escapeHtml(t.raw));
163-
pre += t.href ? `<a href="${escapeHtml(t.href)}">${span}</a>` : span;
173+
pre += linkSpan(STYLE_VAR, t.raw, t.href);
164174
break;
165175
}
166176
case "section":
167177
case "inverted":
168178
case "close": {
169-
const span = styledSpan(STYLE_SECTION, escapeHtml(t.raw));
170179
// Only open tags (section/inverted) carry an href; close tags don't.
171180
const href = "href" in t ? t.href : undefined;
172-
pre += href ? `<a href="${escapeHtml(href)}">${span}</a>` : span;
181+
pre += linkSpan(STYLE_SECTION, t.raw, href);
173182
break;
174183
}
175184
case "partial": {
176-
const span = styledSpan(STYLE_PARTIAL, escapeHtml(t.raw));
177-
pre += t.href ? `<a href="${escapeHtml(t.href)}">${span}</a>` : span;
185+
pre += linkSpan(STYLE_PARTIAL, t.raw, t.href);
178186
break;
179187
}
180188
case "comment": {

0 commit comments

Comments
 (0)