diff --git a/common/prerender_annotation_walker_test.ts b/common/prerender_annotation_walker_test.ts index 3646b682..885e5833 100644 --- a/common/prerender_annotation_walker_test.ts +++ b/common/prerender_annotation_walker_test.ts @@ -84,7 +84,13 @@ describe('prerender_annotation_walker', () => { const nodes = Array.from(walkAllAnnotations(root)); expect(nodes.length).toBe(1); const node = nodes[0]!; - node.replace(new HTMLElement('script', {})); + node.replace(new HTMLElement( + 'script' /* tagName */, + {} /* keyAttrs */, + '' /* rawAttrs */, + null /* parentNode */, + [0, 0] /* range */, + )); const extracted = root.toString(); expect(extracted).toBe(` @@ -146,8 +152,13 @@ describe('prerender_annotation_walker', () => { node.remove(); // Update the node. // Try to update it again. - expect(() => node.replace(new HTMLElement('script', {}))) - .toThrowError('Node was already updated, cannot replace it.'); + expect(() => node.replace(new HTMLElement( + 'script' /* tagName */, + {} /* keyAttrs */, + '' /* rawAttrs */, + null /* parentNode */, + [0, 0] /* range */, + ))).toThrowError('Node was already updated, cannot replace it.'); }); }); -}); \ No newline at end of file +}); diff --git a/examples/site/blog/blog_test.ts b/examples/site/blog/blog_test.ts index 08a0df79..0b8c10c7 100644 --- a/examples/site/blog/blog_test.ts +++ b/examples/site/blog/blog_test.ts @@ -10,7 +10,7 @@ describe('Blog', () => { // Renders the blog page. const page = parse(new TextDecoder().decode(index!.contents)); - expect(page.querySelector('title').text).toBe('Blog'); + expect(page.querySelector('title')!.text).toBe('Blog'); // Renders links to all generated pages. const posts = Object.fromEntries(page.querySelectorAll('article ul a') @@ -31,9 +31,9 @@ describe('Blog', () => { // Renders the Foo post. const page = parse(new TextDecoder().decode(post!.contents)); - expect(page.querySelector('title').text).toBe('Foo'); + expect(page.querySelector('title')!.text).toBe('Foo'); - const article = page.querySelector('article'); + const article = page.querySelector('article')!; expect(article.text).toContain('This is a blog post about Foo!'); }); @@ -46,9 +46,9 @@ describe('Blog', () => { // Renders the Bar post. const page = parse(new TextDecoder().decode(post!.contents)); - expect(page.querySelector('title').text).toBe('Bar'); + expect(page.querySelector('title')!.text).toBe('Bar'); - const article = page.querySelector('article'); + const article = page.querySelector('article')!; expect(article.text) .toContain('This is another blog post generated from markdown.'); }); @@ -62,9 +62,9 @@ describe('Blog', () => { // Renders the Baz post. const page = parse(new TextDecoder().decode(post!.contents)); - expect(page.querySelector('title').text).toBe('Baz'); + expect(page.querySelector('title')!.text).toBe('Baz'); - const article = page.querySelector('article'); + const article = page.querySelector('article')!; expect(article.text).toContain( 'Here is one more blog post about nothing in particular'); }); diff --git a/examples/site/components/base/base_test.ts b/examples/site/components/base/base_test.ts index 8be7f1b6..c06c9f6d 100644 --- a/examples/site/components/base/base_test.ts +++ b/examples/site/components/base/base_test.ts @@ -12,7 +12,7 @@ describe('base', () => { expect(callback).toHaveBeenCalledOnceWith(); // Title should be set. - expect(fragment.querySelector('html head title').text) + expect(fragment.querySelector('html head title')!.text) .toBe('Some title'); // Renders the header and footer. @@ -20,7 +20,7 @@ describe('base', () => { expect(fragment.querySelector('[comp-footer]')).toBeDefined(); // Callback should be placed under `
` tag. - const main = fragment.querySelector('body main'); + const main = fragment.querySelector('body main')!; const mainChildren = main.childNodes .filter((node) => node.nodeType === NodeType.ELEMENT_NODE); expect(mainChildren.length).toBe(1); @@ -36,7 +36,7 @@ describe('base', () => { expect(callback).toHaveBeenCalledOnceWith(); // Title should be set. - expect(fragment.querySelector('html head title').text) + expect(fragment.querySelector('html head title')!.text) .toBe('Some title'); // Renders the header and footer. @@ -44,7 +44,7 @@ describe('base', () => { expect(fragment.querySelector('[comp-footer]')).toBeDefined(); // Callback should be placed under `
` tag. - const main = fragment.querySelector('body main'); + const main = fragment.querySelector('body main')!; const mainChildren = main.childNodes .filter((node) => node.nodeType === NodeType.ELEMENT_NODE); expect(mainChildren.length).toBe(1); diff --git a/examples/site/components/counter/counter_prerender_test.ts b/examples/site/components/counter/counter_prerender_test.ts index 3a84d75c..3b5c69c0 100644 --- a/examples/site/components/counter/counter_prerender_test.ts +++ b/examples/site/components/counter/counter_prerender_test.ts @@ -11,11 +11,11 @@ describe('counter', () => { expect(counter).toBeDefined(); // Custom element light DOM should be prerendered. - expect(counter.getAttribute('initial')).toBe('5'); - expect(counter.querySelector('#label').text) + expect(counter!.getAttribute('initial')).toBe('5'); + expect(counter!.querySelector('#label')!.text) .toBe('The current count is: 5.'); - expect(counter.querySelector('#decrement')).toBeDefined(); - expect(counter.querySelector('#increment')).toBeDefined(); + expect(counter!.querySelector('#decrement')).toBeDefined(); + expect(counter!.querySelector('#increment')).toBeDefined(); }); }); }); diff --git a/examples/site/components/footer/footer_test.ts b/examples/site/components/footer/footer_test.ts index 7c692974..9e1842bc 100644 --- a/examples/site/components/footer/footer_test.ts +++ b/examples/site/components/footer/footer_test.ts @@ -6,8 +6,12 @@ describe('footer', () => { it('renders a footer', () => { const fragment = parse(renderFooter()); - expect(fragment.structuredText) - .toContain('Made with Bazel and rules_prerender.'); + const footerText = fragment.textContent + .trim() + .split('\n') + .map((line) => line.trim()) + .join(' '); + expect(footerText).toBe('Made with Bazel and rules_prerender.'); }); }); }); diff --git a/package.json b/package.json index 2fa386ee..f164146f 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "http-server": "^14.1.1", "lightningcss": "^1.19.0", "markdown-it": "^12.0.4", - "node-html-parser": "^2.0.0", + "node-html-parser": "^6.1.5", "rollup": "^2.35.1", "yargs": "^16.2.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 332fc59a..abb882d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ specifiers: jasmine: ^4.3.0 lightningcss: ^1.19.0 markdown-it: ^12.0.4 - node-html-parser: ^2.0.0 + node-html-parser: ^6.1.5 rollup: ^2.35.1 tree-kill: ^1.2.2 typescript: 4.9.5 @@ -31,7 +31,7 @@ dependencies: http-server: 14.1.1 lightningcss: 1.19.0 markdown-it: 12.0.4 - node-html-parser: 2.0.0 + node-html-parser: 6.1.5 rollup: 2.35.1 yargs: 16.2.0 @@ -600,6 +600,10 @@ packages: readable-stream: 3.6.0 dev: true + /boolbase/1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -789,6 +793,16 @@ packages: which: 2.0.2 dev: true + /css-select/5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.0.1 + nth-check: 2.1.1 + dev: false + /css-shorthand-properties/1.1.1: resolution: {integrity: sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==} dev: true @@ -797,6 +811,11 @@ packages: resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} dev: true + /css-what/6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -916,6 +935,33 @@ packages: esutils: 2.0.3 dev: true + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + dev: false + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils/3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + /edge-paths/2.2.1: resolution: {integrity: sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw==} dependencies: @@ -943,6 +989,11 @@ packages: resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} dev: false + /entities/4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + dev: false + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -1867,9 +1918,10 @@ packages: whatwg-url: 5.0.0 dev: true - /node-html-parser/2.0.0: - resolution: {integrity: sha512-3wJdYSxiVIBxuiFm9UtfNWAlBw2P+Vb/RN1nqf40q2JeZDpcJ1HsrWuWV3j15SSJ25TvfnOoac2Q+uDU9iY0sw==} + /node-html-parser/6.1.5: + resolution: {integrity: sha512-fAaM511feX++/Chnhe475a0NHD8M7AxDInsqQpz6x63GRF7xYNdS8Vo5dKsIVPgsOvG7eioRRTZQnWBrhDHBSg==} dependencies: + css-select: 5.1.0 he: 1.2.0 dev: false @@ -1883,6 +1935,12 @@ packages: engines: {node: '>=10'} dev: true + /nth-check/2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + /object-inspect/1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: false diff --git a/tools/binaries/resource_injector/injector.ts b/tools/binaries/resource_injector/injector.ts index 61a39c29..6cb613ed 100644 --- a/tools/binaries/resource_injector/injector.ts +++ b/tools/binaries/resource_injector/injector.ts @@ -60,7 +60,13 @@ function getOrInjectHead(root: HTMLElement): HTMLElement { const existingHead = root.querySelector('head'); if (existingHead) return existingHead; - const head = new HTMLElement('head', {}); + const head = new HTMLElement( + 'head' /* tagName */, + {} /* keyAttrs */, + '' /* rawAttrs */, + null /* parentNode */, + [0, 0] /* range */, + ); const html = root.querySelector('html'); if (!html) throw new Error(' element could not be found.'); @@ -81,7 +87,13 @@ function injectScript(root: HTMLElement, action: InjectScript): void { const head = getOrInjectHead(root); // Insert a `