diff --git a/__tests__/preprocess-embedded-templates-tests.js b/__tests__/preprocess-embedded-templates-tests.js index 8a70fd03..6d238c18 100644 --- a/__tests__/preprocess-embedded-templates-tests.js +++ b/__tests__/preprocess-embedded-templates-tests.js @@ -245,6 +245,55 @@ describe('htmlbars-inline-precompile: preprocessEmbeddedTemplates', () => { `); }); + it('it does not process templates or tokens in comments', () => { + let preprocessed = preprocessEmbeddedTemplates( + stripIndent` + // + /* */ + /* + + other tokens + \`"'/ + */ + + + `, + TEMPLATE_TAG_CONFIG + ); + + expect(preprocessed).toMatchInlineSnapshot(` + Object { + "output": "// + /* */ + /* + + other tokens + \`\\"'/ + */ + + [GLIMMER_TEMPLATE(\`\`)]", + "replacements": Array [ + Object { + "index": 106, + "newLength": 19, + "oldLength": 10, + "originalCol": 1, + "originalLine": 9, + "type": "start", + }, + Object { + "index": 116, + "newLength": 3, + "oldLength": 11, + "originalCol": 11, + "originalLine": 9, + "type": "end", + }, + ], + } + `); + }); + it('works with class templates', () => { let preprocessed = preprocessEmbeddedTemplates( stripIndent` @@ -621,6 +670,59 @@ describe('htmlbars-inline-precompile: preprocessEmbeddedTemplates', () => { `); }); + it('it does not process templates or tokens in comments', () => { + let preprocessed = preprocessEmbeddedTemplates( + stripIndent` + import { hbs } from 'ember-template-imports'; + + // hbs\`hello\` + /* hbs\`hello\` */ + /* + hbs\`hello\` + other tokens + \`"'/ + */ + + export default hbs\`hello\`; + `, + TEMPLATE_LITERAL_CONFIG + ); + + expect(preprocessed).toMatchInlineSnapshot(` + Object { + "output": "import { hbs } from 'ember-template-imports'; + + // hbs\`hello\` + /* hbs\`hello\` */ + /* + hbs\`hello\` + other tokens + \`\\"'/ + */ + + export default hbs(\`hello\`);", + "replacements": Array [ + Object { + "index": 135, + "newLength": 5, + "oldLength": 4, + "originalCol": 16, + "originalLine": 11, + "type": "start", + }, + Object { + "index": 144, + "newLength": 2, + "oldLength": 1, + "originalCol": 25, + "originalLine": 11, + "type": "end", + }, + ], + } + `); + }); + it('exposes template identifiers', () => { let preprocessed = preprocessEmbeddedTemplates( stripIndent` diff --git a/src/parse-templates.ts b/src/parse-templates.ts index cf43a58f..6d1d6761 100644 --- a/src/parse-templates.ts +++ b/src/parse-templates.ts @@ -19,6 +19,11 @@ export interface TemplateLiteralMatch { const escapeChar = '\\'; const stringOrRegexDelimiter = /['"/]/; +const singleLineCommentStart = /\/\//; +const newLine = /\n/; +const multiLineCommentStart = /\/\*/; +const multiLineCommentEnd = /\*\//; + const templateLiteralStart = /([$a-zA-Z_][0-9a-zA-Z_$]*)?`/; const templateLiteralEnd = /`/; @@ -70,7 +75,20 @@ export function parseTemplates( const argumentsMatchRegex = new RegExp(`<${templateTag}[^<]*\\S[^<]*>`); const allTokens = new RegExp( - `["'\`/]|([$a-zA-Z_][0-9a-zA-Z_$]*)\`|\\\${|{|}|<${templateTag}[^<]*?>|<\\/${templateTag}>`, + [ + singleLineCommentStart.source, + newLine.source, + multiLineCommentStart.source, + multiLineCommentEnd.source, + stringOrRegexDelimiter.source, + templateLiteralStart.source, + templateLiteralEnd.source, + dynamicSegmentStart.source, + dynamicSegmentEnd.source, + blockStart.source, + templateTagStart.source, + templateTagEnd.source, + ].join('|'), 'g' ); @@ -93,21 +111,21 @@ export function parseTemplates( tokens: RegExpMatchArray[], isTopLevel = false ) { - if (token[0].match(stringOrRegexDelimiter)) { - parseStringOrRegex(results, template, token, tokens); - } - - if (token[0].match(templateLiteralStart)) { + if (token[0].match(multiLineCommentStart)) { + parseMultiLineComment(results, template, token, tokens); + } else if (token[0].match(singleLineCommentStart)) { + parseSingleLineComment(results, template, token, tokens); + } else if (token[0].match(templateLiteralStart)) { parseTemplateLiteral(results, template, token, tokens, isTopLevel); - } - - if ( + } else if ( isTopLevel && templateTag !== undefined && templateTagStart && token[0].match(templateTagStart) ) { parseTemplateTag(results, template, token, tokens); + } else if (token[0].match(stringOrRegexDelimiter)) { + parseStringOrRegex(results, template, token, tokens); } } @@ -130,6 +148,44 @@ export function parseTemplates( } } + /** + * Parse a string or a regex. All tokens within a string or regex are ignored + * since there are no dynamic segments within these. + */ + function parseSingleLineComment( + _results: TemplateMatch[], + _template: string, + _startToken: RegExpMatchArray, + tokens: RegExpMatchArray[] + ) { + while (tokens.length > 0) { + const currentToken = expect(tokens.shift(), 'expected token'); + + if (currentToken[0] === '\n') { + return; + } + } + } + + /** + * Parse a string or a regex. All tokens within a string or regex are ignored + * since there are no dynamic segments within these. + */ + function parseMultiLineComment( + _results: TemplateMatch[], + _template: string, + _startToken: RegExpMatchArray, + tokens: RegExpMatchArray[] + ) { + while (tokens.length > 0) { + const currentToken = expect(tokens.shift(), 'expected token'); + + if (currentToken[0] === '*/') { + return; + } + } + } + /** * Parse a template literal. If a dynamic segment is found, enters the dynamic * segment and parses it recursively. If no dynamic segments are found and the