diff --git a/src/index.d.ts b/src/index.d.ts index 38a469b..f5e62f8 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -32,7 +32,8 @@ export interface ParseOptions { templateOnly?: boolean; /** * Custom JS/TS parser. Called with the placeholder JS string - * (templates replaced with backtick expressions of equal length). + * (templates replaced with `void `...`` expressions, or `static{`...`}` + * blocks for class members, of equal length). * Must return at least `{ ast }`. */ parser?: (placeholderJS: string) => { ast: ASTNode; [key: string]: unknown }; diff --git a/src/parse.js b/src/parse.js index a41491e..4ce476c 100644 --- a/src/parse.js +++ b/src/parse.js @@ -55,7 +55,7 @@ const preprocessor = new Preprocessor(); const PLACEHOLDER_TYPES = new Set([ "ExpressionStatement", "StaticBlock", - "TemplateLiteral", + "UnaryExpression", "ExportDefaultDeclaration", ]); @@ -250,7 +250,7 @@ export function toTree(source, options = {}) { setParent(ast, parent); // Recurse into the Glimmer subtree so visitors fire on its nodes too. // The Glimmer root's parentPath reflects its true JS parent — the - // placeholder (TemplateLiteral / StaticBlock) is an internal artifact. + // placeholder (UnaryExpression / StaticBlock) is an internal artifact. if (hasVisitors) walkWithKeys(ast, parentPath); return; } @@ -348,9 +348,16 @@ export const parse = toTree; * Replaces regions with placeholder expressions * of the same character length that are valid JS/TS. * - * Expression templates become: `content ` (backtick, space-padded) + * Expression templates become: void `content ` (void + backtick, space-padded) * Class member templates become: static{`content `} (static block, space-padded) * + * The `void` prefix matters at a statement start: a bare backtick literal + * after an unterminated expression statement continues it as a tagged + * template (`const y = x\n`...`` reads as `x`...``), whereas `void` cannot + * continue an expression, so automatic semicolon insertion applies exactly + * as it does for the real `