From 7faa0dda541f19ba7a7fd9f8274f5453651a2360 Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Mon, 8 Jan 2024 23:16:42 -0500 Subject: [PATCH] Add generated types and large end-to-end test With this, we're ready to release v1.0.0! There's still work to do, but all the functionality is implemented, strongly typed, and completely tested. --- .eslintrc | 7 + README.md | 16 +- lib/template.d.ts | 11 + package.json | 2 + pnpm-lock.yaml | 321 +++++++++++++++++++++++- test/large.test.js | 40 +++ test/large/components/_message-link.hbs | 9 + test/large/components/app.js | 29 +++ test/large/components/helpers.js | 46 ++++ test/large/components/introduction.hbs | 9 + test/large/index.html | 15 ++ test/large/main.js | 24 ++ test/large/types.js | 14 ++ vitest.config.js | 11 + 14 files changed, 534 insertions(+), 20 deletions(-) create mode 100644 lib/template.d.ts create mode 100644 test/large.test.js create mode 100644 test/large/components/_message-link.hbs create mode 100644 test/large/components/app.js create mode 100644 test/large/components/helpers.js create mode 100644 test/large/components/introduction.hbs create mode 100644 test/large/index.html create mode 100644 test/large/main.js create mode 100644 test/large/types.js diff --git a/.eslintrc b/.eslintrc index aee7c74..093bf6a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -50,5 +50,12 @@ "no-console": [ "error", { "allow": [ "warn", "error" ]} ] + }, + "settings": { + "jsdoc": { + "preferredTypes": { + "Object": "object" + } + } } } diff --git a/README.md b/README.md index a2abb92..cdd8d0f 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,8 @@ [Rollup][] plugin to precompile [Handlebars][] templates into [JavaScript modules][] -_**Status**: I've still got a bit of work to do before publishing v1.0.0. I need -to add tests based on the mbland/tomcat-servlet-testing-example project from -whence this came and add more documentation. I plan to finish this by -2024-01-11._ +_**Note**: I still need to add more documentation, but the plugin is fully +functional and tested._ Source: @@ -52,16 +50,6 @@ Each generated Handlebars template module exports two functions: Most of the time, you'll want to use the default export, imported as `Template()` by convention. -## Configuration - -## Motivation - -## Examples - -My [mbland/tomcat-servlet-testing-example][] project - -### Component pattern - ## Development Uses [pnpm][] and [Vitest][] for building and testing. The [Vitest browser diff --git a/lib/template.d.ts b/lib/template.d.ts new file mode 100644 index 0000000..c9fef53 --- /dev/null +++ b/lib/template.d.ts @@ -0,0 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +declare module "*.hbs" { + export const RawTemplate: HandlebarsTemplateDelegate + export default function (context: any, options?: RuntimeOptions): + DocumentFragment +} diff --git a/package.json b/package.json index d487d20..f0d23f0 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,9 @@ "jsdoc": "^4.0.2", "jsdoc-cli-wrapper": "^1.0.4", "jsdoc-plugin-typescript": "^2.2.1", + "jsdom": "^23.2.0", "rollup": "^4.9.4", + "test-page-opener": "^1.0.5", "typescript": "^5.3.3", "vitest": "^1.1.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c21054..7241b99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,15 +49,21 @@ devDependencies: jsdoc-plugin-typescript: specifier: ^2.2.1 version: 2.2.1 + jsdom: + specifier: ^23.2.0 + version: 23.2.0 rollup: specifier: ^4.9.4 version: 4.9.4 + test-page-opener: + specifier: ^1.0.5 + version: 1.0.5 typescript: specifier: ^5.3.3 version: 5.3.3 vitest: specifier: ^1.1.3 - version: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3) + version: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0) packages: @@ -74,6 +80,14 @@ packages: '@jridgewell/trace-mapping': 0.3.20 dev: true + /@asamuzakjp/dom-selector@2.0.1: + resolution: {integrity: sha512-QJAJffmCiymkv6YyQ7voyQb5caCth6jzZsQncYCpHXrJ7RqdYG5y43+is8mnFcYubdOkr7cn1+na9BdFMxqw7w==} + dependencies: + bidi-js: 1.0.3 + css-tree: 2.3.1 + is-potential-custom-element-name: 1.0.1 + dev: true + /@babel/code-frame@7.23.5: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} @@ -859,7 +873,7 @@ packages: magicast: 0.3.2 picocolors: 1.0.0 test-exclude: 6.0.0 - vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3) + vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0) transitivePeerDependencies: - supports-color dev: true @@ -882,7 +896,7 @@ packages: std-env: 3.7.0 test-exclude: 6.0.0 v8-to-istanbul: 9.2.0 - vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3) + vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0) transitivePeerDependencies: - supports-color dev: true @@ -929,7 +943,7 @@ packages: pathe: 1.1.1 picocolors: 1.0.0 sirv: 2.0.4 - vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3) + vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0) dev: true /@vitest/utils@1.1.3: @@ -960,6 +974,15 @@ packages: hasBin: true dev: true + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -1031,6 +1054,10 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -1040,6 +1067,12 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + dependencies: + require-from-string: 2.0.2 + dev: true + /bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true @@ -1166,6 +1199,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: true + /comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -1188,6 +1228,29 @@ packages: which: 2.0.2 dev: true + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: true + + /cssstyle@4.0.1: + resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==} + engines: {node: '>=18'} + dependencies: + rrweb-cssom: 0.6.0 + dev: true + + /data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + dev: true + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -1200,6 +1263,10 @@ packages: ms: 2.1.2 dev: true + /decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + dev: true + /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} @@ -1229,6 +1296,11 @@ packages: object-keys: 1.1.1 dev: true + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: true + /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1256,6 +1328,11 @@ packages: resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} dev: true + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} @@ -1405,7 +1482,7 @@ packages: dependencies: '@typescript-eslint/utils': 6.17.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 - vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3) + vitest: 1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0) transitivePeerDependencies: - supports-color - typescript @@ -1603,6 +1680,15 @@ packages: is-callable: 1.2.7 dev: true + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -1790,15 +1876,49 @@ packages: function-bind: 1.1.2 dev: true + /html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + dependencies: + whatwg-encoding: 3.1.1 + dev: true + /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /http-proxy-agent@7.0.0: + resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} dev: true + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + /ignore@5.3.0: resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} engines: {node: '>= 4'} @@ -1912,6 +2032,10 @@ packages: engines: {node: '>=8'} dev: true + /is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -2068,6 +2192,42 @@ packages: underscore: 1.13.6 dev: true + /jsdom@23.2.0: + resolution: {integrity: sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + '@asamuzakjp/dom-selector': 2.0.1 + cssstyle: 4.0.1 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + is-potential-custom-element-name: 1.0.1 + parse5: 7.1.2 + rrweb-cssom: 0.6.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.3 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.16.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -2213,6 +2373,10 @@ packages: hasBin: true dev: true + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: true + /mdurl@1.0.1: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} dev: true @@ -2234,6 +2398,18 @@ packages: picomatch: 2.3.1 dev: true + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -2377,6 +2553,12 @@ packages: callsites: 3.1.0 dev: true + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: true + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2449,11 +2631,19 @@ packages: react-is: 18.2.0 dev: true + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: true + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} dev: true + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -2471,6 +2661,15 @@ packages: set-function-name: 2.0.1 dev: true + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + /requizzle@0.2.4: resolution: {integrity: sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==} dependencies: @@ -2516,6 +2715,10 @@ packages: '@rollup/rollup-win32-x64-msvc': 4.9.4 fsevents: 2.3.3 + /rrweb-cssom@0.6.0: + resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -2541,6 +2744,17 @@ packages: is-regex: 1.1.4 dev: true + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + dev: true + /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2724,6 +2938,10 @@ packages: has-flag: 4.0.0 dev: true + /symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: true + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -2733,6 +2951,13 @@ packages: minimatch: 3.1.2 dev: true + /test-page-opener@1.0.5: + resolution: {integrity: sha512-KglC6Rbauoy9Rr106TVYPmxA24r13a/xODd229s/1XowaJkmya/NlTtKIY6tkw8eIoAqzHBbDwhSBVwDIXuBEw==} + engines: {node: '>= 18.0.0'} + dependencies: + istanbul-lib-coverage: 3.2.2 + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -2768,6 +2993,23 @@ packages: engines: {node: '>=6'} dev: true + /tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + + /tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + dependencies: + punycode: 2.3.1 + dev: true + /ts-api-utils@1.0.3(typescript@5.3.3): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} @@ -2871,6 +3113,11 @@ packages: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + /update-browserslist-db@1.0.13(browserslist@4.22.2): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -2888,6 +3135,13 @@ packages: punycode: 2.3.1 dev: true + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + /v8-to-istanbul@9.2.0: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} @@ -2954,7 +3208,7 @@ packages: fsevents: 2.3.3 dev: true - /vitest@1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3): + /vitest@1.1.3(@types/node@20.10.8)(@vitest/ui@1.1.3)(jsdom@23.2.0): resolution: {integrity: sha512-2l8om1NOkiA90/Y207PsEvJLYygddsOyr81wLQ20Ra8IlLKbyQncWsGZjnbkyG2KwwuTXLQjEPOJuxGMG8qJBQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2991,6 +3245,7 @@ packages: chai: 4.4.0 debug: 4.3.4 execa: 8.0.1 + jsdom: 23.2.0 local-pkg: 0.5.0 magic-string: 0.30.5 pathe: 1.1.1 @@ -3012,6 +3267,38 @@ packages: - terser dev: true + /w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + dependencies: + xml-name-validator: 5.0.0 + dev: true + + /webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: true + + /whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + dependencies: + iconv-lite: 0.6.3 + dev: true + + /whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + dev: true + + /whatwg-url@14.0.0: + resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + engines: {node: '>=18'} + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + dev: true + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -3058,6 +3345,28 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true + /ws@8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + + /xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + dev: true + + /xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: true + /xmlcreate@2.0.4: resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} dev: true diff --git a/test/large.test.js b/test/large.test.js new file mode 100644 index 0000000..59edaa2 --- /dev/null +++ b/test/large.test.js @@ -0,0 +1,40 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { afterAll, beforeAll, describe, expect, test } from 'vitest' +import TestPageOpener from 'test-page-opener' + +describe('rollup-plugin-handlebars-precompiler', () => { + /** @type {TestPageOpener} */ + let opener + /** @type {Document} */ + let document + + beforeAll(async () => { + opener = await TestPageOpener.create('/') + + const page = await opener.open('test/large/index.html') + document = page.document + }) + + afterAll(() => opener.closeAll()) + + test('renders element with Template', async () => { + /** @type {(HTMLAnchorElement | null)} */ + const templateElem = document.querySelector('#app h1 a') + + expect(templateElem).not.toBeNull() + expect((templateElem || {}).href).toContain('%22Hello,_World!%22') + }) + + test('renders element with RawTemplate', async () => { + /** @type {(HTMLAnchorElement | null)} */ + const rawTemplateElem = document.querySelector('#app div a') + + expect(rawTemplateElem).not.toBeNull() + expect((rawTemplateElem || {}).href).toContain('%22Hello,_World!%22') + }) +}) diff --git a/test/large/components/_message-link.hbs b/test/large/components/_message-link.hbs new file mode 100644 index 0000000..f1ed04e --- /dev/null +++ b/test/large/components/_message-link.hbs @@ -0,0 +1,9 @@ +{{!-- + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + + This is an example of a Handlebars partial template that invokes a custom + helper. See: https://handlebarsjs.com/guide/expressions.html#helpers +--}} +{{link message href=url}} diff --git a/test/large/components/app.js b/test/large/components/app.js new file mode 100644 index 0000000..09520cb --- /dev/null +++ b/test/large/components/app.js @@ -0,0 +1,29 @@ +/* eslint-env browser */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import Template, { RawTemplate } from './introduction.hbs' +// eslint-disable-next-line no-unused-vars +import { InitParams } from '../types.js' + + +export default class App { + /** + * Initializes the Introduction within the document. + * @param {InitParams} config - app initialization parameters + */ + init({ appElem }) { + const args = { + message: 'Hello, World!', + url: 'https://en.wikipedia.org/wiki/%22Hello,_World!%22_program' + } + appElem.appendChild(Template(args)) + + const rawVersionElem = document.createElement('div') + rawVersionElem.innerHTML = RawTemplate(args) + appElem.appendChild(rawVersionElem) + } +} diff --git a/test/large/components/helpers.js b/test/large/components/helpers.js new file mode 100644 index 0000000..3449e7c --- /dev/null +++ b/test/large/components/helpers.js @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * This is an example of a custom Handlebars helper, adapted directly from: + * - https://handlebarsjs.com/guide/expressions.html#helpers + */ + + +/** + * Exports a function to register Handlebars helpers. + * + * Passed to rollup-plugin-handlebars-precompiler via options.helpers. + * @see https://handlebarsjs.com/api-reference/runtime.html#handlebars-registerhelper-name-helper + * @module components/helpers + */ + +/** + * Registers helper functions via Handlebars.registerHelper(). + * @function default + * @param {module} Handlebars The Handlebars runtime module + */ +export default function(Handlebars) { + /** + * @typedef {object} LinkHelperOptions + * @property {Object.} hash - hash arguments from the link tag + * @see https://handlebarsjs.com/guide/expressions.html#helpers + */ + + /** + * @param {string} text - the anchor text for the generated link + * @param {LinkHelperOptions} options - options including the href URL + * @returns {Handlebars.SafeString} - properly escaped element text + */ + const linkHelper = function(text, options) { + const attrs = Object.keys(options.hash).map(key => { + return `${Handlebars.escapeExpression(key)}=` + + `"${Handlebars.escapeExpression(options.hash[key])}"` + }) + return new Handlebars.SafeString( + `${Handlebars.escapeExpression(text)}` + ) + } + Handlebars.registerHelper('link', linkHelper) +} diff --git a/test/large/components/introduction.hbs b/test/large/components/introduction.hbs new file mode 100644 index 0000000..ae9cfe4 --- /dev/null +++ b/test/large/components/introduction.hbs @@ -0,0 +1,9 @@ +{{!-- + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + + This is an example of a Handlebars template that invokes a partial template + via '{{>'. See: https://handlebarsjs.com/guide/partials.html#basic-partials +--}} +

{{> message-link }}

diff --git a/test/large/index.html b/test/large/index.html new file mode 100644 index 0000000..77b5075 --- /dev/null +++ b/test/large/index.html @@ -0,0 +1,15 @@ + + + + + + + Test Page for TestPageOpener + + + +
+ + diff --git a/test/large/main.js b/test/large/main.js new file mode 100644 index 0000000..6e06c2a --- /dev/null +++ b/test/large/main.js @@ -0,0 +1,24 @@ +/* eslint-env browser */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import App from './components/app.js' +// eslint-disable-next-line no-unused-vars +import { InitParams } from './types.js' + +document.addEventListener( + 'DOMContentLoaded', + () => { + /** @type {(HTMLDivElement | null)} */ + const appElem = document.querySelector('#app') + if (appElem === null) return console.error('no #app element') + + /** @type {InitParams} */ + const initParams = { appElem } + new App().init(initParams) + }, + { once: true } +) diff --git a/test/large/types.js b/test/large/types.js new file mode 100644 index 0000000..2245c14 --- /dev/null +++ b/test/large/types.js @@ -0,0 +1,14 @@ +/* eslint-env browser */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +/** + * Parameters that main.js passes to all Init() functions + * @typedef {object} InitParams + * @property {HTMLDivElement} appElem - root element of the application + */ +/** @type {InitParams} */ +export let InitParams diff --git a/vitest.config.js b/vitest.config.js index 723af0d..70ed47a 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -1,11 +1,22 @@ +import HandlebarsPrecompiler from './index.js' import { defineConfig, configDefaults } from 'vitest/config' export default defineConfig({ + plugins: [ + HandlebarsPrecompiler({ helpers: ['test/large/components/helpers.js'] }) + ], test: { outputFile: 'TESTS-TestSuites.xml', coverage: { reportsDirectory: 'coverage', exclude: [...(configDefaults.coverage.exclude || []), 'jsdoc', 'out'] + }, + server: { + deps: { + // Without this, jsdom tests will fail to import '.hbs' files + // transformed by rollup-plugin-handlebars-precompiler. + inline: ['test-page-opener'] + } } } })