diff --git a/CHANGELOG.md b/CHANGELOG.md index ddaa1ce..855f04e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Template errors now include approximate line numbers from the offending + template. They also print the registered custom element tag name (#201). + ## [1.1.1] - 2024-11-09 ### Fixed diff --git a/test/test-initialization-errors.js b/test/test-initialization-errors.js index a97dce2..0d20954 100644 --- a/test/test-initialization-errors.js +++ b/test/test-initialization-errors.js @@ -106,7 +106,7 @@ it('errors are thrown in connectedCallback when template result fails to render' try { el.connectedCallback(); } catch (error) { - const expected = ' — Invalid template for "TestElement" at path "test-element-3"'; + const expected = 'Invalid template for "TestElement" / at path "test-element-3".'; message = error.message; passed = error.message.endsWith(expected); } @@ -142,7 +142,7 @@ it('errors are thrown in connectedCallback when template result fails to render try { el.connectedCallback(); } catch (error) { - const expected = ' — Invalid template for "TestElement" at path "test-element-4[id="testing"][class="foo bar"][boolean][variation="primary"]"'; + const expected = 'Invalid template for "TestElement" / at path "test-element-4[id="testing"][class="foo bar"][boolean][variation="primary"]".'; message = error.message; passed = error.message.endsWith(expected); } diff --git a/test/test-template-engine.js b/test/test-template-engine.js index 100dd52..575df73 100644 --- a/test/test-template-engine.js +++ b/test/test-template-engine.js @@ -846,6 +846,7 @@ describe('rendering errors', () => { container.remove(); }); + // Note that this is line “1” because it’s perfectly inlined. it('throws for unquoted attributes', () => { const templateResultReference = html`
Gotta double-quote those.
`; const container = document.createElement('div'); @@ -856,12 +857,14 @@ describe('rendering errors', () => { } catch (e) { error = e; } - assert(error?.message === `Found invalid template string "
{ - const templateResultReference = html`
Gotta double-quote those.
`; + const templateResultReference = html`\n
Gotta double-quote those.
`; const container = document.createElement('div'); document.body.append(container); let error; @@ -870,12 +873,12 @@ describe('rendering errors', () => { } catch (e) { error = e; } - assert(error?.message === `Found invalid template string "
{ - const templateResultReference = html`
Gotta double-quote those.
`; + const templateResultReference = html`\n\n\n
Gotta double-quote those.
`; const container = document.createElement('div'); document.body.append(container); let error; @@ -884,7 +887,7 @@ describe('rendering errors', () => { } catch (e) { error = e; } - assert(error?.message === `Found invalid template string "
{ } catch (e) { error = e; } - assert(error?.message === `Found invalid template string "
at path "${pathString}".`; throw new Error(message, { cause: error }); } } @@ -1385,7 +1387,10 @@ class TemplateEngine { string = string.slice(0, -3 - name.length) + `${TemplateEngine.#ATTRIBUTE_PREFIXES.property}${iii}="${name}`; state.index = 1; // Accounts for an expected quote character next. } else { - throw new Error(`Found invalid template string "${string}" at "${string.slice(state.index)}".`); + // It’s “on or after” because interpolated JS can span multiple lines. + const handled = [...strings.slice(0, iii), string.slice(0, state.index)].join(''); + const lineCount = handled.split('\n').length; + throw new Error(`Found invalid template on or after line ${lineCount} in substring \`${string}\`. Failed to parse \`${string.slice(state.index)}\`.`); } } } else {