From d2e61be6b2027a63fbd20e88eab608181e662721 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:42:37 +1000 Subject: [PATCH 001/169] feat: Refactor compile for improved performance and byte size reduction --- src/compile.ts | 118 ++++++++++++++++++++++++++----------------------- src/types.ts | 20 ++++----- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/src/compile.ts b/src/compile.ts index fc74cce..e0a844f 100644 --- a/src/compile.ts +++ b/src/compile.ts @@ -1,89 +1,95 @@ -import type { Ref, Refs, S1Node } from './types'; +import type { LowercaseKeys, Ref, Refs, S1View } from './types'; import { create } from './utils'; const compilerTemplate = create('template'); const treeWalker = document.createTreeWalker(compilerTemplate); +let str; -const collector = (node: Node): string | void => { +const collector = (node: Node): string | undefined => { // 1 = Node.ELEMENT_NODE if (node.nodeType === 1) { const attrs = (node as Element).attributes; let index = attrs.length; while (index--) { - const aname = attrs[index].name; - if (aname[0] === '#') { - (node as Element).removeAttribute(aname); - return aname.slice(1); + str = attrs[index].name; + if (str[0] === '@') { + (node as Element).removeAttribute(str); + return str.slice(1); } } return; } - const content = node.nodeValue; - if (content && content[0] === '#') { + str = node.nodeValue; + if (str && str[0] === '@') { node.nodeValue = ''; - return content.slice(1); + return str.slice(1); } }; -const roll = (n: number) => { - while (--n) treeWalker.nextNode(); - return treeWalker.currentNode; -}; +/** + * Creates a DOM node from a template and collects ref node metadata. + * @param template - HTML template string. + */ +export const h = ( + template: string, +): S1View & T => { + compilerTemplate.innerHTML = template + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replace(/> /g, '>') + .replace(/ { - const indices: Ref[] = []; - let ref: string | void; - let index = 0; - treeWalker.currentNode = node; + const node = compilerTemplate.content.firstChild as S1View & T; + const metadata: Ref[] = (node._refs = []); + let current: Node | null = (treeWalker.currentNode = node); + let distance = 0; - while (node) { - if ((ref = collector(node))) { - indices.push({ i: index + 1, ref }); - index = 1; + while (current) { + if ((str = collector(current))) { + metadata.push({ k: str, d: distance }); + distance = 1; } else { - index++; + distance++; } - (node as Node | null) = treeWalker.nextNode(); + current = treeWalker.nextNode(); } - return indices; + return node; }; -// eslint-disable-next-line func-names -const collect = function (this: S1Node, node: Node): T { +export const html = ( + template: TemplateStringsArray, + ...substitutions: unknown[] +): S1View => h(String.raw(template, ...substitutions)); + +/** + * Collects node refs from a compiled template view. + * @param root - Root node. + * @param view - Compiled template view. + * @returns An object mapping ref nodes keyed by their ref name. Note that some + * browsers lowercase rendered HTML element attribute names so we lowercase the + * typed key names to bring awareness to this. + */ +export const collect = ( + root: Node, + view: S1View, +): LowercaseKeys => { + const len = view._refs.length; const refs: Refs = {}; - treeWalker.currentNode = node; + let index = 0; + let metadata; + let distance; + treeWalker.currentNode = root; - for (const x of this._refs) { - refs[x.ref] = roll(x.i); + for (; index < len; index++) { + metadata = view._refs[index]; + distance = metadata.d; + while (distance--) treeWalker.nextNode(); + refs[metadata.k] = treeWalker.currentNode; } - return refs as T; + return refs as LowercaseKeys; }; - -export const h = (template: string): S1Node => { - // Compatible template literal minifier is mandatory for production consumers! - compilerTemplate.innerHTML = - process.env.NODE_ENV === 'production' - ? template - : template - // to get the correct first node - .trim() - // faster genPath and cleaner test snapshots - .replace(/\n\s+/g, '\n') - // remove whitespace around ref tags in Text nodes - .replace(/>\s+#(\w+)\s+#$1<'); - - const node = compilerTemplate.content.firstChild as S1Node; - node._refs = genPath(node); - node.collect = collect; - - return node; -}; - -export const html = ( - template: TemplateStringsArray, - ...substitutions: unknown[] -): S1Node => h(String.raw(template, ...substitutions)); diff --git a/src/types.ts b/src/types.ts index d2843fd..76d1ec1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,14 @@ -/** @internal */ +/** @private */ export interface Ref { - readonly i: number; - readonly ref: string; + /** Ref key name. */ + readonly k: string; + /** Distance from previous ref node or root. */ + readonly d: number; +} + +export interface S1View extends Node, ChildNode { + /** @private */ + _refs: readonly Ref[]; } export type Refs = Record; @@ -9,10 +16,3 @@ export type Refs = Record; export type LowercaseKeys = { [K in keyof T as Lowercase]: T[K]; }; - -export interface S1Node extends Node, ChildNode { - _refs: Ref[]; - // Some browsers lowercase rendered HTMLElement attribute names so we - // lowercase the ref keys to bring awareness to this. - collect(node: Node): LowercaseKeys; -} From 046042e9d18c3ed85fc54cb1b2b02071faedf309 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:43:02 +1000 Subject: [PATCH 002/169] chore: Tweak VS Code settings --- .vscode/launch.json | 41 ----------------------------------------- .vscode/settings.json | 2 +- 2 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 2b4338f..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,41 +0,0 @@ -// https://code.visualstudio.com/docs/editor/debugging#_launch-configurations -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Attach by Process ID", - "type": "pwa-node", - "processId": "${command:PickProcess}", - "request": "attach", - "sourceMaps": true, - "skipFiles": ["/**"], - "smartStep": true - }, - // https://github.com/Microsoft/vscode-recipes/tree/master/debugging-jest-tests - { - "name": "uvu All", - "type": "pwa-node", - "request": "launch", - "sourceMaps": true, - "skipFiles": [ - "/**", - "${workspaceFolder}/node_modules/uvu/**" - ], - "program": "${workspaceFolder}/node_modules/uvu/bin.js", - "args": ["-r", "tsm", "./test", "\\.test\\.ts$"], - "console": "integratedTerminal" - }, - { - "name": "uvu Current File", - "type": "pwa-node", - "request": "launch", - "sourceMaps": true, - "skipFiles": [ - "/**", - "${workspaceFolder}/node_modules/uvu/**" - ], - "args": ["-r", "tsm", "${relativeFile}"], - "console": "integratedTerminal" - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json index dbeb24b..2403de4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ "editor.formatOnSave": true, "editor.formatOnType": false, "eslint.lintTask.options": "--ignore-path .gitignore", - "git.branchProtection": ["master"], + "git.branchProtection": ["master", "next"], "js/ts.implicitProjectConfig.checkJs": true, "prettier.ignorePath": ".gitignore", "typescript.tsdk": "node_modules/typescript/lib", From b750dce2b20a67122ab2cc2948bf3bc4e63054ea Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:47:17 +1000 Subject: [PATCH 003/169] chore: Migrate to bun and refactor package --- bun.lockb | Bin 0 -> 119686 bytes package.json | 39 +++++++++++++++++---------------------- 2 files changed, 17 insertions(+), 22 deletions(-) create mode 100755 bun.lockb diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..60f8ae099373940e74db7edbe3d15816bae728e7 GIT binary patch literal 119686 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 Date: Sat, 15 Jul 2023 01:47:39 +1000 Subject: [PATCH 004/169] chore: Migrate CI to bun + tweaks --- .github/workflows/ci.yml | 64 +++++++++++++++++--------- .github/workflows/codeql-analysis.yml | 5 +- .github/workflows/semgrep-analysis.yml | 1 + 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97c8e98..4bd250d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,37 +1,57 @@ name: ci on: push: - branches: [master] + branches: [master, next] + paths-ignore: ['**.md'] pull_request: - branches: [master] + branches: [master, next] jobs: test: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: oven-sh/setup-bun@v1 with: - node-version: 18 - - run: npm install --global pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm run build - - run: pnpm run test - - name: Report coverage - if: ${{ github.repository_owner == 'maxmilton' }} - run: | - curl -Lo ./cc-test-reporter https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 - chmod +x ./cc-test-reporter - ./cc-test-reporter format-coverage -t lcov -o coverage/codeclimate.json coverage/lcov.info - ./cc-test-reporter upload-coverage - env: - CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + bun-version: latest + - run: bun install --frozen-lockfile + - run: bun run build + - run: bun run test + # FIXME: Enable coverage reporting once bun test supports it; https://github.com/oven-sh/bun/issues/2311 + # - name: Report coverage + # if: ${{ github.repository_owner == 'maxmilton' }} + # run: | + # curl -Lo ./cc-test-reporter https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 + # chmod +x ./cc-test-reporter + # ./cc-test-reporter format-coverage -t lcov -o coverage/codeclimate.json coverage/lcov.info + # ./cc-test-reporter upload-coverage + # env: + # CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + e2e: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - run: bun install --frozen-lockfile + - run: bun playwright install chromium + - run: bun run build + - run: bun run test:e2e --reporter=dot,html + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 lint: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: oven-sh/setup-bun@v1 with: - node-version: 18 - - run: npm install --global pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm run lint + bun-version: latest + - run: bun install --frozen-lockfile + - run: bun run lint diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 79932c1..b38123c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,14 +1,15 @@ name: codeql on: push: - branches: [master] + branches: [master, next] pull_request: - branches: [master] + branches: [master, next] schedule: - cron: '28 6 * * 4' jobs: analyze: runs-on: ubuntu-latest + timeout-minutes: 10 permissions: actions: read contents: read diff --git a/.github/workflows/semgrep-analysis.yml b/.github/workflows/semgrep-analysis.yml index c43c76b..730bff4 100644 --- a/.github/workflows/semgrep-analysis.yml +++ b/.github/workflows/semgrep-analysis.yml @@ -9,6 +9,7 @@ on: jobs: analyze: runs-on: ubuntu-latest + timeout-minutes: 5 container: image: returntocorp/semgrep permissions: From 9baa1337d03ae0e945ea9b33e7837b463c145856 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:48:29 +1000 Subject: [PATCH 005/169] chore: Refactor TypeScript configuration --- test/tsconfig.json | 9 --------- tsconfig.d.json | 10 ++++++++++ tsconfig.json | 19 ++++++++++--------- tsconfig.node.json | 9 +++++++++ 4 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 test/tsconfig.json create mode 100644 tsconfig.d.json create mode 100644 tsconfig.node.json diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index ac9be8b..0000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "rootDir": "..", - "noEmit": true - }, - "include": ["../**/*", "../.*.cjs", "../*.mjs"], - "exclude": ["../coverage", "../dist", "../node_modules"] -} diff --git a/tsconfig.d.json b/tsconfig.d.json new file mode 100644 index 0000000..ee1e43e --- /dev/null +++ b/tsconfig.d.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "emitDeclarationOnly": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json index 54d6869..8801de2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,12 @@ { "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "target": "esnext", "module": "esnext", "moduleResolution": "bundler", - "esModuleInterop": true, + "esModuleInterop": false, "resolveJsonModule": true, "skipLibCheck": true, - "allowJs": true, - "checkJs": true, + "allowJs": false, "strict": true, "allowUnreachableCode": false, @@ -21,7 +16,13 @@ "noImplicitOverride": true, "noUnusedLocals": false, // covered by eslint "noUnusedParameters": false, // covered by eslint - "verbatimModuleSyntax": true + "verbatimModuleSyntax": true, + + "types": [ + "bun-types", + "./node_modules/typescript/lib/lib.esnext.full.d.ts" // workaround for bun-types breaking dom types + ] }, - "exclude": ["coverage", "dist", "node_modules", "test", "build.mjs"] + "include": ["src", "test", "build.ts", "playwright.config.ts"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..37fa35a --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + }, + "include": [".eslintrc.cjs", "package.json"] +} From 32464fbada9ffdadd9987da9987fb08a9ac2a58a Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:48:49 +1000 Subject: [PATCH 006/169] chore: Remove old lockfile --- pnpm-lock.yaml | 2891 ------------------------------------------------ 1 file changed, 2891 deletions(-) delete mode 100644 pnpm-lock.yaml diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index d89a2f3..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,2891 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -devDependencies: - '@types/jsdom': - specifier: 21.1.1 - version: 21.1.1 - '@types/node': - specifier: 20.4.1 - version: 20.4.1 - '@typescript-eslint/eslint-plugin': - specifier: 5.61.0 - version: 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@5.1.6) - '@typescript-eslint/parser': - specifier: 5.61.0 - version: 5.61.0(eslint@8.44.0)(typescript@5.1.6) - c8: - specifier: 8.0.0 - version: 8.0.0 - esbuild: - specifier: 0.18.11 - version: 0.18.11 - eslint: - specifier: 8.44.0 - version: 8.44.0 - eslint-config-airbnb-base: - specifier: 15.0.0 - version: 15.0.0(eslint-plugin-import@2.27.5)(eslint@8.44.0) - eslint-config-airbnb-typescript: - specifier: 17.0.0 - version: 17.0.0(@typescript-eslint/eslint-plugin@5.61.0)(@typescript-eslint/parser@5.61.0)(eslint-plugin-import@2.27.5)(eslint@8.44.0) - eslint-config-prettier: - specifier: 8.8.0 - version: 8.8.0(eslint@8.44.0) - eslint-plugin-import: - specifier: 2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0) - eslint-plugin-prettier: - specifier: 5.0.0-alpha.2 - version: 5.0.0-alpha.2(eslint-config-prettier@8.8.0)(eslint@8.44.0)(prettier@3.0.0) - jsdom: - specifier: 22.1.0 - version: 22.1.0 - nanospy: - specifier: 1.0.0 - version: 1.0.0 - prettier: - specifier: 3.0.0 - version: 3.0.0 - tsm: - specifier: 2.3.0 - version: 2.3.0 - typescript: - specifier: 5.1.6 - version: 5.1.6 - uvu: - specifier: 0.5.6 - version: 0.5.6 - -packages: - - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - - /@esbuild/android-arm64@0.18.11: - resolution: {integrity: sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.15.18: - resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.18.11: - resolution: {integrity: sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.18.11: - resolution: {integrity: sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.18.11: - resolution: {integrity: sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.18.11: - resolution: {integrity: sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.18.11: - resolution: {integrity: sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.18.11: - resolution: {integrity: sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.18.11: - resolution: {integrity: sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.18.11: - resolution: {integrity: sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.18.11: - resolution: {integrity: sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.15.18: - resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.18.11: - resolution: {integrity: sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.18.11: - resolution: {integrity: sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.18.11: - resolution: {integrity: sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.18.11: - resolution: {integrity: sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.18.11: - resolution: {integrity: sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.18.11: - resolution: {integrity: sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.18.11: - resolution: {integrity: sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.18.11: - resolution: {integrity: sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.18.11: - resolution: {integrity: sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.18.11: - resolution: {integrity: sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.18.11: - resolution: {integrity: sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.18.11: - resolution: {integrity: sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.44.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 8.44.0 - eslint-visitor-keys: 3.4.1 - dev: true - - /@eslint-community/regexpp@4.5.1: - resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - - /@eslint/eslintrc@2.1.0: - resolution: {integrity: sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.0 - globals: 13.20.0 - ignore: 5.2.4 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@eslint/js@8.44.0: - resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true - - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - - /@jridgewell/trace-mapping@0.3.18: - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 - dev: true - - /@pkgr/utils@2.4.2: - resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dependencies: - cross-spawn: 7.0.3 - fast-glob: 3.3.0 - is-glob: 4.0.3 - open: 9.1.0 - picocolors: 1.0.0 - tslib: 2.6.0 - dev: true - - /@tootallnate/once@2.0.0: - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} - dev: true - - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - - /@types/jsdom@21.1.1: - resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==} - dependencies: - '@types/node': 20.4.1 - '@types/tough-cookie': 4.0.2 - parse5: 7.1.2 - dev: true - - /@types/json-schema@7.0.12: - resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} - dev: true - - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true - - /@types/node@20.4.1: - resolution: {integrity: sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==} - dev: true - - /@types/semver@7.5.0: - resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} - dev: true - - /@types/tough-cookie@4.0.2: - resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==} - dev: true - - /@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@5.1.6): - resolution: {integrity: sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/type-utils': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.44.0 - graphemer: 1.4.0 - ignore: 5.2.4 - natural-compare-lite: 1.4.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/parser@5.61.0(eslint@8.44.0)(typescript@5.1.6): - resolution: {integrity: sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.44.0 - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/scope-manager@5.61.0: - resolution: {integrity: sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/visitor-keys': 5.61.0 - dev: true - - /@typescript-eslint/type-utils@5.61.0(eslint@8.44.0)(typescript@5.1.6): - resolution: {integrity: sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.1.6) - '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.44.0 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/types@5.61.0: - resolution: {integrity: sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/typescript-estree@5.61.0(typescript@5.1.6): - resolution: {integrity: sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/visitor-keys': 5.61.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/utils@5.61.0(eslint@8.44.0)(typescript@5.1.6): - resolution: {integrity: sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.44.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.1.6) - eslint: 8.44.0 - eslint-scope: 5.1.1 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/visitor-keys@5.61.0: - resolution: {integrity: sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.61.0 - eslint-visitor-keys: 3.4.1 - dev: true - - /abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - dev: true - - /acorn-jsx@5.3.2(acorn@8.9.0): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.9.0 - dev: true - - /acorn@8.9.0: - resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} - dependencies: - call-bind: 1.0.2 - is-array-buffer: 3.0.2 - dev: true - - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - get-intrinsic: 1.2.1 - is-string: 1.0.7 - dev: true - - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - es-shim-unscopables: 1.0.0 - dev: true - - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - es-shim-unscopables: 1.0.0 - 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'} - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /big-integer@1.6.51: - resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} - engines: {node: '>=0.6'} - dev: true - - /bplist-parser@0.2.0: - resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} - engines: {node: '>= 5.10.0'} - dependencies: - big-integer: 1.6.51 - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /bundle-name@3.0.0: - resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} - engines: {node: '>=12'} - dependencies: - run-applescript: 5.0.0 - dev: true - - /c8@8.0.0: - resolution: {integrity: sha512-XHA5vSfCLglAc0Xt8eLBZMv19lgiBSjnb1FLAQgnwkuhJYEonpilhEB4Ea3jPAbm0FhD6VVJrc0z73jPe7JyGQ==} - engines: {node: '>=12'} - hasBin: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@istanbuljs/schema': 0.1.3 - find-up: 5.0.0 - foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-reports: 3.1.5 - rimraf: 3.0.2 - test-exclude: 6.0.0 - v8-to-istanbul: 9.1.0 - yargs: 16.2.0 - yargs-parser: 20.2.9 - dev: true - - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.4: - 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 - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /confusing-browser-globals@1.0.11: - resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} - dev: true - - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /cssstyle@3.0.0: - resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} - engines: {node: '>=14'} - dependencies: - rrweb-cssom: 0.6.0 - dev: true - - /data-urls@4.0.0: - resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} - engines: {node: '>=14'} - dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 12.0.1 - dev: true - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /decimal.js@10.4.3: - resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /default-browser-id@3.0.0: - resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} - engines: {node: '>=12'} - dependencies: - bplist-parser: 0.2.0 - untildify: 4.0.0 - dev: true - - /default-browser@4.0.0: - resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} - engines: {node: '>=14.16'} - dependencies: - bundle-name: 3.0.0 - default-browser-id: 3.0.0 - execa: 7.1.1 - titleize: 3.0.0 - dev: true - - /define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - dev: true - - /define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true - - /dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - dev: true - - /diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} - engines: {node: '>=0.3.1'} - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /domexception@4.0.0: - resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} - engines: {node: '>=12'} - dependencies: - webidl-conversions: 7.0.0 - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - dev: true - - /es-abstract@1.21.2: - resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.10 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.7 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.9 - dev: true - - /es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - has-tostringtag: 1.0.0 - dev: true - - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - - /esbuild-android-64@0.15.18: - resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-android-arm64@0.15.18: - resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-64@0.15.18: - resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-arm64@0.15.18: - resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-64@0.15.18: - resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64@0.15.18: - resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-32@0.15.18: - resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-64@0.15.18: - resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64@0.15.18: - resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm@0.15.18: - resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-mips64le@0.15.18: - resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le@0.15.18: - resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-riscv64@0.15.18: - resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-s390x@0.15.18: - resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-netbsd-64@0.15.18: - resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-openbsd-64@0.15.18: - resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64@0.15.18: - resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-32@0.15.18: - resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-64@0.15.18: - resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-arm64@0.15.18: - resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild@0.15.18: - resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.15.18 - '@esbuild/linux-loong64': 0.15.18 - esbuild-android-64: 0.15.18 - esbuild-android-arm64: 0.15.18 - esbuild-darwin-64: 0.15.18 - esbuild-darwin-arm64: 0.15.18 - esbuild-freebsd-64: 0.15.18 - esbuild-freebsd-arm64: 0.15.18 - esbuild-linux-32: 0.15.18 - esbuild-linux-64: 0.15.18 - esbuild-linux-arm: 0.15.18 - esbuild-linux-arm64: 0.15.18 - esbuild-linux-mips64le: 0.15.18 - esbuild-linux-ppc64le: 0.15.18 - esbuild-linux-riscv64: 0.15.18 - esbuild-linux-s390x: 0.15.18 - esbuild-netbsd-64: 0.15.18 - esbuild-openbsd-64: 0.15.18 - esbuild-sunos-64: 0.15.18 - esbuild-windows-32: 0.15.18 - esbuild-windows-64: 0.15.18 - esbuild-windows-arm64: 0.15.18 - dev: true - - /esbuild@0.18.11: - resolution: {integrity: sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.11 - '@esbuild/android-arm64': 0.18.11 - '@esbuild/android-x64': 0.18.11 - '@esbuild/darwin-arm64': 0.18.11 - '@esbuild/darwin-x64': 0.18.11 - '@esbuild/freebsd-arm64': 0.18.11 - '@esbuild/freebsd-x64': 0.18.11 - '@esbuild/linux-arm': 0.18.11 - '@esbuild/linux-arm64': 0.18.11 - '@esbuild/linux-ia32': 0.18.11 - '@esbuild/linux-loong64': 0.18.11 - '@esbuild/linux-mips64el': 0.18.11 - '@esbuild/linux-ppc64': 0.18.11 - '@esbuild/linux-riscv64': 0.18.11 - '@esbuild/linux-s390x': 0.18.11 - '@esbuild/linux-x64': 0.18.11 - '@esbuild/netbsd-x64': 0.18.11 - '@esbuild/openbsd-x64': 0.18.11 - '@esbuild/sunos-x64': 0.18.11 - '@esbuild/win32-arm64': 0.18.11 - '@esbuild/win32-ia32': 0.18.11 - '@esbuild/win32-x64': 0.18.11 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.27.5)(eslint@8.44.0): - resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.2 - dependencies: - confusing-browser-globals: 1.0.11 - eslint: 8.44.0 - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0) - object.assign: 4.1.4 - object.entries: 1.1.6 - semver: 6.3.0 - dev: true - - /eslint-config-airbnb-typescript@17.0.0(@typescript-eslint/eslint-plugin@5.61.0)(@typescript-eslint/parser@5.61.0)(eslint-plugin-import@2.27.5)(eslint@8.44.0): - resolution: {integrity: sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.13.0 - '@typescript-eslint/parser': ^5.0.0 - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.3 - dependencies: - '@typescript-eslint/eslint-plugin': 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@5.1.6) - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - eslint: 8.44.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.27.5)(eslint@8.44.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0) - dev: true - - /eslint-config-prettier@8.8.0(eslint@8.44.0): - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - dependencies: - eslint: 8.44.0 - dev: true - - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} - dependencies: - debug: 3.2.7 - is-core-module: 2.12.1 - resolve: 1.22.2 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - debug: 3.2.7 - eslint: 8.44.0 - eslint-import-resolver-node: 0.3.7 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.1.6) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.44.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0) - has: 1.0.3 - is-core-module: 2.12.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.2 - semver: 6.3.0 - tsconfig-paths: 3.14.2 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - - /eslint-plugin-prettier@5.0.0-alpha.2(eslint-config-prettier@8.8.0)(eslint@8.44.0)(prettier@3.0.0): - resolution: {integrity: sha512-F6YBCbrRzvZwcINw3crm1+/uX/i+rJYaFErPtwCfUoPLywRfY7pwBtI3yMe5OpIotuaiws8cd29oM80ca6NQSQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - dependencies: - eslint: 8.44.0 - eslint-config-prettier: 8.8.0(eslint@8.44.0) - prettier: 3.0.0 - prettier-linter-helpers: 1.0.0 - synckit: 0.8.5 - dev: true - - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - - /eslint-visitor-keys@3.4.1: - resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /eslint@8.44.0: - resolution: {integrity: sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.44.0) - '@eslint-community/regexpp': 4.5.1 - '@eslint/eslintrc': 2.1.0 - '@eslint/js': 8.44.0 - '@humanwhocodes/config-array': 0.11.10 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.1 - espree: 9.6.0 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.20.0 - graphemer: 1.4.0 - ignore: 5.2.4 - import-fresh: 3.3.0 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree@9.6.0: - resolution: {integrity: sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.9.0 - acorn-jsx: 5.3.2(acorn@8.9.0) - eslint-visitor-keys: 3.4.1 - dev: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /execa@7.1.1: - resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==} - engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 4.3.1 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.1.0 - onetime: 6.0.0 - signal-exit: 3.0.7 - strip-final-newline: 3.0.0 - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true - - /fast-glob@3.3.0: - resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - dependencies: - reusify: 1.0.4 - dev: true - - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.0.4 - dev: true - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 - dev: true - - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true - - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - dependencies: - is-callable: 1.2.7 - dev: true - - /foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - dependencies: - cross-spawn: 7.0.3 - signal-exit: 3.0.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 - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true - - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - functions-have-names: 1.2.3 - dev: true - - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-intrinsic@1.2.1: - resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-proto: 1.0.1 - has-symbols: 1.0.3 - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /globals@13.20.0: - resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.0 - dev: true - - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.0 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.1 - dev: true - - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - dependencies: - get-intrinsic: 1.2.1 - dev: true - - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - dev: true - - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true - - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - dev: true - - /html-encoding-sniffer@3.0.0: - resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} - engines: {node: '>=12'} - dependencies: - whatwg-encoding: 2.0.0 - dev: true - - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - - /http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /human-signals@4.3.1: - resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} - engines: {node: '>=14.18.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.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - side-channel: 1.0.4 - dev: true - - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.10 - dev: true - - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - dependencies: - has-bigints: 1.0.2 - dev: true - - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true - - /is-core-module@2.12.1: - resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} - dependencies: - has: 1.0.3 - dev: true - - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - dev: true - - /is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - dependencies: - is-docker: 3.0.0 - dev: true - - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - dev: true - - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - 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'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - dependencies: - call-bind: 1.0.2 - dev: true - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true - - /is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - - /is-typed-array@1.1.10: - resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - dev: true - - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - dependencies: - call-bind: 1.0.2 - dev: true - - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - dependencies: - is-docker: 2.2.1 - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - dev: true - - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} - dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 - supports-color: 7.2.0 - dev: true - - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 - dev: true - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /jsdom@22.1.0: - resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} - engines: {node: '>=16'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - dependencies: - abab: 2.0.6 - cssstyle: 3.0.0 - data-urls: 4.0.0 - decimal.js: 10.4.3 - domexception: 4.0.0 - form-data: 4.0.0 - html-encoding-sniffer: 3.0.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.5 - 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: 4.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - whatwg-url: 12.0.1 - ws: 8.13.0 - xml-name-validator: 4.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - - /kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - dev: true - - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.0 - dev: true - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - 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@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true - - /mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /nanospy@1.0.0: - resolution: {integrity: sha512-wvmmALNstRRhLhy7RV11NCRY2k1zxstImiju4VyyKNNRIKDVjyBtmEd/Q4G82/3dN4VSTe+0PRR3DUAASSbEEQ==} - engines: {node: ^8.0.0 || ^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0 || >=20.0.0} - dev: true - - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /npm-run-path@5.1.0: - resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - path-key: 4.0.0 - dev: true - - /nwsapi@2.2.5: - resolution: {integrity: sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==} - dev: true - - /object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - dev: true - - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true - - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: true - - /object.entries@1.1.6: - resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - dev: true - - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - dependencies: - mimic-fn: 4.0.0 - dev: true - - /open@9.1.0: - resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} - engines: {node: '>=14.16'} - dependencies: - default-browser: 4.0.0 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - is-wsl: 2.2.0 - dev: true - - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} - dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - 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'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - dependencies: - fast-diff: 1.3.0 - dev: true - - /prettier@3.0.0: - resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==} - engines: {node: '>=14'} - hasBin: true - dev: true - - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: true - - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - 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 - - /regexp.prototype.flags@1.5.0: - resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - functions-have-names: 1.2.3 - dev: true - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: true - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} - hasBin: true - dependencies: - is-core-module: 2.12.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /rrweb-cssom@0.6.0: - resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - dev: true - - /run-applescript@5.0.0: - resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} - engines: {node: '>=12'} - dependencies: - execa: 5.1.1 - dev: true - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - dependencies: - mri: 1.2.0 - dev: true - - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - 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.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /string.prototype.trim@1.2.7: - resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - dev: true - - /string.prototype.trimend@1.0.6: - resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - dev: true - - /string.prototype.trimstart@1.0.6: - resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.2 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - dev: true - - /synckit@0.8.5: - resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} - engines: {node: ^14.18.0 || >=16.0.0} - dependencies: - '@pkgr/utils': 2.4.2 - tslib: 2.6.0 - dev: true - - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /titleize@3.0.0: - resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} - engines: {node: '>=12'} - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - 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.0 - universalify: 0.2.0 - url-parse: 1.5.10 - dev: true - - /tr46@4.1.1: - resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} - engines: {node: '>=14'} - dependencies: - punycode: 2.3.0 - dev: true - - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - dev: true - - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tslib@2.6.0: - resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} - dev: true - - /tsm@2.3.0: - resolution: {integrity: sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==} - engines: {node: '>=12'} - hasBin: true - dependencies: - esbuild: 0.15.18 - dev: true - - /tsutils@3.21.0(typescript@5.1.6): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 5.1.6 - dev: true - - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - is-typed-array: 1.1.10 - dev: true - - /typescript@5.1.6: - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - dependencies: - call-bind: 1.0.2 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - dev: true - - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - dev: true - - /untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.0 - 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 - - /uvu@0.5.6: - resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} - engines: {node: '>=8'} - hasBin: true - dependencies: - dequal: 2.0.3 - diff: 5.1.0 - kleur: 4.1.5 - sade: 1.8.1 - dev: true - - /v8-to-istanbul@9.1.0: - resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.18 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 - dev: true - - /w3c-xmlserializer@4.0.0: - resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} - engines: {node: '>=14'} - dependencies: - xml-name-validator: 4.0.0 - dev: true - - /webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - dev: true - - /whatwg-encoding@2.0.0: - resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} - engines: {node: '>=12'} - dependencies: - iconv-lite: 0.6.3 - dev: true - - /whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} - dev: true - - /whatwg-url@12.0.1: - resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} - engines: {node: '>=14'} - dependencies: - tr46: 4.1.1 - webidl-conversions: 7.0.0 - dev: true - - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - dev: true - - /which-typed-array@1.1.9: - resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - is-typed-array: 1.1.10 - dev: true - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - 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@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} - dev: true - - /xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dev: true - - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - dev: true - - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true From 41d3c349719f81d5197c87abe6914cd06c56cffe Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:49:40 +1000 Subject: [PATCH 007/169] chore: Set sideEffects=false in package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6175b21..74479c1 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", - "homepage": "https://github.com/maxmilton/stage1", "author": "Max Milton ", "license": "MIT", + "sideEffects": false, "main": "dist/index.js", "exports": { ".": "./dist/index.js", From 1da83bceafdab682aee428930b80af7ee603ccab Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:50:38 +1000 Subject: [PATCH 008/169] chore: Refactor linting configuration --- .eslintrc.cjs | 50 ++++++++++++++++++++++++++++++++++++++++++++------ .prettierrc | 2 +- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 7e1c51f..9abf6a8 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,34 +2,42 @@ const OFF = 0; const WARN = 1; const ERROR = 2; -// TODO: Types -// /** @type {import('eslint/lib/shared/types').ConfigData & { parserOptions: import('@typescript-eslint/types').ParserOptions }} */ +/** @type {import('eslint/lib/shared/types').ConfigData & { parserOptions: import('@typescript-eslint/types').ParserOptions }} */ module.exports = { root: true, reportUnusedDisableDirectives: true, parser: '@typescript-eslint/parser', parserOptions: { - project: ['./test/tsconfig.json'], + project: ['tsconfig.json', 'tsconfig.node.json'], tsconfigRootDir: __dirname, }, extends: [ 'eslint:recommended', - 'plugin:@typescript-eslint/eslint-recommended', 'airbnb-base', 'airbnb-typescript/base', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'plugin:@typescript-eslint/strict-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + 'plugin:unicorn/recommended', 'prettier', ], plugins: ['prettier'], rules: { '@typescript-eslint/explicit-module-boundary-types': ERROR, + // byte savings + '@typescript-eslint/no-confusing-void-expression': OFF, + '@typescript-eslint/no-non-null-assertion': WARN, + // worse performance + '@typescript-eslint/prefer-string-starts-ends-with': OFF, + // worse performance + '@typescript-eslint/prefer-for-of': OFF, // void return can be used for efficient code (if used safely!) 'consistent-return': WARN, 'default-param-last': WARN, 'import/prefer-default-export': OFF, // useful for compact and memory efficient code... but be careful! 'no-cond-assign': OFF, + // more compact at the cost of being harder to read + 'no-multi-assign': OFF, // can be used for efficient code (if used safely!) 'no-param-reassign': WARN, 'no-plusplus': OFF, @@ -39,5 +47,35 @@ module.exports = { // used in synthetic event handler names 'no-underscore-dangle': OFF, 'prettier/prettier': WARN, + // byte savings + faster + 'unicorn/explicit-length-check': OFF, + 'unicorn/filename-case': OFF, + 'unicorn/no-abusive-eslint-disable': WARN, + 'unicorn/no-array-callback-reference': OFF, + // forEach is often faster (in Chrome and Firefox but not Safari) + 'unicorn/no-array-for-each': OFF, + 'unicorn/no-await-expression-member': OFF, + 'unicorn/no-null': OFF, + 'unicorn/prefer-add-event-listener': OFF, + 'unicorn/prefer-dom-node-append': OFF, + 'unicorn/prefer-module': WARN, + // indexOf is faster (in Chrome) + 'unicorn/prefer-includes': OFF, + // saves 3 bytes to use arrow function + 'unicorn/prefer-native-coercion-functions': OFF, + // slower and worse browser support + 'unicorn/prefer-string-replace-all': OFF, + 'unicorn/prefer-top-level-await': WARN, + 'unicorn/prefer-query-selector': OFF, + 'unicorn/prevent-abbreviations': OFF, + 'unicorn/switch-case-braces': [ERROR, 'avoid'], }, + overrides: [ + { + files: ['*.spec.ts', '*.test.ts', 'build.ts', '*.config.ts', '*.d.ts'], + rules: { + 'import/no-extraneous-dependencies': OFF, + }, + }, + ], }; diff --git a/.prettierrc b/.prettierrc index 3c4fdd8..4c3ca9b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,7 +5,7 @@ "trailingComma": "all", "overrides": [ { - "files": ["*.test.ts"], + "files": ["*.spec.ts", "*.test.ts"], "options": { "printWidth": 100 } From 74e22944317c8a7ff2b321132401d6b88b2ef519 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:51:45 +1000 Subject: [PATCH 009/169] chore: Refactor build process --- build.mjs | 35 ----------------------------------- build.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 35 deletions(-) delete mode 100644 build.mjs create mode 100644 build.ts diff --git a/build.mjs b/build.mjs deleted file mode 100644 index 5d13ae6..0000000 --- a/build.mjs +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies, no-console */ - -import esbuild from 'esbuild'; - -// We don't use NODE_ENV here to avoid confusion with process.env.NODE_ENV -// which we want kept in the build output -const dev = !!process.env.DEV_BUILD; - -/** @type {esbuild.BuildOptions} */ -const esbuildConfig = { - entryPoints: [ - 'src/index.ts', - 'src/store.ts', - 'src/reconcile/keyed.ts', - 'src/reconcile/non-keyed.ts', - 'src/reconcile/reuse-nodes.ts', - ], - outdir: 'dist', - platform: 'neutral', - bundle: true, - sourcemap: true, - metafile: !dev && process.stdout.isTTY, - logLevel: 'debug', -}; - -if (dev) { - const context = await esbuild.context(esbuildConfig); - await context.watch(); -} else { - const out = await esbuild.build(esbuildConfig); - - if (out.metafile) { - console.log(await esbuild.analyzeMetafile(out.metafile)); - } -} diff --git a/build.ts b/build.ts new file mode 100644 index 0000000..3277c70 --- /dev/null +++ b/build.ts @@ -0,0 +1,52 @@ +/* eslint-disable no-console */ + +export {}; + +console.time('build'); + +// Minified browser bundle which includes "regular mode" functions, utils, and store. +const out = await Bun.build({ + entrypoints: ['src/browser.ts'], + outdir: 'dist', + target: 'browser', + // FIXME: Use iife once Bun.build supports it (but we should have 2 bundles, esm and iife) + // format: 'iife', + minify: true, + sourcemap: 'external', +}); + +const out2 = await Bun.build({ + entrypoints: ['src/index.ts', 'src/store.ts'], + outdir: 'dist', + target: 'browser', + sourcemap: 'external', +}); + +const out3 = await Bun.build({ + entrypoints: [ + 'src/reconcile/keyed.ts', + 'src/reconcile/non-keyed.ts', + 'src/reconcile/reuse-nodes.ts', + ], + outdir: 'dist/reconcile', + target: 'browser', + sourcemap: 'external', +}); + +const out4 = await Bun.build({ + entrypoints: ['src/runtime/index.ts'], + outdir: 'dist/runtime', + target: 'browser', + sourcemap: 'external', +}); + +const out5 = await Bun.build({ + entrypoints: ['src/runtime/macro.ts'], + outdir: 'dist/runtime', + target: 'bun', + minify: true, + sourcemap: 'external', +}); + +console.timeEnd('build'); +console.log(out, out2, out3, out4, out5); From 6ed6963af6937fad2a02ac0b07a0c3c69647f5a5 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:52:27 +1000 Subject: [PATCH 010/169] feat: Add new browser bundle for CDN use --- src/browser.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/browser.ts diff --git a/src/browser.ts b/src/browser.ts new file mode 100644 index 0000000..e4c5cad --- /dev/null +++ b/src/browser.ts @@ -0,0 +1,5 @@ +export * from './compile'; +export * from './events'; +export * from './store'; +export * from './types'; +export * from './utils'; From 5ae2fcec89c0c52215f0a40f878c5a9b9ae089cb Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:52:52 +1000 Subject: [PATCH 011/169] feat: Add new clone utility function --- src/utils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 792e881..98dfccd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,13 +9,15 @@ export const append = (node: T, parent: Node): T => parent.appendChild(node); export const prepend = (node: T, parent: Node): T => parent.insertBefore(node, parent.firstChild); +export const clone = (node: T): T => node.cloneNode(true) as T; /** * Runs callback function when a specified node is removed from the DOM. * - * @remarks Use sparingly to minimize performance overhead. + * @remarks Somewhat computationally expensive, especially when there are many + * DOM mutations. Use sparingly to minimize performance overhead. */ -export const onNodeRemove = (node: Node, fn: () => void): void => { +export const onRemove = (node: Node, fn: () => void): void => { new MutationObserver((mutations, observer) => { for (const mutation of mutations) { for (const removedNode of mutation.removedNodes) { @@ -26,7 +28,7 @@ export const onNodeRemove = (node: Node, fn: () => void): void => { } } } - }).observe(document.documentElement, { + }).observe(document, { childList: true, subtree: true, }); From 3dd3a7329f0ec60ced7f501195a3a1d5c9a69750 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:53:17 +1000 Subject: [PATCH 012/169] feat: Improve store documentation --- src/store.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/store.ts b/src/store.ts index 16ac23e..2208b6a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -7,11 +7,13 @@ type Store = T & { }; /** - * Creates a proxied state object that triggers callback functions when its - * properties are set. + * Create a reactive data store. * - * @param initialState - An initial store state. The provided object should not - * have an `on` property because it is used internally. + * @param initialState - An initial store state object. It must not have an `on` + * property because that is used to register callback functions. + * + * @returns A proxied state object that triggers registered callback handler + * functions when its properties are set. */ export const store = >( initialState: T & { on?: never }, @@ -21,6 +23,7 @@ export const store = >( return new Proxy( // proxied state object { + // shallow copy to prevent mutation of the initial state object ...initialState, on(key, fn) { (handlers[key] ??= []).push(fn); From 949774aa6b0b550815052e019e37fcd9ecb84018 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:54:06 +1000 Subject: [PATCH 013/169] feat: Refactor reconsilers to remove most lint errors --- src/reconcile/keyed.ts | 268 +++++++++++++++++------------------ src/reconcile/non-keyed.ts | 253 ++++++++++++++++----------------- src/reconcile/reuse-nodes.ts | 67 ++++----- 3 files changed, 277 insertions(+), 311 deletions(-) diff --git a/src/reconcile/keyed.ts b/src/reconcile/keyed.ts index 9b10ff5..1e75a8c 100644 --- a/src/reconcile/keyed.ts +++ b/src/reconcile/keyed.ts @@ -1,20 +1,65 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unused-expressions */ -/* eslint-disable @typescript-eslint/no-use-before-define */ -/* eslint-disable block-scoped-var */ -/* eslint-disable no-continue */ -/* eslint-disable no-labels */ -/* eslint-disable no-multi-assign */ -/* eslint-disable no-sequences */ -/* eslint-disable no-var */ -/* eslint-disable vars-on-top */ +/* eslint-disable no-continue, no-labels, unicorn/no-for-loop, unicorn/no-new-array */ import { noop } from '../utils'; +// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L396C10-L396C30 +const findGreatestIndexLEQ = (seq: number[], n: number) => { + // invariant: lo is guaranteed to be index of a value <= n, hi to be > + // therefore, they actually start out of range: (-1, last + 1) + let lo = -1; + let hi = seq.length; + + // fast path for simple increasing sequences + if (hi > 0 && seq[hi - 1] <= n) return hi - 1; + + while (hi - lo > 1) { + const mid = Math.floor((lo + hi) / 2); + if (seq[mid] > n) { + hi = mid; + } else { + lo = mid; + } + } + + return lo; +}; + +// return an array of the indices of ns that comprise the longest increasing subsequence within ns +// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L368C10-L368C46 +const longestPositiveIncreasingSubsequence = ( + ns: number[], + newStart: number, +) => { + const seq = []; + const is = []; + const pre = new Array(ns.length); + const len = ns.length; + let i = newStart; + let l = -1; + + for (; i < len; i++) { + const n = ns[i]; + if (n < 0) continue; + const j = findGreatestIndexLEQ(seq, n); + if (j !== -1) pre[i] = is[j]; + if (j === l) { + l++; + seq[l] = n; + is[l] = i; + } else if (n < seq[j + 1]) { + seq[j + 1] = n; + is[j + 1] = i; + } + } + + for (i = is[l]; l >= 0; i = pre[i], l--) { + seq[l] = i; + } + + return seq; +}; + // This is almost straightforward implementation of reconcillation algorithm // based on ivi documentation: // https://github.com/localvoid/ivi/blob/2c81ead934b9128e092cc2a5ef2d3cabc73cb5dd/packages/ivi/src/vdom/implementation.ts#L1366 @@ -24,30 +69,30 @@ import { noop } from '../utils'; // How this implementation differs from others, is that it's working with data directly, // without maintaining nodes arrays, and uses dom props firstChild/lastChild/nextSibling // for markers moving. -export const reconcile = ( - key: keyof N, +export const reconcile = ( + key: keyof T, parent: Element, - renderedValues: any[], - data: any[], - createFn: (...args: T) => N, - updateFn: (node: N, ...args: T) => void = noop, + renderedData: T[], + data: T[], + createFn: (itemData: T) => N, + updateFn: (node: N, itemData: T) => void = noop, beforeNode?: Node, afterNode?: Node | null, ): void => { + const dataLen = data.length; + // Fast path for clear - if (data.length === 0) { + if (dataLen === 0) { if (beforeNode !== undefined || afterNode !== undefined) { let node = - beforeNode !== undefined ? beforeNode.nextSibling : parent.firstChild; + beforeNode === undefined ? parent.firstChild : beforeNode.nextSibling; let tmp; if (afterNode === undefined) afterNode = null; while (node !== afterNode) { - // @ts-expect-error - FIXME:! - tmp = node.nextSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(node); + tmp = node!.nextSibling; + node!.remove(); node = tmp; } } else { @@ -57,14 +102,17 @@ export const reconcile = ( } // Fast path for create - if (renderedValues.length === 0) { + if (renderedData.length === 0) { + const insert = afterNode !== undefined; + let index = 0; let node; - const mode = afterNode !== undefined ? 1 : 0; - for (let i = 0, len = data.length; i < len; i++) { - // @ts-expect-error - FIXME:! - node = createFn(data[i]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + for (; index < dataLen; index++) { + node = createFn(data[index]); + if (insert) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } } return; } @@ -72,8 +120,8 @@ export const reconcile = ( let prevStart = 0; let newStart = 0; let loop = true; - let prevEnd = renderedValues.length - 1; - let newEnd = data.length - 1; + let prevEnd = renderedData.length - 1; + let newEnd = dataLen - 1; let a; let b; let prevStartNode = beforeNode ? beforeNode.nextSibling : parent.firstChild; @@ -82,71 +130,69 @@ export const reconcile = ( fixes: while (loop) { loop = false; - let _node; + let tmpNode; // Skip prefix - (a = renderedValues[prevStart]), (b = data[newStart]); + a = renderedData[prevStart]; + b = data[newStart]; while (a[key] === b[key]) { // @ts-expect-error - FIXME:! updateFn(prevStartNode, b); prevStart++; newStart++; - // @ts-expect-error - FIXME:! - newStartNode = prevStartNode = prevStartNode.nextSibling; + newStartNode = prevStartNode = prevStartNode!.nextSibling; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevStart]; + a = renderedData[prevStart]; b = data[newStart]; } // Skip suffix - (a = renderedValues[prevEnd]), (b = data[newEnd]); + a = renderedData[prevEnd]; + b = data[newEnd]; while (a[key] === b[key]) { // @ts-expect-error - FIXME:! updateFn(prevEndNode, b); prevEnd--; newEnd--; afterNode = prevEndNode; - // @ts-expect-error - FIXME:! - prevEndNode = prevEndNode.previousSibling; + prevEndNode = prevEndNode!.previousSibling; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevEnd]; + a = renderedData[prevEnd]; b = data[newEnd]; } // Fast path to swap backward - (a = renderedValues[prevEnd]), (b = data[newStart]); + a = renderedData[prevEnd]; + b = data[newStart]; while (a[key] === b[key]) { loop = true; // @ts-expect-error - FIXME:! updateFn(prevEndNode, b); - // @ts-expect-error - FIXME:! - _node = prevEndNode.previousSibling; - // @ts-expect-error - FIXME:! - parent.insertBefore(prevEndNode, newStartNode); - prevEndNode = _node; + tmpNode = prevEndNode!.previousSibling; + parent.insertBefore(prevEndNode!, newStartNode); + prevEndNode = tmpNode; newStart++; prevEnd--; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevEnd]; + a = renderedData[prevEnd]; b = data[newStart]; } // Fast path to swap forward - (a = renderedValues[prevStart]), (b = data[newEnd]); + a = renderedData[prevStart]; + b = data[newEnd]; while (a[key] === b[key]) { loop = true; // @ts-expect-error - FIXME:! updateFn(prevStartNode, b); - // @ts-expect-error - FIXME:! - _node = prevStartNode.nextSibling; - // @ts-expect-error - FIXME:! - parent.insertBefore(prevStartNode, afterNode); + tmpNode = prevStartNode!.nextSibling; + parent.insertBefore(prevStartNode!, afterNode!); prevStart++; afterNode = prevStartNode; - prevStartNode = _node; + prevStartNode = tmpNode; newEnd--; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevStart]; + a = renderedData[prevStart]; b = data[newEnd]; } } @@ -157,13 +203,10 @@ export const reconcile = ( let next; while (prevStart <= prevEnd) { if (prevEnd === 0) { - // @ts-expect-error - FIXME:! - parent.removeChild(prevEndNode); + prevEndNode!.remove(); } else { - // @ts-expect-error - FIXME:! - next = prevEndNode.previousSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(prevEndNode); + next = prevEndNode!.previousSibling; + prevEndNode!.remove(); prevEndNode = next; } prevEnd--; @@ -178,10 +221,12 @@ export const reconcile = ( let node; const mode = afterNode ? 1 : 0; while (newStart <= newEnd) { - // @ts-expect-error - FIXME:! node = createFn(data[newStart]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + if (mode) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } newStart++; } } @@ -189,19 +234,19 @@ export const reconcile = ( } // Positions for reusing nodes from current DOM state - const P = new Array(newEnd + 1 - newStart); + const P = new Array(newEnd + 1 - newStart); for (let i = newStart; i <= newEnd; i++) P[i] = -1; // Index to resolve position from current to new const I = new Map(); for (let i = newStart; i <= newEnd; i++) I.set(data[i][key], i); - let reusingNodes = newStart + data.length - 1 - newEnd; + let reusingNodes = newStart + dataLen - 1 - newEnd; const toRemove = []; for (let i = prevStart; i <= prevEnd; i++) { - if (I.has(renderedValues[i][key])) { - P[I.get(renderedValues[i][key])] = i; + if (I.has(renderedData[i][key])) { + P[I.get(renderedData[i][key])] = i; reusingNodes++; } else { toRemove.push(i); @@ -212,16 +257,14 @@ export const reconcile = ( if (reusingNodes === 0) { if (beforeNode !== undefined || afterNode !== undefined) { let node = - beforeNode !== undefined ? beforeNode.nextSibling : parent.firstChild; + beforeNode === undefined ? parent.firstChild : beforeNode.nextSibling; let tmp; if (afterNode === undefined) afterNode = null; while (node !== afterNode) { - // @ts-expect-error - FIXME:! - tmp = node.nextSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(node); + tmp = node!.nextSibling; + node!.remove(); node = tmp; prevStart++; } @@ -232,10 +275,12 @@ export const reconcile = ( let node; const mode = afterNode ? 1 : 0; for (let i = newStart; i <= newEnd; i++) { - // @ts-expect-error - FIXME:! node = createFn(data[i]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + if (mode) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } } return; @@ -249,17 +294,15 @@ export const reconcile = ( let tmpC = prevStartNode; for (let i = prevStart; i <= prevEnd; i++) { nodes[i] = tmpC; - // @ts-expect-error - FIXME:! - tmpC = tmpC.nextSibling; + tmpC = tmpC!.nextSibling; } for (let i = 0; i < toRemove.length; i++) { - // @ts-expect-error - FIXME:! - parent.removeChild(nodes[toRemove[i]]); + nodes[toRemove[i]]!.remove(); } let lisIdx = longestSeq.length - 1; - let tmpD; + let tmpD: Node; for (let i = newEnd; i >= newStart; i--) { if (longestSeq[lisIdx] === i) { afterNode = nodes[P[longestSeq[lisIdx]]]; @@ -268,69 +311,14 @@ export const reconcile = ( lisIdx--; } else { if (P[i] === -1) { - // @ts-expect-error - FIXME:! tmpD = createFn(data[i]); } else { - tmpD = nodes[P[i]]; + tmpD = nodes[P[i]]!; // @ts-expect-error - FIXME:! updateFn(tmpD, data[i]); } - // @ts-expect-error - FIXME:! - parent.insertBefore(tmpD, afterNode); + parent.insertBefore(tmpD, afterNode!); afterNode = tmpD; } } }; - -// Picked from -// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L368 - -// return an array of the indices of ns that comprise the longest increasing subsequence within ns -const longestPositiveIncreasingSubsequence = (ns: any[], newStart: number) => { - const seq = []; - const is = []; - let l = -1; - const pre = new Array(ns.length); - - for (var i = newStart, len = ns.length; i < len; i++) { - const n = ns[i]; - if (n < 0) continue; - const j = findGreatestIndexLEQ(seq, n); - if (j !== -1) pre[i] = is[j]; - if (j === l) { - l++; - seq[l] = n; - is[l] = i; - } else if (n < seq[j + 1]) { - seq[j + 1] = n; - is[j + 1] = i; - } - } - - for (i = is[l]; l >= 0; i = pre[i], l--) { - seq[l] = i; - } - - return seq; -}; - -const findGreatestIndexLEQ = (seq: any[], n: number) => { - // invariant: lo is guaranteed to be index of a value <= n, hi to be > - // therefore, they actually start out of range: (-1, last + 1) - let lo = -1; - let hi = seq.length; - - // fast path for simple increasing sequences - if (hi > 0 && seq[hi - 1] <= n) return hi - 1; - - while (hi - lo > 1) { - const mid = Math.floor((lo + hi) / 2); - if (seq[mid] > n) { - hi = mid; - } else { - lo = mid; - } - } - - return lo; -}; diff --git a/src/reconcile/non-keyed.ts b/src/reconcile/non-keyed.ts index 6421f0a..f733b19 100644 --- a/src/reconcile/non-keyed.ts +++ b/src/reconcile/non-keyed.ts @@ -1,20 +1,65 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unused-expressions */ -/* eslint-disable @typescript-eslint/no-use-before-define */ -/* eslint-disable block-scoped-var */ -/* eslint-disable no-continue */ -/* eslint-disable no-labels */ -/* eslint-disable no-multi-assign */ -/* eslint-disable no-sequences */ -/* eslint-disable no-var */ -/* eslint-disable vars-on-top */ +/* eslint-disable no-continue, no-labels, unicorn/no-for-loop, unicorn/no-new-array */ import { noop } from '../utils'; +// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L396C10-L396C30 +const findGreatestIndexLEQ = (seq: number[], n: number) => { + // invariant: lo is guaranteed to be index of a value <= n, hi to be > + // therefore, they actually start out of range: (-1, last + 1) + let lo = -1; + let hi = seq.length; + + // fast path for simple increasing sequences + if (hi > 0 && seq[hi - 1] <= n) return hi - 1; + + while (hi - lo > 1) { + const mid = Math.floor((lo + hi) / 2); + if (seq[mid] > n) { + hi = mid; + } else { + lo = mid; + } + } + + return lo; +}; + +// return an array of the indices of ns that comprise the longest increasing subsequence within ns +// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L368C10-L368C46 +const longestPositiveIncreasingSubsequence = ( + ns: number[], + newStart: number, +) => { + const seq = []; + const is = []; + const pre = new Array(ns.length); + const len = ns.length; + let i = newStart; + let l = -1; + + for (; i < len; i++) { + const n = ns[i]; + if (n < 0) continue; + const j = findGreatestIndexLEQ(seq, n); + if (j !== -1) pre[i] = is[j]; + if (j === l) { + l++; + seq[l] = n; + is[l] = i; + } else if (n < seq[j + 1]) { + seq[j + 1] = n; + is[j + 1] = i; + } + } + + for (i = is[l]; l >= 0; i = pre[i], l--) { + seq[l] = i; + } + + return seq; +}; + // This is almost straightforward implementation of reconcillation algorithm // based on ivi documentation: // https://github.com/localvoid/ivi/blob/2c81ead934b9128e092cc2a5ef2d3cabc73cb5dd/packages/ivi/src/vdom/implementation.ts#L1366 @@ -24,12 +69,12 @@ import { noop } from '../utils'; // How this implementation differs from others, is that it's working with data directly, // without maintaining nodes arrays, and uses dom props firstChild/lastChild/nextSibling // for markers moving. -export const reconcile = ( +export const reconcile = ( parent: Element, - renderedValues: any[], - data: any[], - createFn: (...args: T) => N, - updateFn: (node: N, ...args: T) => void = noop, + renderedData: T[], + data: T[], + createFn: (itemData: T) => N, + updateFn: (node: N, itemData: T) => void = noop, beforeNode?: Node, afterNode?: Node | null, ): void => { @@ -37,16 +82,14 @@ export const reconcile = ( if (data.length === 0) { if (beforeNode !== undefined || afterNode !== undefined) { let node = - beforeNode !== undefined ? beforeNode.nextSibling : parent.firstChild; + beforeNode === undefined ? parent.firstChild : beforeNode.nextSibling; let tmp; if (afterNode === undefined) afterNode = null; while (node !== afterNode) { - // @ts-expect-error - FIXME:! - tmp = node.nextSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(node); + tmp = node!.nextSibling; + node!.remove(); node = tmp; } } else { @@ -56,14 +99,16 @@ export const reconcile = ( } // Fast path for create - if (renderedValues.length === 0) { + if (renderedData.length === 0) { let node; - const mode = afterNode !== undefined ? 1 : 0; + const mode = afterNode === undefined ? 0 : 1; for (let i = 0, len = data.length; i < len; i++) { - // @ts-expect-error - FIXME:! node = createFn(data[i]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + if (mode) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } } return; } @@ -71,7 +116,7 @@ export const reconcile = ( let prevStart = 0; let newStart = 0; let loop = true; - let prevEnd = renderedValues.length - 1; + let prevEnd = renderedData.length - 1; let newEnd = data.length - 1; let a; let b; @@ -81,71 +126,69 @@ export const reconcile = ( fixes: while (loop) { loop = false; - let _node; + let tmpNode; // Skip prefix - (a = renderedValues[prevStart]), (b = data[newStart]); + a = renderedData[prevStart]; + b = data[newStart]; while (a === b) { // @ts-expect-error - FIXME:! updateFn(prevStartNode, b); prevStart++; newStart++; - // @ts-expect-error - FIXME:! - newStartNode = prevStartNode = prevStartNode.nextSibling; + newStartNode = prevStartNode = prevStartNode!.nextSibling; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevStart]; + a = renderedData[prevStart]; b = data[newStart]; } // Skip suffix - (a = renderedValues[prevEnd]), (b = data[newEnd]); + a = renderedData[prevEnd]; + b = data[newEnd]; while (a === b) { // @ts-expect-error - FIXME:! updateFn(prevEndNode, b); prevEnd--; newEnd--; afterNode = prevEndNode; - // @ts-expect-error - FIXME:! - prevEndNode = prevEndNode.previousSibling; + prevEndNode = prevEndNode!.previousSibling; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevEnd]; + a = renderedData[prevEnd]; b = data[newEnd]; } // Fast path to swap backward - (a = renderedValues[prevEnd]), (b = data[newStart]); + a = renderedData[prevEnd]; + b = data[newStart]; while (a === b) { loop = true; // @ts-expect-error - FIXME:! updateFn(prevEndNode, b); - // @ts-expect-error - FIXME:! - _node = prevEndNode.previousSibling; - // @ts-expect-error - FIXME:! - parent.insertBefore(prevEndNode, newStartNode); - prevEndNode = _node; + tmpNode = prevEndNode!.previousSibling; + parent.insertBefore(prevEndNode!, newStartNode); + prevEndNode = tmpNode; newStart++; prevEnd--; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevEnd]; + a = renderedData[prevEnd]; b = data[newStart]; } // Fast path to swap forward - (a = renderedValues[prevStart]), (b = data[newEnd]); + a = renderedData[prevStart]; + b = data[newEnd]; while (a === b) { loop = true; // @ts-expect-error - FIXME:! updateFn(prevStartNode, b); - // @ts-expect-error - FIXME:! - _node = prevStartNode.nextSibling; - // @ts-expect-error - FIXME:! - parent.insertBefore(prevStartNode, afterNode); + tmpNode = prevStartNode!.nextSibling; + parent.insertBefore(prevStartNode!, afterNode!); prevStart++; afterNode = prevStartNode; - prevStartNode = _node; + prevStartNode = tmpNode; newEnd--; if (prevEnd < prevStart || newEnd < newStart) break fixes; - a = renderedValues[prevStart]; + a = renderedData[prevStart]; b = data[newEnd]; } } @@ -156,13 +199,10 @@ export const reconcile = ( let next; while (prevStart <= prevEnd) { if (prevEnd === 0) { - // @ts-expect-error - FIXME:! - parent.removeChild(prevEndNode); + prevEndNode!.remove(); } else { - // @ts-expect-error - FIXME:! - next = prevEndNode.previousSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(prevEndNode); + next = prevEndNode!.previousSibling; + prevEndNode!.remove(); prevEndNode = next; } prevEnd--; @@ -177,10 +217,12 @@ export const reconcile = ( let node; const mode = afterNode ? 1 : 0; while (newStart <= newEnd) { - // @ts-expect-error - FIXME:! node = createFn(data[newStart]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + if (mode) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } newStart++; } } @@ -188,7 +230,7 @@ export const reconcile = ( } // Positions for reusing nodes from current DOM state - const P = new Array(newEnd + 1 - newStart); + const P = new Array(newEnd + 1 - newStart); for (let i = newStart; i <= newEnd; i++) P[i] = -1; // Index to resolve position from current to new @@ -199,8 +241,8 @@ export const reconcile = ( const toRemove = []; for (let i = prevStart; i <= prevEnd; i++) { - if (I.has(renderedValues[i])) { - P[I.get(renderedValues[i])] = i; + if (I.has(renderedData[i])) { + P[I.get(renderedData[i])] = i; reusingNodes++; } else { toRemove.push(i); @@ -211,16 +253,14 @@ export const reconcile = ( if (reusingNodes === 0) { if (beforeNode !== undefined || afterNode !== undefined) { let node = - beforeNode !== undefined ? beforeNode.nextSibling : parent.firstChild; + beforeNode === undefined ? parent.firstChild : beforeNode.nextSibling; let tmp; if (afterNode === undefined) afterNode = null; while (node !== afterNode) { - // @ts-expect-error - FIXME:! - tmp = node.nextSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(node); + tmp = node!.nextSibling; + node!.remove(); node = tmp; prevStart++; } @@ -231,10 +271,12 @@ export const reconcile = ( let node; const mode = afterNode ? 1 : 0; for (let i = newStart; i <= newEnd; i++) { - // @ts-expect-error - FIXME:! node = createFn(data[i]); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(node, afterNode) : parent.appendChild(node); + if (mode) { + parent.insertBefore(node, afterNode!); + } else { + parent.appendChild(node); + } } return; @@ -248,17 +290,15 @@ export const reconcile = ( let tmpC = prevStartNode; for (let i = prevStart; i <= prevEnd; i++) { nodes[i] = tmpC; - // @ts-expect-error - FIXME:! - tmpC = tmpC.nextSibling; + tmpC = tmpC!.nextSibling; } for (let i = 0; i < toRemove.length; i++) { - // @ts-expect-error - FIXME:! - parent.removeChild(nodes[toRemove[i]]); + nodes[toRemove[i]]!.remove(); } let lisIdx = longestSeq.length - 1; - let tmpD; + let tmpD: Node; for (let i = newEnd; i >= newStart; i--) { if (longestSeq[lisIdx] === i) { afterNode = nodes[P[longestSeq[lisIdx]]]; @@ -267,69 +307,14 @@ export const reconcile = ( lisIdx--; } else { if (P[i] === -1) { - // @ts-expect-error - FIXME:! tmpD = createFn(data[i]); } else { - tmpD = nodes[P[i]]; + tmpD = nodes[P[i]]!; // @ts-expect-error - FIXME:! updateFn(tmpD, data[i]); } - // @ts-expect-error - FIXME:! - parent.insertBefore(tmpD, afterNode); + parent.insertBefore(tmpD, afterNode!); afterNode = tmpD; } } }; - -// Picked from -// https://github.com/adamhaile/surplus/blob/master/src/runtime/content.ts#L368 - -// return an array of the indices of ns that comprise the longest increasing subsequence within ns -const longestPositiveIncreasingSubsequence = (ns: any[], newStart: number) => { - const seq = []; - const is = []; - let l = -1; - const pre = new Array(ns.length); - - for (var i = newStart, len = ns.length; i < len; i++) { - const n = ns[i]; - if (n < 0) continue; - const j = findGreatestIndexLEQ(seq, n); - if (j !== -1) pre[i] = is[j]; - if (j === l) { - l++; - seq[l] = n; - is[l] = i; - } else if (n < seq[j + 1]) { - seq[j + 1] = n; - is[j + 1] = i; - } - } - - for (i = is[l]; l >= 0; i = pre[i], l--) { - seq[l] = i; - } - - return seq; -}; - -const findGreatestIndexLEQ = (seq: any[], n: number) => { - // invariant: lo is guaranteed to be index of a value <= n, hi to be > - // therefore, they actually start out of range: (-1, last + 1) - let lo = -1; - let hi = seq.length; - - // fast path for simple increasing sequences - if (hi > 0 && seq[hi - 1] <= n) return hi - 1; - - while (hi - lo > 1) { - const mid = Math.floor((lo + hi) / 2); - if (seq[mid] > n) { - hi = mid; - } else { - lo = mid; - } - } - - return lo; -}; diff --git a/src/reconcile/reuse-nodes.ts b/src/reconcile/reuse-nodes.ts index e4fedee..2c9a359 100644 --- a/src/reconcile/reuse-nodes.ts +++ b/src/reconcile/reuse-nodes.ts @@ -1,32 +1,26 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unused-expressions */ - import { noop } from '../utils'; -export const reconcile = ( +export const reconcile = ( parent: Element, - renderedValues: any[], - data: any[], - createFn: (...args: T) => N, - updateFn: (node: N, ...args: T) => void = noop, + renderedData: T[], + data: T[], + createFn: (itemData: T) => N, + updateFn: (node: N, itemData: T) => void = noop, beforeNode?: Node, afterNode?: Node | null, ): void => { - if (data.length === 0) { + const len = data.length; + if (len === 0) { if (beforeNode !== undefined || afterNode !== undefined) { let node = - beforeNode !== undefined ? beforeNode.nextSibling : parent.firstChild; + beforeNode === undefined ? parent.firstChild : beforeNode.nextSibling; let tmp; if (afterNode === undefined) afterNode = null; while (node !== afterNode) { - // @ts-expect-error - FIXME:! - tmp = node.nextSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(node); + tmp = node!.nextSibling; + node!.remove(); node = tmp; } } else { @@ -34,40 +28,39 @@ export const reconcile = ( } return; } - if (renderedValues.length > data.length) { - let i = renderedValues.length; - let tail = - // @ts-expect-error - FIXME:! - afterNode !== undefined ? afterNode.previousSibling : parent.lastChild; + if (renderedData.length > len) { + let index = renderedData.length; + let tail = afterNode == null ? parent.lastChild : afterNode.previousSibling; let tmp; - while (i > data.length) { - // @ts-expect-error - FIXME:! - tmp = tail.previousSibling; - // @ts-expect-error - FIXME:! - parent.removeChild(tail); + while (index > len) { + tmp = tail!.previousSibling; + tail!.remove(); tail = tmp; - i--; + index--; } } - let _head = beforeNode ? beforeNode.nextSibling : parent.firstChild; - // @ts-expect-error - FIXME:! - if (_head === afterNode) _head = undefined; + let head = beforeNode ? beforeNode.nextSibling : parent.firstChild; + if (head === afterNode) head = null; - const _mode = afterNode ? 1 : 0; - for (let i = 0, item, head = _head, mode = _mode; i < data.length; i++) { - item = data[i]; + const mode = afterNode ? 1 : 0; + let index = 0; + let item; + for (; index < len; index++) { + item = data[index]; if (head) { // @ts-expect-error - FIXME:! updateFn(head, item); } else { // @ts-expect-error - FIXME:! head = createFn(item); - // @ts-expect-error - FIXME:! - mode ? parent.insertBefore(head, afterNode) : parent.appendChild(head); + if (mode) { + parent.insertBefore(head!, afterNode!); + } else { + parent.appendChild(head!); + } } - // @ts-expect-error - FIXME:! - head = head.nextSibling; + head = head!.nextSibling; if (head === afterNode) head = null; } }; From 7d60122506ca02e25a253f18612857a0c15a7d0c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:54:27 +1000 Subject: [PATCH 014/169] feat: Add new precompileed runtime mode --- src/runtime/index.ts | 6 ++++ src/runtime/macro.ts | 75 ++++++++++++++++++++++++++++++++++++++++++ src/runtime/runtime.ts | 55 +++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 src/runtime/index.ts create mode 100644 src/runtime/macro.ts create mode 100644 src/runtime/runtime.ts diff --git a/src/runtime/index.ts b/src/runtime/index.ts new file mode 100644 index 0000000..7120c94 --- /dev/null +++ b/src/runtime/index.ts @@ -0,0 +1,6 @@ +export * from './runtime'; + +export * from '../events'; +export * from '../utils'; + +export type { LowercaseKeys, Refs } from '../types'; diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts new file mode 100644 index 0000000..f05e4c4 --- /dev/null +++ b/src/runtime/macro.ts @@ -0,0 +1,75 @@ +/** + * Bun macro which compiles a template string into a format that can be used by + * the runtime. + * @param template - HTML template string. + * @param keepComments - Whether to keep HTML comments in the output. + */ +export async function compile( + template: string, + keepComments?: boolean, + // @ts-expect-error - Bun macros always return synchronous output. +): { html: string; k: readonly string[]; d: readonly number[] } { + const rewriter = new HTMLRewriter(); + const k: string[] = []; + const d: number[] = []; + let distance = 0; + let whitespaceSensitiveBlock = false; + + rewriter.on('*', { + element(node) { + if (node.tagName === 'pre' || node.tagName === 'code') { + whitespaceSensitiveBlock = true; + node.onEndTag(() => { + whitespaceSensitiveBlock = false; + }); + } + for (const [name] of node.attributes) { + if (name[0] === '@') { + k.push(name.slice(1)); + d.push(distance); + distance = 0; + node.removeAttribute(name); + break; + } + } + distance++; + }, + text(chunk) { + if (!chunk.lastInTextNode) { + const content = chunk.text.trim(); + if (!content) { + if (!whitespaceSensitiveBlock) { + chunk.remove(); + } + return; + } + if (content[0] === '@') { + k.push(content.slice(1)); + d.push(distance); + distance = 0; + chunk.replace(' '); + } + distance++; + } + }, + comments(node) { + if (keepComments) { + distance++; + } else { + node.remove(); + } + }, + }); + + const res = rewriter.transform( + new Response( + template + .trim() + // reduce any whitespace to a single space + .replace(/\s+/g, ' '), + ), + ); + const html = await res.text(); + + return { html, k, d }; +} diff --git a/src/runtime/runtime.ts b/src/runtime/runtime.ts new file mode 100644 index 0000000..535a9ef --- /dev/null +++ b/src/runtime/runtime.ts @@ -0,0 +1,55 @@ +import type { LowercaseKeys, Refs } from '../types'; +import { create } from '../utils'; + +const compilerTemplate = create('template'); +const treeWalker = document.createTreeWalker(compilerTemplate); + +/** + * Creates a DOM node from a compiled template. + * @param template - HTML template string. + */ +export const h = ( + template: string, +): T => { + compilerTemplate.innerHTML = template; + return compilerTemplate.content.firstChild as T; +}; + +// const next = (d: number) => { +// while (d--) treeWalker.nextNode(); +// return treeWalker.currentNode; +// }; + +/** + * Collects node refs from a compiled template. + * @param root - Root node. + * @param k - Ref key names. + * @param d - Distances from previous ref node or root. + * @returns An object mapping ref nodes keyed by their ref name. Note that some + * browsers lowercase rendered HTML element attribute names so we lowercase the + * typed key names to bring awareness to this. + */ +export const collect = ( + root: Node, + k: readonly string[], + d: readonly number[], +): LowercaseKeys => { + const refs: Refs = {}; + const len = k.length; + let index = 0; + let distance; + // TODO: Performance test setting treeWalker to a local variable. + treeWalker.currentNode = root; + + // TODO: Performance test these 2 approaches. + // for (; index < len; index++) { + // refs[k[index]] = next(d[index]); + // } + for (; index < len; index++) { + distance = d[index]; + while (distance--) treeWalker.nextNode(); + refs[k[index]] = treeWalker.currentNode; + } + + return refs as LowercaseKeys; +}; From 70cd100ae878e23727ce814de55c1bab2bd8d85a Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:54:51 +1000 Subject: [PATCH 015/169] feat: Update exports in package --- package.json | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 74479c1..de41759 100644 --- a/package.json +++ b/package.json @@ -8,28 +8,35 @@ "license": "MIT", "sideEffects": false, "main": "dist/index.js", + "browser": "dist/browser.js", "exports": { ".": "./dist/index.js", + "./macro": "./dist/runtime/macro.js", + "./runtime": "./dist/runtime/index.js", + "./store": "./dist/store.js", "./reconcile/keyed": "./dist/reconcile/keyed.js", "./reconcile/non-keyed": "./dist/reconcile/non-keyed.js", "./reconcile/reuse-nodes": "./dist/reconcile/reuse-nodes.js", - "./store": "./dist/store.js", + "./browser": "./dist/browser.js", "./package.json": "./package.json" }, "types": "dist/index.d.ts", "typesVersions": { "*": { - "reconcile/keyed": [ - "dist/reconcile/keyed.d.ts" - ], - "reconcile/non-keyed": [ - "dist/reconcile/non-keyed.d.ts" + "macro": [ + "dist/runtime/macro.d.ts" ], - "reconcile/reuse-nodes": [ - "dist/reconcile/reuse-nodes.d.ts" + "runtime": [ + "dist/runtime/index.d.ts" ], "store": [ "dist/store.d.ts" + ], + "reconcile/*": [ + "dist/reconcile/*.d.ts" + ], + "browser": [ + "dist/browser.d.ts" ] } }, From b27b53410ad34f00f036a2683d7d758cc4b6e99f Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:55:49 +1000 Subject: [PATCH 016/169] test: Refactor unit tests --- test/compile.test.ts | 234 ------------------------- test/events.test.ts | 154 ----------------- test/exports.test.ts | 93 ---------- test/setup.ts | 40 ++++- test/unit/compile.test.ts | 183 ++++++++++++++++++++ test/unit/events.test.ts | 158 +++++++++++++++++ test/unit/exports.test.ts | 154 +++++++++++++++++ test/unit/runtime.test.ts | 193 +++++++++++++++++++++ test/unit/store.test.ts | 176 +++++++++++++++++++ test/unit/utils.test.ts | 351 ++++++++++++++++++++++++++++++++++++++ test/{ => unit}/utils.ts | 65 ++++--- test/utils.test.ts | 235 ------------------------- 12 files changed, 1281 insertions(+), 755 deletions(-) delete mode 100644 test/compile.test.ts delete mode 100644 test/events.test.ts delete mode 100644 test/exports.test.ts create mode 100644 test/unit/compile.test.ts create mode 100644 test/unit/events.test.ts create mode 100644 test/unit/exports.test.ts create mode 100644 test/unit/runtime.test.ts create mode 100644 test/unit/store.test.ts create mode 100644 test/unit/utils.test.ts rename test/{ => unit}/utils.ts (55%) delete mode 100644 test/utils.test.ts diff --git a/test/compile.test.ts b/test/compile.test.ts deleted file mode 100644 index 541d2ba..0000000 --- a/test/compile.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import * as assert from 'uvu/assert'; -import { h, html } from '../src/compile'; -import { cleanup, describe, render } from './utils'; - -describe('h', (test) => { - test.after.each(cleanup); - - test('renders basic template', () => { - const view = h(` -
    -
  • A
  • -
  • B
  • -
  • C
  • -
- `); - const rendered = render(view); - assert.fixture(rendered.container.innerHTML, '
    \n
  • A
  • \n
  • B
  • \n
  • C
  • \n
'); - }); - - test('renders SVG template', () => { - const view = h(` - - - - `); - const rendered = render(view); - assert.fixture( - rendered.container.innerHTML, - '\n\n', - ); - assert.instance(view, window.SVGElement); - }); - - test('returns root element', () => { - const view = h(` -
    -
  • A
  • -
  • B
  • -
  • C
  • -
- `); - assert.is(view.nodeName, 'UL'); - assert.is((view as unknown as HTMLUListElement).id, 'root'); - }); - - test('removes refs in template from output DOM', () => { - const view = h(` -
    -
  • A
  • -
  • B
  • -
- `); - const rendered = render(view); - assert.fixture(rendered.container.innerHTML, '
    \n
  • A
  • \n
  • B
  • \n
'); - }); - - test('collects all refs', () => { - const view = h(` -
-
- -
-
-

Test

-

This is a test.

-
    -
  1. One
  2. -
  3. Two
  4. -
-
- - - -
-
-
- #s -
-
- `); - const nodes = view.collect(view); - assert.instance(nodes.a, window.HTMLDivElement); - assert.is(nodes.a.nodeName, 'DIV'); - assert.instance(nodes.b, window.HTMLElement); - assert.is(nodes.b.nodeName, 'HEADER'); - assert.instance(nodes.c, window.HTMLElement); - assert.is(nodes.c.nodeName, 'NAV'); - assert.instance(nodes.d, window.HTMLAnchorElement); - assert.is(nodes.d.nodeName, 'A'); - assert.instance(nodes.e, window.HTMLAnchorElement); - assert.is(nodes.e.nodeName, 'A'); - assert.instance(nodes.f, window.HTMLElement); - assert.is(nodes.f.nodeName, 'MAIN'); - assert.instance(nodes.g, window.HTMLHeadingElement); - assert.is(nodes.g.nodeName, 'H1'); - assert.instance(nodes.h, window.HTMLParagraphElement); - assert.is(nodes.h.nodeName, 'P'); - assert.instance(nodes.i, window.HTMLElement); - assert.is(nodes.i.nodeName, 'B'); - assert.instance(nodes.j, window.HTMLAnchorElement); - assert.is(nodes.j.nodeName, 'A'); - assert.instance(nodes.k, window.HTMLOListElement); - assert.is(nodes.k.nodeName, 'OL'); - assert.instance(nodes.l, window.HTMLLIElement); - assert.is(nodes.l.nodeName, 'LI'); - assert.instance(nodes.m, window.HTMLLIElement); - assert.is(nodes.m.nodeName, 'LI'); - assert.instance(nodes.n, window.HTMLFormElement); - assert.is(nodes.n.nodeName, 'FORM'); - assert.instance(nodes.o, window.HTMLInputElement); - assert.is(nodes.o.nodeName, 'INPUT'); - assert.instance(nodes.p, window.HTMLTextAreaElement); - assert.is(nodes.p.nodeName, 'TEXTAREA'); - assert.instance(nodes.q, window.HTMLButtonElement); - assert.is(nodes.q.nodeName, 'BUTTON'); - assert.instance(nodes.r, window.HTMLElement); - assert.is(nodes.r.nodeName, 'FOOTER'); - assert.instance(nodes.s, window.Text); - assert.is(nodes.s.nodeName, '#text'); - }); - - test('collects ref at start of element attributes', () => { - const view = h(` -
- -
- `); - const nodes = view.collect(view); - assert.instance(nodes.search, window.HTMLInputElement); - }); - - test('collects ref at end of element attributes', () => { - const view = h(` -
- -
- `); - const nodes = view.collect(view); - assert.instance(nodes.search, window.HTMLInputElement); - }); - - test('collects ref in middle of element attributes', () => { - const view = h(` -
- -
- `); - const nodes = view.collect(view); - assert.instance(nodes.search, window.HTMLInputElement); - }); - - test('does not format template when NODE_ENV=production', () => { - const oldNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - const view = h(`
    -
  • A
  • -
  • B
  • -
  • C
  • -
`); - const rendered = render(view); - assert.fixture( - rendered.container.innerHTML, - '
    \n
  • A
  • \n
  • B
  • \n
  • C
  • \n
', - ); - process.env.NODE_ENV = oldNodeEnv; - }); - - test('omits leading space to correctly render HTMLDivElement when not NODE_ENV=production', () => { - assert.is.not(process.env.NODE_ENV, 'production'); - const view = h('
'); - const rendered = render(view); - assert.instance(rendered.container.firstChild, window.HTMLDivElement); - }); - - test('does not omit leading space and renders Text node when NODE_ENV=production', () => { - const oldNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - const view = h('
'); - const rendered = render(view); - assert.instance(rendered.container.firstChild, window.Text); - process.env.NODE_ENV = oldNodeEnv; - }); -}); - -describe('html', (test) => { - test.after.each(cleanup); - - test('renders basic template', () => { - const view = html` -
    -
  • A
  • -
  • B
  • -
  • C
  • -
- `; - const rendered = render(view); - assert.fixture(rendered.container.innerHTML, '
    \n
  • A
  • \n
  • B
  • \n
  • C
  • \n
'); - }); - - test('does not format template when NODE_ENV=production', () => { - const oldNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - const view = html`
    -
  • A
  • -
  • B
  • -
  • C
  • -
`; - const rendered = render(view); - assert.fixture( - rendered.container.innerHTML, - '
    \n
  • A
  • \n
  • B
  • \n
  • C
  • \n
', - ); - process.env.NODE_ENV = oldNodeEnv; - }); - - test('omits leading space to correctly render HTMLDivElement when not NODE_ENV=production', () => { - assert.is.not(process.env.NODE_ENV, 'production'); - const view = html`
`; - const rendered = render(view); - assert.instance(rendered.container.firstChild, window.HTMLDivElement); - }); - - test('does not omit leading space and renders Text node when NODE_ENV=production', () => { - const oldNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - const view = html`
`; - const rendered = render(view); - assert.instance(rendered.container.firstChild, window.Text); - process.env.NODE_ENV = oldNodeEnv; - }); -}); diff --git a/test/events.test.ts b/test/events.test.ts deleted file mode 100644 index 33054a5..0000000 --- a/test/events.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { spy } from 'nanospy'; -import * as assert from 'uvu/assert'; -import { deleteSyntheticEvent, setupSyntheticEvent } from '../src/events'; -import { cleanup, describe, render } from './utils'; - -declare global { - interface HTMLElement { - /** `stage1` synthetic click event handler. */ - __click?(event: MouseEvent): void; - } -} - -describe('setupSyntheticEvent', (test) => { - test.after.each(cleanup); - - test('is a function', () => { - assert.type(setupSyntheticEvent, 'function'); - }); - - test('expects 1 parameter', () => { - assert.is(setupSyntheticEvent.length, 1); - }); - - test('returns undefined', () => { - assert.is(setupSyntheticEvent('abort'), undefined); - }); - - test('calls synthetic click handler on click event', () => { - const button = document.createElement('button'); - const callback = spy(); - button.__click = callback; - render(button); - setupSyntheticEvent('click'); - button.click(); - button.click(); - button.click(); - assert.is(callback.callCount, 3); - deleteSyntheticEvent('click'); - }); - - test('propagates click event from deeply nested element', () => { - const button = document.createElement('button'); - const div = document.createElement('div'); - const span = document.createElement('span'); - const img = document.createElement('img'); - const callback = spy(); - button.__click = callback; - button.appendChild(div); - div.appendChild(span); - span.appendChild(img); - render(button); - setupSyntheticEvent('click'); - img.click(); - img.click(); - img.click(); - assert.is(callback.callCount, 3); - deleteSyntheticEvent('click'); - }); - - test('propagates up to document body', () => { - const button = document.createElement('button'); - const callback = spy(); - document.body.__click = callback; - render(button); - setupSyntheticEvent('click'); - button.click(); - assert.is(callback.callCount, 1); - deleteSyntheticEvent('click'); - delete document.body.__click; - }); - - test('no longer propagates click event once handled', () => { - const div1 = document.createElement('div'); - const div2 = document.createElement('div'); - const callback = spy(); - div1.__click = callback; - div2.__click = callback; - div1.appendChild(div2); - render(div1); - setupSyntheticEvent('click'); - div2.click(); - assert.is(callback.callCount, 1); // only called once - deleteSyntheticEvent('click'); - }); - - test('does not call handler if synthetic event is not setup', () => { - const button = document.createElement('button'); - const callback = spy(); - button.__click = callback; - render(button); - button.click(); - assert.is(callback.callCount, 0); - }); - - test('does not call handler if event originates from another DOM tree branch', () => { - const div = document.createElement('div'); - const button1 = document.createElement('button'); - const button2 = document.createElement('button'); - const callback1 = spy(); - const callback2 = spy(); - button1.__click = callback1; - button2.__click = callback2; - render(div); - div.appendChild(button1); - div.appendChild(button2); - setupSyntheticEvent('click'); - button1.click(); - assert.is(callback1.callCount, 1); - assert.is(callback2.callCount, 0); - deleteSyntheticEvent('click'); - }); - - test('only registers synthetic click handler once', () => { - const button = document.createElement('button'); - const callback = spy(); - button.__click = callback; - render(button); - setupSyntheticEvent('click'); - setupSyntheticEvent('click'); - button.click(); - assert.is(callback.callCount, 1); - deleteSyntheticEvent('click'); - }); -}); - -describe('deleteSyntheticEvent', (test) => { - test('is a function', () => { - assert.type(deleteSyntheticEvent, 'function'); - }); - - test('expects 1 parameter', () => { - assert.is(deleteSyntheticEvent.length, 1); - }); - - test('returns undefined', () => { - assert.is(deleteSyntheticEvent('abort'), undefined); - }); - - test('does not call synthetic click handler after delete', () => { - const button = document.createElement('button'); - const callback = spy(); - button.__click = callback; - render(button); - setupSyntheticEvent('click'); - button.click(); - assert.is(callback.callCount, 1); - deleteSyntheticEvent('click'); - button.click(); - button.click(); - button.click(); - assert.is(callback.callCount, 1); // still only one call - cleanup(); - }); -}); diff --git a/test/exports.test.ts b/test/exports.test.ts deleted file mode 100644 index d3f8b56..0000000 --- a/test/exports.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* eslint-disable guard-for-in */ - -import * as assert from 'uvu/assert'; -import * as indexExports from '../src/index'; -import * as keyedExports from '../src/reconcile/keyed'; -import * as nonKeyedExports from '../src/reconcile/non-keyed'; -import * as reuseNodesExports from '../src/reconcile/reuse-nodes'; -import * as storeExports from '../src/store'; -import { describe } from './utils'; - -describe('index', (test) => { - const PUBLIC_EXPORTS = [ - ['h', 'Function'], - ['html', 'Function'], - ['setupSyntheticEvent', 'Function'], - ['deleteSyntheticEvent', 'Function'], - ['noop', 'Function'], - ['createFragment', 'Function'], - ['create', 'Function'], - ['append', 'Function'], - ['prepend', 'Function'], - ['onNodeRemove', 'Function'], - ] as const; - - for (const [name, type] of PUBLIC_EXPORTS) { - test(`exports public "${name}" ${type}`, () => { - assert.ok(Object.hasOwnProperty.call(indexExports, name)); - assert.is(Object.prototype.toString.call(indexExports[name]), `[object ${type}]`); - }); - } - - test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - assert.is(publicExportNames.length, Object.keys(indexExports).length); - for (const name in indexExports) { - assert.ok((publicExportNames as string[]).includes(name)); - } - }); - - test('has no default export', () => { - assert.not.ok(Object.hasOwnProperty.call(indexExports, 'default')); - }); -}); - -describe('store', (test) => { - const PUBLIC_EXPORTS = [['store', 'Function']] as const; - - for (const [name, type] of PUBLIC_EXPORTS) { - test(`exports public "${name}" ${type}`, () => { - assert.ok(Object.hasOwnProperty.call(storeExports, name)); - assert.is(Object.prototype.toString.call(storeExports[name]), `[object ${type}]`); - }); - } - - test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - assert.is(publicExportNames.length, Object.keys(storeExports).length); - for (const name in storeExports) { - assert.ok((publicExportNames as string[]).includes(name)); - } - }); - - test('has no default export', () => { - assert.not.ok(Object.hasOwnProperty.call(storeExports, 'default')); - }); -}); - -const RECONSILERS = [ - ['keyed', keyedExports], - ['non-keyed', nonKeyedExports], - ['reuse-nodes', reuseNodesExports], -] as const; - -for (const [reconsiler, exports] of RECONSILERS) { - describe(`reconcile/${reconsiler}`, (test) => { - test('exports public "reconcile" Function', () => { - assert.ok(Object.hasOwnProperty.call(exports, 'reconcile')); - assert.is(Object.prototype.toString.call(exports.reconcile), '[object Function]'); - }); - - test('does not export any private internals', () => { - const publicExportNames = ['reconcile']; - assert.is(publicExportNames.length, Object.keys(exports).length); - for (const name in exports) { - assert.ok(publicExportNames.includes(name)); - } - }); - - test('has no default export', () => { - assert.not.ok(Object.hasOwnProperty.call(exports, 'default')); - }); - }); -} diff --git a/test/setup.ts b/test/setup.ts index bddfaa6..e585dc9 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,4 +1,38 @@ -import { setupDOM, setupMocks } from './utils'; +import { GlobalWindow, type Window } from 'happy-dom'; -setupDOM(); -setupMocks(); +declare global { + // eslint-disable-next-line no-var, vars-on-top + var happyDOM: Window['happyDOM']; +} + +// Increase stack limit from 10 (v8 default) +global.Error.stackTraceLimit = 50; + +function setupDOM() { + const dom = new GlobalWindow({ + url: 'chrome-extension://cpcibnbdmpmcmnkhoiilpnlaepkepknb/', + }); + global.happyDOM = dom.happyDOM; + // @ts-expect-error - happy-dom only implements a subset of the DOM API + global.window = dom.window.document.defaultView; + global.document = window.document; + global.console = window.console; + global.setTimeout = window.setTimeout; + global.clearTimeout = window.clearTimeout; + global.DocumentFragment = window.DocumentFragment; + global.CSSStyleSheet = window.CSSStyleSheet; + global.Text = window.Text; + global.fetch = window.fetch; + global.MutationObserver = window.MutationObserver; +} + +function setupMocks(): void { + // TODO:! +} + +export function reset(): void { + setupDOM(); + setupMocks(); +} + +reset(); diff --git a/test/unit/compile.test.ts b/test/unit/compile.test.ts new file mode 100644 index 0000000..8aa1919 --- /dev/null +++ b/test/unit/compile.test.ts @@ -0,0 +1,183 @@ +// XXX: This file has the same tests as test/unit/runtime.test.ts, keep them in sync. + +import { afterEach, describe, expect, test } from 'bun:test'; +import { collect, h, html } from '../../src/compile'; +import { cleanup, render } from './utils'; + +// FIXME: Use inline snapshots once bun:test supports them. + +describe('h', () => { + afterEach(cleanup); + + test('renders basic template', () => { + const view = h(` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); + }); + + test('renders SVG template', () => { + const view = h(` + + + + `); + const rendered = render(view); + expect(view).toBeInstanceOf(window.SVGSVGElement); + expect(rendered.container.innerHTML).toBe( + '', + ); + }); + + test('returns root element', () => { + const view = h(` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `); + const rendered = render(view); + expect(view).toBeInstanceOf(window.HTMLUListElement); + expect(view.id).toBe('root'); + expect(rendered.container.firstChild).toBe(view); + }); + + test('removes refs in template from output DOM', () => { + const view = h(` +
    +
  • A
  • +
  • B
  • +
+ `); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
'); + }); +}); + +describe('html', () => { + afterEach(cleanup); + + test('renders basic template', () => { + const view = html` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `; + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); + }); +}); + +describe('collect', () => { + test('collects all refs', () => { + const view = h(` +
+
+ +
+
+

Test

+

This is a test.

+
    +
  1. One
  2. +
  3. Two
  4. +
+
+ + + +
+
+
+ @s +
+
+ `); + const refs = collect(view, view); + expect(refs.a.nodeName).toEqual('DIV'); + expect(refs.a).toBeInstanceOf(window.HTMLDivElement); + expect(refs.b.nodeName).toEqual('HEADER'); + expect(refs.b).toBeInstanceOf(window.HTMLElement); + expect(refs.c.nodeName).toEqual('NAV'); + expect(refs.c).toBeInstanceOf(window.HTMLElement); + expect(refs.d.nodeName).toEqual('A'); + expect(refs.d).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.e.nodeName).toEqual('A'); + expect(refs.e).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.f.nodeName).toEqual('MAIN'); + expect(refs.f).toBeInstanceOf(window.HTMLDivElement); + expect(refs.g.nodeName).toEqual('H1'); + expect(refs.g).toBeInstanceOf(window.HTMLHeadingElement); + expect(refs.h.nodeName).toEqual('P'); + expect(refs.h).toBeInstanceOf(window.HTMLParagraphElement); + expect(refs.i.nodeName).toEqual('B'); + expect(refs.i).toBeInstanceOf(window.HTMLElement); + expect(refs.j.nodeName).toEqual('A'); + expect(refs.j).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.k.nodeName).toEqual('OL'); + expect(refs.k).toBeInstanceOf(window.HTMLOListElement); + expect(refs.l.nodeName).toEqual('LI'); + expect(refs.l).toBeInstanceOf(window.HTMLLIElement); + expect(refs.m.nodeName).toEqual('LI'); + expect(refs.m).toBeInstanceOf(window.HTMLLIElement); + expect(refs.n.nodeName).toEqual('FORM'); + expect(refs.n).toBeInstanceOf(window.HTMLFormElement); + expect(refs.o.nodeName).toEqual('INPUT'); + expect(refs.o).toBeInstanceOf(window.HTMLInputElement); + expect(refs.p.nodeName).toEqual('TEXTAREA'); + expect(refs.p).toBeInstanceOf(window.HTMLTextAreaElement); + expect(refs.q.nodeName).toEqual('BUTTON'); + expect(refs.q).toBeInstanceOf(window.HTMLButtonElement); + expect(refs.r.nodeName).toEqual('FOOTER'); + expect(refs.r).toBeInstanceOf(window.HTMLElement); + expect(refs.s.nodeName).toEqual('#text'); + expect(refs.s).toBeInstanceOf(window.Text); + }); + + test('collects ref at start of element attributes', () => { + const view = h(` +
+ +
+ `); + const refs = collect<{ search: HTMLInputElement }>(view, view); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); + + test('collects ref at end of element attributes', () => { + const view = h(` +
+ +
+ `); + const refs = collect<{ search: HTMLInputElement }>(view, view); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); + + test('collects ref in middle of element attributes', () => { + const view = h(` +
+ +
+ `); + const refs = collect<{ search: HTMLInputElement }>(view, view); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); +}); diff --git a/test/unit/events.test.ts b/test/unit/events.test.ts new file mode 100644 index 0000000..bf0465a --- /dev/null +++ b/test/unit/events.test.ts @@ -0,0 +1,158 @@ +import { afterEach, describe, expect, mock, test } from 'bun:test'; +import { deleteSyntheticEvent, setupSyntheticEvent } from '../../src/events'; +import { cleanup, render } from './utils'; + +declare global { + interface HTMLElement { + /** `stage1` synthetic click event handler. */ + __click?(event: MouseEvent): void; + } +} + +describe('setupSyntheticEvent', () => { + test('is a function', () => { + expect(setupSyntheticEvent).toBeInstanceOf(Function); + }); + + test('expects 1 parameter', () => { + expect(setupSyntheticEvent).toHaveLength(1); + }); + + test('returns undefined', () => { + expect(setupSyntheticEvent('abort')).toBeUndefined(); + }); + + describe('rendered', () => { + afterEach(cleanup); + + test('calls synthetic click handler on click event', () => { + const button = document.createElement('button'); + const callback = mock(() => {}); + button.__click = callback; + render(button); + setupSyntheticEvent('click'); + button.click(); + button.click(); + button.click(); + expect(callback).toHaveBeenCalledTimes(3); + deleteSyntheticEvent('click'); + }); + + test('propagates click event from deeply nested element', () => { + const button = document.createElement('button'); + const div = document.createElement('div'); + const span = document.createElement('span'); + const img = document.createElement('img'); + const callback = mock(() => {}); + button.__click = callback; + button.appendChild(div); + div.appendChild(span); + span.appendChild(img); + render(button); + setupSyntheticEvent('click'); + img.click(); + img.click(); + img.click(); + expect(callback).toHaveBeenCalledTimes(3); + deleteSyntheticEvent('click'); + }); + + test('propagates up to document body', () => { + const button = document.createElement('button'); + const callback = mock(() => {}); + document.body.__click = callback; + render(button); + setupSyntheticEvent('click'); + button.click(); + expect(callback).toHaveBeenCalledTimes(1); + deleteSyntheticEvent('click'); + delete document.body.__click; + }); + + test('no longer propagates click event once handled', () => { + const div1 = document.createElement('div'); + const div2 = document.createElement('div'); + const callback = mock(() => {}); + div1.__click = callback; + div2.__click = callback; + div1.appendChild(div2); + render(div1); + setupSyntheticEvent('click'); + div2.click(); + expect(callback).toHaveBeenCalledTimes(1); // only called once + deleteSyntheticEvent('click'); + }); + + test('does not call handler if synthetic event is not setup', () => { + const button = document.createElement('button'); + const callback = mock(() => {}); + button.__click = callback; + render(button); + button.click(); + expect(callback).not.toHaveBeenCalled(); + }); + + test('does not call handler if event originates from another DOM tree branch', () => { + const div = document.createElement('div'); + const button1 = document.createElement('button'); + const button2 = document.createElement('button'); + const callback1 = mock(() => {}); + const callback2 = mock(() => {}); + button1.__click = callback1; + button2.__click = callback2; + render(div); + div.appendChild(button1); + div.appendChild(button2); + setupSyntheticEvent('click'); + button1.click(); + expect(callback1).toHaveBeenCalledTimes(1); + expect(callback2).not.toHaveBeenCalled(); + deleteSyntheticEvent('click'); + }); + + test('only registers synthetic click handler once', () => { + const button = document.createElement('button'); + const callback = mock(() => {}); + button.__click = callback; + render(button); + setupSyntheticEvent('click'); + setupSyntheticEvent('click'); + button.click(); + expect(callback).toHaveBeenCalledTimes(1); + deleteSyntheticEvent('click'); + }); + }); +}); + +describe('deleteSyntheticEvent', () => { + test('is a function', () => { + expect(deleteSyntheticEvent).toBeInstanceOf(Function); + }); + + test('expects 1 parameter', () => { + expect(deleteSyntheticEvent).toHaveLength(1); + }); + + test('returns undefined', () => { + expect(deleteSyntheticEvent('abort')).toBeUndefined(); + }); + + describe('rendered', () => { + afterEach(cleanup); + + test('does not call synthetic click handler after delete', () => { + const button = document.createElement('button'); + const callback = mock(() => {}); + button.__click = callback; + render(button); + setupSyntheticEvent('click'); + button.click(); + expect(callback).toHaveBeenCalledTimes(1); + deleteSyntheticEvent('click'); + button.click(); + button.click(); + button.click(); + expect(callback).toHaveBeenCalledTimes(1); // still only one call + }); + }); +}); diff --git a/test/unit/exports.test.ts b/test/unit/exports.test.ts new file mode 100644 index 0000000..117a696 --- /dev/null +++ b/test/unit/exports.test.ts @@ -0,0 +1,154 @@ +/* eslint-disable guard-for-in */ + +import { describe, expect, test } from 'bun:test'; +import * as indexExports from '../../src/index'; +import * as keyedExports from '../../src/reconcile/keyed'; +import * as nonKeyedExports from '../../src/reconcile/non-keyed'; +import * as reuseNodesExports from '../../src/reconcile/reuse-nodes'; +import * as runtimeExports from '../../src/runtime/index'; +import * as macroExports from '../../src/runtime/macro'; +import * as storeExports from '../../src/store'; + +describe('index', () => { + const PUBLIC_EXPORTS = [ + ['h', Function], + ['html', Function], + ['collect', Function], + ['setupSyntheticEvent', Function], + ['deleteSyntheticEvent', Function], + ['noop', Function], + ['createFragment', Function], + ['create', Function], + ['append', Function], + ['prepend', Function], + ['clone', Function], + ['onRemove', Function], + ] as const; + + for (const [name, type] of PUBLIC_EXPORTS) { + test(`exports public "${name}" ${type.name}`, () => { + expect(indexExports).toHaveProperty(name); + expect(indexExports[name]).toBeInstanceOf(type); + }); + } + + test('does not export any private internals', () => { + const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + expect(publicExportNames).toHaveLength(Object.keys(indexExports).length); + for (const name in indexExports) { + expect(publicExportNames).toContain(name); + } + }); + + test('has no default export', () => { + expect(indexExports).not.toHaveProperty('default'); + }); +}); + +describe('runtime', () => { + const PUBLIC_EXPORTS = [ + ['h', Function], + ['collect', Function], + ['setupSyntheticEvent', Function], + ['deleteSyntheticEvent', Function], + ['noop', Function], + ['createFragment', Function], + ['create', Function], + ['append', Function], + ['prepend', Function], + ['clone', Function], + ['onRemove', Function], + ] as const; + + for (const [name, type] of PUBLIC_EXPORTS) { + test(`exports public "${name}" ${type.name}`, () => { + expect(runtimeExports).toHaveProperty(name); + expect(runtimeExports[name]).toBeInstanceOf(type); + }); + } + + test('does not export any private internals', () => { + const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + expect(publicExportNames).toHaveLength(Object.keys(runtimeExports).length); + for (const name in runtimeExports) { + expect(publicExportNames).toContain(name); + } + }); + + test('has no default export', () => { + expect(runtimeExports).not.toHaveProperty('default'); + }); +}); + +describe('macro', () => { + const PUBLIC_EXPORTS = [['compile', Function]] as const; + + for (const [name, type] of PUBLIC_EXPORTS) { + test(`exports public "${name}" ${type.name}`, () => { + expect(macroExports).toHaveProperty(name); + expect(macroExports[name]).toBeInstanceOf(type); + }); + } + + test('does not export any private internals', () => { + const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + expect(publicExportNames).toHaveLength(Object.keys(macroExports).length); + for (const name in macroExports) { + expect(publicExportNames).toContain(name); + } + }); + + test('has no default export', () => { + expect(macroExports).not.toHaveProperty('default'); + }); +}); + +describe('store', () => { + const PUBLIC_EXPORTS = [['store', Function]] as const; + + for (const [name, type] of PUBLIC_EXPORTS) { + test(`exports public "${name}" ${type.name}`, () => { + expect(storeExports).toHaveProperty(name); + expect(storeExports[name]).toBeInstanceOf(type); + }); + } + + test('does not export any private internals', () => { + const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + expect(publicExportNames).toHaveLength(Object.keys(storeExports).length); + for (const name in storeExports) { + expect(publicExportNames).toContain(name); + } + }); + + test('has no default export', () => { + expect(storeExports).not.toHaveProperty('default'); + }); +}); + +const RECONSILERS = [ + ['keyed', keyedExports], + ['non-keyed', nonKeyedExports], + ['reuse-nodes', reuseNodesExports], +] as const; + +for (const [reconsiler, exports] of RECONSILERS) { + describe(`reconcile/${reconsiler}`, () => { + test('exports public "reconcile" Function', () => { + expect(exports).toHaveProperty('reconcile'); + expect(exports.reconcile).toBeInstanceOf(Function); + }); + + test('does not export any private internals', () => { + const publicExportNames = ['reconcile']; + expect(publicExportNames).toHaveLength(Object.keys(exports).length); + for (const name in exports) { + expect(publicExportNames).toContain(name); + } + }); + + test('has no default export', () => { + expect(exports).not.toHaveProperty('default'); + }); + }); +} diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts new file mode 100644 index 0000000..741c572 --- /dev/null +++ b/test/unit/runtime.test.ts @@ -0,0 +1,193 @@ +// XXX: This file has the same tests as test/unit/compile.test.ts, keep them in sync. + +import { afterEach, describe, expect, test } from 'bun:test'; +import { collect, h } from '../../src/runtime/index'; +import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; +import { cleanup, render } from './utils'; + +// FIXME: Use inline snapshots once bun:test supports them. + +describe('h', () => { + afterEach(cleanup); + + test('renders basic template', () => { + const meta = compile(` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `); + const view = h(meta.html); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); + }); + + test('renders SVG template', () => { + const meta = compile(` + + + + `); + const view = h(meta.html); + const rendered = render(view); + expect(view).toBeInstanceOf(window.SVGSVGElement); + expect(rendered.container.innerHTML).toBe( + '', + ); + }); + + test('returns root element', () => { + const meta = compile(` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `); + const view = h(meta.html); + const rendered = render(view); + expect(view).toBeInstanceOf(window.HTMLUListElement); + expect(view.id).toBe('root'); + expect(rendered.container.firstChild).toBe(view); + }); + + test('removes refs in template from output DOM', () => { + const meta = compile(` +
    +
  • A
  • +
  • B
  • +
+ `); + const view = h(meta.html); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
'); + }); +}); + +// describe('html', () => { +// afterEach(cleanup); +// +// test('renders basic template', () => { +// const view = html` +//
    +//
  • A
  • +//
  • B
  • +//
  • C
  • +//
+// `; +// const view = h(meta.html); +// const rendered = render(view); +// expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); +// }); +// }); + +describe('collect', () => { + test('collects all refs', () => { + const meta = compile(` +
+
+ +
+
+

Test

+

This is a test.

+
    +
  1. One
  2. +
  3. Two
  4. +
+
+ + + +
+
+
+ @s +
+
+ `); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('DIV'); + expect(refs.a).toBeInstanceOf(window.HTMLDivElement); + expect(refs.b.nodeName).toEqual('HEADER'); + expect(refs.b).toBeInstanceOf(window.HTMLElement); + expect(refs.c.nodeName).toEqual('NAV'); + expect(refs.c).toBeInstanceOf(window.HTMLElement); + expect(refs.d.nodeName).toEqual('A'); + expect(refs.d).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.e.nodeName).toEqual('A'); + expect(refs.e).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.f.nodeName).toEqual('MAIN'); + expect(refs.f).toBeInstanceOf(window.HTMLDivElement); + expect(refs.g.nodeName).toEqual('H1'); + expect(refs.g).toBeInstanceOf(window.HTMLHeadingElement); + expect(refs.h.nodeName).toEqual('P'); + expect(refs.h).toBeInstanceOf(window.HTMLParagraphElement); + expect(refs.i.nodeName).toEqual('B'); + expect(refs.i).toBeInstanceOf(window.HTMLElement); + expect(refs.j.nodeName).toEqual('A'); + expect(refs.j).toBeInstanceOf(window.HTMLAnchorElement); + expect(refs.k.nodeName).toEqual('OL'); + expect(refs.k).toBeInstanceOf(window.HTMLOListElement); + expect(refs.l.nodeName).toEqual('LI'); + expect(refs.l).toBeInstanceOf(window.HTMLLIElement); + expect(refs.m.nodeName).toEqual('LI'); + expect(refs.m).toBeInstanceOf(window.HTMLLIElement); + expect(refs.n.nodeName).toEqual('FORM'); + expect(refs.n).toBeInstanceOf(window.HTMLFormElement); + expect(refs.o.nodeName).toEqual('INPUT'); + expect(refs.o).toBeInstanceOf(window.HTMLInputElement); + expect(refs.p.nodeName).toEqual('TEXTAREA'); + expect(refs.p).toBeInstanceOf(window.HTMLTextAreaElement); + expect(refs.q.nodeName).toEqual('BUTTON'); + expect(refs.q).toBeInstanceOf(window.HTMLButtonElement); + expect(refs.r.nodeName).toEqual('FOOTER'); + expect(refs.r).toBeInstanceOf(window.HTMLElement); + expect(refs.s.nodeName).toEqual('#text'); + expect(refs.s).toBeInstanceOf(window.Text); + }); + + test('collects ref at start of element attributes', () => { + const meta = compile(` +
+ +
+ `); + const view = h(meta.html); + const refs = collect<{ search: HTMLInputElement }>(view, meta.k, meta.d); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); + + test('collects ref at end of element attributes', () => { + const meta = compile(` +
+ +
+ `); + const view = h(meta.html); + const refs = collect<{ search: HTMLInputElement }>(view, meta.k, meta.d); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); + + test('collects ref in middle of element attributes', () => { + const meta = compile(` +
+ +
+ `); + const view = h(meta.html); + const refs = collect<{ search: HTMLInputElement }>(view, meta.k, meta.d); + expect(refs.search).toBeInstanceOf(window.HTMLInputElement); + expect(refs.search.id).toBe('search'); + expect(refs.search.name).toBe('q'); + }); +}); diff --git a/test/unit/store.test.ts b/test/unit/store.test.ts new file mode 100644 index 0000000..8730a87 --- /dev/null +++ b/test/unit/store.test.ts @@ -0,0 +1,176 @@ +import { describe, expect, mock, test } from 'bun:test'; +import { isProxy } from 'node:util/types'; +import { store } from '../../src/store'; + +describe('store', () => { + test('is a function', () => { + expect(store).toBeInstanceOf(Function); + }); + + test('expects 1 parameter', () => { + expect(store).toHaveLength(1); + }); + + test('returns a Proxy', () => { + const state = store({}); + expect(isProxy(state)).toBe(true); + }); + + test('returns an object with the same properties', () => { + // eslint-disable-next-line @typescript-eslint/no-extraneous-class + class TestClass {} + const s = Symbol('s'); + const initialState = { + a: 1, + b: 2, + c: null, + d: undefined, + e: 'hello', + f: true, + g: false, + h: () => {}, + i: [1, 2, 3], + j: { ja: Number.POSITIVE_INFINITY, jb: Number.NEGATIVE_INFINITY }, + k: Symbol('k'), + l: new Date(), + m: new Map(), + n: new Set(), + o: document.createElement('div'), + p: new Error('test'), + q: Promise.resolve(), + r: new Promise(() => {}), + [s]: 'symbol', + t: new Uint8Array(), + u: window.location, + v: new TestClass(), + w: TestClass, + x: /test/, + // eslint-disable-next-line prefer-regex-literals + y: new RegExp('test'), + z: window, + }; + const state = store(initialState); + // eslint-disable-next-line guard-for-in + for (const key in initialState) { + expect(state).toHaveProperty(key, initialState[key as keyof typeof initialState]); + } + }); + + test('returns an object with an on() function', () => { + const state = store({}); + expect(state.on).toBeInstanceOf(Function); + expect(state.on).toHaveLength(2); // 2 parameters + }); + + test('returns off() function from on()', () => { + const state = store({ a: 1 }); + const off = state.on('a', () => {}); + expect(off).toBeInstanceOf(Function); + expect(off).toHaveLength(0); // 0 parameters + }); + + test('mutating initial state does not mutate store state', () => { + const initialState = { a: 1 }; + const state = store(initialState); + initialState.a = 2; + expect(state.a).toBe(1); + }); + + test('mutating store state does not mutate initial state', () => { + const initialState = { a: 1 }; + const state = store(initialState); + state.a = 2; + expect(initialState.a).toBe(1); + }); + + test('mutating store state triggers callback', () => { + const initialState = { a: 0 }; + const state = store(initialState); + const callback = mock(() => {}); + state.on('a', callback); + state.a = 1; + // TODO: Uncomment once bun:test mocks support toHaveBeenCalledWith() + // expect(callback).toHaveBeenCalledWith(1, 0); + state.a = 2; + // expect(callback).toHaveBeenCalledWith(2, 1); + state.a = 3; + // expect(callback).toHaveBeenCalledWith(3, 2); + expect(callback).toHaveBeenCalledTimes(3); + }); + + test('mutating store state does not trigger callback after off()', () => { + const initialState = { a: 0 }; + const state = store(initialState); + const callback = mock(() => {}); + const off = state.on('a', callback); + state.a = 1; + expect(callback).toHaveBeenCalledTimes(1); + off(); + state.a = 2; + state.a = 3; + expect(callback).toHaveBeenCalledTimes(1); // still called only once + }); + + // TODO: Don't skip once bun:test mocks support toHaveBeenCalledWith() + test.skip('calls callback with new value and previous value', () => { + // const initialState = { a: 'old' }; + // const state = store(initialState); + // const callback = mock(() => {}); + // state.on('a', callback); + // state.a = 'new'; + // expect(callback).toHaveBeenCalledWith('new', 'old'); + }); + + test('calls all callbacks for mutated property', () => { + const initialState = { a: 0 }; + const state = store(initialState); + const callback1 = mock(() => {}); + const callback2 = mock(() => {}); + const callback3 = mock(() => {}); + state.on('a', callback1); + state.on('a', callback2); + state.on('a', callback3); + state.a = 1; + expect(callback1).toHaveBeenCalledTimes(1); + expect(callback2).toHaveBeenCalledTimes(1); + expect(callback3).toHaveBeenCalledTimes(1); + state.a = 2; + expect(callback1).toHaveBeenCalledTimes(2); + expect(callback2).toHaveBeenCalledTimes(2); + expect(callback3).toHaveBeenCalledTimes(2); + state.a = 3; + state.a = 4; + expect(callback1).toHaveBeenCalledTimes(4); + expect(callback2).toHaveBeenCalledTimes(4); + expect(callback3).toHaveBeenCalledTimes(4); + }); + + test('calls only callbacks for mutated property', () => { + const initialState = { a: 0, b: 0, c: 0 }; + const state = store(initialState); + const callbackA = mock(() => {}); + const callbackB = mock(() => {}); + const callbackC1 = mock(() => {}); + const callbackC2 = mock(() => {}); + state.on('a', callbackA); + state.on('b', callbackB); + state.on('c', callbackC1); + state.on('c', callbackC2); + state.a = 1; + expect(callbackA).toHaveBeenCalledTimes(1); + expect(callbackB).toHaveBeenCalledTimes(0); + expect(callbackC1).toHaveBeenCalledTimes(0); + expect(callbackC2).toHaveBeenCalledTimes(0); + state.b = 2; + expect(callbackA).toHaveBeenCalledTimes(1); + expect(callbackB).toHaveBeenCalledTimes(1); + expect(callbackC1).toHaveBeenCalledTimes(0); + expect(callbackC2).toHaveBeenCalledTimes(0); + state.c = 3; + state.c = 4; + expect(callbackA).toHaveBeenCalledTimes(1); + expect(callbackB).toHaveBeenCalledTimes(1); + expect(callbackC1).toHaveBeenCalledTimes(2); + expect(callbackC2).toHaveBeenCalledTimes(2); + }); +}); diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts new file mode 100644 index 0000000..42e53a9 --- /dev/null +++ b/test/unit/utils.test.ts @@ -0,0 +1,351 @@ +import { describe, expect, mock, test } from 'bun:test'; +import { append, clone, create, createFragment, noop, onRemove, prepend } from '../../src/utils'; + +const ul = document.createElement('ul'); +const liA = document.createElement('li'); +liA.className = 'a'; +const liB = document.createElement('li'); +liB.className = 'b'; +const liC = document.createElement('li'); +liC.className = 'c'; + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +class Sample {} + +const NOT_DOM_NODES = [ + null, + undefined, + '', + 'div', + '
', + '
', + 0, + 1, + -1, + 1n, + -1n, + Number.MAX_VALUE, + Number.MIN_VALUE, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + Number.NaN, + true, + false, + {}, + [], + [liA.cloneNode()], + () => {}, + () => liA.cloneNode(), + function div() {}, + Sample, + new Sample(), + Symbol('test'), + new Map(), + new Set(), + new Int8Array(1), + new Uint8Array(1), +] as const; + +describe('noop', () => { + test('is a function', () => { + expect(noop).toBeInstanceOf(Function); + }); + + test('expects no parameters', () => { + expect(noop).toHaveLength(0); + }); + + test('returns undefined', () => { + expect(noop()).toBeUndefined(); + }); + + test('is an empty function', () => { + expect(noop.toString()).toBe('() => {\n}'); + }); +}); + +describe('createFragment', () => { + test('is a function', () => { + expect(createFragment).toBeInstanceOf(Function); + }); + + test('expects no parameters', () => { + expect(createFragment).toHaveLength(0); + }); + + test('returns a DocumentFragment', () => { + expect(createFragment()).toBeInstanceOf(window.DocumentFragment); + }); +}); + +describe('create', () => { + test('is a function', () => { + expect(create).toBeInstanceOf(Function); + }); + + test('expects 1 parameter', () => { + expect(create).toHaveLength(1); + }); + + // TODO: happy-dom is missing HTMLOptionElement and HTMLOptGroupElement... remove these definitions when they are added + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (window.HTMLOptionElement || window.HTMLOptGroupElement) + throw new Error('Remove this when happy-dom adds HTMLOptionElement'); + // @ts-expect-error - temporary + window.HTMLOptionElement = window.HTMLElement; + // @ts-expect-error - temporary + window.HTMLOptGroupElement = window.HTMLElement; + + const inputs = [ + ['x', window.HTMLUnknownElement], + ['div', window.HTMLDivElement], + ['span', window.HTMLSpanElement], + ['a', window.HTMLAnchorElement], + ['img', window.HTMLImageElement], + ['h1', window.HTMLHeadingElement], + ['h2', window.HTMLHeadingElement], + ['h3', window.HTMLHeadingElement], + ['h4', window.HTMLHeadingElement], + ['h5', window.HTMLHeadingElement], + ['h6', window.HTMLHeadingElement], + ['p', window.HTMLParagraphElement], + ['input', window.HTMLInputElement], + ['textarea', window.HTMLTextAreaElement], + ['button', window.HTMLButtonElement], + ['select', window.HTMLSelectElement], + ['option', window.HTMLOptionElement], + ['optgroup', window.HTMLOptGroupElement], + ['datalist', window.HTMLDataListElement], + ['form', window.HTMLFormElement], + ['fieldset', window.HTMLFieldSetElement], + ['legend', window.HTMLLegendElement], + ['label', window.HTMLLabelElement], + ['ul', window.HTMLUListElement], + ['ol', window.HTMLOListElement], + ['li', window.HTMLLIElement], + ['dl', window.HTMLDListElement], + ['dt', window.HTMLElement], + ['dd', window.HTMLElement], + ['table', window.HTMLTableElement], + ['caption', window.HTMLTableCaptionElement], + ['thead', window.HTMLTableSectionElement], + ['tbody', window.HTMLTableSectionElement], + ['tfoot', window.HTMLTableSectionElement], + ['colgroup', window.HTMLTableColElement], + ['col', window.HTMLTableColElement], + ['tr', window.HTMLTableRowElement], + ['td', window.HTMLTableCellElement], + ['th', window.HTMLTableCellElement], + ['hr', window.HTMLHRElement], + ['br', window.HTMLBRElement], + ['pre', window.HTMLPreElement], + ['blockquote', window.HTMLQuoteElement], + ['q', window.HTMLQuoteElement], + ['ins', window.HTMLModElement], + ['del', window.HTMLModElement], + ['iframe', window.HTMLIFrameElement], + ['embed', window.HTMLEmbedElement], + ['object', window.HTMLObjectElement], + ['video', window.HTMLVideoElement], + ['audio', window.HTMLAudioElement], + ['source', window.HTMLSourceElement], + ['track', window.HTMLTrackElement], + ['canvas', window.HTMLCanvasElement], + ['map', window.HTMLMapElement], + ['area', window.HTMLAreaElement], + ['time', window.HTMLTimeElement], + ['template', window.HTMLTemplateElement], + ['slot', window.HTMLSlotElement], + ] as const; + + for (const [input, expected] of inputs) { + test(`returns ${expected.name} for "${input}" argument`, () => { + // @ts-expect-error - "x" is an intentional invalid element name + expect(create(input)).toBeInstanceOf(expected); + }); + } +}); + +describe('append', () => { + test('is a function', () => { + expect(append).toBeInstanceOf(Function); + }); + + test('expects 2 parameters', () => { + expect(append).toHaveLength(2); + }); + + test('throws without parameters', () => { + // @ts-expect-error - intentional invalid parameters + expect(() => append()).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => append(null)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + // eslint-disable-next-line unicorn/no-useless-undefined + expect(() => append(undefined)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => append(null, null)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + // eslint-disable-next-line unicorn/no-useless-undefined + expect(() => append(undefined, undefined)).toThrow(window.TypeError); + }); + + test('throws when parameters are not an element', () => { + for (const input of NOT_DOM_NODES) { + // @ts-expect-error - intentional invalid parameters + expect(() => append(ul.cloneNode(), input)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => append(input, ul.cloneNode())).toThrow(window.TypeError); + } + }); + + test('appends child element', () => { + const root = ul.cloneNode() as HTMLUListElement; + append(liA.cloneNode(), root); + append(liB.cloneNode(), root); + append(liC.cloneNode(), root); + expect(root.outerHTML).toBe( + '
', + ); + }); +}); + +describe('prepend', () => { + test('is a function', () => { + expect(prepend).toBeInstanceOf(Function); + }); + + test('expects 2 parameters', () => { + expect(prepend).toHaveLength(2); + }); + + test('throws without parameters', () => { + // @ts-expect-error - intentional invalid parameters + expect(() => prepend()).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => prepend(null)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + // eslint-disable-next-line unicorn/no-useless-undefined + expect(() => prepend(undefined)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => prepend(null, null)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + // eslint-disable-next-line unicorn/no-useless-undefined + expect(() => prepend(undefined, undefined)).toThrow(window.TypeError); + }); + + test('throws when parameters are not an element', () => { + for (const input of NOT_DOM_NODES) { + // @ts-expect-error - intentional invalid parameters + expect(() => prepend(ul.cloneNode(), input)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => prepend(input, ul.cloneNode())).toThrow(window.TypeError); + } + }); + + test('prepends child element', () => { + const root = ul.cloneNode() as HTMLUListElement; + prepend(liA.cloneNode(), root); + prepend(liB.cloneNode(), root); + prepend(liC.cloneNode(), root); + expect(root.outerHTML).toBe( + '
', + ); + }); +}); + +describe('clone', () => { + test('is a function', () => { + expect(clone).toBeInstanceOf(Function); + }); + + test('expects 1 parameter', () => { + expect(clone).toHaveLength(1); + }); + + test('throws without parameters', () => { + // @ts-expect-error - intentional invalid parameters + expect(() => clone()).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + expect(() => clone(null)).toThrow(window.TypeError); + // @ts-expect-error - intentional invalid parameters + // eslint-disable-next-line unicorn/no-useless-undefined + expect(() => clone(undefined)).toThrow(window.TypeError); + }); + + const inputs = [ + document.createElement('div'), + document.createElement('span'), + document.createElement('p'), + document.createElement('a'), + document.createElement('button'), + document.createElement('input'), + document.createElement('textarea'), + document.createElement('select'), + ] as const; + + for (const input of inputs) { + test(`returns cloned ${input.tagName} element`, () => { + const result = clone(input); + expect(result).not.toBe(input); + expect(result.tagName).toBe(input.tagName); + }); + } +}); + +describe('onRemove', () => { + test('is a function', () => { + expect(onRemove).toBeInstanceOf(Function); + }); + + test('expects 2 parameters', () => { + expect(onRemove).toHaveLength(2); + }); + + // TODO: Don't skip these tests. Currently happy-dom doesn't support the 2nd + // parameter in MutationObserver callbacks. Open an issue! + + test.skip('calls callback when watched element is removed', () => { + const spy = mock(() => {}); + const root = document.createElement('div'); + document.body.appendChild(root); + onRemove(root, spy); + root.remove(); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test.skip('calls callback when parent parent element is removed', () => { + const spy = mock(() => {}); + const root = document.createElement('div'); + const parent = document.createElement('div'); + const child = document.createElement('div'); + parent.appendChild(child); + root.appendChild(parent); + document.body.appendChild(root); + onRemove(child, spy); + root.remove(); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test.skip('does not call callback when nested child element is removed', () => { + const spy = mock(() => {}); + const root = document.createElement('div'); + const child = document.createElement('div'); + root.appendChild(child); + document.body.appendChild(root); + onRemove(root, spy); + child.remove(); + expect(spy).not.toHaveBeenCalled(); + }); + + test.skip('does not call callback when element is added or moved', () => { + const spy = mock(() => {}); + const root = document.createElement('div'); + const child = document.createElement('div'); + document.body.appendChild(root); + onRemove(root, spy); + root.appendChild(child); + document.body.appendChild(root); + expect(spy).not.toHaveBeenCalled(); + }); +}); diff --git a/test/utils.ts b/test/unit/utils.ts similarity index 55% rename from test/utils.ts rename to test/unit/utils.ts index f0c3f16..204cabe 100644 --- a/test/utils.ts +++ b/test/unit/utils.ts @@ -1,34 +1,4 @@ -import { JSDOM } from 'jsdom'; -import { suite, type Context, type Test } from 'uvu'; - -// increase limit from 10 -global.Error.stackTraceLimit = 100; - -const mountedContainers = new Set(); - -export function describe( - name: string, - fn: (test: Test) => void, -): void { - const test = suite(name); - fn(test); - test.run(); -} - -export function setupDOM(): void { - const dom = new JSDOM('', { - pretendToBeVisual: true, - runScripts: 'dangerously', - url: 'http://localhost/', - }); - - global.window = dom.window.document.defaultView!; - global.document = global.window.document; -} - -export function setupMocks(): void { - global.DocumentFragment = global.window.DocumentFragment; -} +import { expect, spyOn, type Mock } from 'bun:test'; export interface RenderResult { /** A wrapper DIV which contains your mounted component. */ @@ -40,10 +10,12 @@ export interface RenderResult { * * @param el - An element to inspect. Default is the mounted container. */ - debug(el?: Element): void; + debug(el?: Element): Promise; unmount(): void; } +const mountedContainers = new Set(); + export function render(component: Node): RenderResult { const container = document.createElement('div'); @@ -54,18 +26,20 @@ export function render(component: Node): RenderResult { return { container, - debug(el = container) { - /* prettier-ignore */ // eslint-disable-next-line - console.log('DEBUG:\n' + require('prettier').format(el.innerHTML, { parser: 'html' })); + async debug(el = container) { + const { format } = await import('prettier'); + // eslint-disable-next-line no-console + console.log(`DEBUG:\n${await format(el.innerHTML, { parser: 'html' })}`); }, unmount() { + // eslint-disable-next-line unicorn/prefer-dom-node-remove container.removeChild(component); }, }; } export function cleanup(): void { - if (!mountedContainers || mountedContainers.size === 0) { + if (mountedContainers.size === 0) { throw new Error( 'No mounted components exist, did you forget to call render()?', ); @@ -79,3 +53,22 @@ export function cleanup(): void { mountedContainers.delete(container); }); } + +const consoleMethods = Object.getOwnPropertyNames( + window.console, +) as (keyof Console)[]; + +export function consoleSpy(): () => void { + const spies: Mock<() => void>[] = []; + + for (const method of consoleMethods) { + spies.push(spyOn(window.console, method)); + } + + return () => { + for (const spy of spies) { + expect(spy).toHaveBeenCalledTimes(0); + spy.mockRestore(); + } + }; +} diff --git a/test/utils.test.ts b/test/utils.test.ts deleted file mode 100644 index bf936ad..0000000 --- a/test/utils.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import * as assert from 'uvu/assert'; -import { append, create, createFragment, noop, prepend } from '../src/utils'; -import { describe } from './utils'; - -const ul = document.createElement('ul'); -const liA = document.createElement('li'); -liA.className = 'a'; -const liB = document.createElement('li'); -liB.className = 'b'; -const liC = document.createElement('li'); -liC.className = 'c'; - -class Sample {} - -const NOT_DOM_NODES = [ - null, - undefined, - '', - 'div', - '
', - '
', - 0, - 1, - -1, - 1n, - -1n, - Number.MAX_VALUE, - Number.MIN_VALUE, - Number.POSITIVE_INFINITY, - Number.NEGATIVE_INFINITY, - Number.NaN, - true, - false, - {}, - [], - [liA.cloneNode()], - () => {}, - () => liA.cloneNode(), - function div() {}, - Sample, - new Sample(), - Symbol('test'), - new Map(), - new Set(), - new Int8Array(1), - new Uint8Array(1), -] as const; - -describe('noop', (test) => { - test('is a function', () => { - assert.type(noop, 'function'); - }); - - test('expects no parameters', () => { - assert.is(noop.length, 0); - }); - - test('returns undefined', () => { - assert.is(noop(), undefined); - }); - - test('is an empty function', () => { - assert.fixture(noop.toString(), '() => {\n}'); - }); -}); - -describe('createFragment', (test) => { - test('is a function', () => { - assert.type(createFragment, 'function'); - }); - - test('expects no parameters', () => { - assert.is(createFragment.length, 0); - }); - - test('returns a DocumentFragment', () => { - assert.instance(createFragment(), DocumentFragment); - }); -}); - -describe('create', (test) => { - test('is a function', () => { - assert.type(create, 'function'); - }); - - test('expects 1 parameter', () => { - assert.is(create.length, 1); - }); - - test('returns expected element', () => { - // @ts-expect-error - intentional invalid element name - assert.instance(create('x'), window.HTMLUnknownElement); - assert.instance(create('div'), window.HTMLDivElement); - assert.instance(create('span'), window.HTMLSpanElement); - assert.instance(create('a'), window.HTMLAnchorElement); - assert.instance(create('img'), window.HTMLImageElement); - assert.instance(create('h1'), window.HTMLHeadingElement); - assert.instance(create('h2'), window.HTMLHeadingElement); - assert.instance(create('h3'), window.HTMLHeadingElement); - assert.instance(create('h4'), window.HTMLHeadingElement); - assert.instance(create('h5'), window.HTMLHeadingElement); - assert.instance(create('h6'), window.HTMLHeadingElement); - assert.instance(create('p'), window.HTMLParagraphElement); - assert.instance(create('input'), window.HTMLInputElement); - assert.instance(create('textarea'), window.HTMLTextAreaElement); - assert.instance(create('button'), window.HTMLButtonElement); - assert.instance(create('select'), window.HTMLSelectElement); - assert.instance(create('option'), window.HTMLOptionElement); - assert.instance(create('optgroup'), window.HTMLOptGroupElement); - assert.instance(create('form'), window.HTMLFormElement); - assert.instance(create('fieldset'), window.HTMLFieldSetElement); - assert.instance(create('legend'), window.HTMLLegendElement); - assert.instance(create('label'), window.HTMLLabelElement); - assert.instance(create('ul'), window.HTMLUListElement); - assert.instance(create('ol'), window.HTMLOListElement); - assert.instance(create('li'), window.HTMLLIElement); - assert.instance(create('dl'), window.HTMLDListElement); - assert.instance(create('dt'), window.HTMLElement); - assert.instance(create('dd'), window.HTMLElement); - assert.instance(create('table'), window.HTMLTableElement); - assert.instance(create('caption'), window.HTMLTableCaptionElement); - assert.instance(create('thead'), window.HTMLTableSectionElement); - assert.instance(create('tbody'), window.HTMLTableSectionElement); - assert.instance(create('tfoot'), window.HTMLTableSectionElement); - assert.instance(create('colgroup'), window.HTMLTableColElement); - assert.instance(create('col'), window.HTMLTableColElement); - assert.instance(create('tr'), window.HTMLTableRowElement); - assert.instance(create('td'), window.HTMLTableCellElement); - assert.instance(create('th'), window.HTMLTableCellElement); - assert.instance(create('hr'), window.HTMLHRElement); - assert.instance(create('br'), window.HTMLBRElement); - assert.instance(create('pre'), window.HTMLPreElement); - assert.instance(create('blockquote'), window.HTMLQuoteElement); - assert.instance(create('q'), window.HTMLQuoteElement); - assert.instance(create('ins'), window.HTMLModElement); - assert.instance(create('del'), window.HTMLModElement); - assert.instance(create('iframe'), window.HTMLIFrameElement); - assert.instance(create('embed'), window.HTMLEmbedElement); - assert.instance(create('object'), window.HTMLObjectElement); - assert.instance(create('video'), window.HTMLVideoElement); - assert.instance(create('audio'), window.HTMLAudioElement); - assert.instance(create('source'), window.HTMLSourceElement); - assert.instance(create('track'), window.HTMLTrackElement); - assert.instance(create('canvas'), window.HTMLCanvasElement); - assert.instance(create('map'), window.HTMLMapElement); - assert.instance(create('area'), window.HTMLAreaElement); - assert.instance(create('time'), window.HTMLTimeElement); - }); -}); - -describe('append', (test) => { - test('is a function', () => { - assert.type(append, 'function'); - }); - - test('expects 2 parameters', () => { - assert.is(append.length, 2); - }); - - test('throws without parameters', () => { - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append()); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(null)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(undefined)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(null, null)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(undefined, undefined)); - }); - - test('throws when parameters are not an element', () => { - for (const input of NOT_DOM_NODES) { - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(ul.cloneNode(), input)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => append(input, ul.cloneNode())); - } - }); - - test('appends child element', () => { - const root = ul.cloneNode() as HTMLUListElement; - append(liA.cloneNode(), root); - append(liB.cloneNode(), root); - append(liC.cloneNode(), root); - assert.snapshot( - root.outerHTML, - '
', - ); - }); -}); - -describe('prepend', (test) => { - test('is a function', () => { - assert.type(prepend, 'function'); - }); - - test('expects 2 parameters', () => { - assert.is(prepend.length, 2); - }); - - test('throws without parameters', () => { - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend()); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(null)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(undefined)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(null, null)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(undefined, undefined)); - }); - - test('throws when parameters are not an element', () => { - for (const input of NOT_DOM_NODES) { - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(ul.cloneNode(), input)); - // @ts-expect-error - intentional invalid parameters - assert.throws(() => prepend(input, ul.cloneNode())); - } - }); - - test('prepends child element', () => { - const root = ul.cloneNode() as HTMLUListElement; - prepend(liA.cloneNode(), root); - prepend(liB.cloneNode(), root); - prepend(liC.cloneNode(), root); - assert.snapshot( - root.outerHTML, - '
', - ); - }); -}); From 3d88304bb6620a9552a0acc4586ecdfad8b7c2f5 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:56:08 +1000 Subject: [PATCH 017/169] test: Add initial files for e2e tests --- playwright.config.ts | 5 +++++ test/e2e/browser.spec.ts | 2 ++ test/e2e/index.spec.ts | 5 +++++ test/e2e/runtime.spec.ts | 2 ++ 4 files changed, 14 insertions(+) create mode 100644 playwright.config.ts create mode 100644 test/e2e/browser.spec.ts create mode 100644 test/e2e/index.spec.ts create mode 100644 test/e2e/runtime.spec.ts diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..83c3cf2 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testMatch: 'test/e2e/**/*.spec.ts', +}); diff --git a/test/e2e/browser.spec.ts b/test/e2e/browser.spec.ts new file mode 100644 index 0000000..155ed00 --- /dev/null +++ b/test/e2e/browser.spec.ts @@ -0,0 +1,2 @@ +// FIXME:! +export {}; diff --git a/test/e2e/index.spec.ts b/test/e2e/index.spec.ts new file mode 100644 index 0000000..7d8e2c3 --- /dev/null +++ b/test/e2e/index.spec.ts @@ -0,0 +1,5 @@ +import { expect, test } from '@playwright/test'; + +test('placeholder', () => { + expect(1 + 2).toBe(3); +}); diff --git a/test/e2e/runtime.spec.ts b/test/e2e/runtime.spec.ts new file mode 100644 index 0000000..155ed00 --- /dev/null +++ b/test/e2e/runtime.spec.ts @@ -0,0 +1,2 @@ +// FIXME:! +export {}; From 6065d49bbebbc2b3af2bae51e21ece2d0df04932 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:56:22 +1000 Subject: [PATCH 018/169] chore: Update readme --- README.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3b5b955..3cda5da 100644 --- a/README.md +++ b/README.md @@ -25,24 +25,25 @@ Originally a fork of the excellent project. - `create` - `append` - `prepend` - - `onNodeRemove` + - `onRemove` - New reactive store feature - Differences from the original `stage0` project: - - `h` is now `function h(template: string): S1Node` e.g., `h('

#text

')` - - `html` is available to use as a string template literal tag function e.g., `` html`

#text

` `` - - Import paths - - Other than reconcilers, everything is a named export from `stage1` - - Reconcilers all export a `reconcile` function - - `/keyed` --> `/reconcile/keyed` - - `/reconcile` --> `/reconcile/non-keyed` - - `/reuse-nodes` --> `/reconcile/reuse-nodes` + - There are now 2 runtime modes: + - New pre-compiled runtime mode for ultimate performance. Compiles templates at build-time via a bun macro that minifies templates, generates metadata, and then includes minimal runtime code in your JS bundle. Currently only works with [Bun.build](https://bun.sh/docs/bundler). + - The regular mode is still availiable which generates metadata when your JS is run in the browser. Regular mode can be used with or without a build process. + - `h` is now `function h(template: string): S1Node` e.g., `h('

:key

')` + - `html` is available to use as a string template literal tag function e.g., `` html`

:key

` `` (regular mode only) + - `view.collect` is now a `collect` function that needs to be imported seperately - Extra DOM utils - New reactive `store` factory can be imported from `stage1/store` - Improved TypeScript support - Reduced size and improved load and runtime performance - - `process.env.NODE_ENV` must be defined - - If `process.env.NODE_ENV === 'production` you must minify `h`/`html` strings with a compatible minifier - - Add full example with `esbuild` + `esbuild-minify-templates` + - Import paths: + - Other than reconcilers and the store, everything is a named export from `stage1` + - Reconcilers all export a `reconcile` function + - `/keyed` --> `/reconcile/keyed` + - `/reconcile` --> `/reconcile/non-keyed` + - `/reuse-nodes` --> `/reconcile/reuse-nodes` - Ref names must be lowercase because some browsers normalise element attribute names when rendering HTML - Add API and usage documentation - Add more tests @@ -64,13 +65,13 @@ Minimum browser version required: Some optional features require a higher browser version: -- Compiler `html` tagged template literal function uses `String.raw`; [requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw#browser_compatibility) +- `html` tagged template literal function uses `String.raw`; [requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw#browser_compatibility) - `createFragment` utility function uses `DocumentFragment`; [requirements](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment/DocumentFragment#browser_compatibility) -- `onNodeRemove` utility function uses `for...of`; [requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#browser_compatibility) +- `onRemove` utility function uses `for...of` and `MutationObserver`; [requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#browser_compatibility), [requirements](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/) - `store` uses `Proxy`; [requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy#browser_compatibility) - Also uses [logical nullish assignment](<(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment#browser_compatibility)>) and [optional chaining operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#browser_compatibility), however, build tools can transform these for old browser targets -SSR via Node.js or Deno is not supported and is not the intended use of this library. +SSR (server-side rendering) is not supported and is not the intended use of this library. ## Bugs From 732e60ec45fe6b48343718686b8250e0174241dd Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 01:58:46 +1000 Subject: [PATCH 019/169] chore: Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3cda5da..844b9cb 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Originally a fork of the excellent project. - There are now 2 runtime modes: - New pre-compiled runtime mode for ultimate performance. Compiles templates at build-time via a bun macro that minifies templates, generates metadata, and then includes minimal runtime code in your JS bundle. Currently only works with [Bun.build](https://bun.sh/docs/bundler). - The regular mode is still availiable which generates metadata when your JS is run in the browser. Regular mode can be used with or without a build process. + - Ref nodes are now marked with `@` rather than `#` - `h` is now `function h(template: string): S1Node` e.g., `h('

:key

')` - `html` is available to use as a string template literal tag function e.g., `` html`

:key

` `` (regular mode only) - `view.collect` is now a `collect` function that needs to be imported seperately From 18d46edf830cdc38833961ea8533a5d98601a85e Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 02:01:54 +1000 Subject: [PATCH 020/169] chore: Update dependencies --- README.md | 4 ++-- bun.lockb | Bin 119686 -> 119622 bytes package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 844b9cb..311b66a 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ Originally a fork of the excellent project. - New pre-compiled runtime mode for ultimate performance. Compiles templates at build-time via a bun macro that minifies templates, generates metadata, and then includes minimal runtime code in your JS bundle. Currently only works with [Bun.build](https://bun.sh/docs/bundler). - The regular mode is still availiable which generates metadata when your JS is run in the browser. Regular mode can be used with or without a build process. - Ref nodes are now marked with `@` rather than `#` - - `h` is now `function h(template: string): S1Node` e.g., `h('

:key

')` - - `html` is available to use as a string template literal tag function e.g., `` html`

:key

` `` (regular mode only) + - `h` is now `function h(template: string): S1Node` e.g., `h('

@key

')` + - `html` is available to use as a string template literal tag function e.g., `` html`

@key

` `` (regular mode only) - `view.collect` is now a `collect` function that needs to be imported seperately - Extra DOM utils - New reactive `store` factory can be imported from `stage1/store` diff --git a/bun.lockb b/bun.lockb index 60f8ae099373940e74db7edbe3d15816bae728e7..5a0453bf116c6687a7f257a601fe1dc1953b21f8 100755 GIT binary patch delta 29255 zcmeHw2UrzH_x{dR6ws@nA|NQB5=8|O5wW0PtgNVL6uTl^1VuoKg6(1~Q52(2bS$y= z8e7EPD{3sMrWiGeEy^XC0=A1KUW@oSW?oM4- z_SD+4vxEHVmK$eXy*{zds0YDe{+G(F*!@6S9KjoGALv@m{oXH~{ddplI>&0sN=-@2 zmZTTTNRqQ8<&W2>Q(2YI()c~#T~MBC8I>mC*s7J!(C9o+Pn0KGEE$0*SyCeERRrG; z)CqJC{t)ktPN<&>_)|fWtodD`P#%JMp#Gr4vI6tsN2E&enL{(;GqWt-kV7#)B`a`f zYWfhV3zVq=SIEned}vyFrbUt*!Ba=16rY+U<(gIgX9ra;DJ3m2FegK5fySs_utHl( z`5A$!=?U@KFgrD6L`t?43^PgLb5tackAkNTGgC%n#wSUVVg({F%7wRad}hdS=#Y9+ zYJ7IKB~iMDYUHRTDiwOI|{9 zeClwN4|P|=mmHrJ2os0)2T$!Z^icIDfRcCd!$v_{l5#Rr0*7TuQbtZ%UP5}J#f(9P zCD#0}pjZuxvtbB@B`H2Ddn77kT5_^dlJcZn6p}xkyj1(=fl?frfs%eE>eT>^1BJ*) zjEmlqgn#)lkdq-1TKnHsSKIp(w7k?-%3p)p6qp5|@ScmxKYjL;!Ch*}fw-v z2PnmF6)43s7?j-8-O99NrKgUvNCEXF2@%Qn0i`&)g3`Rfz|*)&0~%1+yrukk=ztmu z&^**9MsNk*-PFoArlDFq8Fo>ab3v)Ugp|OPw4`*2Uov@E9UH09m1meilo1wb z1ZHMJU{YEdp{4oV&DM>)~t zaMhq+8}fJqtkQ2f91oAkfECTvj&Fk!KO{3g!GaMO*g}=B2Bl&77L>|ISTcuN5EXry z+8QiLn4m8s8j*()Jm;47u3m06;sj>l&tJwS?Os_pfnW)G){V6{DcO`)5?*m zhtIW96E`zTZD<>K8Uk1F6oH}X8Hs2{Iu3oR=Lk6&m_+FxpO74`={;Z7j zV-3o`7bRJhlQ&U7GvpK~d4lB2v<$W6ZUaw-{TQu=ZWVa)r~s5gpASm8(L>XF7L*JO z0Ht=kK}o-Tj2h8f=$P~`fl|AhBe4LJrAr{73WvI=4bK2io(upbOYdR`DEkvFLvn^n zk~9K&K*wv4(-N4No{*iHl4dCaPwjP%RrObar!k)w!S9u+;k>zr+C1;UyE{#F)-Moe zD)F06OI`Lpmp}Fum-XNGyn3U4B_DYVzvR-5`?~mYU)Q=GqbDcb3hJ8E#Cge$cPE$q zsBy!JjzfIr?7YV_T!Z*c{B0EA{5S6~g(EO2Lj@w_G0m`P-gNcsEyHmmAaG z%ii9l*fHxs&rMrR74PrNcTQ&f%W~aZV!zqdZ2if1L!(NS`)Sx`TPyI4@<;e!b25L& z+;L~`3TGIPbg9cTTsrdaE1hk(E~Rv0Pc>Hb*ZIHj$eVgdIdXa9_(@C z&T>=TKocf(n9^8mYolH`gcMcA?HZc^A(lo8wVTn{X(#U7)@bY*Og7aBJ8y?T*j8<< zmQio5GcT5#me)+W1(i&0b`RBUOe)8V{fuT`#$rP`V6uM&(7g15aPOn5s9s4G*$*n2|27pL2oS5%!|7;)wzjg?%dUA z`T#0W(`ESOT1G2BKu9JzP>$(QZ;#cCG)vnHCu_no_QGQjlJ6y|{{SJi3EyoQ&;kpZ z>X@A{4?;>HCI9qrpM$U^kEs!=3(8^<4doYVh3fXTfPhl0EO%`ZtZPk$up^C~=GJ%Yl&QE7n@u^0*g5s$OCq+=oz|9Co2;>7n+ntO0sPPJ@uV|Rep+b_qaZz<8 z={bZFli4=Nm+JE98isMP0g}`mD(J)(?PCGFxQ5Y5xq95$$5x@9kvO*5wYVNH@G&a9 zTaOppDs-$5tI&gTwb8R;YkeN=YgD*bpBLD;h7EYJuhHMI2I_)@3yX&_M4KD%Xg{O+ zg9g07#>E8M?`b9lszFq)>-sD@3Sl_E;AdQzA3_jjzgRU4GL~!GDjE+VjWw=1ws0;E z;svz~Q!WSb;#!97r5a*mtp?Y2Md}YBE&3%U`$`DgKv-gd{un}97D_~}b}%onP2;}7 z>If_D>A}4Mm1hhiDmT(yx$J4Ib?qR;>g;Xg@oWg_Qmyo*FIMLvLex+%axV#18VonQI31JR|6sQt0c?Uvc-spC^z#cS9 zONQ<0xBx5K+R zv&5x68bXRv2{$K0s13bsPkahO8jce8Gp45MZB&Wsi4YnKkRFhw5K^1UJ(8XlpEl(M zK}K5CgL7&mkj#3$(GXI|OYDLVLP*iY`elpm7Z6f(OZXSjObsNe+cqRw5JDN6c2}rP z5K?%sEwkOPeF~wLL^h#6B;-no>O&zU%@T8H6C@Nf+?3cZ>R*y3FRW%v^?LYNsl*;U z83L-NTyOM1?0}GVQ6+92e}RyCRc>Q-&1R@e(*a3t+q8~=kb+wx5St+ErE1zD?u<_| zs7)+yKF0FaHiA2c8EZ;ZD;^zYjN4+gOBIwP&=<5fA;f~#*qF}l*xk^WDR&2Y0(5H4 zqnjEHO@ay;j;y!kT@i#7ZJ1-bAl8WF&f$hRmNq;(+_>f(hITt16K?ce`dKxFlu57K z7Y$)6e!k}TsS^cqYN)`+q4wI?!Ok+f|}Z%-M!QR67m?EBLaesB+&EWLkMWihyS)Y z5YWM{EnPDKLQ0YnrmTRlvm!*Vy5{E)8kwVy=Cd7nL4@J`GAy53x3*RJE`(|ib~Cq5 zCrRq98d%kcla+*YkEjRkZ3w#anC6CG0cahrkzclpUwSl;Zf)4G4l2(nD%fu54ONt} z?dRquMni)jppnMrw6&4(D`XxWX*6^TDl{caM5ZRfqPA{#TQv$ox^Q51unqbl2;0+b zwr)e|7<6f$1>GS~udH@sI~T&1l%#stUxPsH(Qb*XiB(Sv;&< z+V|?xRUO+BpRe?X&=?NA=UotLtE=r(CKK+SXinqWWxGQUg|LAVfH~ETXb$ei3)&gc zJOq{BEWqDFsJUUA{exm3bHUyMA(Uz0ZJIwrNb4gOVB1}}j5$Q{!v4r+^)d*DLg;G0 z{D=3Dq<#=qw7UemQ&FZ$qdKgI!j5#;Gw@w$b`1_JxpEkP=&nmms7$ zS>k$j1wvR<(#ASSi{A)8gHRm}yN?W8_R%N5-J&rS!r%CP4?=YVW49vI>#JWl?LG)d zf)Lj`x-1$W2)7?(#Q!#mk)*1{+VGsR6$^~6nsd0Z(&Kv(!Vdhxpiq4{2QO{pFDY{Z ze^pAKP-EID2hlPBhEzF-n)s3-O|2%J!4u{9JxZ;?Q01_vB!@A|@q3i?`fGYbiAUOW zm&kxYS^-fi7_8BFjSc~&gD90J094PS@kyZMUMe8*hy-^los0lTE1eh|zelOn3`I+& zrEs35@kFUSTjPmRyQ2V-j|S)8#g` zlroi;#`y~X$){=Z$5Aq-K+~I{=@BJ)p(dZD$sb3_**OSYk3>&bC!8Uf<%RL~*}bB-vBy`!GOJIjYg)pmf+%DnF@6RZ4xH(Rh1G zHk<{B7Hj38O6u7Qln&2piWfBcnno{b6@QOX2bVNGdrI=lnw+Qu@Rl@O_3$07fGACk zYZ_0KB5@O-20jAlAWHnl#Ne=}q<=?|s+7{H@hBD21gKqx9f0N$QeQTT>%S1$97cfztm8(kOHTC9`^h;-A!u{%Dj=lCC|A&13?wIQ~wqnXfr0vx@xw!8krG&&+!sl9?-CaVU<5k1=zH!!oPP zV-LsiJK$ag=f>HQIKE)4nOly?%$;us*KwSgyX}^lCy(D9$G-=65}X%zEsEpo$D{11 z%&PPFqj9|V1eAgE;jYKxxTDp~bB@W(k4L>6$M=9+^Rmop@uMh9&NuTZCuHW&FQ16x z9{7$`lan&5!zZ4M<7dEq0xp0zIu*xrpEvU@FUYJupAN3>Bs2f~l*|Hov(xYo+>+BW zYsl|{n>N|ZW6sE|5np%){!KCSpTRZeozB8Pa9hsGtOWPTJ}-C1VtFJupbgJ76O&%ch zS0Y~X%>0`xvMFBTZC*#bz^-{+HYG^>0odgENb)yilSSey-+-e6Ie{54lzSdWW`P@j zTxKc!EV$eS@a2ST8ZPl4pjvmKnZG$xW+Qk&E*u3{m@Bh%eihubMerm~W+VCZJfzlQ zI07z)`lU$1 z@iH6FH;jjm%aDWou37ly9y3IFS8ju?|BU5YK#@QLLM*){(&o;B(oR!RdCbRz`w~d zo5QD1hJS0}A2`mNO@V*lmQ0b^JboA4f_3n3s>}pmI2Hb_hkxJ}@=hc zPJ@3Nu%v)n!r65Aw-HOqbeS#V+rc?*!m?2yvlTqP0RDkH32qg4#UxAKjD*8Dtl=YP z!oMw8C<orz`yNCnK?4s$?t=^1Fq*>nZ3$a%!PkD-~*Rg5s&5YZzp^Jx0kb* z;2${4OETNfw}V^13qD}d9OUuy;NPpr9!!(N+;0K=+YPH1$m}S;3~mp&CJSYDoKIW` z|B7HWxRbomBKWrlRxgs-X?_FT8F1|u%j_(lvl#yEh1KBB@%van>+XY{OJsI|uUG>A zz&R|H*+m|^6#ngpo!~BWwhaCqfSt=^_B!7V?hd%|D`oa3Ka1J3;2?5hmCWAed8^>x zA>;(Ot2|&e`~z3GT4wL@tKiljMoz4e*#~_38u)hvIRWlN-fS)WJBplGE3+H?F1S75 zV%Ev*BffAQ{5yu60QU*+v>yH)N6xR8*=_z1+!=5KHpuKQ->?Dxoj}fSl-Z}e&qnxn z5;+g1_&Z=P6v?KFj91%(_4G1)*&~}=87~GKeg$c? zS2k5<{K{Uer(m1xlTB`nKfe#_>FY=&udJgbbgw zDc+S3{tsow?>L`m;nOw7D*YWDQ>ce&zyIuAPW{yj<;;JV;TKtdOz|n{S^tvNf1fed zKNqgYcTC~ef8{zPB`t`42TD=>12W|QA5(lvdRFzfxqs5?zt0$}7A^{*{!8A^E2}?r zqsTmMne~r$LI!^5rv9MqE~vgN{~u*m=it~>$Z)lDZj|2HQ?`R5dV9X|0mkB{!<-m{UZKPBdmWo3N-$IB3!?T zmVIK*sb|X>{nz~$A)|bvJ{~8tK2G>Qlv$YqyeLs78)v*FLg`u`7R zzhp-L%HHfB3ja3jKh&pO{T)%D1*rfxDplcBRCn9L^*b`_A60xxdfMlIzhmK3>R282 z0*wEk3D@6ljP(zW)1U5`av`jrngjN`t6#}HB~qLQMSLBy#5Qc_^>3!N=zbgj13-s6 zD4muD>XQJ6hbE)%K~};!eFc)fl}~!~Wy~scf}@%yqc3c_F|n@^>k{w~GWy=6uU1wb z=k#q-s^_Q4urx~RMWYZ_Ibsb?u~ETSgw^KhyPInPI_Ues_(vaPNFUG%4u4JNit}PI zk($_`6sTV#CM|r(C*9Cwbv5-W;OX1tR4qW0;j=brySPkE=-;fauNAqY=yQOM2Aa$R z=Q{za76=(R=?Q!%{2HT)S8+-zO*C~coEK@bFiqwS{t-acnrbpUv_aY{MmA=nE74a@ zO9Ku7eUJ4MCLT0qLDus)zW~&MY5;&cPi3eYfCd6VKtmuH2mu-c^nHLPKp4;z2nU)0 z&4CsGe(omWr=U_K5CyaWo(0+h?SS?`2cQ!bMdL&U=v%$VffIo89dA(jode~A8&DOX ze4@PY0;&V_o%<`|ekki|{Tl2yKrTcpfVXfiKo!{S zU_Y=MI18Oqz-fTK$4>c7`CAj9@4LSR`P;xnfD(2&K&i13pf4@I4^Yy62wVpilN&Fi za0W0Fpq23jU?PwYj0eU6^np|&FbIePdIR)D^Ev>fb3K6al=3nNXb1!YjR8tNN;XQa zaG)7L|JBzLh@kI&w*sPoHo&t$Tc91#9_Rpc1Udo9znhM+6~NCZ9x{|RslxD9*+90ra6+ktI>GxX9xF~hCWS2+0^xC`6^J_SAlXsZ7Q z_yYJ6cnvrK90hg(^!>$eK<@+Paefk@b+Izw4bYl58)ft@`i;PP;1c*Xz&c`l$8gv}* zh$Z2yv0HhZ(ppY)lIAAm>{{^&imWuxQUNlN%%k;S6|e$W4lDzf0;7N|faY8#kPeIh zsA;NC<6;34fp}mrKy#1gT^FDu&>m<9v<2D#t!XS;;e;2FRls14Kt z`~Y8|22dTS1b71;fIHvHySP zeV`uD00;zvfMB2*&m z0~1MQDo&;VlYq&<3&1o$0CRxZzzpC;U?wmNDAdl0z65Y!E-(+64=e&`*cJmX151FF z0QK_*unzbIM|m=lPBuWW9_R?118D3w0UH65ZwIykTY=5M7T^`&7;p&K3G4u<{z2dX zupih5>;ZNIuL8S(B496Y1UO6~Itm;IP5^oX#W+6;Py=UxQvfw^5;zS|o(ux|0IvgA zfb+m>zy;tUa0$2!kTY)rbY-S1G_6>4<)SOL)dhdd0ELc1=?72_d;n1R-v{0XX#C#; z-UY4#?`ZT6=r_PMfR@C&pd_QElGblp$3F&77mG5$M>waxz5_m?@xO_a(kLhe+{U>H z^hZzz`Z?%zfR?ylK)wYY0Y3ph01tuhfvtLB8BZEjrW#rX;fOJ0vz68Di{sWMqp8-@x?GZ?yDAl2JGUPg7Z@?$$UlEdm z9!3fcd8&7+%k6dOoXROubgp+ux<6|&IwymuEz;3J^{xX%t@H4Qu0DE$6lSWZ^F)cK z@uh|-B6KY!Z>dvigxb&zpkbusqHQ5j$|=gD7Jz+Qbjd`$fxi*jD^cSVT1q~;e$iB= zgLtB}zodMidlE`iU2e1??zd)@t?jj<8c=JEbE32*CAlA{A80z@i*st$AG8)gD?x35 zCRa`HwE?~EaLAqkPrEMKiRtYH;M`xU=MGwzVL7#LoNP=5Xv;>o57Y=XN_$J%&XF$Z zJPXj)j^xw<8A}FI8Ex@GfJT606#n2?E$&9L)vQU;tSFXSDolUow*J6Z6B`&B6cQ8+ zFC3K1K)(J+SfwPCN+KLYnuU3U=@0y_>d>cpm+F(wnpk*HsG^}iB0Qo?Mqc$P$6BIp za8RR0L5+el9mE0DHO+PqZ&_Gp({cwW|m2 zUh_t+BThBXISVgd1c%8K*g zz4b@&?>uXr+h*uyf3(mDgMqfUmYqNBcNO+HiR)?1BSd>De|}u-8!-bOoV}qmp~O*t zZvWZBaTVN6Z|0g9#AsUt4`bfm`a}8k=M1ABI;O63&En-@FfzD;xC9$aEh>n6!!Tm{ zQ}!FKYjxz-lp*64cN@`&9jz$3564IicMFdub zM)fA>Fjy>4W!|PXmBpb{bcR8HCzaK6e!a5#Na>U+;#xN3XDW%v5eDrnj>WKQrb}+( zS`7MIRaG?Tg2MjpViqY4br_w_9Iynl$+8%hvb?`T%9 zwu`U&EbHN*&e(XRmfxTAO202*ZhS` z2Ux1VE1^rnV=Fz2k5_?aV|7A3X1yVAF$&0*fgNCn{(glaBWp)Qma7WWhxSlimG>#E-&(jWZ4_{++hj=#Uqtn{WV4Z#5-s3YvrUkT9smCgfh$3$go z8fa60IY8OgsRjFd4<(|6<{wIS1c+^@>;2@qnnsxZ!hlu7M&;x^>Q`NDgBsCaDKKf9 zSl;iiVP7nD?DK!CQ6S*B5g-u@|Wa>_xs+l15u?{D9^8AddPDy_PWgs+T&o!UsG$mB9oh{QS2P#NL~l12FH;Tur3w*W9ob&&(j*x*XvA^ZS=~Zhf`;ka z7UCXigz2wS7_%*Ea+j7XXoEltEUw-2B9y!Nd^e9J4XTx-0 z#d0FWKvL8yde4AnC8U0Z$ocoY#`fq9O^Q7Nu_RJ#hNkysXke$9Kd{U79(QBwQi@Rk zuwosL6xT`P5;Uqpqhjf$HwT4y=i7R_6)CFpgt=cviV6MEt7DWH*Avt=N_^Q{-Aj2# ziER*t1w^U;12AII0lzu%hmN5U%2&iW93?b6%U%6?Uhm!IMk>vRQ1qUS5|4T!+j>BQ z4Dgt8X5pdU8$QwuK;4umF}p8w^MP_Elqx`J_Zt{&t^qhS13mB{Y}6ACnq zc6n_U?LXR%)=`vG9xc#Js8!|Al4WmS{!Finp^g%-QQd8t3AL>41HSsqmsWhlh$i(Z zlvG5&V^?*Jj^BEoQjL}>l)M=wyyFnRd(gl=ZGJ}NxJ^f_Eh=alNF-Am(G415`Wr4L zu0CGr-O`1$uhrVn-+|#!DSOZI#qAeqCD>E6Ya^CY>-y_EdT;Lkz%RA?8;XYFcgb7` z5jA>aGqbIYxI`)REK0Hdy?1P@3dJX8=_D!t> zx&E-7=-(Hn=x-b;)pK;gt@+;HY8r^9nn)hr`a4RNFLVy`**o(KO#}U^CV1!pG^jpB z^}s&C39>?&%pp$-J@$0J3cViHC)Gf1>%Es;AoL08{p7?}2hh#IuNl%(E|T|Jb2 zn;LuN&QUi=4bEett7uh@6p@25?e+K2WIo#T!&^6J>i1<&S`(F9i9=n)EYy8cqN1)o z2C5An;_Jb-X|E5A=M$D=+_t%R?Hvr z%zOW}qDfk0F*HwTPqWvgt?A;G1lB36Ob<1IP>nu3&QH49dPmQ|@K0QrJ4#$2(SKN_ zzwX9`)#)LE60!Z`Jw&%eglZMmU)m~$bskecXxSG*uq0Hy#Bc5)CMUACCbdS5(jiZ< zP25apyK&Q4v?zmlGZS`=dq%QdrrP+xA`?{oe4wENvPQenFUrVbHJAyXG0e_J1nq7w zzt3iOoW9Iq@CTpei@Q1OSrI&nMLG>0rOLJz<&9!a4x&L3Yr&d`U^9fd0EFZ(lii|?mLA-c^If$kw*d}wMpzNVzELoYB zgq+MQ5j&1~7nM87{8-WOmzZGU<%z69O=a*%FFq|R1)k@nTC%coGBVOLv$Fyd(o@qj z#fn_!B?g>g%f!9sS$hX%%OjdhV(p4@PP6$;R9M2wiGeS(t1kAT&B~6?7EPD1AH|@v ztfDwq#3~lmJ=3KI>IVymB02zOxXO0v9oVQ&GrL7RHK3E@Q8|s)I3o2P f-N70%(e*XxF5iW^-(&DfiQS7Z6mI9(NXP#NR=AI6 delta 29120 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 BxrhJ& diff --git a/package.json b/package.json index de41759..20aa18f 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@typescript-eslint/eslint-plugin": "6.0.0", "@typescript-eslint/parser": "6.0.0", "bun-types": "0.6.14", - "eslint": "8.44.0", + "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "8.8.0", From 12f3c4828a04016580254962c850b0ff2e47779a Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 15 Jul 2023 02:05:45 +1000 Subject: [PATCH 021/169] v0.8.0-next.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 20aa18f..1429b73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.7.2", + "version": "0.8.0-next.0", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From cdb28d69927882800c10b6343dc4ae9ace0bfd0e Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 18 Jul 2023 08:32:54 +1000 Subject: [PATCH 022/169] chore: Update dependencies --- bun.lockb | Bin 119622 -> 120486 bytes package.json | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lockb b/bun.lockb index 5a0453bf116c6687a7f257a601fe1dc1953b21f8..781e4eabe9154d0801c9d554b219391e7245b863 100755 GIT binary patch delta 33628 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 diff --git a/package.json b/package.json index 1429b73..120b575 100644 --- a/package.json +++ b/package.json @@ -54,9 +54,9 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.36.0", - "@typescript-eslint/eslint-plugin": "6.0.0", - "@typescript-eslint/parser": "6.0.0", + "@playwright/test": "1.36.1", + "@typescript-eslint/eslint-plugin": "6.1.0", + "@typescript-eslint/parser": "6.1.0", "bun-types": "0.6.14", "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", @@ -64,8 +64,8 @@ "eslint-config-prettier": "8.8.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-prettier": "5.0.0", - "eslint-plugin-unicorn": "47.0.0", - "happy-dom": "10.3.2", + "eslint-plugin-unicorn": "48.0.0", + "happy-dom": "10.5.1", "prettier": "3.0.0", "typescript": "5.1.6" } From 8990650a012ca22d17ee65bc575b3158efe09d1c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 18 Jul 2023 08:33:15 +1000 Subject: [PATCH 023/169] chore: Better doc comment --- src/runtime/macro.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index f05e4c4..fa09c81 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,6 +1,6 @@ /** - * Bun macro which compiles a template string into a format that can be used by - * the runtime. + * Bun macro which compiles a template string at build-time into a format that + * can be used by the runtime. * @param template - HTML template string. * @param keepComments - Whether to keep HTML comments in the output. */ From d4a060ee1bf4bf4bfafd6c2846d93a30dd0c7ba4 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 18 Jul 2023 11:02:32 +1000 Subject: [PATCH 024/169] feat: Rename internal node property for easier name mangling --- src/compile.ts | 8 ++++---- src/types.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compile.ts b/src/compile.ts index e0a844f..5c5f3fe 100644 --- a/src/compile.ts +++ b/src/compile.ts @@ -1,4 +1,4 @@ -import type { LowercaseKeys, Ref, Refs, S1View } from './types'; +import type { LowercaseKeys, RefInfo, Refs, S1View } from './types'; import { create } from './utils'; const compilerTemplate = create('template'); @@ -43,7 +43,7 @@ export const h = ( .replace(/ ( root: Node, view: S1View, ): LowercaseKeys => { - const len = view._refs.length; + const len = view.$$refs.length; const refs: Refs = {}; let index = 0; let metadata; @@ -85,7 +85,7 @@ export const collect = ( treeWalker.currentNode = root; for (; index < len; index++) { - metadata = view._refs[index]; + metadata = view.$$refs[index]; distance = metadata.d; while (distance--) treeWalker.nextNode(); refs[metadata.k] = treeWalker.currentNode; diff --git a/src/types.ts b/src/types.ts index 76d1ec1..6f74b55 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ /** @private */ -export interface Ref { +export interface RefInfo { /** Ref key name. */ readonly k: string; /** Distance from previous ref node or root. */ @@ -8,7 +8,7 @@ export interface Ref { export interface S1View extends Node, ChildNode { /** @private */ - _refs: readonly Ref[]; + $$refs: readonly RefInfo[]; } export type Refs = Record; From 1a8f6216f106d3d9c7f28d2e3b6be936dd8948a9 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 18 Jul 2023 11:03:09 +1000 Subject: [PATCH 025/169] feat: Improve collect performance --- src/compile.ts | 7 ++++--- src/runtime/macro.ts | 2 +- src/runtime/runtime.ts | 17 ++++------------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/compile.ts b/src/compile.ts index 5c5f3fe..f50bd36 100644 --- a/src/compile.ts +++ b/src/compile.ts @@ -77,18 +77,19 @@ export const collect = ( root: Node, view: S1View, ): LowercaseKeys => { + const walker = treeWalker; const len = view.$$refs.length; const refs: Refs = {}; let index = 0; let metadata; let distance; - treeWalker.currentNode = root; + walker.currentNode = root; for (; index < len; index++) { metadata = view.$$refs[index]; distance = metadata.d; - while (distance--) treeWalker.nextNode(); - refs[metadata.k] = treeWalker.currentNode; + while (distance--) walker.nextNode(); + refs[metadata.k] = walker.currentNode; } return refs as LowercaseKeys; diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index fa09c81..f15383c 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -7,7 +7,7 @@ export async function compile( template: string, keepComments?: boolean, - // @ts-expect-error - Bun macros always return synchronous output. + // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { const rewriter = new HTMLRewriter(); const k: string[] = []; diff --git a/src/runtime/runtime.ts b/src/runtime/runtime.ts index 535a9ef..2e129e2 100644 --- a/src/runtime/runtime.ts +++ b/src/runtime/runtime.ts @@ -15,11 +15,6 @@ export const h = ( return compilerTemplate.content.firstChild as T; }; -// const next = (d: number) => { -// while (d--) treeWalker.nextNode(); -// return treeWalker.currentNode; -// }; - /** * Collects node refs from a compiled template. * @param root - Root node. @@ -34,21 +29,17 @@ export const collect = ( k: readonly string[], d: readonly number[], ): LowercaseKeys => { + const walker = treeWalker; const refs: Refs = {}; const len = k.length; let index = 0; let distance; - // TODO: Performance test setting treeWalker to a local variable. - treeWalker.currentNode = root; + walker.currentNode = root; - // TODO: Performance test these 2 approaches. - // for (; index < len; index++) { - // refs[k[index]] = next(d[index]); - // } for (; index < len; index++) { distance = d[index]; - while (distance--) treeWalker.nextNode(); - refs[k[index]] = treeWalker.currentNode; + while (distance--) walker.nextNode(); + refs[k[index]] = walker.currentNode; } return refs as LowercaseKeys; From ad2e89e9fe1afa5f6bbf6943e1cee0f9521d89b3 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 18 Jul 2023 11:04:11 +1000 Subject: [PATCH 026/169] v0.8.0-next.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 120b575..2b94a1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.0", + "version": "0.8.0-next.1", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 982b74e233e5a2d9caad1e23de830a40e517c1a0 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 19 Jul 2023 12:39:00 +1000 Subject: [PATCH 027/169] bug: Fix whitespace handling in whitespace sensitive nodes + add new macro option --- src/runtime/macro.ts | 40 ++++++++++++++++++++++++++------------- test/unit/runtime.test.ts | 32 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index f15383c..313054c 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,3 +1,17 @@ +export interface CompileOptions { + /** + * Keep HTML comments in output HTML? + * @default false + */ + keepComments?: boolean; + /** + * Keep spaces adjacent to tags in output HTML? When keepSpace is `false`, + * `

x
` becomes `
x
`. + * @default false + */ + keepSpace?: boolean; +} + /** * Bun macro which compiles a template string at build-time into a format that * can be used by the runtime. @@ -6,7 +20,7 @@ */ export async function compile( template: string, - keepComments?: boolean, + { keepComments, keepSpace }: CompileOptions = {}, // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { const rewriter = new HTMLRewriter(); @@ -35,19 +49,26 @@ export async function compile( distance++; }, text(chunk) { + // Since the response given to HTMLRewriter.transform() is not streamed, + // this text handler is called once with the acual text, and then again + // with an empty last chunk. if (!chunk.lastInTextNode) { - const content = chunk.text.trim(); - if (!content) { + const text = chunk.text.trim(); + if (!text) { if (!whitespaceSensitiveBlock) { chunk.remove(); } return; } - if (content[0] === '@') { - k.push(content.slice(1)); + if (text[0] === '@') { + k.push(text.slice(1)); d.push(distance); distance = 0; + // replace with single space which will be turned into a text node chunk.replace(' '); + } else if (!whitespaceSensitiveBlock) { + // reduce any whitespace to a single space + chunk.replace((keepSpace ? chunk.text : text).replace(/\s+/g, ' ')); } distance++; } @@ -61,14 +82,7 @@ export async function compile( }, }); - const res = rewriter.transform( - new Response( - template - .trim() - // reduce any whitespace to a single space - .replace(/\s+/g, ' '), - ), - ); + const res = rewriter.transform(new Response(template.trim())); const html = await res.text(); return { html, k, d }; diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 741c572..12ce13b 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -63,6 +63,38 @@ describe('h', () => { const rendered = render(view); expect(rendered.container.innerHTML).toBe('
  • A
  • B
'); }); + + // FIXME: Don't skip this test once bun v0.7.0 or v0.6.15 is released. + test.skip('does not minify in whitespace-sensitive blocks', () => { + const meta = compile(` +
+
+          a
+          b
+          c
+
+
+        
+ + Foo + + + <span> + Foo + </span> + + +
+ `); + const view = h(meta.html); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe( + '
\n          a\n          b\n          c\n\n\n        
Foo\n <span>\n Foo\n </span>\n
', + ); + }); + + // FIXME: Test for each of the compile macro options; keepComments, keepSpace + // ↳ When keepComments, check refs metadata calculations are still correct. }); // describe('html', () => { From e82f0431c069c0c00ccb8601c2c2798b4570f922 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 19 Jul 2023 12:41:14 +1000 Subject: [PATCH 028/169] v0.8.0-next.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b94a1d..8935ff6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.1", + "version": "0.8.0-next.2", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 9158596d0c2b219e9b738b6a9aef5ec79080acae Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 22 Jul 2023 12:06:15 +1000 Subject: [PATCH 029/169] chore: Update dependencies --- bun.lockb | Bin 120486 -> 120333 bytes package.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bun.lockb b/bun.lockb index 781e4eabe9154d0801c9d554b219391e7245b863..b436c85392d3659411c04fb1c7ec2543966eab35 100755 GIT binary patch delta 20000 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 Up24@on(-BZ_{}PTWdEA~2jcao?f?J) delta 19936 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 diff --git a/package.json b/package.json index 8935ff6..23d6f5f 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@playwright/test": "1.36.1", "@typescript-eslint/eslint-plugin": "6.1.0", "@typescript-eslint/parser": "6.1.0", - "bun-types": "0.6.14", + "bun-types": "0.7.0", "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", @@ -65,7 +65,7 @@ "eslint-plugin-import": "2.27.5", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.0", - "happy-dom": "10.5.1", + "happy-dom": "10.5.2", "prettier": "3.0.0", "typescript": "5.1.6" } From 61e3aaee3cf42cf446d04934cf5d559b7282eead Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 22 Jul 2023 12:08:30 +1000 Subject: [PATCH 030/169] test: Add and update macro tests --- test/unit/runtime.test.ts | 47 +++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 12ce13b..f586c0b 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -7,6 +7,38 @@ import { cleanup, render } from './utils'; // FIXME: Use inline snapshots once bun:test supports them. +describe('compile', () => { + // FIXME: Test for each of the compile macro options; keepComments, keepSpace + // ↳ When keepComments, check refs metadata calculations are still correct. + + test('does not minify in whitespace-sensitive blocks', () => { + const meta = compile(` +
+
+          a
+           b
+          c
+
+
+          <span> Foo  </span>
+        
+ + Bar + + + <span> + Baz + </span> + + +
+ `); + expect(meta.html).toBe( + '
\n          a\n           b\n          c\n\n\n          <span> Foo  </span>\n        
Bar\n <span>\n Baz\n </span>\n
', + ); + }); +}); + describe('h', () => { afterEach(cleanup); @@ -64,23 +96,23 @@ describe('h', () => { expect(rendered.container.innerHTML).toBe('
  • A
  • B
'); }); - // FIXME: Don't skip this test once bun v0.7.0 or v0.6.15 is released. - test.skip('does not minify in whitespace-sensitive blocks', () => { + test('does not minify in whitespace-sensitive blocks', () => { const meta = compile(`
           a
-          b
+           b
           c
 
 
+          <span> Foo  </span>
         
- Foo + Bar <span> - Foo + Baz </span> @@ -89,12 +121,9 @@ describe('h', () => { const view = h(meta.html); const rendered = render(view); expect(rendered.container.innerHTML).toBe( - '
\n          a\n          b\n          c\n\n\n        
Foo\n <span>\n Foo\n </span>\n
', + '
\n          a\n           b\n          c\n\n\n           Foo  \n        
Bar\n \n Baz\n \n
', ); }); - - // FIXME: Test for each of the compile macro options; keepComments, keepSpace - // ↳ When keepComments, check refs metadata calculations are still correct. }); // describe('html', () => { From 36fd32c53750ae5e18d4c4293a9e378041e2b160 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 24 Jul 2023 09:00:23 +1000 Subject: [PATCH 031/169] chore: Clean up lint config --- .eslintrc.cjs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9abf6a8..024362d 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -23,17 +23,26 @@ module.exports = { plugins: ['prettier'], rules: { '@typescript-eslint/explicit-module-boundary-types': ERROR, + '@typescript-eslint/no-non-null-assertion': WARN, + 'import/prefer-default-export': OFF, + 'no-restricted-syntax': OFF, + 'prettier/prettier': WARN, + 'unicorn/filename-case': OFF, + 'unicorn/no-abusive-eslint-disable': WARN, + 'unicorn/no-null': OFF, + 'unicorn/prefer-module': WARN, + 'unicorn/prefer-top-level-await': WARN, + 'unicorn/prevent-abbreviations': OFF, + + /* Performance and byte savings */ // byte savings '@typescript-eslint/no-confusing-void-expression': OFF, - '@typescript-eslint/no-non-null-assertion': WARN, // worse performance '@typescript-eslint/prefer-string-starts-ends-with': OFF, // worse performance '@typescript-eslint/prefer-for-of': OFF, // void return can be used for efficient code (if used safely!) 'consistent-return': WARN, - 'default-param-last': WARN, - 'import/prefer-default-export': OFF, // useful for compact and memory efficient code... but be careful! 'no-cond-assign': OFF, // more compact at the cost of being harder to read @@ -41,34 +50,29 @@ module.exports = { // can be used for efficient code (if used safely!) 'no-param-reassign': WARN, 'no-plusplus': OFF, - 'no-restricted-syntax': OFF, // useful for compact and memory efficient code... but be careful! 'no-return-assign': OFF, - // used in synthetic event handler names - 'no-underscore-dangle': OFF, - 'prettier/prettier': WARN, // byte savings + faster 'unicorn/explicit-length-check': OFF, - 'unicorn/filename-case': OFF, - 'unicorn/no-abusive-eslint-disable': WARN, 'unicorn/no-array-callback-reference': OFF, // forEach is often faster (in Chrome and Firefox but not Safari) 'unicorn/no-array-for-each': OFF, 'unicorn/no-await-expression-member': OFF, - 'unicorn/no-null': OFF, - 'unicorn/prefer-add-event-listener': OFF, - 'unicorn/prefer-dom-node-append': OFF, - 'unicorn/prefer-module': WARN, // indexOf is faster (in Chrome) 'unicorn/prefer-includes': OFF, // saves 3 bytes to use arrow function 'unicorn/prefer-native-coercion-functions': OFF, // slower and worse browser support 'unicorn/prefer-string-replace-all': OFF, - 'unicorn/prefer-top-level-await': WARN, - 'unicorn/prefer-query-selector': OFF, - 'unicorn/prevent-abbreviations': OFF, 'unicorn/switch-case-braces': [ERROR, 'avoid'], + + /* stage1 */ + '@typescript-eslint/consistent-type-definitions': OFF, // FIXME: Issue with stage1 collect Refs + // underscores in synthetic event handler names + 'no-underscore-dangle': OFF, + 'unicorn/prefer-add-event-listener': OFF, + 'unicorn/prefer-dom-node-append': OFF, + 'unicorn/prefer-query-selector': OFF, }, overrides: [ { From 8e709aa698ea6d3756f96f93654366315a98a331 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 27 Jul 2023 07:47:37 +1000 Subject: [PATCH 032/169] bug: Rename macro option keepSpace to keepSpaces --- src/runtime/macro.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index 313054c..3654e24 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,15 +1,15 @@ export interface CompileOptions { /** - * Keep HTML comments in output HTML? + * Keep HTML comments in output HTML. * @default false */ keepComments?: boolean; /** - * Keep spaces adjacent to tags in output HTML? When keepSpace is `false`, + * Keep spaces adjacent to tags in output HTML. When keepSpaces is `false`, * `
x
` becomes `
x
`. * @default false */ - keepSpace?: boolean; + keepSpaces?: boolean; } /** @@ -20,7 +20,7 @@ export interface CompileOptions { */ export async function compile( template: string, - { keepComments, keepSpace }: CompileOptions = {}, + { keepComments, keepSpaces }: CompileOptions = {}, // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { const rewriter = new HTMLRewriter(); @@ -68,7 +68,7 @@ export async function compile( chunk.replace(' '); } else if (!whitespaceSensitiveBlock) { // reduce any whitespace to a single space - chunk.replace((keepSpace ? chunk.text : text).replace(/\s+/g, ' ')); + chunk.replace((keepSpaces ? chunk.text : text).replace(/\s+/g, ' ')); } distance++; } From c075c167d328bfe2c1ae60582fab6830f12b9295 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 27 Jul 2023 10:57:20 +1000 Subject: [PATCH 033/169] chore: Update dependencies --- bun.lockb | Bin 120333 -> 120333 bytes package.json | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bun.lockb b/bun.lockb index b436c85392d3659411c04fb1c7ec2543966eab35..cc318263816222af34e0a9c7bd576f9333426963 100755 GIT binary patch delta 13391 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 XPa*F{);2ecKFK%Z{S8x2@+ Date: Thu, 27 Jul 2023 10:58:03 +1000 Subject: [PATCH 034/169] feat: Add single root check to compile macro --- src/runtime/macro.ts | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index 3654e24..ed02e81 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,12 +1,12 @@ export interface CompileOptions { /** - * Keep HTML comments in output HTML. + * Whether to keep HTML comments in output HTML. * @default false */ keepComments?: boolean; /** - * Keep spaces adjacent to tags in output HTML. When keepSpaces is `false`, - * `
x
` becomes `
x
`. + * Whether to keep spaces adjacent to tags in output HTML. When keepSpaces + * is false, `
x
` becomes `
x
`. * @default false */ keepSpaces?: boolean; @@ -16,10 +16,13 @@ export interface CompileOptions { * Bun macro which compiles a template string at build-time into a format that * can be used by the runtime. * @param template - HTML template string. - * @param keepComments - Whether to keep HTML comments in the output. + * @param options - Compile options. */ export async function compile( template: string, + // FIXME: Actually using objects in macro arguments is broken in bun. + // ↳ https://github.com/oven-sh/bun/issues/3832 + // ↳ Add to documentation if it's not resolved by the time we write proper docs { keepComments, keepSpaces }: CompileOptions = {}, // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { @@ -28,9 +31,25 @@ export async function compile( const d: number[] = []; let distance = 0; let whitespaceSensitiveBlock = false; + let root: boolean | undefined; rewriter.on('*', { element(node) { + if (!root) { + if (root === undefined) { + root = true; + node.onEndTag(() => { + root = false; + }); + } else { + // eslint-disable-next-line no-console + console.error( + 'Expected template to have a single root element:', + template, + ); + } + } + if (node.tagName === 'pre' || node.tagName === 'code') { whitespaceSensitiveBlock = true; node.onEndTag(() => { @@ -48,10 +67,11 @@ export async function compile( } distance++; }, + // This text handler is invoked twice for each Text node: first with the + // actual text, then with an empty last chunk. This behavior stems from + // the fact that the Response provided to HTMLRewriter.transform() is not + // streamed; otherwise, there could be multiple chunks before the last one. text(chunk) { - // Since the response given to HTMLRewriter.transform() is not streamed, - // this text handler is called once with the acual text, and then again - // with an empty last chunk. if (!chunk.lastInTextNode) { const text = chunk.text.trim(); if (!text) { @@ -75,6 +95,7 @@ export async function compile( }, comments(node) { if (keepComments) { + // TODO: Support comments as node refs. distance++; } else { node.remove(); From 9af44bf395bdfc02753f90c805ce49b7b393cf63 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 27 Jul 2023 10:58:15 +1000 Subject: [PATCH 035/169] test: Add more compile macro tests --- test/unit/runtime.test.ts | 99 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index f586c0b..76659fb 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -1,6 +1,6 @@ // XXX: This file has the same tests as test/unit/compile.test.ts, keep them in sync. -import { afterEach, describe, expect, test } from 'bun:test'; +import { afterEach, describe, expect, spyOn, test } from 'bun:test'; import { collect, h } from '../../src/runtime/index'; import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; import { cleanup, render } from './utils'; @@ -10,6 +10,55 @@ import { cleanup, render } from './utils'; describe('compile', () => { // FIXME: Test for each of the compile macro options; keepComments, keepSpace // ↳ When keepComments, check refs metadata calculations are still correct. + // ↳ Currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + + test('outputs object', () => { + const meta = compile('
'); + expect(meta).toBeInstanceOf(Object); + }); + test('outputs html property with string value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('html'); + expect(typeof meta.html).toBe('string'); + }); + test('outputs k property with array value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('k'); + expect(meta.k).toBeInstanceOf(Array); + }); + test('outputs d property with array value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('d'); + expect(meta.d).toBeInstanceOf(Array); + }); + + test('has empty k and d properties when no node refs', () => { + const meta = compile('
'); + expect(meta.k).toHaveLength(0); + expect(meta.d).toHaveLength(0); + }); + + test('has 3 k and d properties when 3 node refs', () => { + const meta = compile('
'); + expect(meta.k).toHaveLength(3); + expect(meta.d).toHaveLength(3); + }); + + test('has 3 k and d properties when 3 node refs with whitespace', () => { + // FIXME: Whitespace handling is broken in happy-dom; https://github.com/capricorn86/happy-dom/issues/971 + // const meta = compile( + // '\n\n\t
\t\t\n\n\n
\n\n
\n', + // ); + const meta = compile(` +
+
+
+
+
+ `); + expect(meta.k).toHaveLength(3); + expect(meta.d).toHaveLength(3); + }); test('does not minify in whitespace-sensitive blocks', () => { const meta = compile(` @@ -37,6 +86,19 @@ describe('compile', () => { '
\n          a\n           b\n          c\n\n\n          <span> Foo  </span>\n        
Bar\n <span>\n Baz\n </span>\n
', ); }); + + // TODO: Don't skip this test. Not sure it's possible to spy on console.error + // for macros because they run before the text execution phase and in a + // different context. + test.skip('logs error when more than one root element', () => { + const spy = spyOn(console, 'error') + // @ts-expect-error - noop stub + .mockImplementation(() => {}); + compile('
'); + // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); + expect(spy).toHaveBeenCalledTimes(1); + spy.mockRestore(); + }); }); describe('h', () => { @@ -126,6 +188,9 @@ describe('h', () => { }); }); +// TODO: Once bun supports macros used as template literals tag functions, we +// could consider adding a html function similar to the standard runtime. + // describe('html', () => { // afterEach(cleanup); // @@ -251,4 +316,36 @@ describe('collect', () => { expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); }); + + // FIXME: Uncomment this test once using objects in macro args is fixed in + // bun; https://github.com/oven-sh/bun/issues/3832 + + // test('collects refs when keepComments is true', () => { + // const meta = compile( + // ` + //
+ // + // @a + // + // + //
+ // + // @c + // + // + //
+ //
+ //
+ // `, + // { keepComments: true }, + // ); + // const view = h(meta.html); + // const refs = collect(view, meta.k, meta.d); + // expect(refs.a.nodeName).toEqual('#text'); + // expect(refs.a).toBeInstanceOf(window.Text); + // expect(refs.b.nodeName).toEqual('DIV'); + // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + // expect(refs.c.nodeName).toEqual('#text'); + // expect(refs.c).toBeInstanceOf(window.Text); + // }); }); From f97d1b18ba2d9ead8c9655ca2b40148c51669e1d Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 27 Jul 2023 11:28:35 +1000 Subject: [PATCH 036/169] v0.8.0-next.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2757c1a..d954d7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.2", + "version": "0.8.0-next.3", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 7f9188776b2c5bd99a77b0cbe703b65276d51102 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 1 Aug 2023 08:04:51 +1000 Subject: [PATCH 037/169] chore: Update dependencies --- bun.lockb | Bin 120333 -> 122251 bytes package.json | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bun.lockb b/bun.lockb index cc318263816222af34e0a9c7bd576f9333426963..76a2e57465f49974bb608f1001a95e1d88252dcd 100755 GIT binary patch delta 33208 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 g7DU9Ftq7`%W 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 G&i)^jM~~wG diff --git a/package.json b/package.json index d954d7b..2d853a4 100644 --- a/package.json +++ b/package.json @@ -55,14 +55,14 @@ }, "devDependencies": { "@playwright/test": "1.36.2", - "@typescript-eslint/eslint-plugin": "6.2.0", - "@typescript-eslint/parser": "6.2.0", - "bun-types": "0.7.0", - "eslint": "8.45.0", + "@typescript-eslint/eslint-plugin": "6.2.1", + "@typescript-eslint/parser": "6.2.1", + "bun-types": "0.7.1", + "eslint": "8.46.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", - "eslint-config-prettier": "8.8.0", - "eslint-plugin-import": "2.27.5", + "eslint-config-prettier": "8.9.0", + "eslint-plugin-import": "2.28.0", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", "happy-dom": "10.5.2", From a4c5bc6e6d368eb7cd5af159292119527ce8e6bb Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 1 Aug 2023 08:08:06 +1000 Subject: [PATCH 038/169] chore: Ignore broken lint rule --- .eslintrc.cjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 024362d..9090139 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -25,6 +25,7 @@ module.exports = { '@typescript-eslint/explicit-module-boundary-types': ERROR, '@typescript-eslint/no-non-null-assertion': WARN, 'import/prefer-default-export': OFF, + 'import/order': OFF, // broken with prettier 'no-restricted-syntax': OFF, 'prettier/prettier': WARN, 'unicorn/filename-case': OFF, From 4fd62d49709b9027812b967fa7352fa59f9a1ac5 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Fri, 4 Aug 2023 16:41:30 +1000 Subject: [PATCH 039/169] chore: Update dependencies --- bun.lockb | Bin 122251 -> 122252 bytes package.json | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bun.lockb b/bun.lockb index 76a2e57465f49974bb608f1001a95e1d88252dcd..6ac9081bc139a30518e72b06c2ea0e7a85512261 100755 GIT binary patch delta 28746 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 delta 28812 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 Lru^_KoB#g+NiLfT diff --git a/package.json b/package.json index 2d853a4..984fe72 100644 --- a/package.json +++ b/package.json @@ -57,16 +57,16 @@ "@playwright/test": "1.36.2", "@typescript-eslint/eslint-plugin": "6.2.1", "@typescript-eslint/parser": "6.2.1", - "bun-types": "0.7.1", + "bun-types": "0.7.2", "eslint": "8.46.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", - "eslint-config-prettier": "8.9.0", + "eslint-config-prettier": "8.10.0", "eslint-plugin-import": "2.28.0", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "10.5.2", - "prettier": "3.0.0", + "happy-dom": "10.7.0", + "prettier": "3.0.1", "typescript": "5.1.6" } } From bb6cbd2c191b35d253cef4442465c2d23b376332 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Fri, 4 Aug 2023 16:42:36 +1000 Subject: [PATCH 040/169] bug: Do not escape html entities in compile macro Output should be raw HTML, the same as what was passed in. --- src/runtime/macro.ts | 10 ++++++---- test/unit/runtime.test.ts | 8 +++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index ed02e81..c27f8fe 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -84,18 +84,20 @@ export async function compile( k.push(text.slice(1)); d.push(distance); distance = 0; - // replace with single space which will be turned into a text node - chunk.replace(' '); + // replace with single space which renders a Text node at runtime + chunk.replace(' ', { html: true }); } else if (!whitespaceSensitiveBlock) { // reduce any whitespace to a single space - chunk.replace((keepSpaces ? chunk.text : text).replace(/\s+/g, ' ')); + chunk.replace((keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), { + html: true, + }); } distance++; } }, comments(node) { if (keepComments) { - // TODO: Support comments as node refs. + // TODO: Support comments as node refs once bun issue #3832 is fixed. distance++; } else { node.remove(); diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 76659fb..450e9ba 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -12,7 +12,7 @@ describe('compile', () => { // ↳ When keepComments, check refs metadata calculations are still correct. // ↳ Currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test('outputs object', () => { + test('outputs an object', () => { const meta = compile('
'); expect(meta).toBeInstanceOf(Object); }); @@ -87,6 +87,12 @@ describe('compile', () => { ); }); + test('does not escape html entities', () => { + const template = '
<span>Foo</span>
'; + const meta = compile(template); + expect(meta.html).toBe(template); + }); + // TODO: Don't skip this test. Not sure it's possible to spy on console.error // for macros because they run before the text execution phase and in a // different context. From 5615850e87d4718f1ce25c29ddebcdb792dcf0fe Mon Sep 17 00:00:00 2001 From: Max Milton Date: Fri, 4 Aug 2023 16:43:43 +1000 Subject: [PATCH 041/169] v0.8.0-next.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 984fe72..b4edb05 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.3", + "version": "0.8.0-next.4", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 44610ef79f3faa84145ce2bcb5f56fa573cd93d2 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 7 Aug 2023 12:42:31 +1000 Subject: [PATCH 042/169] chore: Update dependencies --- bun.lockb | Bin 122252 -> 121852 bytes package.json | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 6ac9081bc139a30518e72b06c2ea0e7a85512261..4dceb9e08825bd68fe785018e268aa930d14c2ca 100755 GIT binary patch delta 19543 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 yh`t9{Ju!PHa} Date: Mon, 7 Aug 2023 12:50:46 +1000 Subject: [PATCH 043/169] test: Add benchmark tooling (WIP) --- .eslintrc.cjs | 2 +- .gitignore | 1 + bench/.eslintrc | 6 + bench/build.ts | 14 ++ bench/cases/index.ts | 1 + bench/cases/replace-vs-replaceAll.ts | 258 +++++++++++++++++++++++++++ bench/package.json | 12 ++ bench/tsconfig.json | 7 + package.json | 2 +- 9 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 bench/.eslintrc create mode 100644 bench/build.ts create mode 100644 bench/cases/index.ts create mode 100644 bench/cases/replace-vs-replaceAll.ts create mode 100644 bench/package.json create mode 100644 bench/tsconfig.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9090139..2c810f5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -8,7 +8,7 @@ module.exports = { reportUnusedDisableDirectives: true, parser: '@typescript-eslint/parser', parserOptions: { - project: ['tsconfig.json', 'tsconfig.node.json'], + project: ['tsconfig.json', 'tsconfig.node.json', 'bench/tsconfig.json'], tsconfigRootDir: __dirname, }, extends: [ diff --git a/.gitignore b/.gitignore index 4aa800e..86a5aa5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *-lock.json* *.lock *.log +/bench/bun.lockb /coverage/ dist node_modules diff --git a/bench/.eslintrc b/bench/.eslintrc new file mode 100644 index 0000000..e1963ca --- /dev/null +++ b/bench/.eslintrc @@ -0,0 +1,6 @@ +{ + "rules": { + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-call": "warn" + } +} diff --git a/bench/build.ts b/bench/build.ts new file mode 100644 index 0000000..b3d4ae2 --- /dev/null +++ b/bench/build.ts @@ -0,0 +1,14 @@ +/* eslint-disable no-console */ +export {}; + +// TODO: Easy way to build a single benchmark test case for running in the browser. + +console.time('build'); +const out = await Bun.build({ + entrypoints: ['src/temp.ts'], + outdir: 'dist', + target: 'browser', + minify: true, +}); +console.timeEnd('build'); +console.log(out); diff --git a/bench/cases/index.ts b/bench/cases/index.ts new file mode 100644 index 0000000..4d9832a --- /dev/null +++ b/bench/cases/index.ts @@ -0,0 +1 @@ +import './replace-vs-replaceAll'; diff --git a/bench/cases/replace-vs-replaceAll.ts b/bench/cases/replace-vs-replaceAll.ts new file mode 100644 index 0000000..af441a8 --- /dev/null +++ b/bench/cases/replace-vs-replaceAll.ts @@ -0,0 +1,258 @@ +import { baseline, bench, group, run } from 'mitata'; + +const html = ` +
+

hello

+

world

+ + +
+

hello

+

world

+ + + + + + + + +
+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

hello

+

world

+
+
+ +
+

hello

+

world

+ +
+

hello

+

world

+ +
+ + + + + + + + +

hello

+

world

+
+
+
+
+

hello

+

world

+ + + + + + + +
+

hello

+

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

world

+

world

+

world

+

world

😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼 +

world

+

world

+

world

+

world

+

world

+

world

+

world

+ 😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼

world

+

world

+

world

+

world

+

world

+

world

+YYYYYYYYYYYYYYYYY

world

+

world

+

world

+

world

+

world

+

world

+

world

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +

world

+

world

+

world

+ 😼

world

+ +
+😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼😼

hello

+

world

+
+
+ +
+

hello

+

world

+ +
+

hello

+

world

+ +
+

hello

+

world

+
+
+
+
+
+`; + +const base = () => ''; + +function one(template: string) { + return ( + template + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replace(/> /g, '>') + .replace(/ /g, '>') + .replaceAll(/ ', '>') + .replaceAll(' <', '<') + ); +} +function twoS2(template: string) { + return ( + template + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replaceAll('> ', '>') + .replaceAll(' <', '<') + ); +} + +function oneB() { + return ( + html + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replace(/> /g, '>') + .replace(/ /g, '>') + .replaceAll(/ + template + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replace(/> /g, '>') + .replace(/ + template + // reduce any whitespace to a single space + .replaceAll(/\s+/g, ' ') + // remove space adjacent to tags + .replaceAll(/> /g, '>') + .replaceAll(/ + html + // reduce any whitespace to a single space + .replace(/\s+/g, ' ') + // remove space adjacent to tags + .replace(/> /g, '>') + .replace(/ + html + // reduce any whitespace to a single space + .replaceAll(/\s+/g, ' ') + // remove space adjacent to tags + .replaceAll(/> /g, '>') + .replaceAll(/ { + baseline('baseline', base); + bench('one:replace', () => one(html)); + bench('two:replaceAll', () => two(html)); + bench('twoS1:replaceAll,string', () => twoS1(html)); + bench('twoS2:combo,string', () => twoS2(html)); + bench('oneB:replace', () => oneB()); + bench('twoB:replaceAll', () => twoB()); + bench('oneC:replace,arrow', () => oneC(html)); + bench('twoC:replaceAll,arrow', () => twoC(html)); +}); + +group('input from global var', () => { + baseline('baseline', base); + bench('oneB2:replace', oneB); + bench('twoB2:replaceAll', twoB); + bench('oneD:replace,arrow', oneD); + bench('twoD:replaceAll,arrow', twoD); +}); + +// console.log('#### SAME', one(html) === two(html)); +// console.log('#########', one(html)); + +const out = await run(); +// await run({ collect: true }); +console.log(out); diff --git a/bench/package.json b/bench/package.json new file mode 100644 index 0000000..1d54670 --- /dev/null +++ b/bench/package.json @@ -0,0 +1,12 @@ +{ + "name": "bench", + "version": "0.0.0", + "private": "true", + "scripts": { + "build": "bun build.ts", + "start": "bun cases/index.ts" + }, + "dependencies": { + "mitata": "0.1.6" + } +} diff --git a/bench/tsconfig.json b/bench/tsconfig.json new file mode 100644 index 0000000..1f5bd2c --- /dev/null +++ b/bench/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "types": ["bun-types"] + }, + "include": ["cases", "build.ts"] +} diff --git a/package.json b/package.json index 4d607ec..a58b0a3 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "scripts": { "build": "bun build.ts", "lint": "bun run lint:js && bun run lint:ts", - "lint:js": "eslint --ignore-path .gitignore --ext .ts,.js,.mjs,.cjs .", + "lint:js": "eslint --ignore-path .gitignore --ignore-pattern bench --ext .ts,.js,.mjs,.cjs .", "lint:ts": "tsc --noEmit", "postbuild": "tsc --project ./tsconfig.d.json", "prebuild": "rm -rf dist", From 95d0da1cd94873025bdc0596c1a664e625542fad Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 7 Aug 2023 12:51:11 +1000 Subject: [PATCH 044/169] test: Show coverage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a58b0a3..b657195 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "lint:ts": "tsc --noEmit", "postbuild": "tsc --project ./tsconfig.d.json", "prebuild": "rm -rf dist", - "test": "bun test --preload ./test/setup.ts test/unit", + "test": "bun test --preload ./test/setup.ts test/unit --coverage", "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { From 57fed98cc0045456638613f8104f60bf0f6d27cd Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 7 Aug 2023 12:52:09 +1000 Subject: [PATCH 045/169] test: Don't skip macro error check test --- test/unit/runtime.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 450e9ba..63f056e 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -2,10 +2,13 @@ import { afterEach, describe, expect, spyOn, test } from 'bun:test'; import { collect, h } from '../../src/runtime/index'; +// eslint-disable-next-line import/no-duplicates import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; +// eslint-disable-next-line import/no-duplicates +import { compile as compileNoMacro } from '../../src/runtime/macro'; import { cleanup, render } from './utils'; -// FIXME: Use inline snapshots once bun:test supports them. +// TODO: Consider using inline snapshots once bun:test supports them. describe('compile', () => { // FIXME: Test for each of the compile macro options; keepComments, keepSpace @@ -93,14 +96,11 @@ describe('compile', () => { expect(meta.html).toBe(template); }); - // TODO: Don't skip this test. Not sure it's possible to spy on console.error - // for macros because they run before the text execution phase and in a - // different context. - test.skip('logs error when more than one root element', () => { + test('logs error when more than one root element', () => { const spy = spyOn(console, 'error') // @ts-expect-error - noop stub .mockImplementation(() => {}); - compile('
'); + compileNoMacro('
'); // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); expect(spy).toHaveBeenCalledTimes(1); spy.mockRestore(); From 258d7ef212437519d746ceb5d58e92b9fb6b6697 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 7 Aug 2023 13:12:49 +1000 Subject: [PATCH 046/169] test: Minor bench tweaks --- bench/.eslintrc | 6 ------ bench/package.json | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 bench/.eslintrc diff --git a/bench/.eslintrc b/bench/.eslintrc deleted file mode 100644 index e1963ca..0000000 --- a/bench/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rules": { - "@typescript-eslint/no-unsafe-assignment": "warn", - "@typescript-eslint/no-unsafe-call": "warn" - } -} diff --git a/bench/package.json b/bench/package.json index 1d54670..10453b3 100644 --- a/bench/package.json +++ b/bench/package.json @@ -4,6 +4,9 @@ "private": "true", "scripts": { "build": "bun build.ts", + "lint": "bun run lint:js && bun run lint:ts", + "lint:js": "eslint --ext .ts .", + "lint:ts": "tsc --noEmit", "start": "bun cases/index.ts" }, "dependencies": { From 84902c3790a74bf3faac6a23e2b802c8c314d7f6 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 7 Aug 2023 14:21:03 +1000 Subject: [PATCH 047/169] test: More improvements --- README.md | 3 +- test/TestComponent_precompiled.ts | 28 +++ test/TestComponent_regular.ts | 26 +++ test/unit/compile.test.ts | 9 +- test/unit/macro.test.ts | 145 +++++++++++++++ test/unit/runtime.test.ts | 292 ++++++++++++++++-------------- test/unit/store.test.ts | 2 +- test/unit/test-utils.test.ts | 136 ++++++++++++++ test/unit/utils.test.ts | 6 +- test/unit/utils.ts | 37 ++-- 10 files changed, 531 insertions(+), 153 deletions(-) create mode 100644 test/TestComponent_precompiled.ts create mode 100644 test/TestComponent_regular.ts create mode 100644 test/unit/macro.test.ts create mode 100644 test/unit/test-utils.test.ts diff --git a/README.md b/README.md index 311b66a..c6d08b6 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Originally a fork of the excellent project. - New reactive store feature - Differences from the original `stage0` project: - There are now 2 runtime modes: - - New pre-compiled runtime mode for ultimate performance. Compiles templates at build-time via a bun macro that minifies templates, generates metadata, and then includes minimal runtime code in your JS bundle. Currently only works with [Bun.build](https://bun.sh/docs/bundler). + - New precompiled runtime mode for ultimate performance. Compiles templates at build-time via a bun macro that minifies templates, generates metadata, and then includes minimal runtime code in your JS bundle. Currently only works with [Bun.build](https://bun.sh/docs/bundler). - The regular mode is still availiable which generates metadata when your JS is run in the browser. Regular mode can be used with or without a build process. - Ref nodes are now marked with `@` rather than `#` - `h` is now `function h(template: string): S1Node` e.g., `h('

@key

')` @@ -47,6 +47,7 @@ Originally a fork of the excellent project. - `/reuse-nodes` --> `/reconcile/reuse-nodes` - Ref names must be lowercase because some browsers normalise element attribute names when rendering HTML - Add API and usage documentation + - The regular mode `h()` function does not support skipping minification in whitespace sensitive HTML blocks like `

` and `` because it would be too slow. The precompiled mode `compile()` macro does however. Same for the other compile options.
 - Add more tests
 - Add examples
 - Set up benchmarking + compare to `stage0` and other JS frameworks
diff --git a/test/TestComponent_precompiled.ts b/test/TestComponent_precompiled.ts
new file mode 100644
index 0000000..0f5388c
--- /dev/null
+++ b/test/TestComponent_precompiled.ts
@@ -0,0 +1,28 @@
+import { collect, h } from '../src/runtime/index';
+import { compile } from '../src/runtime/macro' assert { type: 'macro' };
+
+type TestComponent = HTMLDivElement;
+
+interface TestProps {
+  text: string;
+}
+
+type Refs = {
+  t: Text;
+};
+
+const meta = compile(`
+  
+ @t +
+`); +const view = h(meta.html); + +export function Test(props: TestProps): TestComponent { + const root = view; + const refs = collect(root, meta.k, meta.d); + + refs.t.nodeValue = props.text; + + return root; +} diff --git a/test/TestComponent_regular.ts b/test/TestComponent_regular.ts new file mode 100644 index 0000000..d6d917e --- /dev/null +++ b/test/TestComponent_regular.ts @@ -0,0 +1,26 @@ +import { collect, h } from '../src/index'; + +type TestComponent = HTMLDivElement; + +interface TestProps { + text: string; +} + +type Refs = { + t: Text; +}; + +const view = h(` +
+ @t +
+`); + +export function Test(props: TestProps): TestComponent { + const root = view; + const refs = collect(root, view); + + refs.t.nodeValue = props.text; + + return root; +} diff --git a/test/unit/compile.test.ts b/test/unit/compile.test.ts index 8aa1919..1929d5b 100644 --- a/test/unit/compile.test.ts +++ b/test/unit/compile.test.ts @@ -4,7 +4,7 @@ import { afterEach, describe, expect, test } from 'bun:test'; import { collect, h, html } from '../../src/compile'; import { cleanup, render } from './utils'; -// FIXME: Use inline snapshots once bun:test supports them. +// TODO: Consider using inline snapshots once bun:test supports them. describe('h', () => { afterEach(cleanup); @@ -58,6 +58,10 @@ describe('h', () => { const rendered = render(view); expect(rendered.container.innerHTML).toBe('
  • A
  • B
'); }); + + // NOTE: This is not supported by the current implementation of the h() + // function because it would be too slow. + test.skip('does not minify in whitespace-sensitive blocks', () => {}); }); describe('html', () => { @@ -180,4 +184,7 @@ describe('collect', () => { expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); }); + + // NOTE: The regular mode h() function does not support options like the + // runtime mode compile() macro does. So there's no need to test them here. }); diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts new file mode 100644 index 0000000..57aa6b8 --- /dev/null +++ b/test/unit/macro.test.ts @@ -0,0 +1,145 @@ +// XXX: This file has the same tests as test/unit/compile.test.ts, keep them in sync. + +import { describe, expect, spyOn, test } from 'bun:test'; +// eslint-disable-next-line import/no-duplicates +import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; +// eslint-disable-next-line import/no-duplicates +import { compile as compileNoMacro } from '../../src/runtime/macro'; + +// TODO: Consider using inline snapshots once bun:test supports them. + +describe('compile', () => { + // FIXME: Test for each of the compile macro options; keepComments, keepSpace + // ↳ When keepComments, check refs metadata calculations are still correct. + // ↳ Currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + + test('outputs an object', () => { + const meta = compile('
'); + expect(meta).toBeInstanceOf(Object); + }); + test('outputs html property with string value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('html'); + expect(typeof meta.html).toBe('string'); + }); + test('outputs k property with array value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('k'); + expect(meta.k).toBeInstanceOf(Array); + }); + test('outputs d property with array value', () => { + const meta = compile('
'); + expect(meta).toHaveProperty('d'); + expect(meta.d).toBeInstanceOf(Array); + }); + + test('has empty k and d properties when no node refs', () => { + const meta = compile('
'); + expect(meta.k).toHaveLength(0); + expect(meta.d).toHaveLength(0); + }); + + test('has 3 k and d properties when 3 node refs', () => { + const meta = compile('
'); + expect(meta.k).toHaveLength(3); + expect(meta.d).toHaveLength(3); + }); + + test('has 3 k and d properties when 3 node refs with whitespace', () => { + // FIXME: Whitespace handling is broken in happy-dom; https://github.com/capricorn86/happy-dom/issues/971 + // const meta = compile( + // '\n\n\t
\t\t\n\n\n
\n\n
\n', + // ); + const meta = compile(` +
+
+
+
+
+ `); + expect(meta.k).toHaveLength(3); + expect(meta.d).toHaveLength(3); + }); + + test('does not minify in whitespace-sensitive blocks', () => { + const meta = compile(` +
+
+          a
+           b
+          c
+
+
+          <span> Foo  </span>
+        
+ + Bar + + + <span> + Baz + </span> + + +
+ `); + expect(meta.html).toBe( + '
\n          a\n           b\n          c\n\n\n          <span> Foo  </span>\n        
Bar\n <span>\n Baz\n </span>\n
', + ); + }); + + test('does not escape html entities', () => { + const template = '
<span>Foo</span>
'; + const meta = compile(template); + expect(meta.html).toBe(template); + }); + + test('logs error when more than one root element', () => { + const spy = spyOn(console, 'error') + // @ts-expect-error - noop stub + .mockImplementation(() => {}); + compileNoMacro('
'); + // TODO: Check for specific error message once bun:test supports it. + // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); + expect(spy).toHaveBeenCalledTimes(1); + spy.mockRestore(); + }); + + describe('keepComments option', () => { + test('removes comments by default', () => { + const meta = compile('
'); + expect(meta.html).toBe('
'); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('keeps comments when option is true', () => { + // const meta = compile('
', { keepComments: true }); + // expect(meta.html).toBe('
'); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('removes comments when option is false', () => { + // const meta = compile('
', { keepComments: false }); + // expect(meta.html).toBe('
'); + }); + }); + + describe('keepSpaces option', () => { + test('removes spaces between tags and text by default', () => { + const meta = compile('
x \n\t\t
'); + expect(meta.html).toBe('
x
'); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('keeps spaces between tags and text when option is true', () => { + // const meta = compile('
x \n\t\t
', { keepSpaces: true }); + // expect(meta.html).toBe('
x
'); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('removes spaces between tags and text when option is false', () => { + // const meta = compile('
x \n\t\t
', { keepSpaces: false }); + // expect(meta.html).toBe('
x
'); + }); + }); +}); diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 63f056e..fc8733b 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -1,112 +1,12 @@ // XXX: This file has the same tests as test/unit/compile.test.ts, keep them in sync. -import { afterEach, describe, expect, spyOn, test } from 'bun:test'; +import { afterEach, describe, expect, test } from 'bun:test'; import { collect, h } from '../../src/runtime/index'; -// eslint-disable-next-line import/no-duplicates import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; -// eslint-disable-next-line import/no-duplicates -import { compile as compileNoMacro } from '../../src/runtime/macro'; import { cleanup, render } from './utils'; // TODO: Consider using inline snapshots once bun:test supports them. -describe('compile', () => { - // FIXME: Test for each of the compile macro options; keepComments, keepSpace - // ↳ When keepComments, check refs metadata calculations are still correct. - // ↳ Currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - - test('outputs an object', () => { - const meta = compile('
'); - expect(meta).toBeInstanceOf(Object); - }); - test('outputs html property with string value', () => { - const meta = compile('
'); - expect(meta).toHaveProperty('html'); - expect(typeof meta.html).toBe('string'); - }); - test('outputs k property with array value', () => { - const meta = compile('
'); - expect(meta).toHaveProperty('k'); - expect(meta.k).toBeInstanceOf(Array); - }); - test('outputs d property with array value', () => { - const meta = compile('
'); - expect(meta).toHaveProperty('d'); - expect(meta.d).toBeInstanceOf(Array); - }); - - test('has empty k and d properties when no node refs', () => { - const meta = compile('
'); - expect(meta.k).toHaveLength(0); - expect(meta.d).toHaveLength(0); - }); - - test('has 3 k and d properties when 3 node refs', () => { - const meta = compile('
'); - expect(meta.k).toHaveLength(3); - expect(meta.d).toHaveLength(3); - }); - - test('has 3 k and d properties when 3 node refs with whitespace', () => { - // FIXME: Whitespace handling is broken in happy-dom; https://github.com/capricorn86/happy-dom/issues/971 - // const meta = compile( - // '\n\n\t
\t\t\n\n\n
\n\n
\n', - // ); - const meta = compile(` -
-
-
-
-
- `); - expect(meta.k).toHaveLength(3); - expect(meta.d).toHaveLength(3); - }); - - test('does not minify in whitespace-sensitive blocks', () => { - const meta = compile(` -
-
-          a
-           b
-          c
-
-
-          <span> Foo  </span>
-        
- - Bar - - - <span> - Baz - </span> - - -
- `); - expect(meta.html).toBe( - '
\n          a\n           b\n          c\n\n\n          <span> Foo  </span>\n        
Bar\n <span>\n Baz\n </span>\n
', - ); - }); - - test('does not escape html entities', () => { - const template = '
<span>Foo</span>
'; - const meta = compile(template); - expect(meta.html).toBe(template); - }); - - test('logs error when more than one root element', () => { - const spy = spyOn(console, 'error') - // @ts-expect-error - noop stub - .mockImplementation(() => {}); - compileNoMacro('
'); - // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); - expect(spy).toHaveBeenCalledTimes(1); - spy.mockRestore(); - }); -}); - describe('h', () => { afterEach(cleanup); @@ -323,35 +223,165 @@ describe('collect', () => { expect(refs.search.name).toBe('q'); }); - // FIXME: Uncomment this test once using objects in macro args is fixed in - // bun; https://github.com/oven-sh/bun/issues/3832 + // TODO: Instead of repeating similar tests multiple times, we should create + // a reusable test suite and create a test matrix that covers all the + // different combinations of options. + + describe('keepComments option', () => { + test('collects refs when option is default', () => { + const meta = compile(` +
+ + @a + + +
+ + @c + + +
+
+
+ `); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b.nodeName).toEqual('DIV'); + expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + expect(refs.c.nodeName).toEqual('#text'); + expect(refs.c).toBeInstanceOf(window.Text); + }); - // test('collects refs when keepComments is true', () => { - // const meta = compile( - // ` - //
- // - // @a - // - // - //
- // - // @c - // - // - //
- //
- //
- // `, - // { keepComments: true }, - // ); - // const view = h(meta.html); - // const refs = collect(view, meta.k, meta.d); - // expect(refs.a.nodeName).toEqual('#text'); - // expect(refs.a).toBeInstanceOf(window.Text); - // expect(refs.b.nodeName).toEqual('DIV'); - // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - // expect(refs.c.nodeName).toEqual('#text'); - // expect(refs.c).toBeInstanceOf(window.Text); - // }); + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('collects refs when option is true', () => { + // const meta = compile( + // ` + //
+ // + // @a + // + // + //
+ // + // @c + // + // + //
+ //
+ //
+ // `, + // { keepComments: true }, + // ); + // const view = h(meta.html); + // const refs = collect(view, meta.k, meta.d); + // expect(refs.a.nodeName).toEqual('#text'); + // expect(refs.a).toBeInstanceOf(window.Text); + // expect(refs.b.nodeName).toEqual('DIV'); + // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + // expect(refs.c.nodeName).toEqual('#text'); + // expect(refs.c).toBeInstanceOf(window.Text); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('collects refs when option is false', () => { + // const meta = compile( + // ` + //
+ // + // @a + // + // + //
+ // + // @c + // + // + //
+ //
+ //
+ // `, + // { keepComments: false }, + // ); + // const view = h(meta.html); + // const refs = collect(view, meta.k, meta.d); + // expect(refs.a.nodeName).toEqual('#text'); + // expect(refs.a).toBeInstanceOf(window.Text); + // expect(refs.b.nodeName).toEqual('DIV'); + // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + // expect(refs.c.nodeName).toEqual('#text'); + // expect(refs.c).toBeInstanceOf(window.Text); + }); + }); + + describe('keepSpaces option', () => { + test('collects refs when option is default', () => { + const meta = compile(` +
+ @a +
+ @c +
+
+
+ `); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b.nodeName).toEqual('DIV'); + expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + expect(refs.c.nodeName).toEqual('#text'); + expect(refs.c).toBeInstanceOf(window.Text); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('collects refs when option is true', () => { + // const meta = compile( + // ` + //
+ // @a + //
+ // @c + //
+ //
+ //
+ // `, + // { keepSpaces: true }, + // ); + // const view = h(meta.html); + // const refs = collect(view, meta.k, meta.d); + // expect(refs.a.nodeName).toEqual('#text'); + // expect(refs.a).toBeInstanceOf(window.Text); + // expect(refs.b.nodeName).toEqual('DIV'); + // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + // expect(refs.c.nodeName).toEqual('#text'); + // expect(refs.c).toBeInstanceOf(window.Text); + }); + + // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 + test.todo('collects refs when option is false', () => { + // const meta = compile( + // ` + //
+ // @a + //
+ // @c + //
+ //
+ //
+ // `, + // { keepSpaces: false }, + // ); + // const view = h(meta.html); + // const refs = collect(view, meta.k, meta.d); + // expect(refs.a.nodeName).toEqual('#text'); + // expect(refs.a).toBeInstanceOf(window.Text); + // expect(refs.b.nodeName).toEqual('DIV'); + // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + // expect(refs.c.nodeName).toEqual('#text'); + // expect(refs.c).toBeInstanceOf(window.Text); + }); + }); }); diff --git a/test/unit/store.test.ts b/test/unit/store.test.ts index 8730a87..782063f 100644 --- a/test/unit/store.test.ts +++ b/test/unit/store.test.ts @@ -112,7 +112,7 @@ describe('store', () => { }); // TODO: Don't skip once bun:test mocks support toHaveBeenCalledWith() - test.skip('calls callback with new value and previous value', () => { + test.todo('calls callback with new value and previous value', () => { // const initialState = { a: 'old' }; // const state = store(initialState); // const callback = mock(() => {}); diff --git a/test/unit/test-utils.test.ts b/test/unit/test-utils.test.ts new file mode 100644 index 0000000..8b17bbd --- /dev/null +++ b/test/unit/test-utils.test.ts @@ -0,0 +1,136 @@ +import { afterEach, describe, expect, spyOn, test } from 'bun:test'; +import { Test as TestPrecompiled } from '../TestComponent_precompiled'; +import { Test as TestRegular } from '../TestComponent_regular'; +import { cleanup, render } from './utils'; + +describe('render', () => { + afterEach(cleanup); + + test('returns a container element', () => { + const rendered = render(document.createElement('div')); + expect(rendered.container).toBeInstanceOf(window.Element); + }); + + test('mounts supplied element in container', () => { + const el = document.createElement('span'); + const rendered = render(el); + expect(rendered.container.firstChild).toBe(el); + }); + + test('mounts container div to document body', () => { + expect(document.body.firstChild).toBeNull(); + const rendered = render(document.createElement('div')); + expect(document.body.firstChild).toBe(rendered.container); + expect(document.body.firstChild).toBeInstanceOf(window.HTMLDivElement); + }); + + test('mounts containers when other DOM elements exist on document body', () => { + document.body.append(document.createElement('span')); + document.body.append(document.createElement('span')); + render(document.createElement('a')); + render(document.createElement('a')); + document.body.append(document.createElement('span')); + expect(document.body.childNodes).toHaveLength(5); + expect(document.body.innerHTML).toBe( + '
', + ); + document.body.textContent = ''; + }); + + test('returns an unmount function', () => { + const rendered = render(document.createElement('div')); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(rendered.unmount).toBeInstanceOf(Function); + }); + + test('unmount removes supplied element from container', () => { + const rendered = render(document.createElement('div')); + expect(rendered.container.firstChild).toBeTruthy(); + rendered.unmount(); + expect(rendered.container).toBeTruthy(); + expect(rendered.container.firstChild).toBeNull(); + }); + + test('returns a debug function', () => { + const rendered = render(document.createElement('div')); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(rendered.debug).toBeInstanceOf(Function); + }); + + test('debug function prints to console', async () => { + const logSpy = spyOn(console, 'log') + // @ts-expect-error - noop mock + .mockImplementation(() => {}); + const rendered = render(document.createElement('div')); + await rendered.debug(); + expect(logSpy).toHaveBeenCalledTimes(1); + // TODO: Use this once bun:test supports it. + // expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n'); + logSpy.mockRestore(); + }); + + test('debug function prints prettified container DOM to console', async () => { + const logSpy = spyOn(console, 'log') + // @ts-expect-error - noop mock + .mockImplementation(() => {}); + const main = document.createElement('main'); + main.append( + document.createElement('div'), + document.createElement('div'), + document.createElement('div'), + ); + const rendered = render(main); + await rendered.debug(); + expect(logSpy).toHaveBeenCalledTimes(1); + // TODO: Use this once bun:test supports it. + // expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n
\n
\n
\n
\n'); + logSpy.mockRestore(); + }); + + test('renders TestRegular component correctly', () => { + const rendered = render(TestRegular({ text: 'abc' })); + expect(rendered.container.innerHTML).toBe('
abc
'); + }); + + test('renders TestPrecompiled component correctly', () => { + const rendered = render(TestPrecompiled({ text: 'abc' })); + expect(rendered.container.innerHTML).toBe('
abc
'); + }); +}); + +describe('cleanup', () => { + test('throws when there are no rendered components', () => { + expect(() => cleanup()).toThrow(); + }); + + test('removes mounted container from document body', () => { + render(document.createElement('div')); + expect(document.body.firstChild).toBeTruthy(); + cleanup(); + expect(document.body.firstChild).toBeNull(); + }); + + test('removes multiple mounted containers from document body', () => { + render(document.createElement('div')); + render(document.createElement('div')); + render(document.createElement('div')); + expect(document.body.childNodes).toHaveLength(3); + cleanup(); + expect(document.body.childNodes).toHaveLength(0); + }); + + test('only removes mounted containers and not other DOM nodes', () => { + document.body.append(document.createElement('span')); + document.body.append(document.createElement('span')); + render(document.createElement('a')); + render(document.createElement('a')); + document.body.append(document.createElement('span')); + expect(document.body.childNodes).toHaveLength(5); + cleanup(); + expect(document.body.childNodes).toHaveLength(3); + for (const node of document.body.childNodes) { + expect(node).toBeInstanceOf(window.HTMLSpanElement); + } + document.body.textContent = ''; + }); +}); diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index 42e53a9..7f5c8ac 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -302,9 +302,10 @@ describe('onRemove', () => { expect(onRemove).toHaveLength(2); }); - // TODO: Don't skip these tests. Currently happy-dom doesn't support the 2nd + // FIXME: Don't skip these tests. Currently happy-dom doesn't support the 2nd // parameter in MutationObserver callbacks. Open an issue! + // TODO: Don't skip this test. test.skip('calls callback when watched element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); @@ -314,6 +315,7 @@ describe('onRemove', () => { expect(spy).toHaveBeenCalledTimes(1); }); + // TODO: Don't skip this test. test.skip('calls callback when parent parent element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); @@ -327,6 +329,7 @@ describe('onRemove', () => { expect(spy).toHaveBeenCalledTimes(1); }); + // TODO: Don't skip this test. test.skip('does not call callback when nested child element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); @@ -338,6 +341,7 @@ describe('onRemove', () => { expect(spy).not.toHaveBeenCalled(); }); + // TODO: Don't skip this test. test.skip('does not call callback when element is added or moved', () => { const spy = mock(() => {}); const root = document.createElement('div'); diff --git a/test/unit/utils.ts b/test/unit/utils.ts index 204cabe..f2fc1e4 100644 --- a/test/unit/utils.ts +++ b/test/unit/utils.ts @@ -1,4 +1,4 @@ -import { expect, spyOn, type Mock } from 'bun:test'; +// import { expect, spyOn, type Mock } from 'bun:test'; export interface RenderResult { /** A wrapper DIV which contains your mounted component. */ @@ -54,21 +54,22 @@ export function cleanup(): void { }); } -const consoleMethods = Object.getOwnPropertyNames( - window.console, -) as (keyof Console)[]; +// TODO: Remove if unused. +// const consoleMethods = Object.getOwnPropertyNames( +// window.console, +// ) as (keyof Console)[]; -export function consoleSpy(): () => void { - const spies: Mock<() => void>[] = []; - - for (const method of consoleMethods) { - spies.push(spyOn(window.console, method)); - } - - return () => { - for (const spy of spies) { - expect(spy).toHaveBeenCalledTimes(0); - spy.mockRestore(); - } - }; -} +// export function consoleSpy(): () => void { +// const spies: Mock<() => void>[] = []; +// +// for (const method of consoleMethods) { +// spies.push(spyOn(window.console, method)); +// } +// +// return () => { +// for (const spy of spies) { +// expect(spy).toHaveBeenCalledTimes(0); +// spy.mockRestore(); +// } +// }; +// } From f3766d6d7479ad26b65402c64b6a433986535060 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 3 Sep 2023 14:52:04 +1000 Subject: [PATCH 048/169] chore: Update dependencies --- bun.lockb | Bin 121852 -> 122284 bytes package.json | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bun.lockb b/bun.lockb index 4dceb9e08825bd68fe785018e268aa930d14c2ca..52e587b61895f09bec6c7f15d7fca472c859ad6a 100755 GIT binary patch delta 25737 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 delta 25373 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 diff --git a/package.json b/package.json index b657195..0a1ffe4 100644 --- a/package.json +++ b/package.json @@ -54,19 +54,19 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.36.2", - "@typescript-eslint/eslint-plugin": "6.2.1", - "@typescript-eslint/parser": "6.2.1", - "bun-types": "0.7.3", - "eslint": "8.46.0", + "@playwright/test": "1.37.1", + "@typescript-eslint/eslint-plugin": "6.5.0", + "@typescript-eslint/parser": "6.5.0", + "bun-types": "0.8.1", + "eslint": "8.48.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "9.0.0", - "eslint-plugin-import": "2.28.0", + "eslint-plugin-import": "2.28.1", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "10.8.0", - "prettier": "3.0.1", - "typescript": "5.1.6" + "happy-dom": "10.11.2", + "prettier": "3.0.3", + "typescript": "5.2.2" } } From 685a1835a4d1251fdf461c86c18c05d2f2c41e3c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 3 Sep 2023 14:52:19 +1000 Subject: [PATCH 049/169] chore: Tweak lint rules --- .eslintrc.cjs | 4 +++- test/unit/macro.test.ts | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2c810f5..5c8c6f1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -39,9 +39,11 @@ module.exports = { // byte savings '@typescript-eslint/no-confusing-void-expression': OFF, // worse performance - '@typescript-eslint/prefer-string-starts-ends-with': OFF, + '@typescript-eslint/prefer-includes': OFF, // worse performance '@typescript-eslint/prefer-for-of': OFF, + // worse performance + '@typescript-eslint/prefer-string-starts-ends-with': OFF, // void return can be used for efficient code (if used safely!) 'consistent-return': WARN, // useful for compact and memory efficient code... but be careful! diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index 57aa6b8..c160b67 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -8,6 +8,9 @@ import { compile as compileNoMacro } from '../../src/runtime/macro'; // TODO: Consider using inline snapshots once bun:test supports them. +// TODO: Test not text ref when text includes whitespace +// TODO: Test not text ref when text has escapsed @ character (e.g. \@) + describe('compile', () => { // FIXME: Test for each of the compile macro options; keepComments, keepSpace // ↳ When keepComments, check refs metadata calculations are still correct. From 969f65abd756db7058f07728f8a13da5e0885144 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 7 Sep 2023 06:51:55 +1000 Subject: [PATCH 050/169] chore: Update dependencies --- bun.lockb | Bin 122284 -> 122316 bytes package.json | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 52e587b61895f09bec6c7f15d7fca472c859ad6a..1e4c05cbd683fede77839a014605494b7754feb0 100755 GIT binary patch delta 6630 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 todY8l)&v&ds$Sd#$7t_TW<{5)>bzX0|cavuNy diff --git a/package.json b/package.json index 0a1ffe4..455bafd 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ }, "devDependencies": { "@playwright/test": "1.37.1", - "@typescript-eslint/eslint-plugin": "6.5.0", - "@typescript-eslint/parser": "6.5.0", + "@typescript-eslint/eslint-plugin": "6.6.0", + "@typescript-eslint/parser": "6.6.0", "bun-types": "0.8.1", "eslint": "8.48.0", "eslint-config-airbnb-base": "15.0.0", @@ -65,7 +65,7 @@ "eslint-plugin-import": "2.28.1", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "10.11.2", + "happy-dom": "11.0.1", "prettier": "3.0.3", "typescript": "5.2.2" } From 8cbf23b5c7547fe14966b2f9ad538abe3ad74e46 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 2 Oct 2023 12:43:19 +1100 Subject: [PATCH 051/169] chore: Update dependencies --- bun.lockb | Bin 122316 -> 123229 bytes package.json | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bun.lockb b/bun.lockb index 1e4c05cbd683fede77839a014605494b7754feb0..f36f055b6d87881bd12b1accbead8d2b34d7e7a5 100755 GIT binary patch delta 13871 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 delta 16263 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 ZTjNvNg-E;Eo=sFZ-V2z2B&{9Pu@0qF9U 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 diff --git a/package.json b/package.json index 455bafd..d71e97f 100644 --- a/package.json +++ b/package.json @@ -54,18 +54,18 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.37.1", - "@typescript-eslint/eslint-plugin": "6.6.0", - "@typescript-eslint/parser": "6.6.0", - "bun-types": "0.8.1", - "eslint": "8.48.0", + "@playwright/test": "1.38.1", + "@typescript-eslint/eslint-plugin": "6.7.3", + "@typescript-eslint/parser": "6.7.3", + "bun-types": "1.0.3", + "eslint": "8.50.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-import": "2.28.1", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "11.0.1", + "happy-dom": "12.1.2", "prettier": "3.0.3", "typescript": "5.2.2" } From 49638e1fa466a56e111ff46eeded8b21ad76e0df Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 2 Oct 2023 12:45:35 +1100 Subject: [PATCH 052/169] chore: Remove unnecessary TS ignore comment --- test/unit/macro.test.ts | 4 +--- test/unit/test-utils.test.ts | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index c160b67..a635682 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -98,9 +98,7 @@ describe('compile', () => { }); test('logs error when more than one root element', () => { - const spy = spyOn(console, 'error') - // @ts-expect-error - noop stub - .mockImplementation(() => {}); + const spy = spyOn(console, 'error').mockImplementation(() => {}); compileNoMacro('
'); // TODO: Check for specific error message once bun:test supports it. // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); diff --git a/test/unit/test-utils.test.ts b/test/unit/test-utils.test.ts index 8b17bbd..5ff39c2 100644 --- a/test/unit/test-utils.test.ts +++ b/test/unit/test-utils.test.ts @@ -58,9 +58,7 @@ describe('render', () => { }); test('debug function prints to console', async () => { - const logSpy = spyOn(console, 'log') - // @ts-expect-error - noop mock - .mockImplementation(() => {}); + const logSpy = spyOn(console, 'log').mockImplementation(() => {}); const rendered = render(document.createElement('div')); await rendered.debug(); expect(logSpy).toHaveBeenCalledTimes(1); @@ -70,9 +68,7 @@ describe('render', () => { }); test('debug function prints prettified container DOM to console', async () => { - const logSpy = spyOn(console, 'log') - // @ts-expect-error - noop mock - .mockImplementation(() => {}); + const logSpy = spyOn(console, 'log').mockImplementation(() => {}); const main = document.createElement('main'); main.append( document.createElement('div'), From 2a53cacc1c21cd327d70448e13841e65f02d3373 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 8 Oct 2023 12:02:49 +1100 Subject: [PATCH 053/169] chore: Fix TypeScript module resolution value --- tsconfig.node.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.node.json b/tsconfig.node.json index 37fa35a..447dbc6 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "composite": true, - "moduleResolution": "node", + "moduleResolution": "node10", "allowSyntheticDefaultImports": true }, "include": [".eslintrc.cjs", "package.json"] From bfd6bad518234d1e8723f7b1a2ed2681f12d475c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 8 Oct 2023 12:03:21 +1100 Subject: [PATCH 054/169] chore: Update CI `actions/checkout` action to v4 --- .github/workflows/ci.yml | 6 +++--- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/semgrep-analysis.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bd250d..e6eaf2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v1 with: bun-version: latest @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v1 with: bun-version: latest @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v1 with: bun-version: latest diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b38123c..f2e0d9a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -15,7 +15,7 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: github/codeql-action/init@v2 with: languages: javascript diff --git a/.github/workflows/semgrep-analysis.yml b/.github/workflows/semgrep-analysis.yml index 730bff4..62ab8bf 100644 --- a/.github/workflows/semgrep-analysis.yml +++ b/.github/workflows/semgrep-analysis.yml @@ -17,7 +17,7 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: semgrep ci --sarif --output=semgrep.sarif || true env: SEMGREP_RULES: p/default From 36f41b3bbb16424d11cb61be3a8174b15eb3404c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 8 Oct 2023 12:03:37 +1100 Subject: [PATCH 055/169] chore: Update dependencies --- bun.lockb | Bin 123229 -> 123197 bytes package.json | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lockb b/bun.lockb index f36f055b6d87881bd12b1accbead8d2b34d7e7a5..18f5e0725caca6af88b926523e4db679576654e8 100755 GIT binary patch delta 13895 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 BS8D(O diff --git a/package.json b/package.json index d71e97f..c1b3eb4 100644 --- a/package.json +++ b/package.json @@ -55,17 +55,17 @@ }, "devDependencies": { "@playwright/test": "1.38.1", - "@typescript-eslint/eslint-plugin": "6.7.3", - "@typescript-eslint/parser": "6.7.3", - "bun-types": "1.0.3", - "eslint": "8.50.0", + "@typescript-eslint/eslint-plugin": "6.7.4", + "@typescript-eslint/parser": "6.7.4", + "bun-types": "1.0.4", + "eslint": "8.51.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-import": "2.28.1", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "12.1.2", + "happy-dom": "12.9.0", "prettier": "3.0.3", "typescript": "5.2.2" } From 0da56f6a5279852e44871c268b6aa70e3816b3f3 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sun, 8 Oct 2023 12:04:05 +1100 Subject: [PATCH 056/169] test: Uncommend skipped tests now that happy-dom supports then --- test/unit/utils.test.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index 7f5c8ac..df94fba 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -302,11 +302,7 @@ describe('onRemove', () => { expect(onRemove).toHaveLength(2); }); - // FIXME: Don't skip these tests. Currently happy-dom doesn't support the 2nd - // parameter in MutationObserver callbacks. Open an issue! - - // TODO: Don't skip this test. - test.skip('calls callback when watched element is removed', () => { + test('calls callback when watched element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); document.body.appendChild(root); @@ -315,8 +311,7 @@ describe('onRemove', () => { expect(spy).toHaveBeenCalledTimes(1); }); - // TODO: Don't skip this test. - test.skip('calls callback when parent parent element is removed', () => { + test('calls callback when parent parent element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); const parent = document.createElement('div'); @@ -329,8 +324,7 @@ describe('onRemove', () => { expect(spy).toHaveBeenCalledTimes(1); }); - // TODO: Don't skip this test. - test.skip('does not call callback when nested child element is removed', () => { + test('does not call callback when nested child element is removed', () => { const spy = mock(() => {}); const root = document.createElement('div'); const child = document.createElement('div'); @@ -341,8 +335,7 @@ describe('onRemove', () => { expect(spy).not.toHaveBeenCalled(); }); - // TODO: Don't skip this test. - test.skip('does not call callback when element is added or moved', () => { + test('does not call callback when element is added or moved', () => { const spy = mock(() => {}); const root = document.createElement('div'); const child = document.createElement('div'); From eb5e17bbacc93823d7c44194b5fe08b73d8b122c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 18:49:53 +1100 Subject: [PATCH 057/169] chore: Update dependencies --- bun.lockb | Bin 123197 -> 123763 bytes package.json | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bun.lockb b/bun.lockb index 18f5e0725caca6af88b926523e4db679576654e8..1ef4f881072f9938ddd034512d882e81ef1b0ff6 100755 GIT binary patch delta 30587 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 delta 29843 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 diff --git a/package.json b/package.json index c1b3eb4..51826ac 100644 --- a/package.json +++ b/package.json @@ -54,19 +54,19 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.38.1", - "@typescript-eslint/eslint-plugin": "6.7.4", - "@typescript-eslint/parser": "6.7.4", - "bun-types": "1.0.4", - "eslint": "8.51.0", + "@playwright/test": "1.40.1", + "@typescript-eslint/eslint-plugin": "6.14.0", + "@typescript-eslint/parser": "6.14.0", + "bun-types": "1.0.18", + "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", - "eslint-config-prettier": "9.0.0", - "eslint-plugin-import": "2.28.1", - "eslint-plugin-prettier": "5.0.0", - "eslint-plugin-unicorn": "48.0.1", - "happy-dom": "12.9.0", - "prettier": "3.0.3", - "typescript": "5.2.2" + "eslint-config-prettier": "9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-prettier": "5.0.1", + "eslint-plugin-unicorn": "49.0.0", + "happy-dom": "12.10.3", + "prettier": "3.1.1", + "typescript": "5.3.3" } } From fb72312b54e864a2fbe6c39ce9d9f35af9d76940 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 18:50:46 +1100 Subject: [PATCH 058/169] chore: Update VS Code settings --- .vscode/launch.json | 21 +++++++++++++++++++++ .vscode/settings.json | 14 ++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..82ec167 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Bun", + "type": "bun", + "request": "attach", + // use `bun --inspect` to open a debug port + "url": "ws://localhost:6499/" + }, + { + "name": "bun test ", + "type": "bun", + "request": "launch", + "runtimeArgs": ["test", "--preload", "${workspaceFolder}/test/setup.ts"], + "program": "${file}", + "internalConsoleOptions": "openOnSessionStart" + } + // TODO: Add a way to run all tests + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 2403de4..1de004a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnPaste": false, @@ -11,16 +11,10 @@ "js/ts.implicitProjectConfig.checkJs": true, "prettier.ignorePath": ".gitignore", "typescript.tsdk": "node_modules/typescript/lib", - "[javascript]": { + "[javascript][typescript]": { "editor.codeActionsOnSave": { - "source.sortImports": true, - "source.fixAll": true - } - }, - "[typescript]": { - "editor.codeActionsOnSave": { - "source.sortImports": true, - "source.fixAll": true + "source.sortImports": "explicit", + "source.fixAll": "explicit" } } } From 71f59822b9ae9f990b67ab252bbad25774aa2d68 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 18:52:08 +1100 Subject: [PATCH 059/169] feat: Add support for comments as refs --- src/runtime/macro.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index c27f8fe..465aa2a 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,6 +1,7 @@ export interface CompileOptions { /** - * Whether to keep HTML comments in output HTML. + * Whether to keep HTML comments in output HTML. When keepComments is true, + * comments can be used as refs. * @default false */ keepComments?: boolean; @@ -20,9 +21,6 @@ export interface CompileOptions { */ export async function compile( template: string, - // FIXME: Actually using objects in macro arguments is broken in bun. - // ↳ https://github.com/oven-sh/bun/issues/3832 - // ↳ Add to documentation if it's not resolved by the time we write proper docs { keepComments, keepSpaces }: CompileOptions = {}, // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { @@ -68,7 +66,7 @@ export async function compile( distance++; }, // This text handler is invoked twice for each Text node: first with the - // actual text, then with an empty last chunk. This behavior stems from + // actual text, then with an empty last chunk. This behaviour stems from // the fact that the Response provided to HTMLRewriter.transform() is not // streamed; otherwise, there could be multiple chunks before the last one. text(chunk) { @@ -97,7 +95,20 @@ export async function compile( }, comments(node) { if (keepComments) { - // TODO: Support comments as node refs once bun issue #3832 is fixed. + // TODO: Add documentation that the build/runtime mode also supports + // using comments as refs. Requires the keepComments option to be true. + const text = node.text.trim(); + if (text[0] === '@') { + k.push(text.slice(1)); + d.push(distance); + distance = 0; + // TODO: Use empty comment once lol-html supports it (less alloc than node.replace) + // node.text = ''; + // TODO: use node.replace() once lol-html fixes it for comments + // node.replace('', { html: true }); + node.remove(); + node.after('', { html: true }); + } distance++; } else { node.remove(); From bb6c31f2b339cd057cee815e79f7ca45b046ed87 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 18:52:44 +1100 Subject: [PATCH 060/169] feat: Minor name tweaks and comments --- src/runtime/macro.ts | 7 +++++++ src/runtime/runtime.ts | 16 +++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index 465aa2a..4e7abdd 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,3 +1,10 @@ +// TODO: It would be great if the compile macro could also minify the HTML +// beyond just whitespace. However it seems to not be possible with lol-html. +// ↳ Remove quotes around attributes with no spaces or special characters +// ↳ Make all quotes consistent (but be careful with embedded JS/CSS etc.) +// ↳ Remove unnecessary closing tags +// ↳ Convert tags to self-closing when possible + export interface CompileOptions { /** * Whether to keep HTML comments in output HTML. When keepComments is true, diff --git a/src/runtime/runtime.ts b/src/runtime/runtime.ts index 2e129e2..f6540ec 100644 --- a/src/runtime/runtime.ts +++ b/src/runtime/runtime.ts @@ -1,18 +1,16 @@ import type { LowercaseKeys, Refs } from '../types'; import { create } from '../utils'; -const compilerTemplate = create('template'); -const treeWalker = document.createTreeWalker(compilerTemplate); +const template = create('template'); +const treeWalker = document.createTreeWalker(template); /** * Creates a DOM node from a compiled template. - * @param template - HTML template string. + * @param html - HTML string. */ -export const h = ( - template: string, -): T => { - compilerTemplate.innerHTML = template; - return compilerTemplate.content.firstChild as T; +export const h = (html: string): T => { + template.innerHTML = html; + return template.content.firstChild as T; }; /** @@ -29,7 +27,7 @@ export const collect = ( k: readonly string[], d: readonly number[], ): LowercaseKeys => { - const walker = treeWalker; + const walker = treeWalker; // local var is faster in some JS engines const refs: Refs = {}; const len = k.length; let index = 0; From b090da1737f11610cf0914aac6d494af978a7d2d Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 18:53:39 +1100 Subject: [PATCH 061/169] test: Add and improve many tests --- test/unit/compile.test.ts | 21 ++- test/unit/exports.test.ts | 2 +- test/unit/macro.test.ts | 134 ++++++++++++++---- test/unit/runtime.test.ts | 256 ++++++++++++++++++++--------------- test/unit/store.test.ts | 22 ++- test/unit/test-utils.test.ts | 8 +- 6 files changed, 283 insertions(+), 160 deletions(-) diff --git a/test/unit/compile.test.ts b/test/unit/compile.test.ts index 1929d5b..bd58d9d 100644 --- a/test/unit/compile.test.ts +++ b/test/unit/compile.test.ts @@ -4,8 +4,6 @@ import { afterEach, describe, expect, test } from 'bun:test'; import { collect, h, html } from '../../src/compile'; import { cleanup, render } from './utils'; -// TODO: Consider using inline snapshots once bun:test supports them. - describe('h', () => { afterEach(cleanup); @@ -21,6 +19,21 @@ describe('h', () => { expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); }); + test('renders basic template with messy whitespace', () => { + const view = h(` +
    +
  • A
  • +
  • + B
  • +
  • C +
  • +
+ `); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); + }); + test('renders SVG template', () => { const view = h(` @@ -147,6 +160,7 @@ describe('collect', () => { expect(refs.r).toBeInstanceOf(window.HTMLElement); expect(refs.s.nodeName).toEqual('#text'); expect(refs.s).toBeInstanceOf(window.Text); + expect(Object.keys(refs)).toHaveLength(19); }); test('collects ref at start of element attributes', () => { @@ -159,6 +173,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); test('collects ref at end of element attributes', () => { @@ -171,6 +186,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); test('collects ref in middle of element attributes', () => { @@ -183,6 +199,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); // NOTE: The regular mode h() function does not support options like the diff --git a/test/unit/exports.test.ts b/test/unit/exports.test.ts index 117a696..e65426f 100644 --- a/test/unit/exports.test.ts +++ b/test/unit/exports.test.ts @@ -92,10 +92,10 @@ describe('macro', () => { test('does not export any private internals', () => { const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - expect(publicExportNames).toHaveLength(Object.keys(macroExports).length); for (const name in macroExports) { expect(publicExportNames).toContain(name); } + expect(publicExportNames).toHaveLength(Object.keys(macroExports).length); }); test('has no default export', () => { diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index a635682..58e0df6 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -6,11 +6,6 @@ import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; // eslint-disable-next-line import/no-duplicates import { compile as compileNoMacro } from '../../src/runtime/macro'; -// TODO: Consider using inline snapshots once bun:test supports them. - -// TODO: Test not text ref when text includes whitespace -// TODO: Test not text ref when text has escapsed @ character (e.g. \@) - describe('compile', () => { // FIXME: Test for each of the compile macro options; keepComments, keepSpace // ↳ When keepComments, check refs metadata calculations are still correct. @@ -49,10 +44,6 @@ describe('compile', () => { }); test('has 3 k and d properties when 3 node refs with whitespace', () => { - // FIXME: Whitespace handling is broken in happy-dom; https://github.com/capricorn86/happy-dom/issues/971 - // const meta = compile( - // '\n\n\t
\t\t\n\n\n
\n\n
\n', - // ); const meta = compile(`
@@ -64,6 +55,39 @@ describe('compile', () => { expect(meta.d).toHaveLength(3); }); + test('has 3 k and d properties when 3 node refs with messy whitespace', () => { + const meta = compile( + '\n\n\t
\t\t\n\n\n
\n\n
\n', + ); + expect(meta.k).toHaveLength(3); + expect(meta.d).toHaveLength(3); + }); + + test('has 1 k and d properties when 1 text ref', () => { + const meta = compile('
@a
'); + expect(meta.k).toHaveLength(1); + expect(meta.d).toHaveLength(1); + }); + + // TODO: Add documentation about this since it differs from the default compile.ts h() behaviour + test('has 1 k and d properties when 1 text ref with whitespace', () => { + const meta = compile(`
@a
`); + expect(meta.k).toHaveLength(1); + expect(meta.d).toHaveLength(1); + }); + + test('has empty k and d properties when escaped node ref', () => { + const meta = compile('
'); + expect(meta.k).toHaveLength(0); + expect(meta.d).toHaveLength(0); + }); + + test('has empty k and d properties when escaped text ref', () => { + const meta = compile('
\\@a
'); + expect(meta.k).toHaveLength(0); + expect(meta.d).toHaveLength(0); + }); + test('does not minify in whitespace-sensitive blocks', () => { const meta = compile(`
@@ -91,7 +115,7 @@ describe('compile', () => { ); }); - test('does not escape html entities', () => { + test('does not escape HTML entities', () => { const template = '
<span>Foo</span>
'; const meta = compile(template); expect(meta.html).toBe(template); @@ -99,48 +123,98 @@ describe('compile', () => { test('logs error when more than one root element', () => { const spy = spyOn(console, 'error').mockImplementation(() => {}); - compileNoMacro('
'); - // TODO: Check for specific error message once bun:test supports it. - // expect(spy).toHaveBeenCalledWith('Expected template to have a single root element'); + const template = '
'; + compileNoMacro(template); + expect(spy).toHaveBeenCalledWith('Expected template to have a single root element:', template); expect(spy).toHaveBeenCalledTimes(1); spy.mockRestore(); }); + test('returns expected html for basic template', () => { + const meta = compile(` +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ `); + expect(meta.html).toBe('
  • A
  • B
  • C
'); + }); + + // TODO: Test once lol-html (which powers bun's HTMLRewriter) fix their whitespace handling + test.skip('returns expected html for basic template with messy whitespace', () => { + const meta = compile(` +
    +
  • A
  • +
  • + B
  • +
  • C +
  • +
+ `); + expect(meta.html).toBe('
  • A
  • B
  • C
'); + }); + + test('returns expected html for SVG template', () => { + const meta = compile(` + + + + `); + expect(meta.html).toBe(``); + }); + describe('keepComments option', () => { test('removes comments by default', () => { const meta = compile('
'); expect(meta.html).toBe('
'); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('keeps comments when option is true', () => { - // const meta = compile('
', { keepComments: true }); - // expect(meta.html).toBe('
'); + test('keeps comments when option is true', () => { + const meta = compile('
', { keepComments: true }); + expect(meta.html).toBe('
'); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('removes comments when option is false', () => { - // const meta = compile('
', { keepComments: false }); - // expect(meta.html).toBe('
'); + test('removes comments when option is false', () => { + const meta = compile('
', { keepComments: false }); + expect(meta.html).toBe('
'); + }); + + test('has 1 k and d properties when 1 comment ref when option is true', () => { + const meta = compile('
', { keepComments: true }); + expect(meta.k).toHaveLength(1); + expect(meta.d).toHaveLength(1); + }); + + test('returns expected html for template with comment ref when option is true', () => { + const meta = compile('
', { keepComments: true }); + expect(meta.html).toBe('
'); }); }); describe('keepSpaces option', () => { test('removes spaces between tags and text by default', () => { - const meta = compile('
x \n\t\t
'); + const meta = compile( + '
x \f\n\r\t\v\u0020\u00A0\u1680\u2000\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF
', + ); expect(meta.html).toBe('
x
'); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('keeps spaces between tags and text when option is true', () => { - // const meta = compile('
x \n\t\t
', { keepSpaces: true }); - // expect(meta.html).toBe('
x
'); + test('keeps spaces between tags and text when option is true', () => { + const meta = compile( + '
x \f\n\r\t\v\u0020\u00A0\u1680\u2000\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF
', + { keepSpaces: true }, + ); + expect(meta.html).toBe('
x
'); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('removes spaces between tags and text when option is false', () => { - // const meta = compile('
x \n\t\t
', { keepSpaces: false }); - // expect(meta.html).toBe('
x
'); + test('removes spaces between tags and text when option is false', () => { + const meta = compile( + '
x \f\n\r\t\v\u0020\u00A0\u1680\u2000\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF
', + { keepSpaces: false }, + ); + expect(meta.html).toBe('
x
'); }); }); }); diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index fc8733b..3e30ba5 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -5,8 +5,6 @@ import { collect, h } from '../../src/runtime/index'; import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; import { cleanup, render } from './utils'; -// TODO: Consider using inline snapshots once bun:test supports them. - describe('h', () => { afterEach(cleanup); @@ -23,6 +21,22 @@ describe('h', () => { expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); }); + test('renders basic template with messy whitespace', () => { + const meta = compile(` +
    +
  • A
  • +
  • + B
  • +
  • C +
  • +
+ `); + const view = h(meta.html); + const rendered = render(view); + expect(rendered.container.innerHTML).toBe('
  • A
  • B
  • C
'); + }); + test('renders SVG template', () => { const meta = compile(` @@ -182,6 +196,7 @@ describe('collect', () => { expect(refs.r).toBeInstanceOf(window.HTMLElement); expect(refs.s.nodeName).toEqual('#text'); expect(refs.s).toBeInstanceOf(window.Text); + expect(Object.keys(refs)).toHaveLength(19); }); test('collects ref at start of element attributes', () => { @@ -195,6 +210,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); test('collects ref at end of element attributes', () => { @@ -208,6 +224,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); test('collects ref in middle of element attributes', () => { @@ -221,6 +238,7 @@ describe('collect', () => { expect(refs.search).toBeInstanceOf(window.HTMLInputElement); expect(refs.search.id).toBe('search'); expect(refs.search.name).toBe('q'); + expect(Object.keys(refs)).toHaveLength(1); }); // TODO: Instead of repeating similar tests multiple times, we should create @@ -234,13 +252,13 @@ describe('collect', () => { @a - -
- - @c + +
+ @d + -
+
`); @@ -248,70 +266,85 @@ describe('collect', () => { const refs = collect(view, meta.k, meta.d); expect(refs.a.nodeName).toEqual('#text'); expect(refs.a).toBeInstanceOf(window.Text); - expect(refs.b.nodeName).toEqual('DIV'); - expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - expect(refs.c.nodeName).toEqual('#text'); - expect(refs.c).toBeInstanceOf(window.Text); + expect(refs.b).toBeUndefined(); + expect(refs.c.nodeName).toEqual('DIV'); + expect(refs.c).toBeInstanceOf(window.HTMLDivElement); + expect(refs.d.nodeName).toEqual('#text'); + expect(refs.d).toBeInstanceOf(window.Text); + expect(refs.e).toBeUndefined(); + expect(refs.f.nodeName).toEqual('DIV'); + expect(refs.f).toBeInstanceOf(window.HTMLDivElement); + expect(Object.keys(refs)).toHaveLength(4); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('collects refs when option is true', () => { - // const meta = compile( - // ` - //
- // - // @a - // - // - //
- // - // @c - // - // - //
- //
- //
- // `, - // { keepComments: true }, - // ); - // const view = h(meta.html); - // const refs = collect(view, meta.k, meta.d); - // expect(refs.a.nodeName).toEqual('#text'); - // expect(refs.a).toBeInstanceOf(window.Text); - // expect(refs.b.nodeName).toEqual('DIV'); - // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - // expect(refs.c.nodeName).toEqual('#text'); - // expect(refs.c).toBeInstanceOf(window.Text); + test('collects refs when option is true', () => { + const meta = compile( + ` +
+ + @a + + +
+ + @d + + +
+
+
+ `, + { keepComments: true }, + ); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b.nodeName).toEqual('#comment'); + expect(refs.b).toBeInstanceOf(window.Comment); + expect(refs.c.nodeName).toEqual('DIV'); + expect(refs.c).toBeInstanceOf(window.HTMLDivElement); + expect(refs.d.nodeName).toEqual('#text'); + expect(refs.d).toBeInstanceOf(window.Text); + expect(refs.e.nodeName).toEqual('#comment'); + expect(refs.e).toBeInstanceOf(window.Comment); + expect(refs.f.nodeName).toEqual('DIV'); + expect(refs.f).toBeInstanceOf(window.HTMLDivElement); + expect(Object.keys(refs)).toHaveLength(6); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('collects refs when option is false', () => { - // const meta = compile( - // ` - //
- // - // @a - // - // - //
- // - // @c - // - // - //
- //
- //
- // `, - // { keepComments: false }, - // ); - // const view = h(meta.html); - // const refs = collect(view, meta.k, meta.d); - // expect(refs.a.nodeName).toEqual('#text'); - // expect(refs.a).toBeInstanceOf(window.Text); - // expect(refs.b.nodeName).toEqual('DIV'); - // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - // expect(refs.c.nodeName).toEqual('#text'); - // expect(refs.c).toBeInstanceOf(window.Text); + test('collects refs when option is false', () => { + const meta = compile( + ` +
+ + @a + + +
+ + @d + + +
+
+
+ `, + { keepComments: false }, + ); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b).toBeUndefined(); + expect(refs.c.nodeName).toEqual('DIV'); + expect(refs.c).toBeInstanceOf(window.HTMLDivElement); + expect(refs.d.nodeName).toEqual('#text'); + expect(refs.d).toBeInstanceOf(window.Text); + expect(refs.e).toBeUndefined(); + expect(refs.f.nodeName).toEqual('DIV'); + expect(refs.f).toBeInstanceOf(window.HTMLDivElement); + expect(Object.keys(refs)).toHaveLength(4); }); }); @@ -334,54 +367,55 @@ describe('collect', () => { expect(refs.b).toBeInstanceOf(window.HTMLDivElement); expect(refs.c.nodeName).toEqual('#text'); expect(refs.c).toBeInstanceOf(window.Text); + expect(Object.keys(refs)).toHaveLength(4); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('collects refs when option is true', () => { - // const meta = compile( - // ` - //
- // @a - //
- // @c - //
- //
- //
- // `, - // { keepSpaces: true }, - // ); - // const view = h(meta.html); - // const refs = collect(view, meta.k, meta.d); - // expect(refs.a.nodeName).toEqual('#text'); - // expect(refs.a).toBeInstanceOf(window.Text); - // expect(refs.b.nodeName).toEqual('DIV'); - // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - // expect(refs.c.nodeName).toEqual('#text'); - // expect(refs.c).toBeInstanceOf(window.Text); + test('collects refs when option is true', () => { + const meta = compile( + ` +
+ @a +
+ @c +
+
+
+ `, + { keepSpaces: true }, + ); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b.nodeName).toEqual('DIV'); + expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + expect(refs.c.nodeName).toEqual('#text'); + expect(refs.c).toBeInstanceOf(window.Text); + expect(Object.keys(refs)).toHaveLength(4); }); - // TODO: This test is currently blocked by bun bug; https://github.com/oven-sh/bun/issues/3832 - test.todo('collects refs when option is false', () => { - // const meta = compile( - // ` - //
- // @a - //
- // @c - //
- //
- //
- // `, - // { keepSpaces: false }, - // ); - // const view = h(meta.html); - // const refs = collect(view, meta.k, meta.d); - // expect(refs.a.nodeName).toEqual('#text'); - // expect(refs.a).toBeInstanceOf(window.Text); - // expect(refs.b.nodeName).toEqual('DIV'); - // expect(refs.b).toBeInstanceOf(window.HTMLDivElement); - // expect(refs.c.nodeName).toEqual('#text'); - // expect(refs.c).toBeInstanceOf(window.Text); + test('collects refs when option is false', () => { + const meta = compile( + ` +
+ @a +
+ @c +
+
+
+ `, + { keepSpaces: false }, + ); + const view = h(meta.html); + const refs = collect(view, meta.k, meta.d); + expect(refs.a.nodeName).toEqual('#text'); + expect(refs.a).toBeInstanceOf(window.Text); + expect(refs.b.nodeName).toEqual('DIV'); + expect(refs.b).toBeInstanceOf(window.HTMLDivElement); + expect(refs.c.nodeName).toEqual('#text'); + expect(refs.c).toBeInstanceOf(window.Text); + expect(Object.keys(refs)).toHaveLength(4); }); }); }); diff --git a/test/unit/store.test.ts b/test/unit/store.test.ts index 782063f..99840e9 100644 --- a/test/unit/store.test.ts +++ b/test/unit/store.test.ts @@ -89,12 +89,11 @@ describe('store', () => { const callback = mock(() => {}); state.on('a', callback); state.a = 1; - // TODO: Uncomment once bun:test mocks support toHaveBeenCalledWith() - // expect(callback).toHaveBeenCalledWith(1, 0); + expect(callback).toHaveBeenCalledWith(1, 0); state.a = 2; - // expect(callback).toHaveBeenCalledWith(2, 1); + expect(callback).toHaveBeenCalledWith(2, 1); state.a = 3; - // expect(callback).toHaveBeenCalledWith(3, 2); + expect(callback).toHaveBeenCalledWith(3, 2); expect(callback).toHaveBeenCalledTimes(3); }); @@ -111,14 +110,13 @@ describe('store', () => { expect(callback).toHaveBeenCalledTimes(1); // still called only once }); - // TODO: Don't skip once bun:test mocks support toHaveBeenCalledWith() - test.todo('calls callback with new value and previous value', () => { - // const initialState = { a: 'old' }; - // const state = store(initialState); - // const callback = mock(() => {}); - // state.on('a', callback); - // state.a = 'new'; - // expect(callback).toHaveBeenCalledWith('new', 'old'); + test('calls callback with new value and previous value', () => { + const initialState = { a: 'old' }; + const state = store(initialState); + const callback = mock(() => {}); + state.on('a', callback); + state.a = 'new'; + expect(callback).toHaveBeenCalledWith('new', 'old'); }); test('calls all callbacks for mutated property', () => { diff --git a/test/unit/test-utils.test.ts b/test/unit/test-utils.test.ts index 5ff39c2..db8382e 100644 --- a/test/unit/test-utils.test.ts +++ b/test/unit/test-utils.test.ts @@ -62,8 +62,7 @@ describe('render', () => { const rendered = render(document.createElement('div')); await rendered.debug(); expect(logSpy).toHaveBeenCalledTimes(1); - // TODO: Use this once bun:test supports it. - // expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n'); + expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n'); logSpy.mockRestore(); }); @@ -78,8 +77,9 @@ describe('render', () => { const rendered = render(main); await rendered.debug(); expect(logSpy).toHaveBeenCalledTimes(1); - // TODO: Use this once bun:test supports it. - // expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n
\n
\n
\n
\n'); + expect(logSpy).toHaveBeenCalledWith( + 'DEBUG:\n
\n
\n
\n
\n
\n', + ); logSpy.mockRestore(); }); From cc137396c8090d60aa6f03cea04af653919148db Mon Sep 17 00:00:00 2001 From: Max Milton Date: Mon, 18 Dec 2023 19:20:19 +1100 Subject: [PATCH 062/169] test: Improve test utils --- test/setup.ts | 3 --- test/unit/utils.ts | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/setup.ts b/test/setup.ts index e585dc9..5e7f022 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -5,9 +5,6 @@ declare global { var happyDOM: Window['happyDOM']; } -// Increase stack limit from 10 (v8 default) -global.Error.stackTraceLimit = 50; - function setupDOM() { const dom = new GlobalWindow({ url: 'chrome-extension://cpcibnbdmpmcmnkhoiilpnlaepkepknb/', diff --git a/test/unit/utils.ts b/test/unit/utils.ts index f2fc1e4..ab48b13 100644 --- a/test/unit/utils.ts +++ b/test/unit/utils.ts @@ -8,9 +8,9 @@ export interface RenderResult { * prettified and may not accurately represent your actual HTML. It's intended * for debugging tests only and should not be used in any assertions. * - * @param el - An element to inspect. Default is the mounted container. + * @param element - An element to inspect. Default is the mounted container. */ - debug(el?: Element): Promise; + debug(element?: Element): Promise; unmount(): void; } @@ -55,10 +55,11 @@ export function cleanup(): void { } // TODO: Remove if unused. + // const consoleMethods = Object.getOwnPropertyNames( // window.console, // ) as (keyof Console)[]; - +// // export function consoleSpy(): () => void { // const spies: Mock<() => void>[] = []; // From 85e1852624ff930bd2baa2daaf84b9a4e5f9b8c8 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 26 Dec 2023 08:54:44 +1100 Subject: [PATCH 063/169] chore: Switch to @types/bun + package.json#overrides + update TS config --- package.json | 9 ++++++--- tsconfig.json | 15 +++++++++------ tsconfig.node.json | 5 ++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 51826ac..3a90746 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "scripts": { "build": "bun build.ts", "lint": "bun run lint:js && bun run lint:ts", - "lint:js": "eslint --ignore-path .gitignore --ignore-pattern bench --ext .ts,.js,.mjs,.cjs .", + "lint:js": "eslint --ignore-path .gitignore --ignore-pattern bench --ext .ts,.mjs,.js,.cjs .", "lint:ts": "tsc --noEmit", "postbuild": "tsc --project ./tsconfig.d.json", "prebuild": "rm -rf dist", @@ -55,8 +55,8 @@ }, "devDependencies": { "@playwright/test": "1.40.1", - "@typescript-eslint/eslint-plugin": "6.14.0", - "@typescript-eslint/parser": "6.14.0", + "@types/bun": "1.0.0", + "@typescript-eslint/eslint-plugin": "6.16.0", "bun-types": "1.0.18", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", @@ -68,5 +68,8 @@ "happy-dom": "12.10.3", "prettier": "3.1.1", "typescript": "5.3.3" + }, + "overrides": { + "bun-types": "1.0.20" } } diff --git a/tsconfig.json b/tsconfig.json index 8801de2..db058ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,13 +16,16 @@ "noImplicitOverride": true, "noUnusedLocals": false, // covered by eslint "noUnusedParameters": false, // covered by eslint - "verbatimModuleSyntax": true, + "verbatimModuleSyntax": true - "types": [ - "bun-types", - "./node_modules/typescript/lib/lib.esnext.full.d.ts" // workaround for bun-types breaking dom types - ] + // TODO: Remove once @types/bun pulls in bun-types v1.0.19+ (but it + // currently depends on in v1.0.18); when @types/bun releases new version. + // ↳ Also remember to remove bun-types from package.json#overrides too! + // "types": [ + // "bun-types", + // "./node_modules/typescript/lib/lib.esnext.full.d.ts" // workaround for bun-types breaking dom types + // ] }, - "include": ["src", "test", "build.ts", "playwright.config.ts"], + "include": ["src", "test", "build.ts", "*.config.ts"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/tsconfig.node.json b/tsconfig.node.json index 447dbc6..f4cd66d 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -5,5 +5,8 @@ "moduleResolution": "node10", "allowSyntheticDefaultImports": true }, - "include": [".eslintrc.cjs", "package.json"] + "include": [ + ".eslintrc.cjs", + "package.json" // included in package.json#exports + ] } From 797c17523410d34ab9f47fb97b90035fa6180f0c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 26 Dec 2023 08:55:40 +1100 Subject: [PATCH 064/169] chore: Update dependencies --- bun.lockb | Bin 123763 -> 128538 bytes package.json | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 1ef4f881072f9938ddd034512d882e81ef1b0ff6..5a304af8765b1c7ac000de6dba15cfa0b88999a6 100755 GIT binary patch delta 25879 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 delta 23093 zcmeHvcUV+c6Zf8lRW6EvN)rT8tO!zF5M==?uAmqZH8#KnQ3M3+CSVs!6pwmiOwkyP zEp|l|djmW6-Zds_gs6!omhU&WC^7MUzxVmRKXV^v=ggcrb7tnunS1vxo-ZC&esZw# zZ12XROOs(UX6UA_e)wIr)ux+YHQ)Z_h|6V$V?)!cu`PxBeQw`k8oFBM$GPPk4U!3s zCM!EW+2pIy+((zCMw6S7Y0Az{F=bu{Er5OkL2KYU3N8jFxl3A&rYi6$(A9xWY1t_l zm$g&rKaBBq#Lr4iNz2w~=2eo%O(&d#4u{GzW1P})5VQ^Wsixs+7^^8#`WGm839u9T z2bfG5UMX3cOpGJLQh>?OgZLo239KUnUGPy2xDWct&>-OYz=N{9M&-m0N!7$>CTGNF zW|^9xg9KBuypmJX6EwXcO$yw=uR{FfwDe4qMq>|}CL*Eu)GWPo3=X3C^?*Y$A8kHq04?5K!M>)2QJT z1y{tD=%m#6>}=Bj%|nbKFHKp)vQuD$DQoC3Q|2g5=NhunrYtNVjJ*gsuyRZAK}N?X zre~%>-!bqh8f7(Qej#Wya|fg+W@o0P@m*S5wuYB#9fUZ0C7!%o>)`&2gB+xR@mXH5 zCHXdJvTKW@MuRxy>Ud)_H>bH+AksD(xE8Po?GVhJ!sE>xa-yAOo7`Mv8wLZDFV?`c z@+pvZ1&#)WXztS58V$N~+kmD82>>QJ4k7Yw3NZN+?k3{^V6x=|F!}5ZdCHiN%_Y4# zxyR6;0T%AE!YtE};igQDW)^4~Fe*MZH6<%svlnvY+@LH|Rw9B{pwO!otgd{fDSm)g z#^7X?-ce81JJ>^`vBmgkVEB-0%FIm9^vW@f>|bA2+)5Eh92lQE7!$l7U3FFd7G=0Y zk$40>6p0rNWy6DESY6QH!vHK>u6<)Ua$f_}Cal>6^5nS=4GQ@j&U6mp(>*mB#42|j zFsaP~rk#LAP9K46InY!N=QPZHF{82MKl=sxRvcV(vs3Oo8UMZ`@4_aAB8GJl_U(9WPk4B+Y|#6Le8>QK!gupcM6s~TW>;{aSlgjh09x}ZQm<-qn>;WwF zf;FCTe zDVFQ|${|b2G7ZObOjck&IaIN&OY=OZwA^^e(n-hb*f<8g7&)Q*cKxrNihl}NJ#5{z zhoOD7MQ0vcT%X)6Ezj%Im*?7jb9Lpn4%?rnm-v|Gc1gaUmDl0*rllTZH+HePVaCI1 zcHpyX*0C7#F!|Wj>JRGj8#M=NUu$?ryHM7V=h+$9cwS;>5VTs22Kk+9#%=59g$@d( zC5nB<^Xv`m9xt&s2o20Mnof|bEcImaNCyL3$@3fx!aekSgdSh&(cUxXmX4w98y@Ls z5H4fOqZ;H^;-wCH!5t4(MCpiPeYoIcVCQ%wK3#bpKBIXFKBsY^mVq7Qk@&RXd9@5e zJA{u+WW3Z#FU$bd0+bmqwb!$=Jkr@91Rw`VvqsXK!AqPCY!eq;48l|NWXfYPXEx6R zZzYyB2t2JMeTxgV;T{T0bMVZ$ZEd}f1d8-&dA^-q_bsSUKC@N`yTJulgHRL8P8LY^ z!0J3#1DnN5&~q3)NI>$}Sua>15lN?x$LNEIpe{^+IL}e2N>VgWa-ohvu)u~PaWkIZ zA&3YP*YJE7y)Xq7YKR<1-9=C>xm9pW3*=;gGy>DHNS^0z5axnMqA(62zXHlfrkwP; zs;CJ8{FrkH3*&ip4Z=v!6bQy+5ZHB~Xi6rn<1eOx<}wO<;Uzp1SfmhE~F!7&jsZNS*$4HzTquJ zp}qr(vPVj3L672r+9Ye$j&k7B>_Ub0VA61NN-5zbs5YP~^B70H5auYGA+Os=P|7O8 z;C-M-nUqL^HFi5C4deN>^vuZfniz!T;L!@1^L!^gyTS!egRW*RxXEWag$M)C>Mf0@ zMcxgnvos#_GHWh0H3;!2e*Ut~PI_T3sOB)CFe z=VcJyfQM=cyJ!i!alzXl>_Nps370L`R(GX6E3|i&RUzwZ>2=FMMe~_xmS0(X;A2(#IftTt}nnD#_FCEe1uS<#JQqT@4u}>&Kud zSO|PQz3@3G(j{#X;S?xxU7odiU5&;7O2cD(^g=ICw0xl8;6k3~XAmxdM+;S%=f?+e z!QUWsttT%eb|b=ji06UFJmmRh-dHXK7<320OW;_nl+F!25R6&7AP7fySNGzB{h_I>4iT*krMRP(hI?OqK=UIY!R9< zpjyh5hn^L1L67R(=ydZ-x zq{-V2faTi=N?rhjLHnu+?-(3Pii1%XJvEvn*#Jyt!-W^9FbMfg<&}~5&?!)g z*^Lp~5CiMQBSQ?@&0c((OQ`OF7kuPabwY&3-s;|osS{)Yf>sbZV1@{a)(lQyla+v? zwYHFoqggY#4^Ch=2ZHK|J~?EcfodmH&~gS8St4hJJt`f!CKWKN?x1Ks+?_N6XLg=E z%+5lX0WJkkx(C^s`^q7=fDD|H4Q7g+Pd;604`Z;mZ$)g$nL4T(;fT zMX&n^%^)5X7$SU)ma>4TJC{IVvRpx`;4QI>DYs>RM}Z=L5euZjMo`hxBvh{$#HdeB zpAb+~&Sh!>DDqzR_a3NsiRKz8TP2sRWuQo>JnktdCGA@11wVv^A|vmtfoPHzS?3~9 z6hob4^^L#uIqKy;ISYD#dS~YxP|8YpVqHK{B;@pl2pvXbl*g{amvGkgX$*rQMA{AYDdp0 zI(y`PS853h(NZ+m)$7g@#jRR|=&U2LL8v9fp+$uPrXvd$gL)@_8C0mG(Fr1*cvM#d zuiCApuoBd}@N0|}sqUaCZKW{jz6I4=n(;MS9l2Gl5TOIQ<DptO2Fii$|vCpqlfUULiVfgsdB%=@24tv`7Nkiuwtni#*s}FNAki z_giUGJS&01azJrR3%#xwR7=TOa}4Olqw2P_K!eJN{D8Cw6eWOMVDEvVT_8UN2H>#( zDMU8nev%D}l3Y%Xb)e)`Lb7VjyYgwhLUp~m(qd6K)}V#-p`lp(UqMm$q$zcwA89mw zrG@+wEjbM+F_LxF+2o$+0-O~k&kLA3U%XI`O%0MX$R=J=k41b;f+&^+h^pXQI5p7%*7;kABfCZGUikR_Z$$DOOphXUu0N169FpYqV67H|ycwo8+ zQ$NyBLk}h5DsqI$fNX^(O#Q6BIlV zm@dNRfT;lL&jZkvrz(ESkol4TO)wom17;|E!o>d!K>S$%y8a21Lvy6wzhVKrg$lnd zHAvxC3WG2y{#v0cVv<_~p#H@Gx(G8qY>=De$#)V@qajSwf3MJl$^TUfO_=Dl3SAMC z_H_!MFwMFFK>9WVsDBH9t_oNSGpq(XMSzpc_wxH|atfGIu=6@EobtVRmIBBl)U1ivA0SB4cNbK<}t z*&fOO!qn`E51OEl!Y544z6wp46vhLSoC%n^k`#Ul5x59b{}5oBFB6!$vRIHgI)s@>kU3gPDertCVnM_u84_cfe$NSJ75do+L4N2ZD2B_E-)!<1WcZI zD*Y8PP0$p4>hf0ly|w(0q=bK;f#m4XvkzT_DOweueTYvq1umTkT)_W61IeMtlhM0} zBhVD8f1iP*F#P)rBOv)JIj6ApNampRgdpyZwa2ZG_XP9jf9$Y%6YBR!-v^= z+&p}^!;sxmHY6NP9(C|wkH>P{w(}-?RGD&9q_(0br0BJJly)aL3(`cdbY`{%h;^>yPo7U88iQ& z)9h0RS~ObGZ&H=ko6kl(EpOp^JLJYk+9s=O@K&20xz~@zs1+5}zHVo`zyFbseUDe( zwsY^9xe+mgHy`RY^l-l;cVGWjkA0U}6t>~!p;U`j)92i2?$!S67q9YqvJH)PdH)=H za+r3_^dtNcwC*S{vQ=Ez8poG!vEoCv8rcuLd{Z3nQDDUnfLhCK3*)%ORx3WN(8$*F zJ)pLNs=v+1Hu9m{;`qQqD}EN#X70W{jyrC%;*+);@gr#|sA5ooMMhT0#}&o#k=w2K z-6CU@`UZoXF<-~OT41{>ad5rBfKEd^?-p7v`t!h_1J-Ol{Bn;??#&ZZUY_W7(Jq&5 zSbp2WA?M^Xs~V?UgauWupY7ok-r$k-(r3JOkt3hC!^n2*t8g(557cBhf;;`uw{ z_|zR%{28b{JbYIi587$Pm+msMeY_mheNeHxjqCtlygQD6zRQa1_89T&bIhJN-eI>D z-wdjRv%PWrIVjU!BRj&^gId1FireiovSU1cAL6tZaRPOM+wMo4_90IDjjWXK0ksuW z{R2jJnh!mIIPFKAK%M382N983LBt8vW$s%X#~U58 z;`54)>?*$r>H?^?B}R6g=a<00V)zH@CJ#Rh|4QKBVI#ZE%R$`-6???U?()S);NM~R zchty!L<>Q!9P%@V@CFXuLrgKDEvEaWRH0Kark!({(*YTZBM|zKS)0g?}gEU#XG(&PzcRg9r{LddqxO}C-#Xo$UjW(mj8XeW!{?mo&ZnM+hi8n8@$j?o@C-aWYh-4;9MpYK zvFD6T#}}W2hiBp8c_YKGtmon3Id}*Pzb{{ahoDRsjI0V@4{G^&czDssta$uIcz6LG zg2KD=OYra_JiKINwtNq$t)S{(HnJLg=w*0#2_Ay7hXuVPy4q zIjH-fVs9Fw>QmWQF7t?h`&IgC8-HK>#&6p_)>Inl_Sn@lseXxT)~vSerzW{Oyn1{~ z{5Eb==WFE$A9t{?R~~ECS~uwAkCxY(X)5jMZx_aA-f+wr>)LzY;{1v8{7+|jwz-=& zYktxzYq3{spSpVzU(A2z`p5FZ6J9T}eslY>@M@)+FZcW~BDwQ~wU0d(#4rA&JS%xI zy$4e(o%#}p>@(kXWrthB*1jjqZx{XEaoGM=HClgKyt<5Ud9-51g~W(&d?$8lTTs$s zqLX`%;OE+qkJA2F6rWR2ZGqWc*NqOd&quqAY0Hf& zYp)bke|X{Sjv;55N8KM5Mh&y}v|iyl>H6Hnc6WA7-nHWJwm!X2#I`Sg`RxA0o9Ac{-uOPY$2}`P^S&`kUvZAJ z!^fD_nDpy}BD;kd=N+G({x;0hw%)d`1;aX|&N&yWzn0$HDK%$8hnZFTO*;}heBtn0 zuMS<96~24)r!k!u_3>C?#&_IvBGu4DY~4VGrKb=r2maZYHstsDIL)n401}C`*2mp#Hgg zMP7#g#!vr9Fw^x2!%RHRshZxBx}4O%ldU+D z#N**F+(<$v{pBpEkOG@ZtW!%%n_xK$x`l`v+OW{tuiwZQ=FqsIi+brb9bImsZCh3& zrw(}ZrjEct9xc6qrY606bX0gAz|^GSP5`>7U=oks__+}SR|7C;N$54BJ27z4i)xai zSBBpKNWQVm>npu*SD!JPD1w#{V59{Xz160{$OGv&5>nDs;Z;R@Ie;!Ng-7ovZ%Z7! zUKCk7_((N}R9FL6DP2Aa&j$25g-6?;40V=pd*0Z8rK7O0BoV4I-mxiCV+C1a?lA-3s4*23ZQg$2b5y`DZps}g_OLa z@Q~}|X>EWjfbz2rz#ULeqYr|d4=5IazW~ev&|5{?sFMJb z0aE~UbIt{f28;oW1q=fW2Mh&d0^$MqD+5g*KrcW~Ko3Ayz(=Ga7L6zX{<4Ms8ddt? zpMIwJ4zLuk4A2CI{Rn&?K>w-m44?$E^?+$t(k`T3M?WWB0RJN39N+|iHr65lCB?S@ zdf`volQx%`7A}~hu@Jm30W$zI0n-6f0pkJV0Q3X)Cx8S%B47ZZFQ7XBRZG(!O6ixG z835X?v^!}x(zc^*M%#*RfdK&8ICgVMYeAQWH#P>NGZQwp~Ovz66X13<9JAZb0rP;1=LEU^`$ZfC|fMzz={m087YL0VJWF3>XL)1Q-nH z4;Vtf9;HDb9dHkf9|89PKLPFnb^&$+s5-3$RE1m`@N>X3z;A#DfQNubfL{QQ0cC)4 zz^{Pgfc=0yfNcOP==dG@37{JNdQ=}Fu>;c{PzOLiL7gOk0F~-xfF*##fR%vC=sOC$ z18@g$46q(h2-pDF2%yUJ0`L@2k+%i(X246pE5Mt^_|QP17NB+(fMo`naB&zKxN;+< zs#HG+BqbDOJS9<8^ifjLE}-2&nZHbI6~#i>(t>eO?7B8*B3S1EWILq-4S~y2I#61y z2GGiN1W>Tt0c!xXio_>h$S3lV7J(Lnd^!Nw15nMT@w)-EXp{{UA7n<36qv0b$RApP zBEUYtUI4AkLBJt^s(=Ej2KWftw9{#PG2k$uGavy#W#t^;EZ_v76hMo13UC^52H;Lb zib_IV1jijfD@?`H89;^91wci0K4j)e1C#;^9u?gi;9Un?0#M{=LtO=20bEw_&%m^r zHvv?vDU&D_iEl?coGLk0^m|}Xb+-Xfem?|I&QltZ0oA~#{G|M+T&Jv{4fHE$%6ZyQ zw0mEpZ2_zUP^K^dWzicTO07Que*h>2bAHDMZHij})hgO#WB~16nw$(10TqoQBZxcZzvf>d{w3* zO$Mla>JpHl6j_SW&$Rw(2Pvr7roj|q)eyqOBO}cfKFL=?o0QVdC&j8Bl9MNqdFpsF zi1g5sTGRTg9kh0&P^DExH^C$26mq)bQ=}*|q=YajqQt5wPkodtlpn;W_WS)r=cpc2 z#z%rdm@<71pcSCvAUE{UWbgCdr)lzvJfdldX@^ibQcD!*9H}PJjj$nro`V|zIw-=# z3rCx<%5Q?UJ9t9@jnT$GjW<4;0;oWF0BFy9g7yNaV~2o8^U#f!Zn&~OtbcuFkOQ!) zlnN+Wn+8}8poiRwMv@%$lfk5n3?^fUM-RHR{pe0kwSjn4cq>MPzJ`PVTF|z{lHHeqOGFp5mj&f3DS~ueSwj?(G}k?SpV) ztP^^YE*dt(dIjBm*Fy^`phx{5exwb`g2Xl5nG5SG9_h}UoCib54MJ=C_ObgWW5!Sj z>AfL`Cpz&B1UfH*Kuri#y8CO5ShJeLEtsFTUohE3#or!1FT46YA7^WtWx)bTKe&eh zcIY|zWfPk#lkfjv!2*KO1*O-;1g2t%-8$UMgXpHIMryUea5sd`+f>tH#tJ#?~ZrcZwwk=gU+_fX=8#R$M3(uy-7?5rL}&?-7( zRP9N7TS5R4_x1MmPZ9T!wkhI?q0HVq2<2IP){8~4HDc?JfeOX^kI{WhTt(=j*lZfJ z7cYOzVzdu+qIYlRsQptXcIeIgSQT+hZ`f%st|jCq-X_#Ubm#*VBpM0z5p()LONv+} z8z@tBp9wThJO-w-bfN|pq;}n#^>zz&3t?e%L1c#LT2DWG;S$YEh(d~}H?f6C*3&X24`i4+K~%@p3Y( zjux#4GNhZj4E1OgR>e9<(ujhIhd5Mrs*I&QR-TM}`psP}O1Lj=42@L1 z{9V*DH|{T=W_|8lr3?&(Yc%xtM&j5M)}~dZ#&S(jPvKZtR%6w^D+{b3spRGyNZ>Y= zJ37qsmcLiGDoPJ@d@a60iF8)a>8NZ-owlvc&H)ghvIK#eqVFL1Bg-*`$`Th(#;9?g zvh5SrnNBnb?o5?{?mv2b8x}VXLOc(MyGCPhsK^EbNt>*x*nThzaaIrO*mtqBuWhx= z6Ou)+7GI>~$ldS}r>3%IE=W4{zz+3)!`raXR#HtC7bmeA^M|my&DAqJ)c+u_Wla!4 zy3|uX)c->NuE*X_^cceYT-Kl@S3z*Pe41KxW&Ot0Foo_wSc2((V&)LmNjuk1+)a|| zfgZCgT<(F1lDTfLpHN9sc5q36 zIGaYC2@qGNu};lDY=wHtN2Bs8z8BdQym&F>!MCl>;#tN%@RrNC^^sGN4;ML*(fy z%YC<;irzp1JHb03Kr=j89FW2M{&&lv9hM&@?f+moRT@ZCu)Nk#+4AV2vgHGZvQGa{ zqL8t$9q*>-2I+*m+)qQ9zjkei=$eVOQ;#Z%?f>x2AG70sgCDs6(9TV5DW+z^mbZtN z^ziF;tkTK@kWij>%v*_zNQZh{$>??A6Qf%$j+J78x`#Ieq2e#l(Of-)!m?$nackM^ z6_SK>pHok%7&Nf`^AR^fwn;tyH1<}g*fI-ip&oQ$no%QU&XJ7?kU$oC2V)N!#P70D zTcmC0ApVkthdcS!?4q8Uu`z$W)@t@~e4&xTfGrqo5W}(&u=WPAS2hCJ%^-f3&6-#y z81P1o3XVbCn~mhYY7lLPp}$SIxF`qmQQ>0PIN-kF;_Rsi%kpsPD{*d{122OOM}|(5 z440N@ceuEE7$h%;i$^~JhK3uUo0nrmb<9vLZ2r&AV?OGk*o084XM#K$aObDrrjF?( z>5|H4^$5{>ICM0Q5ND5Jc5aA^dZ384`PaAl`MKo2o48YiICeNp?j9ko!yp&+G?&^g zuX6HN{#c?&V!{y-;vGmfA0Hv#Njk$_J1l$ExlBEHzZr!AFedbC3tzK#%W#$z_2wP-Vo+3D~^Xy01wG7{?4qg+OM zc|I81q}F{!9o$n7eHpW)bI15KM+YiB*gl(^_jD0U_?8JgmOt06LW_EY8J(|J9%R2lld3MC00UDQ*6$_l2= zUSM%ozH3WQO^e!z)yBL{*SDFdrmqfu%9;GGOW9w|)f0d;!B2;O+kX0(cdmWFY21id z2eIi`tcZGw(9iK}bgiywzZKD|R z2Gu=`#LdIb4U+%3#if#5hP%WBWNH-dFt(^J9rm}fkIsyaQxXXVsRm$>p_@_;%p$R09&;L?p8J*N`efJH3m(DRx3A>X zv%~T)N3sp2{inR^QBMnHk z+w(3z)D@E7C~Bj8#ho*mW0HCf+}Fd4yi!i-G7%ZQH}Vp%7qI4(mj6F8NX*D)cGB93 zJw9XAgH&TaoN@mgC@JF<@5M{dUkr7bJe#+&_^Rbl{#um`iMr_A&v^0FY}_s#^O;YrU%{Z)6BC01 zkFt@~UOP^Zg)ZL`6Y}xL82R~Fy%7(XmADh6kT5LGD|=LiDNF2M&YTKf<+J@}mE_mY z;-Pu0P1VFyQ+%3y3}S{DIG+_%mzOd#F-&eW8jcF=qJMCGlv6%HsX~%+m}n`9%8z43FpKtdf5-MUj`%@Cw3LV((z@?Bvm5l5OB; z<78ZgpaU$$UTaxBadsK2B$k%3wl<1HGg3jKV*XZEU+j5+Ef6wN64MjYQ`0lW#f5mu z>Aa7%EU-Gr?wEdZxipQ)bx-iM?%CzO-q?lZWub|Qd g^~#wudZiE|T<%QV@+ Date: Tue, 26 Dec 2023 08:57:36 +1100 Subject: [PATCH 065/169] feat: Refactor compile bun macro for efficiency Bun v1.0.20 now supports passing a string directly into `HTMLRewriter().transform`, which we use to avoid a bunch of unnecessary overhead. Also reduce some var allocations. --- build.ts | 4 +- src/runtime/macro.ts | 210 ++++++++++++++++++++++++++----------------- 2 files changed, 130 insertions(+), 84 deletions(-) diff --git a/build.ts b/build.ts index 3277c70..43a72db 100644 --- a/build.ts +++ b/build.ts @@ -5,7 +5,7 @@ export {}; console.time('build'); // Minified browser bundle which includes "regular mode" functions, utils, and store. -const out = await Bun.build({ +const out1 = await Bun.build({ entrypoints: ['src/browser.ts'], outdir: 'dist', target: 'browser', @@ -49,4 +49,4 @@ const out5 = await Bun.build({ }); console.timeEnd('build'); -console.log(out, out2, out3, out4, out5); +console.log(out1, out2, out3, out4, out5); diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index 4e7abdd..a73d946 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -26,105 +26,151 @@ export interface CompileOptions { * @param template - HTML template string. * @param options - Compile options. */ -export async function compile( +export function compile( template: string, { keepComments, keepSpaces }: CompileOptions = {}, - // @ts-expect-error - Bun macros always result in synchronous inlined data. ): { html: string; k: readonly string[]; d: readonly number[] } { - const rewriter = new HTMLRewriter(); const k: string[] = []; const d: number[] = []; let distance = 0; let whitespaceSensitiveBlock = false; let root: boolean | undefined; - rewriter.on('*', { - element(node) { - if (!root) { - if (root === undefined) { - root = true; - node.onEndTag(() => { - root = false; - }); - } else { - // eslint-disable-next-line no-console - console.error( - 'Expected template to have a single root element:', - template, - ); + const html = new HTMLRewriter() + .on('*', { + element(node) { + if (!root) { + if (root === undefined) { + root = true; + node.onEndTag(() => { + root = false; + }); + } else { + // eslint-disable-next-line no-console + console.error( + 'Expected template to have a single root element:', + template, + ); + } } - } - if (node.tagName === 'pre' || node.tagName === 'code') { - whitespaceSensitiveBlock = true; - node.onEndTag(() => { - whitespaceSensitiveBlock = false; - }); - } - for (const [name] of node.attributes) { - if (name[0] === '@') { - k.push(name.slice(1)); - d.push(distance); - distance = 0; - node.removeAttribute(name); - break; + if (node.tagName === 'pre' || node.tagName === 'code') { + whitespaceSensitiveBlock = true; + node.onEndTag(() => { + whitespaceSensitiveBlock = false; + }); } - } - distance++; - }, - // This text handler is invoked twice for each Text node: first with the - // actual text, then with an empty last chunk. This behaviour stems from - // the fact that the Response provided to HTMLRewriter.transform() is not - // streamed; otherwise, there could be multiple chunks before the last one. - text(chunk) { - if (!chunk.lastInTextNode) { - const text = chunk.text.trim(); - if (!text) { - if (!whitespaceSensitiveBlock) { - chunk.remove(); + for (const [name] of node.attributes) { + if (name[0] === '@') { + k.push(name.slice(1)); + d.push(distance); + distance = 0; + node.removeAttribute(name); + break; } - return; - } - if (text[0] === '@') { - k.push(text.slice(1)); - d.push(distance); - distance = 0; - // replace with single space which renders a Text node at runtime - chunk.replace(' ', { html: true }); - } else if (!whitespaceSensitiveBlock) { - // reduce any whitespace to a single space - chunk.replace((keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), { - html: true, - }); } distance++; - } - }, - comments(node) { - if (keepComments) { - // TODO: Add documentation that the build/runtime mode also supports - // using comments as refs. Requires the keepComments option to be true. - const text = node.text.trim(); - if (text[0] === '@') { - k.push(text.slice(1)); - d.push(distance); - distance = 0; - // TODO: Use empty comment once lol-html supports it (less alloc than node.replace) - // node.text = ''; - // TODO: use node.replace() once lol-html fixes it for comments - // node.replace('', { html: true }); + }, + // This text handler is invoked twice for each Text node: first with the + // actual text, then with an empty last chunk. This behaviour stems from + // the fact that the data provided to HTMLRewriter.transform() can be + // streamed; where the last empty chunk signals the end of the text. + text(chunk) { + if (!chunk.lastInTextNode) { + const text = chunk.text.trim(); + if (!text) { + if (!whitespaceSensitiveBlock) { + chunk.remove(); + } + return; + } + if (text[0] === '@') { + k.push(text.slice(1)); + d.push(distance); + distance = 0; + // replace with single space which renders a Text node at runtime + chunk.replace(' ', { html: true }); + } else if (!whitespaceSensitiveBlock) { + // reduce any whitespace to a single space + chunk.replace( + (keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), + { + html: true, + }, + ); + } + distance++; + } + }, + comments(node) { + if (keepComments) { + // TODO: Add documentation that the build/runtime mode also supports + // using comments as refs. Requires the keepComments option to be true. + const text = node.text.trim(); + if (text[0] === '@') { + k.push(text.slice(1)); + d.push(distance); + distance = 0; + // TODO: Use empty comment once lol-html supports it (less alloc than node.replace) + // node.text = ''; + // TODO: use node.replace() once lol-html fixes it for comments + // node.replace('', { html: true }); + node.remove(); + node.after('', { html: true }); + } + distance++; + } else { node.remove(); - node.after('', { html: true }); } - distance++; - } else { - node.remove(); - } - }, - }); - - const res = rewriter.transform(new Response(template.trim())); - const html = await res.text(); + }, + }) + .transform(template.trim()); return { html, k, d }; } + +// FIXME: Decide whether to keep the minifyHTML macro or not. + +// /** +// * Bun macro which minifies whitespace in a HTML string at build-time. +// * @param html - Static HTML code string. +// * @param options - Compile options. +// */ +// export function minifyHTML( +// html: string, +// { keepComments, keepSpaces }: CompileOptions = {}, +// ): string { +// let whitespaceSensitiveBlock = false; +// +// return new HTMLRewriter() +// .on('*', { +// element(node) { +// if (node.tagName === 'pre' || node.tagName === 'code') { +// whitespaceSensitiveBlock = true; +// node.onEndTag(() => { +// whitespaceSensitiveBlock = false; +// }); +// } +// }, +// text(chunk) { +// // see above explanation +// if (!chunk.lastInTextNode) { +// const text = chunk.text.trim(); +// if (!text && !whitespaceSensitiveBlock) { +// chunk.remove(); +// } else if (!whitespaceSensitiveBlock) { +// // reduce any whitespace to a single space +// chunk.replace( +// (keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), +// ); +// } +// } +// }, +// comments(node) { +// if (!keepComments) { +// node.remove(); +// } +// }, +// }) +// .transform(html.trim()); +// } From 26cbbdb8193b94eddd87294994bd0253265d5378 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 26 Dec 2023 09:09:37 +1100 Subject: [PATCH 066/169] Publish v0.8.0-next.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d39ec1c..f4c403d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.4", + "version": "0.8.0-next.5", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From d6fa5c240cc6f4f85b51396288dbfee5caf35c83 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 26 Dec 2023 11:12:07 +1100 Subject: [PATCH 067/169] chore: Clean up macro --- src/runtime/macro.ts | 57 +------------------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/src/runtime/macro.ts b/src/runtime/macro.ts index a73d946..0d07985 100644 --- a/src/runtime/macro.ts +++ b/src/runtime/macro.ts @@ -1,10 +1,3 @@ -// TODO: It would be great if the compile macro could also minify the HTML -// beyond just whitespace. However it seems to not be possible with lol-html. -// ↳ Remove quotes around attributes with no spaces or special characters -// ↳ Make all quotes consistent (but be careful with embedded JS/CSS etc.) -// ↳ Remove unnecessary closing tags -// ↳ Convert tags to self-closing when possible - export interface CompileOptions { /** * Whether to keep HTML comments in output HTML. When keepComments is true, @@ -94,9 +87,7 @@ export function compile( // reduce any whitespace to a single space chunk.replace( (keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), - { - html: true, - }, + { html: true }, ); } distance++; @@ -128,49 +119,3 @@ export function compile( return { html, k, d }; } - -// FIXME: Decide whether to keep the minifyHTML macro or not. - -// /** -// * Bun macro which minifies whitespace in a HTML string at build-time. -// * @param html - Static HTML code string. -// * @param options - Compile options. -// */ -// export function minifyHTML( -// html: string, -// { keepComments, keepSpaces }: CompileOptions = {}, -// ): string { -// let whitespaceSensitiveBlock = false; -// -// return new HTMLRewriter() -// .on('*', { -// element(node) { -// if (node.tagName === 'pre' || node.tagName === 'code') { -// whitespaceSensitiveBlock = true; -// node.onEndTag(() => { -// whitespaceSensitiveBlock = false; -// }); -// } -// }, -// text(chunk) { -// // see above explanation -// if (!chunk.lastInTextNode) { -// const text = chunk.text.trim(); -// if (!text && !whitespaceSensitiveBlock) { -// chunk.remove(); -// } else if (!whitespaceSensitiveBlock) { -// // reduce any whitespace to a single space -// chunk.replace( -// (keepSpaces ? chunk.text : text).replace(/\s+/g, ' '), -// ); -// } -// } -// }, -// comments(node) { -// if (!keepComments) { -// node.remove(); -// } -// }, -// }) -// .transform(html.trim()); -// } From 604a3875454ba169b2d53bb6f301df1aad9e2640 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 26 Dec 2023 11:16:21 +1100 Subject: [PATCH 068/169] chore: Update gitignore --- .gitignore | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 86a5aa5..6c405ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ *-lock.json* +*-lock.yaml +*.bak *.lock *.log -/bench/bun.lockb /coverage/ -dist -node_modules +/dist/ +/node_modules/ From 490b4d7bbd8c7cd5097342b543795fe4a682b7a7 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 12:02:33 +1100 Subject: [PATCH 069/169] chore: Refactor CI triggers and action versions --- .github/workflows/ci.yml | 6 +++--- .github/workflows/codeql-analysis.yml | 10 +++++----- .github/workflows/semgrep-analysis.yml | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6eaf2b..6a91d14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,8 @@ on: push: branches: [master, next] paths-ignore: ['**.md'] - pull_request: - branches: [master, next] + pull_request: {} + workflow_dispatch: {} jobs: test: runs-on: ubuntu-latest @@ -39,7 +39,7 @@ jobs: - run: bun playwright install chromium - run: bun run build - run: bun run test:e2e --reporter=dot,html - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f2e0d9a..9ea48bf 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,8 +2,8 @@ name: codeql on: push: branches: [master, next] - pull_request: - branches: [master, next] + pull_request: {} + workflow_dispatch: {} schedule: - cron: '28 6 * * 4' jobs: @@ -16,9 +16,9 @@ jobs: security-events: write steps: - uses: actions/checkout@v4 - - uses: github/codeql-action/init@v2 + - uses: github/codeql-action/init@v3 with: languages: javascript queries: security-and-quality - - uses: github/codeql-action/autobuild@v2 - - uses: github/codeql-action/analyze@v2 + - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/semgrep-analysis.yml b/.github/workflows/semgrep-analysis.yml index 62ab8bf..f03d6c5 100644 --- a/.github/workflows/semgrep-analysis.yml +++ b/.github/workflows/semgrep-analysis.yml @@ -2,8 +2,8 @@ name: semgrep on: push: branches: [master, next] - pull_request: - branches: [master, next] + pull_request: {} + workflow_dispatch: {} schedule: - cron: '28 6 * * 4' jobs: @@ -18,10 +18,10 @@ jobs: security-events: write steps: - uses: actions/checkout@v4 - - run: semgrep ci --sarif --output=semgrep.sarif || true + - run: semgrep ci --sarif > semgrep.sarif env: SEMGREP_RULES: p/default - - uses: github/codeql-action/upload-sarif@v2 + - uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: semgrep.sarif From 8b57631cc93a9c2d909a155e370fd8e83fb656be Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 19:40:38 +1100 Subject: [PATCH 070/169] chore: Update dependencies --- bun.lockb | Bin 128538 -> 125802 bytes package.json | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 5a304af8765b1c7ac000de6dba15cfa0b88999a6..45f0ec5bdd1db209f82f1fcb9a40cf27f35503f9 100755 GIT binary patch delta 21725 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 wm3`>@?%&Hisp7!87_k-G_DITwcxlf6l7Z761SM delta 22587 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 N7{3+${O-Z5{|6BSS8f0R diff --git a/package.json b/package.json index f4c403d..7bfbbcf 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,9 @@ "devDependencies": { "@playwright/test": "1.40.1", "@types/bun": "1.0.0", - "@typescript-eslint/eslint-plugin": "6.16.0", - "@typescript-eslint/parser": "6.16.0", + "@typescript-eslint/eslint-plugin": "6.17.0", + "@typescript-eslint/parser": "6.17.0", + "esbuild": "0.19.11", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", @@ -70,6 +71,6 @@ "typescript": "5.3.3" }, "overrides": { - "bun-types": "1.0.20" + "bun-types": "1.0.21" } } From 8842afd4a0147fc243bc24195b09e053d3087675 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 21:41:14 +1100 Subject: [PATCH 071/169] feat: Refactor - Reorganise file layout - Prebuild bun mode is now the default - The live browser compile mode is now "browser" mode - Include store in bundles; it's no longer necessary to import seperately - Fix macro not handling top level comments - Rework build and output bundles and their paths --- build.ts | 75 +++++++++++++++++++++++++---------- bun.lockb | Bin 125802 -> 126938 bytes package.json | 3 +- src/browser.ts | 5 --- src/{ => browser}/compile.ts | 16 +++++++- src/browser/index.ts | 6 +++ src/events.ts | 10 ++--- src/index.ts | 4 +- src/{runtime => }/macro.ts | 42 ++++++++++---------- src/{runtime => }/runtime.ts | 4 +- src/runtime/index.ts | 6 --- src/types.ts | 13 ------ 12 files changed, 105 insertions(+), 79 deletions(-) delete mode 100644 src/browser.ts rename src/{ => browser}/compile.ts (88%) create mode 100644 src/browser/index.ts rename src/{runtime => }/macro.ts (89%) rename src/{runtime => }/runtime.ts (93%) delete mode 100644 src/runtime/index.ts diff --git a/build.ts b/build.ts index 43a72db..55eb24a 100644 --- a/build.ts +++ b/build.ts @@ -1,50 +1,81 @@ /* eslint-disable no-console */ -export {}; +import * as rollup from 'rollup'; +import { minify } from 'terser'; console.time('build'); -// Minified browser bundle which includes "regular mode" functions, utils, and store. const out1 = await Bun.build({ - entrypoints: ['src/browser.ts'], - outdir: 'dist', + entrypoints: ['src/browser/index.ts'], + outdir: 'dist/browser', target: 'browser', - // FIXME: Use iife once Bun.build supports it (but we should have 2 bundles, esm and iife) - // format: 'iife', minify: true, - sourcemap: 'external', + sourcemap: 'inline', +}); +const bundle = await rollup.rollup({ + input: out1.outputs[0].path, +}); +await bundle.write({ + file: out1.outputs[0].path, + format: 'iife', + name: 'stage1', + sourcemap: true, + plugins: [ + // @ts-expect-error - TODO: Fix return types + { + name: 'terser', + renderChunk(src) { + return minify(src, { + ecma: 2015, + sourceMap: true, + compress: { + reduce_funcs: false, // prevent functions being inlined + passes: 2, + }, + mangle: { + properties: { + regex: /^\$\$/, + }, + }, + }); + }, + }, + ], }); const out2 = await Bun.build({ - entrypoints: ['src/index.ts', 'src/store.ts'], - outdir: 'dist', + entrypoints: ['src/browser/index.ts'], + outdir: 'dist/browser', target: 'browser', + naming: '[dir]/[name].mjs', + minify: true, sourcemap: 'external', }); const out3 = await Bun.build({ - entrypoints: [ - 'src/reconcile/keyed.ts', - 'src/reconcile/non-keyed.ts', - 'src/reconcile/reuse-nodes.ts', - ], - outdir: 'dist/reconcile', + entrypoints: ['src/index.ts'], + outdir: 'dist', target: 'browser', + minify: true, sourcemap: 'external', }); const out4 = await Bun.build({ - entrypoints: ['src/runtime/index.ts'], - outdir: 'dist/runtime', - target: 'browser', + entrypoints: ['src/macro.ts'], + outdir: 'dist', + target: 'bun', + minify: true, sourcemap: 'external', }); const out5 = await Bun.build({ - entrypoints: ['src/runtime/macro.ts'], - outdir: 'dist/runtime', - target: 'bun', - minify: true, + entrypoints: [ + 'src/reconcile/keyed.ts', + 'src/reconcile/non-keyed.ts', + 'src/reconcile/reuse-nodes.ts', + ], + outdir: 'dist/reconcile', + target: 'browser', sourcemap: 'external', }); diff --git a/bun.lockb b/bun.lockb index 45f0ec5bdd1db209f82f1fcb9a40cf27f35503f9..4d4a7cf504669d8623a59297fb1a715a178ef607 100755 GIT binary patch delta 28583 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 T;^kMor_~{azm-eh>R$Li-TC9a diff --git a/package.json b/package.json index 7bfbbcf..0d43832 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "@types/bun": "1.0.0", "@typescript-eslint/eslint-plugin": "6.17.0", "@typescript-eslint/parser": "6.17.0", - "esbuild": "0.19.11", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", @@ -68,6 +67,8 @@ "eslint-plugin-unicorn": "50.0.1", "happy-dom": "12.10.3", "prettier": "3.1.1", + "rollup": "4.9.2", + "terser": "5.26.0", "typescript": "5.3.3" }, "overrides": { diff --git a/src/browser.ts b/src/browser.ts deleted file mode 100644 index e4c5cad..0000000 --- a/src/browser.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './compile'; -export * from './events'; -export * from './store'; -export * from './types'; -export * from './utils'; diff --git a/src/compile.ts b/src/browser/compile.ts similarity index 88% rename from src/compile.ts rename to src/browser/compile.ts index f50bd36..8f5fa74 100644 --- a/src/compile.ts +++ b/src/browser/compile.ts @@ -1,5 +1,17 @@ -import type { LowercaseKeys, RefInfo, Refs, S1View } from './types'; -import { create } from './utils'; +import type { LowercaseKeys, Refs } from '../types'; +import { create } from '../utils'; + +interface RefInfo { + /** Ref key name. */ + readonly k: string; + /** Distance from previous ref node or root. */ + readonly d: number; +} + +export interface S1View extends Node, ChildNode { + /** @private */ + $$refs: readonly RefInfo[]; +} const compilerTemplate = create('template'); const treeWalker = document.createTreeWalker(compilerTemplate); diff --git a/src/browser/index.ts b/src/browser/index.ts new file mode 100644 index 0000000..c4c62b7 --- /dev/null +++ b/src/browser/index.ts @@ -0,0 +1,6 @@ +export * from './compile'; + +export * from '../events'; +export * from '../store'; +export * from '../types'; +export * from '../utils'; diff --git a/src/events.ts b/src/events.ts index 6a7b066..652c0a6 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,4 +1,4 @@ -const configuredEvents: Record = {}; +const configuredEvents: Record = {}; const nativeToSyntheticEvent = (event: Event) => { // eslint-disable-next-line prefer-template @@ -18,13 +18,11 @@ const nativeToSyntheticEvent = (event: Event) => { }; export const setupSyntheticEvent = (type: keyof DocumentEventMap): void => { - if (configuredEvents[type]) return; - - document.addEventListener(type, nativeToSyntheticEvent); - configuredEvents[type] = true; + configuredEvents[type] ??= + (document.addEventListener(type, nativeToSyntheticEvent), true); }; export const deleteSyntheticEvent = (type: keyof DocumentEventMap): void => { + configuredEvents[type] = null; document.removeEventListener(type, nativeToSyntheticEvent); - configuredEvents[type] = false; }; diff --git a/src/index.ts b/src/index.ts index 9145b25..a37d932 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,6 @@ -export * from './compile'; +export * from './runtime'; + export * from './events'; +export * from './store'; export * from './types'; export * from './utils'; diff --git a/src/runtime/macro.ts b/src/macro.ts similarity index 89% rename from src/runtime/macro.ts rename to src/macro.ts index 0d07985..1143bfe 100644 --- a/src/runtime/macro.ts +++ b/src/macro.ts @@ -30,6 +30,27 @@ export function compile( let root: boolean | undefined; const html = new HTMLRewriter() + .onDocument({ + comments(node) { + if (keepComments) { + // TODO: Add documentation that precompiled mode supports using + // comments as refs. Requires the keepComments option to be true. + const text = node.text.trim(); + if (text[0] === '@') { + k.push(text.slice(1)); + d.push(distance); + distance = 0; + // TODO: use node.replace() once lol-html fixes it for comments + // node.replace('', { html: true }); + node.remove(); + node.after('', { html: true }); + } + distance++; + } else { + node.remove(); + } + }, + }) .on('*', { element(node) { if (!root) { @@ -93,27 +114,6 @@ export function compile( distance++; } }, - comments(node) { - if (keepComments) { - // TODO: Add documentation that the build/runtime mode also supports - // using comments as refs. Requires the keepComments option to be true. - const text = node.text.trim(); - if (text[0] === '@') { - k.push(text.slice(1)); - d.push(distance); - distance = 0; - // TODO: Use empty comment once lol-html supports it (less alloc than node.replace) - // node.text = ''; - // TODO: use node.replace() once lol-html fixes it for comments - // node.replace('', { html: true }); - node.remove(); - node.after('', { html: true }); - } - distance++; - } else { - node.remove(); - } - }, }) .transform(template.trim()); diff --git a/src/runtime/runtime.ts b/src/runtime.ts similarity index 93% rename from src/runtime/runtime.ts rename to src/runtime.ts index f6540ec..c67a16e 100644 --- a/src/runtime/runtime.ts +++ b/src/runtime.ts @@ -1,5 +1,5 @@ -import type { LowercaseKeys, Refs } from '../types'; -import { create } from '../utils'; +import type { LowercaseKeys, Refs } from './types'; +import { create } from './utils'; const template = create('template'); const treeWalker = document.createTreeWalker(template); diff --git a/src/runtime/index.ts b/src/runtime/index.ts deleted file mode 100644 index 7120c94..0000000 --- a/src/runtime/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './runtime'; - -export * from '../events'; -export * from '../utils'; - -export type { LowercaseKeys, Refs } from '../types'; diff --git a/src/types.ts b/src/types.ts index 6f74b55..1236c3b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,16 +1,3 @@ -/** @private */ -export interface RefInfo { - /** Ref key name. */ - readonly k: string; - /** Distance from previous ref node or root. */ - readonly d: number; -} - -export interface S1View extends Node, ChildNode { - /** @private */ - $$refs: readonly RefInfo[]; -} - export type Refs = Record; export type LowercaseKeys = { From 3625ab9b3b761e4d29dc7fde3df5f5b09eeb6d6c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 21:41:59 +1100 Subject: [PATCH 072/169] feat: Refactor exports and paths --- package.json | 65 ++++++++++++++++++++++++++----------------------- tsconfig.d.json | 1 + 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 0d43832..fb1d497 100644 --- a/package.json +++ b/package.json @@ -8,40 +8,45 @@ "license": "MIT", "sideEffects": false, "main": "dist/index.js", - "browser": "dist/browser.js", + "browser": "dist/browser/index.js", + "types": "dist/index.d.ts", "exports": { - ".": "./dist/index.js", - "./macro": "./dist/runtime/macro.js", - "./runtime": "./dist/runtime/index.js", - "./store": "./dist/store.js", - "./reconcile/keyed": "./dist/reconcile/keyed.js", - "./reconcile/non-keyed": "./dist/reconcile/non-keyed.js", - "./reconcile/reuse-nodes": "./dist/reconcile/reuse-nodes.js", - "./browser": "./dist/browser.js", + ".": { + "FIXME__browser": { + "types": "./dist/browser/index.d.ts", + "import": "./dist/browser/index.mjs", + "require": "./dist/browser/index.js" + }, + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./macro": { + "types": "./dist/macro.d.ts", + "default": "./dist/macro.js" + }, + "./browser": { + "types": "./dist/browser/index.d.ts", + "import": "./dist/browser/index.mjs", + "require": "./dist/browser/index.js" + }, + "./reconcile/keyed": { + "types": "./dist/reconcile/keyed.d.ts", + "default": "./dist/reconcile/keyed.js" + }, + "./reconcile/non-keyed": { + "types": "./dist/reconcile/non-keyed.d.ts", + "default": "./dist/reconcile/non-keyed.js" + }, + "./reconcile/reuse-nodes": { + "types": "./dist/reconcile/reuse-nodes.d.ts", + "default": "./dist/reconcile/reuse-nodes.js" + }, + "./dist/*": "./dist/*", "./package.json": "./package.json" }, - "types": "dist/index.d.ts", - "typesVersions": { - "*": { - "macro": [ - "dist/runtime/macro.d.ts" - ], - "runtime": [ - "dist/runtime/index.d.ts" - ], - "store": [ - "dist/store.d.ts" - ], - "reconcile/*": [ - "dist/reconcile/*.d.ts" - ], - "browser": [ - "dist/browser.d.ts" - ] - } - }, "files": [ - "dist" + "dist", + "src" ], "scripts": { "build": "bun build.ts", diff --git a/tsconfig.d.json b/tsconfig.d.json index ee1e43e..b16eed2 100644 --- a/tsconfig.d.json +++ b/tsconfig.d.json @@ -4,6 +4,7 @@ "rootDir": "src", "outDir": "dist", "declaration": true, + "declarationMap": true, "emitDeclarationOnly": true }, "include": ["src"] From 096c21d2854bcff7fa4c7c2bd4c9d1f1de36fd2a Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 21:42:33 +1100 Subject: [PATCH 073/169] chore: 2023 -> 2024 and minor tweaks --- .eslintrc.cjs | 2 ++ LICENSE | 2 +- README.md | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5c8c6f1..592e48f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,3 +1,5 @@ +'use strict'; // eslint-disable-line + const OFF = 0; const WARN = 1; const ERROR = 2; diff --git a/LICENSE b/LICENSE index c66ae18..c81c473 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Max Milton +Copyright (c) 2024 Max Milton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c6d08b6..c4bba17 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ Some optional features require a higher browser version: SSR (server-side rendering) is not supported and is not the intended use of this library. +## Build environment JS runtime support + +The default runtime requires [bun](https://bun.sh/) version 1.0.20 or above. + +The browser bundle does not have any specific build requirements. + ## Bugs Please report any bugs you encounter on the [GitHub issue tracker](https://github.com/maxmilton/stage1/issues). @@ -89,4 +95,4 @@ MIT license. See [LICENSE](https://github.com/maxmilton/stage1/blob/master/LICEN --- -© 2023 [Max Milton](https://maxmilton.com) +© 2024 [Max Milton](https://maxmilton.com) From 52c727085ff9026efda64004fd30ef59a1dd4369 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 21:43:28 +1100 Subject: [PATCH 074/169] test: Refactor and improve tests and tooling --- ...ponent_precompiled.ts => TestComponent.ts} | 4 +- ...nt_regular.ts => TestComponent_browser.ts} | 2 +- test/setup.ts | 40 ++++- ...ompile.test.ts => browser-compile.test.ts} | 2 +- test/unit/exports.test.ts | 56 ++---- test/unit/macro.test.ts | 58 +++++- test/unit/runtime.test.ts | 4 +- test/unit/test-utils.test.ts | 170 +++++++++++++----- test/unit/utils.ts | 40 ++--- 9 files changed, 250 insertions(+), 126 deletions(-) rename test/{TestComponent_precompiled.ts => TestComponent.ts} (76%) rename test/{TestComponent_regular.ts => TestComponent_browser.ts} (86%) rename test/unit/{compile.test.ts => browser-compile.test.ts} (99%) diff --git a/test/TestComponent_precompiled.ts b/test/TestComponent.ts similarity index 76% rename from test/TestComponent_precompiled.ts rename to test/TestComponent.ts index 0f5388c..1f7a606 100644 --- a/test/TestComponent_precompiled.ts +++ b/test/TestComponent.ts @@ -1,5 +1,5 @@ -import { collect, h } from '../src/runtime/index'; -import { compile } from '../src/runtime/macro' assert { type: 'macro' }; +import { compile } from '../src/macro' assert { type: 'macro' }; +import { collect, h } from '../src/runtime'; type TestComponent = HTMLDivElement; diff --git a/test/TestComponent_regular.ts b/test/TestComponent_browser.ts similarity index 86% rename from test/TestComponent_regular.ts rename to test/TestComponent_browser.ts index d6d917e..53c5c8c 100644 --- a/test/TestComponent_regular.ts +++ b/test/TestComponent_browser.ts @@ -1,4 +1,4 @@ -import { collect, h } from '../src/index'; +import { collect, h } from '../src/browser/compile'; type TestComponent = HTMLDivElement; diff --git a/test/setup.ts b/test/setup.ts index 5e7f022..95d47e8 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,19 +1,46 @@ +import { expect } from 'bun:test'; import { GlobalWindow, type Window } from 'happy-dom'; declare global { + /** Real bun console. `console` is mapped to happy-dom's virtual console. */ + // eslint-disable-next-line no-var, vars-on-top + var console2: Console; // eslint-disable-next-line no-var, vars-on-top var happyDOM: Window['happyDOM']; } +declare module 'bun:test' { + interface Matchers { + /** Asserts that a value is a plain `object`. */ + toBePlainObject(): void; + } +} + +expect.extend({ + // XXX: Although bun has a `toBeObject` matcher, it's not as useful since it + // doesn't check for plain objects. + toBePlainObject(received: unknown) { + return Object.prototype.toString.call(received) === '[object Object]' + ? { pass: true } + : { + pass: false, + message: () => `expected ${String(received)} to be a plain object`, + }; + }, +}); + +const originalConsole = global.console; + +const noop = () => {}; + function setupDOM() { - const dom = new GlobalWindow({ - url: 'chrome-extension://cpcibnbdmpmcmnkhoiilpnlaepkepknb/', - }); + const dom = new GlobalWindow(); global.happyDOM = dom.happyDOM; + global.console2 = originalConsole; // @ts-expect-error - happy-dom only implements a subset of the DOM API global.window = dom.window.document.defaultView; global.document = window.document; - global.console = window.console; + global.console = window.console; // https://github.com/capricorn86/happy-dom/wiki/Virtual-Console global.setTimeout = window.setTimeout; global.clearTimeout = window.clearTimeout; global.DocumentFragment = window.DocumentFragment; @@ -24,7 +51,10 @@ function setupDOM() { } function setupMocks(): void { - // TODO:! + // @ts-expect-error - noop stub + global.performance.mark = noop; + // @ts-expect-error - noop stub + global.performance.measure = noop; } export function reset(): void { diff --git a/test/unit/compile.test.ts b/test/unit/browser-compile.test.ts similarity index 99% rename from test/unit/compile.test.ts rename to test/unit/browser-compile.test.ts index bd58d9d..923916f 100644 --- a/test/unit/compile.test.ts +++ b/test/unit/browser-compile.test.ts @@ -1,7 +1,7 @@ // XXX: This file has the same tests as test/unit/runtime.test.ts, keep them in sync. import { afterEach, describe, expect, test } from 'bun:test'; -import { collect, h, html } from '../../src/compile'; +import { collect, h, html } from '../../src/browser/compile'; import { cleanup, render } from './utils'; describe('h', () => { diff --git a/test/unit/exports.test.ts b/test/unit/exports.test.ts index e65426f..af823db 100644 --- a/test/unit/exports.test.ts +++ b/test/unit/exports.test.ts @@ -1,15 +1,14 @@ /* eslint-disable guard-for-in */ import { describe, expect, test } from 'bun:test'; +import * as browserExports from '../../src/browser/index'; import * as indexExports from '../../src/index'; +import * as macroExports from '../../src/macro'; import * as keyedExports from '../../src/reconcile/keyed'; import * as nonKeyedExports from '../../src/reconcile/non-keyed'; import * as reuseNodesExports from '../../src/reconcile/reuse-nodes'; -import * as runtimeExports from '../../src/runtime/index'; -import * as macroExports from '../../src/runtime/macro'; -import * as storeExports from '../../src/store'; -describe('index', () => { +describe('browser', () => { const PUBLIC_EXPORTS = [ ['h', Function], ['html', Function], @@ -23,29 +22,30 @@ describe('index', () => { ['prepend', Function], ['clone', Function], ['onRemove', Function], + ['store', Function], ] as const; for (const [name, type] of PUBLIC_EXPORTS) { test(`exports public "${name}" ${type.name}`, () => { - expect(indexExports).toHaveProperty(name); - expect(indexExports[name]).toBeInstanceOf(type); + expect(browserExports).toHaveProperty(name); + expect(browserExports[name]).toBeInstanceOf(type); }); } test('does not export any private internals', () => { const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - expect(publicExportNames).toHaveLength(Object.keys(indexExports).length); - for (const name in indexExports) { + for (const name in browserExports) { expect(publicExportNames).toContain(name); } + expect(publicExportNames).toHaveLength(Object.keys(browserExports).length); }); test('has no default export', () => { - expect(indexExports).not.toHaveProperty('default'); + expect(browserExports).not.toHaveProperty('default'); }); }); -describe('runtime', () => { +describe('index', () => { const PUBLIC_EXPORTS = [ ['h', Function], ['collect', Function], @@ -58,25 +58,26 @@ describe('runtime', () => { ['prepend', Function], ['clone', Function], ['onRemove', Function], + ['store', Function], ] as const; for (const [name, type] of PUBLIC_EXPORTS) { test(`exports public "${name}" ${type.name}`, () => { - expect(runtimeExports).toHaveProperty(name); - expect(runtimeExports[name]).toBeInstanceOf(type); + expect(indexExports).toHaveProperty(name); + expect(indexExports[name]).toBeInstanceOf(type); }); } test('does not export any private internals', () => { const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - expect(publicExportNames).toHaveLength(Object.keys(runtimeExports).length); - for (const name in runtimeExports) { + for (const name in indexExports) { expect(publicExportNames).toContain(name); } + expect(publicExportNames).toHaveLength(Object.keys(indexExports).length); }); test('has no default export', () => { - expect(runtimeExports).not.toHaveProperty('default'); + expect(indexExports).not.toHaveProperty('default'); }); }); @@ -103,29 +104,6 @@ describe('macro', () => { }); }); -describe('store', () => { - const PUBLIC_EXPORTS = [['store', Function]] as const; - - for (const [name, type] of PUBLIC_EXPORTS) { - test(`exports public "${name}" ${type.name}`, () => { - expect(storeExports).toHaveProperty(name); - expect(storeExports[name]).toBeInstanceOf(type); - }); - } - - test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); - expect(publicExportNames).toHaveLength(Object.keys(storeExports).length); - for (const name in storeExports) { - expect(publicExportNames).toContain(name); - } - }); - - test('has no default export', () => { - expect(storeExports).not.toHaveProperty('default'); - }); -}); - const RECONSILERS = [ ['keyed', keyedExports], ['non-keyed', nonKeyedExports], @@ -141,10 +119,10 @@ for (const [reconsiler, exports] of RECONSILERS) { test('does not export any private internals', () => { const publicExportNames = ['reconcile']; - expect(publicExportNames).toHaveLength(Object.keys(exports).length); for (const name in exports) { expect(publicExportNames).toContain(name); } + expect(publicExportNames).toHaveLength(Object.keys(exports).length); }); test('has no default export', () => { diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index 58e0df6..7ae892b 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -2,9 +2,9 @@ import { describe, expect, spyOn, test } from 'bun:test'; // eslint-disable-next-line import/no-duplicates -import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; +import { compile } from '../../src/macro' assert { type: 'macro' }; // eslint-disable-next-line import/no-duplicates -import { compile as compileNoMacro } from '../../src/runtime/macro'; +import { compile as compileNoMacro } from '../../src/macro'; describe('compile', () => { // FIXME: Test for each of the compile macro options; keepComments, keepSpace @@ -171,16 +171,64 @@ describe('compile', () => { expect(meta.html).toBe('
'); }); - test('keeps comments when option is true', () => { + test('keeps comment when option is true', () => { const meta = compile('
', { keepComments: true }); expect(meta.html).toBe('
'); }); - test('removes comments when option is false', () => { + test('removes comment when option is false', () => { const meta = compile('
', { keepComments: false }); expect(meta.html).toBe('
'); }); + test('keeps multiple comments when option is true', () => { + const meta = compile('
', { + keepComments: true, + }); + expect(meta.html).toBe('
'); + }); + + test('removes multiple comments when option is false', () => { + const meta = compile('
', { + keepComments: false, + }); + expect(meta.html).toBe('
'); + }); + + test('keeps comment when option is true and template is only comment', () => { + const meta = compile('', { keepComments: true }); + expect(meta.html).toBe(''); + }); + + test('removes comment when option is false and template is only comment', () => { + const meta = compile('', { keepComments: false }); + expect(meta.html).toBe(''); + }); + + const templates = [ + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + ]; + + test.each(templates)('keeps comment when option is true for %j', (template) => { + const meta = compileNoMacro(template, { keepComments: true }); + expect(meta.html).toBe(template); + }); + + test.each(templates)('removes comment when option is false for %j', (template) => { + const meta = compileNoMacro(template, { keepComments: false }); + expect(meta.html).toBe('
'); + }); + test('has 1 k and d properties when 1 comment ref when option is true', () => { const meta = compile('
', { keepComments: true }); expect(meta.k).toHaveLength(1); @@ -189,7 +237,7 @@ describe('compile', () => { test('returns expected html for template with comment ref when option is true', () => { const meta = compile('
', { keepComments: true }); - expect(meta.html).toBe('
'); + expect(meta.html).toBe('
'); }); }); diff --git a/test/unit/runtime.test.ts b/test/unit/runtime.test.ts index 3e30ba5..3c12f1e 100644 --- a/test/unit/runtime.test.ts +++ b/test/unit/runtime.test.ts @@ -1,8 +1,8 @@ // XXX: This file has the same tests as test/unit/compile.test.ts, keep them in sync. import { afterEach, describe, expect, test } from 'bun:test'; -import { collect, h } from '../../src/runtime/index'; -import { compile } from '../../src/runtime/macro' assert { type: 'macro' }; +import { compile } from '../../src/macro' assert { type: 'macro' }; +import { collect, h } from '../../src/runtime'; import { cleanup, render } from './utils'; describe('h', () => { diff --git a/test/unit/test-utils.test.ts b/test/unit/test-utils.test.ts index db8382e..23ab6b9 100644 --- a/test/unit/test-utils.test.ts +++ b/test/unit/test-utils.test.ts @@ -1,13 +1,24 @@ import { afterEach, describe, expect, spyOn, test } from 'bun:test'; -import { Test as TestPrecompiled } from '../TestComponent_precompiled'; -import { Test as TestRegular } from '../TestComponent_regular'; -import { cleanup, render } from './utils'; +import { Test } from '../TestComponent'; +import { Test as TestBrowser } from '../TestComponent_browser'; +import { cleanup, consoleSpy, render } from './utils'; + +describe('render (no call)', () => { + test('is a function', () => { + expect(render).toBeInstanceOf(Function); + }); + + test('takes a single argument', () => { + expect(render).toHaveLength(1); + }); +}); describe('render', () => { afterEach(cleanup); test('returns a container element', () => { const rendered = render(document.createElement('div')); + expect(rendered).toHaveProperty('container'); expect(rendered.container).toBeInstanceOf(window.Element); }); @@ -37,64 +48,89 @@ describe('render', () => { document.body.textContent = ''; }); - test('returns an unmount function', () => { - const rendered = render(document.createElement('div')); - // eslint-disable-next-line @typescript-eslint/unbound-method - expect(rendered.unmount).toBeInstanceOf(Function); + test('renders TestBrowser component correctly', () => { + const rendered = render(TestBrowser({ text: 'abc' })); + expect(rendered.container.innerHTML).toBe('
abc
'); }); - test('unmount removes supplied element from container', () => { - const rendered = render(document.createElement('div')); - expect(rendered.container.firstChild).toBeTruthy(); - rendered.unmount(); - expect(rendered.container).toBeTruthy(); - expect(rendered.container.firstChild).toBeNull(); + test('renders Test component correctly', () => { + const rendered = render(Test({ text: 'abc' })); + expect(rendered.container.innerHTML).toBe('
abc
'); }); - test('returns a debug function', () => { - const rendered = render(document.createElement('div')); - // eslint-disable-next-line @typescript-eslint/unbound-method - expect(rendered.debug).toBeInstanceOf(Function); + describe('unmount method', () => { + test('is a function', () => { + const rendered = render(document.createElement('div')); + expect(rendered).toHaveProperty('unmount'); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(rendered.unmount).toBeInstanceOf(Function); + }); + + test('removes supplied element from container', () => { + const rendered = render(document.createElement('div')); + expect(rendered.container.firstChild).toBeTruthy(); + rendered.unmount(); + expect(rendered.container).toBeTruthy(); + expect(rendered.container.firstChild).toBeNull(); + }); }); - test('debug function prints to console', async () => { - const logSpy = spyOn(console, 'log').mockImplementation(() => {}); - const rendered = render(document.createElement('div')); - await rendered.debug(); - expect(logSpy).toHaveBeenCalledTimes(1); - expect(logSpy).toHaveBeenCalledWith('DEBUG:\n
\n'); - logSpy.mockRestore(); - }); - - test('debug function prints prettified container DOM to console', async () => { - const logSpy = spyOn(console, 'log').mockImplementation(() => {}); - const main = document.createElement('main'); - main.append( - document.createElement('div'), - document.createElement('div'), - document.createElement('div'), - ); - const rendered = render(main); - await rendered.debug(); - expect(logSpy).toHaveBeenCalledTimes(1); - expect(logSpy).toHaveBeenCalledWith( - 'DEBUG:\n
\n
\n
\n
\n
\n', - ); - logSpy.mockRestore(); + describe('debug method', () => { + test('is a function', () => { + const rendered = render(document.createElement('div')); + expect(rendered).toHaveProperty('debug'); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(rendered.debug).toBeInstanceOf(Function); + }); + + test('prints to console2', async () => { + const spy = spyOn(console2, 'log').mockImplementation(() => {}); + const rendered = render(document.createElement('div')); + await rendered.debug(); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('DEBUG:\n
\n'); + spy.mockRestore(); + }); + + test('does not print to console, only console2', async () => { + const spy = spyOn(console, 'log').mockImplementation(() => {}); + const spy2 = spyOn(console2, 'log').mockImplementation(() => {}); + const rendered = render(document.createElement('div')); + await rendered.debug(); + expect(spy).not.toHaveBeenCalled(); + expect(spy2).toHaveBeenCalledTimes(1); + spy.mockRestore(); + spy2.mockRestore(); + }); + + test('prints prettified container DOM to console', async () => { + const spy = spyOn(console2, 'log').mockImplementation(() => {}); + const main = document.createElement('main'); + main.append( + document.createElement('div'), + document.createElement('div'), + document.createElement('div'), + ); + const rendered = render(main); + await rendered.debug(); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + 'DEBUG:\n
\n
\n
\n
\n
\n', + ); + spy.mockRestore(); + }); }); +}); - test('renders TestRegular component correctly', () => { - const rendered = render(TestRegular({ text: 'abc' })); - expect(rendered.container.innerHTML).toBe('
abc
'); +describe('cleanup', () => { + test('is a function', () => { + expect(cleanup).toBeInstanceOf(Function); }); - test('renders TestPrecompiled component correctly', () => { - const rendered = render(TestPrecompiled({ text: 'abc' })); - expect(rendered.container.innerHTML).toBe('
abc
'); + test('takes no arguments', () => { + expect(cleanup).toHaveLength(0); }); -}); -describe('cleanup', () => { test('throws when there are no rendered components', () => { expect(() => cleanup()).toThrow(); }); @@ -130,3 +166,39 @@ describe('cleanup', () => { document.body.textContent = ''; }); }); + +describe('consoleSpy', () => { + test('is a function', () => { + expect(consoleSpy).toBeInstanceOf(Function); + }); + + test('takes no arguments', () => { + expect(consoleSpy).toHaveLength(0); + }); + + test('returns a function', () => { + const checkConsoleSpy = consoleSpy(); + expect(checkConsoleSpy).toBeInstanceOf(Function); + checkConsoleSpy(); + }); + + test('returned function takes no arguments', () => { + const checkConsoleSpy = consoleSpy(); + expect(checkConsoleSpy).toHaveLength(0); + checkConsoleSpy(); + }); + + test('passes when no console methods are called', () => { + const checkConsoleSpy = consoleSpy(); + checkConsoleSpy(); + }); + + // FIXME: How to test this? + test.skip('fails when console methods are called', () => { + const checkConsoleSpy = consoleSpy(); + console.log('a'); + console.warn('b'); + console.error('c'); + checkConsoleSpy(); + }); +}); diff --git a/test/unit/utils.ts b/test/unit/utils.ts index ab48b13..3ab22e2 100644 --- a/test/unit/utils.ts +++ b/test/unit/utils.ts @@ -1,4 +1,4 @@ -// import { expect, spyOn, type Mock } from 'bun:test'; +import { expect, spyOn, type Mock } from 'bun:test'; export interface RenderResult { /** A wrapper DIV which contains your mounted component. */ @@ -28,8 +28,8 @@ export function render(component: Node): RenderResult { container, async debug(el = container) { const { format } = await import('prettier'); - // eslint-disable-next-line no-console - console.log(`DEBUG:\n${await format(el.innerHTML, { parser: 'html' })}`); + const html = await format(el.innerHTML, { parser: 'html' }); + console2.log(`DEBUG:\n${html}`); }, unmount() { // eslint-disable-next-line unicorn/prefer-dom-node-remove @@ -54,23 +54,19 @@ export function cleanup(): void { }); } -// TODO: Remove if unused. +const consoleMethods = Object.getOwnPropertyNames(console) as (keyof Console)[]; -// const consoleMethods = Object.getOwnPropertyNames( -// window.console, -// ) as (keyof Console)[]; -// -// export function consoleSpy(): () => void { -// const spies: Mock<() => void>[] = []; -// -// for (const method of consoleMethods) { -// spies.push(spyOn(window.console, method)); -// } -// -// return () => { -// for (const spy of spies) { -// expect(spy).toHaveBeenCalledTimes(0); -// spy.mockRestore(); -// } -// }; -// } +export function consoleSpy(): () => void { + const spies: Mock<() => void>[] = []; + + for (const method of consoleMethods) { + spies.push(spyOn(console, method)); + } + + return /** check */ () => { + for (const spy of spies) { + expect(spy).not.toHaveBeenCalled(); + spy.mockRestore(); + } + }; +} From 72af293faab81aecf3ee51b0edcef0f8275224d2 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 4 Jan 2024 21:46:09 +1100 Subject: [PATCH 075/169] Publish v0.8.0-next.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb1d497..2319e60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.5", + "version": "0.8.0-next.6", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 0b96dd610ba063cfc632d9e95fcd92e5e341733f Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 11:56:40 +1100 Subject: [PATCH 076/169] feat: Refactor browser files - Rename `browser/compile.ts` to `browser/runtime.ts` for consistency with default mode - Rename types including `S1View` to `View` --- src/browser/index.ts | 2 +- src/browser/{compile.ts => runtime.ts} | 20 ++++++++++---------- test/TestComponent_browser.ts | 2 +- test/unit/browser-compile.test.ts | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/browser/{compile.ts => runtime.ts} (86%) diff --git a/src/browser/index.ts b/src/browser/index.ts index c4c62b7..d3c2090 100644 --- a/src/browser/index.ts +++ b/src/browser/index.ts @@ -1,4 +1,4 @@ -export * from './compile'; +export * from './runtime'; export * from '../events'; export * from '../store'; diff --git a/src/browser/compile.ts b/src/browser/runtime.ts similarity index 86% rename from src/browser/compile.ts rename to src/browser/runtime.ts index 8f5fa74..249cca6 100644 --- a/src/browser/compile.ts +++ b/src/browser/runtime.ts @@ -1,16 +1,16 @@ import type { LowercaseKeys, Refs } from '../types'; import { create } from '../utils'; -interface RefInfo { +interface RefMeta { /** Ref key name. */ readonly k: string; /** Distance from previous ref node or root. */ readonly d: number; } -export interface S1View extends Node, ChildNode { +export interface View extends Node, ChildNode { /** @private */ - $$refs: readonly RefInfo[]; + $$refs: readonly RefMeta[]; } const compilerTemplate = create('template'); @@ -46,7 +46,7 @@ const collector = (node: Node): string | undefined => { */ export const h = ( template: string, -): S1View & T => { +): View & T => { compilerTemplate.innerHTML = template // reduce any whitespace to a single space .replace(/\s+/g, ' ') @@ -54,8 +54,8 @@ export const h = ( .replace(/> /g, '>') .replace(/ ( export const html = ( template: TemplateStringsArray, ...substitutions: unknown[] -): S1View => h(String.raw(template, ...substitutions)); +): View => h(String.raw(template, ...substitutions)); /** * Collects node refs from a compiled template view. @@ -87,11 +87,11 @@ export const html = ( */ export const collect = ( root: Node, - view: S1View, + view: View, ): LowercaseKeys => { - const walker = treeWalker; - const len = view.$$refs.length; + const walker = treeWalker; // local var is faster in some JS engines const refs: Refs = {}; + const len = view.$$refs.length; let index = 0; let metadata; let distance; diff --git a/test/TestComponent_browser.ts b/test/TestComponent_browser.ts index 53c5c8c..09ed3e2 100644 --- a/test/TestComponent_browser.ts +++ b/test/TestComponent_browser.ts @@ -1,4 +1,4 @@ -import { collect, h } from '../src/browser/compile'; +import { collect, h } from '../src/browser/runtime'; type TestComponent = HTMLDivElement; diff --git a/test/unit/browser-compile.test.ts b/test/unit/browser-compile.test.ts index 923916f..0c0027d 100644 --- a/test/unit/browser-compile.test.ts +++ b/test/unit/browser-compile.test.ts @@ -1,7 +1,7 @@ // XXX: This file has the same tests as test/unit/runtime.test.ts, keep them in sync. import { afterEach, describe, expect, test } from 'bun:test'; -import { collect, h, html } from '../../src/browser/compile'; +import { collect, h, html } from '../../src/browser/runtime'; import { cleanup, render } from './utils'; describe('h', () => { From 2a5437c19250cad0246cebb88a911044e4336c5f Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 11:58:01 +1100 Subject: [PATCH 077/169] test: Clean up test setup script --- test/setup.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/setup.ts b/test/setup.ts index 95d47e8..cb3adbc 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -30,7 +30,6 @@ expect.extend({ }); const originalConsole = global.console; - const noop = () => {}; function setupDOM() { @@ -41,12 +40,7 @@ function setupDOM() { global.window = dom.window.document.defaultView; global.document = window.document; global.console = window.console; // https://github.com/capricorn86/happy-dom/wiki/Virtual-Console - global.setTimeout = window.setTimeout; - global.clearTimeout = window.clearTimeout; global.DocumentFragment = window.DocumentFragment; - global.CSSStyleSheet = window.CSSStyleSheet; - global.Text = window.Text; - global.fetch = window.fetch; global.MutationObserver = window.MutationObserver; } From 903756fa2daebdfa6d6d815615c310172355279f Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 11:58:13 +1100 Subject: [PATCH 078/169] test: Add tests for setup script --- test/unit/test-setup.test.ts | 103 +++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 test/unit/test-setup.test.ts diff --git a/test/unit/test-setup.test.ts b/test/unit/test-setup.test.ts new file mode 100644 index 0000000..d964454 --- /dev/null +++ b/test/unit/test-setup.test.ts @@ -0,0 +1,103 @@ +import { describe, expect, test } from 'bun:test'; +import { VirtualConsole } from 'happy-dom'; + +describe('matcher: toBePlainObject', () => { + const plainObjects = [ + {}, + { foo: 'bar' }, + Object.create(null), + Object.create({}), + // eslint-disable-next-line no-new-object + new Object(), + ]; + + const nonPlainObjects = [ + null, + // eslint-disable-next-line unicorn/no-new-array + new Array(1), + [[{}]], // double array due to quirk of bun test; resolves to [{}] + [[null]], // double array due to quirk of bun test; resolves to [null] + () => {}, + // eslint-disable-next-line @typescript-eslint/no-implied-eval + new Function(), + Function, + Object, + new Date(), + // eslint-disable-next-line prefer-regex-literals + new RegExp(''), + // eslint-disable-next-line unicorn/error-message + new Error(), + new Map(), + new Set(), + new WeakMap(), + new WeakSet(), + new Promise(() => {}), + new Int8Array(), + ]; + + const nonObjects = [ + 'Hello', + 123, + true, + false, + undefined, + Symbol('sym'), + BigInt(1234), + // eslint-disable-next-line unicorn/prefer-number-properties + NaN, + // eslint-disable-next-line unicorn/prefer-number-properties + Infinity, + ]; + + test.each(plainObjects)('matches plain object %#', (item) => { + expect(item).toBePlainObject(); + }); + + test.each(nonPlainObjects)('does not match non-plain object %#', (item) => { + expect(item).not.toBePlainObject(); + }); + + test.each(nonObjects)('does not match non-object %#', (item) => { + expect(item).not.toBePlainObject(); + }); +}); + +describe('console2', () => { + test('global exists', () => { + expect(console2).toBeDefined(); + }); + + // TODO: How to test this? Since setup.ts is preloaded, there's no way to get + // the original console. + // test('is the original console', () => { + // expect(console2).toBe(originalConsole); + // }); + + test('is not a happy-dom virtual console', () => { + expect(window.console).toBeInstanceOf(VirtualConsole); + expect(console).toStrictEqual(window.console); + expect(console2).not.toBe(console); + expect(console2).not.toBe(window.console); + }); +}); + +describe('happy-dom', () => { + const globals = [ + 'happyDOM', + 'window', + 'document', + 'console', + 'DocumentFragment', + 'MutationObserver', + ]; + + test.each(globals)('"%s" global exists', (global) => { + expect(global).toBeDefined(); + }); + + test('console is a virtual console', () => { + expect(window.console).toBeInstanceOf(VirtualConsole); + expect(console).toBeInstanceOf(VirtualConsole); + expect(console).toStrictEqual(window.console); + }); +}); From 04702a83e02ddb428f1304beda7ef48075169a16 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 12:12:04 +1100 Subject: [PATCH 079/169] feat: Refactor build, paths, and types - Completely refactor how types are gnerated and consumed - Simplify browser bundle path - Clean up build - Tweak TS config options --- build.ts | 43 ++++++++++++++++++++++++++++++------------- package.json | 23 +++++++++-------------- tsconfig.d.json | 11 ----------- tsconfig.json | 3 ++- 4 files changed, 41 insertions(+), 39 deletions(-) delete mode 100644 tsconfig.d.json diff --git a/build.ts b/build.ts index 55eb24a..837db2b 100644 --- a/build.ts +++ b/build.ts @@ -1,22 +1,24 @@ /* eslint-disable no-console */ -import * as rollup from 'rollup'; +import { createBundle } from 'dts-buddy'; +import { rollup } from 'rollup'; import { minify } from 'terser'; console.time('build'); -const out1 = await Bun.build({ +const out = await Bun.build({ entrypoints: ['src/browser/index.ts'], - outdir: 'dist/browser', + outdir: 'dist', + naming: '[dir]/browser.js', target: 'browser', minify: true, sourcemap: 'inline', }); -const bundle = await rollup.rollup({ - input: out1.outputs[0].path, +const bundle = await rollup({ + input: out.outputs[0].path, }); await bundle.write({ - file: out1.outputs[0].path, + file: out.outputs[0].path, format: 'iife', name: 'stage1', sourcemap: true, @@ -43,16 +45,16 @@ await bundle.write({ ], }); -const out2 = await Bun.build({ +await Bun.build({ entrypoints: ['src/browser/index.ts'], - outdir: 'dist/browser', + outdir: 'dist', target: 'browser', - naming: '[dir]/[name].mjs', + naming: '[dir]/browser.mjs', minify: true, sourcemap: 'external', }); -const out3 = await Bun.build({ +await Bun.build({ entrypoints: ['src/index.ts'], outdir: 'dist', target: 'browser', @@ -60,7 +62,7 @@ const out3 = await Bun.build({ sourcemap: 'external', }); -const out4 = await Bun.build({ +await Bun.build({ entrypoints: ['src/macro.ts'], outdir: 'dist', target: 'bun', @@ -68,7 +70,7 @@ const out4 = await Bun.build({ sourcemap: 'external', }); -const out5 = await Bun.build({ +await Bun.build({ entrypoints: [ 'src/reconcile/keyed.ts', 'src/reconcile/non-keyed.ts', @@ -80,4 +82,19 @@ const out5 = await Bun.build({ }); console.timeEnd('build'); -console.log(out1, out2, out3, out4, out5); +console.time('dts'); + +await createBundle({ + output: 'dist/index.d.ts', + modules: { + stage1: 'src/index.ts', + 'stage1/browser': 'src/browser/index.ts', + 'stage1/macro': 'src/macro.ts', + 'stage1/reconcile/keyed': 'src/reconcile/keyed.ts', + 'stage1/reconcile/non-keyed': 'src/reconcile/non-keyed.ts', + 'stage1/reconcile/reuse-nodes': 'src/reconcile/reuse-nodes.ts', + }, + include: ['src'], +}); + +console.timeEnd('dts'); diff --git a/package.json b/package.json index 2319e60..034c4bc 100644 --- a/package.json +++ b/package.json @@ -8,37 +8,32 @@ "license": "MIT", "sideEffects": false, "main": "dist/index.js", - "browser": "dist/browser/index.js", + "browser": "dist/browser.js", "types": "dist/index.d.ts", "exports": { ".": { - "FIXME__browser": { - "types": "./dist/browser/index.d.ts", - "import": "./dist/browser/index.mjs", - "require": "./dist/browser/index.js" - }, "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "./macro": { - "types": "./dist/macro.d.ts", + "types": "./dist/index.d.ts", "default": "./dist/macro.js" }, "./browser": { - "types": "./dist/browser/index.d.ts", - "import": "./dist/browser/index.mjs", - "require": "./dist/browser/index.js" + "types": "./dist/index.d.ts", + "import": "./dist/browser.mjs", + "require": "./dist/browser.js" }, "./reconcile/keyed": { - "types": "./dist/reconcile/keyed.d.ts", + "types": "./dist/index.d.ts", "default": "./dist/reconcile/keyed.js" }, "./reconcile/non-keyed": { - "types": "./dist/reconcile/non-keyed.d.ts", + "types": "./dist/index.d.ts", "default": "./dist/reconcile/non-keyed.js" }, "./reconcile/reuse-nodes": { - "types": "./dist/reconcile/reuse-nodes.d.ts", + "types": "./dist/index.d.ts", "default": "./dist/reconcile/reuse-nodes.js" }, "./dist/*": "./dist/*", @@ -53,7 +48,6 @@ "lint": "bun run lint:js && bun run lint:ts", "lint:js": "eslint --ignore-path .gitignore --ignore-pattern bench --ext .ts,.mjs,.js,.cjs .", "lint:ts": "tsc --noEmit", - "postbuild": "tsc --project ./tsconfig.d.json", "prebuild": "rm -rf dist", "test": "bun test --preload ./test/setup.ts test/unit --coverage", "test:e2e": "TZ=UTC playwright test" @@ -63,6 +57,7 @@ "@types/bun": "1.0.0", "@typescript-eslint/eslint-plugin": "6.17.0", "@typescript-eslint/parser": "6.17.0", + "dts-buddy": "0.4.3", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", diff --git a/tsconfig.d.json b/tsconfig.d.json deleted file mode 100644 index b16eed2..0000000 --- a/tsconfig.d.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "emitDeclarationOnly": true - }, - "include": ["src"] -} diff --git a/tsconfig.json b/tsconfig.json index db058ca..3b2e49a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "target": "esnext", "module": "esnext", + "moduleDetection": "force", "moduleResolution": "bundler", "esModuleInterop": false, "resolveJsonModule": true, @@ -26,6 +27,6 @@ // "./node_modules/typescript/lib/lib.esnext.full.d.ts" // workaround for bun-types breaking dom types // ] }, - "include": ["src", "test", "build.ts", "*.config.ts"], + "include": ["src", "test", "build.ts", "*.config.ts", "*.d.ts"], "references": [{ "path": "./tsconfig.node.json" }] } From 63fa8b256a0c685e221cc2cc3a092e425a7def1b Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 12:12:18 +1100 Subject: [PATCH 080/169] chore: Update dependencies --- bun.lockb | Bin 126938 -> 130650 bytes package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lockb b/bun.lockb index 4d4a7cf504669d8623a59297fb1a715a178ef607..9cd68651679286d6fbefc4d8f341358b765c0cde 100755 GIT binary patch delta 26335 zcmeHwXINBM*Y@m@QI3j&Qbbfl6h#Cn(gYc>VCMKN!Z>-+P)KfdcZm-noF@4D97dJ>wv%K8z zq>t#i@5RZ}C$BuT_bo_wIxy$Ns%}4(Z1?-0ugm}b`tyyWADM=(*0ZCW&EL0_iAIw# zC??+MqtU!aQfZAQYmhNL!(&}O-dSUPSa>Um(*ygBH|8Y705#h&x53jrbAYTOogll z*#@!(q!*+!WO+qC*U9O>K~nryNUCoUBq`EA!#Kp4GALsPxD|L>x^a+skja?-0@{-$ z56WsZhMvs^(dHGJmeEZ5oYkqUr`1Glx*DD~1K}{z)-|1{vct&rt{Y!I&|4 zkO^uTGX@Sere|t8V^~nN#tif+)W3mz6~Rv;p3L|Socyu_!-Du8KBj~-%je5VI0)5U zN&c>cvt#d?8V$N2s|h45%K9Gl(-5D= zeJmWz4sLSm_aUj(2DRlDE`cLsRti379Cw1GahXy_9;cDuWJMZGq

H<$BsfQaz>X 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 diff --git a/package.json b/package.json index 034c4bc..bb31976 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "eslint-plugin-unicorn": "50.0.1", "happy-dom": "12.10.3", "prettier": "3.1.1", - "rollup": "4.9.2", + "rollup": "4.9.3", "terser": "5.26.0", "typescript": "5.3.3" }, From 66f148388f7587dc49e1d36849e9156b83b4ae8a Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 6 Jan 2024 12:14:49 +1100 Subject: [PATCH 081/169] Publish `0.8.0-next.7` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb31976..503880c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.6", + "version": "0.8.0-next.7", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 86ebb02b6dc3fc5b95345b874307b7e6be2352f2 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 16 Jan 2024 12:44:34 +1100 Subject: [PATCH 082/169] chore: Update VS Code settings --- .vscode/extensions.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 7efca3f..cd965d4 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,6 @@ { "recommendations": [ + "oven.bun-vscode", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode" ] From 6dc63d0c36d87d6bec81f6bff70a9e5a5f04a3f8 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 16 Jan 2024 12:45:35 +1100 Subject: [PATCH 083/169] chore: Update dependencies --- bun.lockb | Bin 130650 -> 130674 bytes package.json | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bun.lockb b/bun.lockb index 9cd68651679286d6fbefc4d8f341358b765c0cde..5e9b44095e16b260f352b56e4e7fd54083874160 100755 GIT binary patch delta 16655 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 dV>;f3`U)lYgfLbtI5@3YE_n{2z)%JFx%& delta 16872 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 Dg?Xf; diff --git a/package.json b/package.json index 503880c..34e2480 100644 --- a/package.json +++ b/package.json @@ -54,24 +54,24 @@ }, "devDependencies": { "@playwright/test": "1.40.1", - "@types/bun": "1.0.0", - "@typescript-eslint/eslint-plugin": "6.17.0", - "@typescript-eslint/parser": "6.17.0", - "dts-buddy": "0.4.3", + "@types/bun": "1.0.1", + "@typescript-eslint/eslint-plugin": "6.19.0", + "@typescript-eslint/parser": "6.19.0", + "dts-buddy": "0.4.4", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-prettier": "5.1.2", + "eslint-plugin-prettier": "5.1.3", "eslint-plugin-unicorn": "50.0.1", - "happy-dom": "12.10.3", - "prettier": "3.1.1", - "rollup": "4.9.3", + "happy-dom": "13.1.4", + "prettier": "3.2.2", + "rollup": "4.9.5", "terser": "5.26.0", "typescript": "5.3.3" }, "overrides": { - "bun-types": "1.0.21" + "bun-types": "1.0.22" } } From fc6122682af3a74ddef6bc8c8c86e8af654b534b Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 16 Jan 2024 12:46:15 +1100 Subject: [PATCH 084/169] test: Fixes for new happy-dom API --- test/setup.ts | 10 ++++++++-- test/unit/utils.test.ts | 12 ++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/test/setup.ts b/test/setup.ts index cb3adbc..8c0fd0f 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -51,9 +51,15 @@ function setupMocks(): void { global.performance.measure = noop; } -export function reset(): void { +export async function reset(): Promise { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (global.happyDOM) { + await happyDOM.abort(); + window.close(); + } + setupDOM(); setupMocks(); } -reset(); +await reset(); diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index df94fba..5af9323 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -302,16 +302,17 @@ describe('onRemove', () => { expect(onRemove).toHaveLength(2); }); - test('calls callback when watched element is removed', () => { + test('calls callback when watched element is removed', async () => { const spy = mock(() => {}); const root = document.createElement('div'); document.body.appendChild(root); onRemove(root, spy); root.remove(); + await happyDOM.waitUntilComplete(); expect(spy).toHaveBeenCalledTimes(1); }); - test('calls callback when parent parent element is removed', () => { + test('calls callback when parent parent element is removed', async () => { const spy = mock(() => {}); const root = document.createElement('div'); const parent = document.createElement('div'); @@ -321,10 +322,11 @@ describe('onRemove', () => { document.body.appendChild(root); onRemove(child, spy); root.remove(); + await happyDOM.waitUntilComplete(); expect(spy).toHaveBeenCalledTimes(1); }); - test('does not call callback when nested child element is removed', () => { + test('does not call callback when nested child element is removed', async () => { const spy = mock(() => {}); const root = document.createElement('div'); const child = document.createElement('div'); @@ -332,10 +334,11 @@ describe('onRemove', () => { document.body.appendChild(root); onRemove(root, spy); child.remove(); + await happyDOM.waitUntilComplete(); expect(spy).not.toHaveBeenCalled(); }); - test('does not call callback when element is added or moved', () => { + test('does not call callback when element is added or moved', async () => { const spy = mock(() => {}); const root = document.createElement('div'); const child = document.createElement('div'); @@ -343,6 +346,7 @@ describe('onRemove', () => { onRemove(root, spy); root.appendChild(child); document.body.appendChild(root); + await happyDOM.waitUntilComplete(); expect(spy).not.toHaveBeenCalled(); }); }); From c320afb6f59410f485dd01ce86257955a656999c Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 18 Jan 2024 08:45:35 +1100 Subject: [PATCH 085/169] chore: Update dependencies --- bun.lockb | Bin 130674 -> 130674 bytes package.json | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lockb b/bun.lockb index 5e9b44095e16b260f352b56e4e7fd54083874160..0a8791df3d9d54796729bc83138abc973a078071 100755 GIT binary patch delta 1175 zcmezLhyBwZ_6d3lt7R>gPc_{XG`~R2Y+d4-l{Gf^tc>^XuWFpoGwH0i*R+j(ZK90Q zlO091CpU<4Y~~QVz&2UJ+F&z>>;z4w8YZBG8c1UD2{!@eRVPnQb`VvCD0B~CoGc+> zu(`t{Kz6c(vcY7IGyz6&pn7$%dXKaTlc&gOfY}`BK8%_$D<*fO^C0m~K;`r|yJR$q zI^^lPyR!yva!_u4K4W@*>HH$62N`^SZFZcGyt;V;!=@~CwU=(krp%jkea@WgbJsKN z<=*{rZ*)w2xxr=EAiaB6Zfs_)OW<@6&EC3T<0-D)nbt8YgBO)}ZrWCUVaZ`_t(O}g z|9jSCpVxeB^UGxux*Y|l?pk2zY5h>#m!asx#gkp9P4iw9NVtk_UfQl<>0q+aM51S_ z#r^^}rS97vwSMlpEN+rJ&)05SJ<0pBXsOx4c@JOiy2avCzKY*MOKMGD^5qbD58FfL zM|Si1@xKu)oXmSr!a@DV6ESXqI~P?S^DgCTwoUny&Hpfiz@4W zqV?XG_%Ah~PrtY-&D$SPYiympt7M^pMaL8;$E?g)S^wtaLB_63N*9*cbE|w?IxS&y z>EQs4`gKMj{$Dtj+piINly@ZAzlLL*M9zd=-3CRr@^^f-1poB!Q;@BmQSaz_Y=QN( z)mh20k3_VOe)`?bvpLJx!bw|;fq{XM;UE7$Mg|6FAcg@J?ebQqZ7DalHk8eKRdD9t z>|UPpPXdZ7UN-F#a0}7e%XCR(pO$lVh@_6xDS49(?aqJgcYl)IQKUYJP0RkyOh#|1 z$+2%vI5f|z-p8UG=zjM7Vo8SkcelrUFE5ZF zZPC|nMwH~bNKDl>TK?%zA2X-h@5!le3+knIf9^kL>Qke;M0jALTSxNBI!HmRqHvGa0L z->qqo5q)p>@9E0Px$g=b0+Jd$J;G=GT6SYk)YZ?~pAHr<-CDeiA#nYT3vUZNK1%-F z5z(@kaf&q8>zyt-A)hp6w>^2YyKce8m2qv)@Cu``+Vrp| zK)%RtMrlUl=?1?U&rVN%1{BEu%_u+J<`1L$biv(>O4FDAVUz}2eE1JzH<%Ilm$8r0 Jc=Ex|lK{C{@9zKr delta 1169 zcmezLhyBwZ_6d3l0hd>QTPC;uXkKuDMO7YCqsA*&=8co{W^VQJ?sHlGIA)_?n<%5y zWJgi$$qk|$n>oZTuuYcGHQ3A{J3*7FoCzqQ29lV3!cBmA#mSSC9Yj?j3f%)3C*M#u z*xca}AUjz?-e59EngF91P`x@>y+_)F$r9o~(R3e1jma04!NyPSNasP~oq)>eZ+6LO z6m=-q4wh;(TTmfw8lUcO!6@);6=U`tm77&B!%EnkvZnp2zS42-gH9~F{HF=Z(T}%t z&(Un!D^`^%tE=a=K1Ds0bu(*S0;hwlLD7z7#fNvVwNp6vJoobUEblEoU2k5@4zSPJ z;S{juD^nuZYPo$sBvOBcsr#(!zFq&x@>24v^(X!-^sQjwp7Uh$(sm6?hvvP9RODY9 z{J48;Mz3n;)N4{|;XAuSo#Xz>8vm)tGW?Z1>0XW4G_{Eqx3|6ieqM8KuF1)t!7VG_ z#{7yD?p0nmb29Hi35VK$j-@Nvs*}Haa`SA`TDCpt&ga~%rm~@DDt`7BSMHJg^o4K! za`U|pDyD}2{2eQ$V-+pbGF{*3Us_pJvPD8m)8^EJ7Z@GVxprFUygM*qTR+#bB`&&e ztW9|>cCn^xSdb~5ANhC5+lOcO{$y)%(U-e((RO=>C8Lx_S@rIGs~bn}-TH31gq?SD z>EQs4dYcdLPigq7hHh0ZU3)=)x$!@CXOr$<>tih{rzjR&iq<2 z*UI8=Vdq8VvmN~Yv|L$ndJgBO{O3X5DUvg)GTw_t|7~h6JG;H}Pne#;+fx;L4WFKF zo*et;gu}d@X?Y*}P0|*BZsJTW=5OV0GH?y{{}G;Y$W!`T$I76;HEXgapRL%CxK@Ra zO?gG8s?vqN8M}&V1&&|utH075HaYceLA~IzSqF}st8migl)gX9$#(y$gA-zN_MA89 zi@#wj_29QYYb8`I6^r!*{g)qMK&ut92$gvZqXvC&9g^hEaJ&4(x6 zbgWRCVv?)tw~zn$W^3NRMZE_cw@%!1iN~^mZ@Q}HxkIN`vP&M`tZ-w(=D*tx9pl~U z=zOQoTf;E#WICBE6@{mU$713km(3Q>#_ zjE37SqZrK@8I7hFMl%{Qnr&Ya%@}XNXgHl^3gb+$vISEZ#X*eiyQVNkGXYhIO=o<^ zHNEK=qr!HTMT|2HrW?*;RG5C}5~Dh!*>uGpAmPi5rHs?XHUNd+EM(-^e((yTvD);{ zw}E_--;B~g%M5-qo}FH_87Pqdn^Atc%^ybh=^t-1DotPdhfx}A?cqO+-C#!GU&cO0 Kqsa$9PXYke4*SOd diff --git a/package.json b/package.json index 34e2480..399a1c2 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.40.1", - "@types/bun": "1.0.1", + "@playwright/test": "1.41.0", + "@types/bun": "1.0.2", "@typescript-eslint/eslint-plugin": "6.19.0", "@typescript-eslint/parser": "6.19.0", "dts-buddy": "0.4.4", @@ -66,12 +66,12 @@ "eslint-plugin-prettier": "5.1.3", "eslint-plugin-unicorn": "50.0.1", "happy-dom": "13.1.4", - "prettier": "3.2.2", + "prettier": "3.2.4", "rollup": "4.9.5", - "terser": "5.26.0", + "terser": "5.27.0", "typescript": "5.3.3" }, "overrides": { - "bun-types": "1.0.22" + "bun-types": "1.0.23" } } From d7444a1cdd0e714f09771b3bb4dfa4e8b1e52841 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Thu, 18 Jan 2024 08:46:00 +1100 Subject: [PATCH 086/169] test: Clean up --- test/unit/test-setup.test.ts | 103 ------------------ test/unit/test-utils.test.ts | 204 ----------------------------------- test/unit/utils.ts | 19 ---- 3 files changed, 326 deletions(-) delete mode 100644 test/unit/test-setup.test.ts delete mode 100644 test/unit/test-utils.test.ts diff --git a/test/unit/test-setup.test.ts b/test/unit/test-setup.test.ts deleted file mode 100644 index d964454..0000000 --- a/test/unit/test-setup.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { describe, expect, test } from 'bun:test'; -import { VirtualConsole } from 'happy-dom'; - -describe('matcher: toBePlainObject', () => { - const plainObjects = [ - {}, - { foo: 'bar' }, - Object.create(null), - Object.create({}), - // eslint-disable-next-line no-new-object - new Object(), - ]; - - const nonPlainObjects = [ - null, - // eslint-disable-next-line unicorn/no-new-array - new Array(1), - [[{}]], // double array due to quirk of bun test; resolves to [{}] - [[null]], // double array due to quirk of bun test; resolves to [null] - () => {}, - // eslint-disable-next-line @typescript-eslint/no-implied-eval - new Function(), - Function, - Object, - new Date(), - // eslint-disable-next-line prefer-regex-literals - new RegExp(''), - // eslint-disable-next-line unicorn/error-message - new Error(), - new Map(), - new Set(), - new WeakMap(), - new WeakSet(), - new Promise(() => {}), - new Int8Array(), - ]; - - const nonObjects = [ - 'Hello', - 123, - true, - false, - undefined, - Symbol('sym'), - BigInt(1234), - // eslint-disable-next-line unicorn/prefer-number-properties - NaN, - // eslint-disable-next-line unicorn/prefer-number-properties - Infinity, - ]; - - test.each(plainObjects)('matches plain object %#', (item) => { - expect(item).toBePlainObject(); - }); - - test.each(nonPlainObjects)('does not match non-plain object %#', (item) => { - expect(item).not.toBePlainObject(); - }); - - test.each(nonObjects)('does not match non-object %#', (item) => { - expect(item).not.toBePlainObject(); - }); -}); - -describe('console2', () => { - test('global exists', () => { - expect(console2).toBeDefined(); - }); - - // TODO: How to test this? Since setup.ts is preloaded, there's no way to get - // the original console. - // test('is the original console', () => { - // expect(console2).toBe(originalConsole); - // }); - - test('is not a happy-dom virtual console', () => { - expect(window.console).toBeInstanceOf(VirtualConsole); - expect(console).toStrictEqual(window.console); - expect(console2).not.toBe(console); - expect(console2).not.toBe(window.console); - }); -}); - -describe('happy-dom', () => { - const globals = [ - 'happyDOM', - 'window', - 'document', - 'console', - 'DocumentFragment', - 'MutationObserver', - ]; - - test.each(globals)('"%s" global exists', (global) => { - expect(global).toBeDefined(); - }); - - test('console is a virtual console', () => { - expect(window.console).toBeInstanceOf(VirtualConsole); - expect(console).toBeInstanceOf(VirtualConsole); - expect(console).toStrictEqual(window.console); - }); -}); diff --git a/test/unit/test-utils.test.ts b/test/unit/test-utils.test.ts deleted file mode 100644 index 23ab6b9..0000000 --- a/test/unit/test-utils.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { afterEach, describe, expect, spyOn, test } from 'bun:test'; -import { Test } from '../TestComponent'; -import { Test as TestBrowser } from '../TestComponent_browser'; -import { cleanup, consoleSpy, render } from './utils'; - -describe('render (no call)', () => { - test('is a function', () => { - expect(render).toBeInstanceOf(Function); - }); - - test('takes a single argument', () => { - expect(render).toHaveLength(1); - }); -}); - -describe('render', () => { - afterEach(cleanup); - - test('returns a container element', () => { - const rendered = render(document.createElement('div')); - expect(rendered).toHaveProperty('container'); - expect(rendered.container).toBeInstanceOf(window.Element); - }); - - test('mounts supplied element in container', () => { - const el = document.createElement('span'); - const rendered = render(el); - expect(rendered.container.firstChild).toBe(el); - }); - - test('mounts container div to document body', () => { - expect(document.body.firstChild).toBeNull(); - const rendered = render(document.createElement('div')); - expect(document.body.firstChild).toBe(rendered.container); - expect(document.body.firstChild).toBeInstanceOf(window.HTMLDivElement); - }); - - test('mounts containers when other DOM elements exist on document body', () => { - document.body.append(document.createElement('span')); - document.body.append(document.createElement('span')); - render(document.createElement('a')); - render(document.createElement('a')); - document.body.append(document.createElement('span')); - expect(document.body.childNodes).toHaveLength(5); - expect(document.body.innerHTML).toBe( - '

', - ); - document.body.textContent = ''; - }); - - test('renders TestBrowser component correctly', () => { - const rendered = render(TestBrowser({ text: 'abc' })); - expect(rendered.container.innerHTML).toBe('
abc
'); - }); - - test('renders Test component correctly', () => { - const rendered = render(Test({ text: 'abc' })); - expect(rendered.container.innerHTML).toBe('
abc
'); - }); - - describe('unmount method', () => { - test('is a function', () => { - const rendered = render(document.createElement('div')); - expect(rendered).toHaveProperty('unmount'); - // eslint-disable-next-line @typescript-eslint/unbound-method - expect(rendered.unmount).toBeInstanceOf(Function); - }); - - test('removes supplied element from container', () => { - const rendered = render(document.createElement('div')); - expect(rendered.container.firstChild).toBeTruthy(); - rendered.unmount(); - expect(rendered.container).toBeTruthy(); - expect(rendered.container.firstChild).toBeNull(); - }); - }); - - describe('debug method', () => { - test('is a function', () => { - const rendered = render(document.createElement('div')); - expect(rendered).toHaveProperty('debug'); - // eslint-disable-next-line @typescript-eslint/unbound-method - expect(rendered.debug).toBeInstanceOf(Function); - }); - - test('prints to console2', async () => { - const spy = spyOn(console2, 'log').mockImplementation(() => {}); - const rendered = render(document.createElement('div')); - await rendered.debug(); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith('DEBUG:\n
\n'); - spy.mockRestore(); - }); - - test('does not print to console, only console2', async () => { - const spy = spyOn(console, 'log').mockImplementation(() => {}); - const spy2 = spyOn(console2, 'log').mockImplementation(() => {}); - const rendered = render(document.createElement('div')); - await rendered.debug(); - expect(spy).not.toHaveBeenCalled(); - expect(spy2).toHaveBeenCalledTimes(1); - spy.mockRestore(); - spy2.mockRestore(); - }); - - test('prints prettified container DOM to console', async () => { - const spy = spyOn(console2, 'log').mockImplementation(() => {}); - const main = document.createElement('main'); - main.append( - document.createElement('div'), - document.createElement('div'), - document.createElement('div'), - ); - const rendered = render(main); - await rendered.debug(); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - 'DEBUG:\n
\n
\n
\n
\n
\n', - ); - spy.mockRestore(); - }); - }); -}); - -describe('cleanup', () => { - test('is a function', () => { - expect(cleanup).toBeInstanceOf(Function); - }); - - test('takes no arguments', () => { - expect(cleanup).toHaveLength(0); - }); - - test('throws when there are no rendered components', () => { - expect(() => cleanup()).toThrow(); - }); - - test('removes mounted container from document body', () => { - render(document.createElement('div')); - expect(document.body.firstChild).toBeTruthy(); - cleanup(); - expect(document.body.firstChild).toBeNull(); - }); - - test('removes multiple mounted containers from document body', () => { - render(document.createElement('div')); - render(document.createElement('div')); - render(document.createElement('div')); - expect(document.body.childNodes).toHaveLength(3); - cleanup(); - expect(document.body.childNodes).toHaveLength(0); - }); - - test('only removes mounted containers and not other DOM nodes', () => { - document.body.append(document.createElement('span')); - document.body.append(document.createElement('span')); - render(document.createElement('a')); - render(document.createElement('a')); - document.body.append(document.createElement('span')); - expect(document.body.childNodes).toHaveLength(5); - cleanup(); - expect(document.body.childNodes).toHaveLength(3); - for (const node of document.body.childNodes) { - expect(node).toBeInstanceOf(window.HTMLSpanElement); - } - document.body.textContent = ''; - }); -}); - -describe('consoleSpy', () => { - test('is a function', () => { - expect(consoleSpy).toBeInstanceOf(Function); - }); - - test('takes no arguments', () => { - expect(consoleSpy).toHaveLength(0); - }); - - test('returns a function', () => { - const checkConsoleSpy = consoleSpy(); - expect(checkConsoleSpy).toBeInstanceOf(Function); - checkConsoleSpy(); - }); - - test('returned function takes no arguments', () => { - const checkConsoleSpy = consoleSpy(); - expect(checkConsoleSpy).toHaveLength(0); - checkConsoleSpy(); - }); - - test('passes when no console methods are called', () => { - const checkConsoleSpy = consoleSpy(); - checkConsoleSpy(); - }); - - // FIXME: How to test this? - test.skip('fails when console methods are called', () => { - const checkConsoleSpy = consoleSpy(); - console.log('a'); - console.warn('b'); - console.error('c'); - checkConsoleSpy(); - }); -}); diff --git a/test/unit/utils.ts b/test/unit/utils.ts index 3ab22e2..d3154f9 100644 --- a/test/unit/utils.ts +++ b/test/unit/utils.ts @@ -1,5 +1,3 @@ -import { expect, spyOn, type Mock } from 'bun:test'; - export interface RenderResult { /** A wrapper DIV which contains your mounted component. */ container: HTMLDivElement; @@ -53,20 +51,3 @@ export function cleanup(): void { mountedContainers.delete(container); }); } - -const consoleMethods = Object.getOwnPropertyNames(console) as (keyof Console)[]; - -export function consoleSpy(): () => void { - const spies: Mock<() => void>[] = []; - - for (const method of consoleMethods) { - spies.push(spyOn(console, method)); - } - - return /** check */ () => { - for (const spy of spies) { - expect(spy).not.toHaveBeenCalled(); - spy.mockRestore(); - } - }; -} From 898ca020899317728030598431d8af55bd7cf8b0 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 23 Jan 2024 09:04:35 +1100 Subject: [PATCH 087/169] chore: Update dependencies --- bun.lockb | Bin 130674 -> 128842 bytes package.json | 14 +++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bun.lockb b/bun.lockb index 0a8791df3d9d54796729bc83138abc973a078071..c7fac0cd1ef37d66cbce2e6329ae06cd09b0f26c 100755 GIT binary patch delta 25717 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 delta 26389 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 diff --git a/package.json b/package.json index 399a1c2..1e3a898 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,10 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { - "@playwright/test": "1.41.0", - "@types/bun": "1.0.2", - "@typescript-eslint/eslint-plugin": "6.19.0", - "@typescript-eslint/parser": "6.19.0", + "@playwright/test": "1.41.1", + "@types/bun": "1.0.3", + "@typescript-eslint/eslint-plugin": "6.19.1", + "@typescript-eslint/parser": "6.19.1", "dts-buddy": "0.4.4", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", @@ -65,13 +65,13 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-unicorn": "50.0.1", - "happy-dom": "13.1.4", + "happy-dom": "13.2.1", "prettier": "3.2.4", - "rollup": "4.9.5", + "rollup": "4.9.6", "terser": "5.27.0", "typescript": "5.3.3" }, "overrides": { - "bun-types": "1.0.23" + "bun-types": "1.0.24" } } From aa17ad0dfb2dc62a9f1e4cb71e0d9a7c13439927 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 23 Jan 2024 09:06:00 +1100 Subject: [PATCH 088/169] test: Remove workaround for missing element classes in happy-dom --- test/setup.ts | 3 +-- test/unit/utils.test.ts | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/test/setup.ts b/test/setup.ts index 8c0fd0f..a60776f 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -17,8 +17,7 @@ declare module 'bun:test' { } expect.extend({ - // XXX: Although bun has a `toBeObject` matcher, it's not as useful since it - // doesn't check for plain objects. + // XXX: Bun's `toBeObject` matcher is the equivalent of `typeof x === 'object'`. toBePlainObject(received: unknown) { return Object.prototype.toString.call(received) === '[object Object]' ? { pass: true } diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index 5af9323..04a159c 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -87,15 +87,6 @@ describe('create', () => { expect(create).toHaveLength(1); }); - // TODO: happy-dom is missing HTMLOptionElement and HTMLOptGroupElement... remove these definitions when they are added - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (window.HTMLOptionElement || window.HTMLOptGroupElement) - throw new Error('Remove this when happy-dom adds HTMLOptionElement'); - // @ts-expect-error - temporary - window.HTMLOptionElement = window.HTMLElement; - // @ts-expect-error - temporary - window.HTMLOptGroupElement = window.HTMLElement; - const inputs = [ ['x', window.HTMLUnknownElement], ['div', window.HTMLDivElement], From a92d885fcb6adaa292d8a19b06db1fa546082703 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 23 Jan 2024 09:07:42 +1100 Subject: [PATCH 089/169] feat: Allow returning a value from synthetic events This allows for example returning false from a `__click` handler to prevent default. --- src/events.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/events.ts b/src/events.ts index 652c0a6..d55e241 100644 --- a/src/events.ts +++ b/src/events.ts @@ -9,9 +9,8 @@ const nativeToSyntheticEvent = (event: Event) => { // @ts-expect-error - unavoidable string indexing if (node[eventKey]) { // @ts-expect-error - unavoidable string indexing - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - node[eventKey](event); - return; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return + return node[eventKey](event); } node = node.parentNode; } From 41a585dc57c5438b63e9e7e7ba8648330d1515c7 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 23 Jan 2024 09:12:56 +1100 Subject: [PATCH 090/169] Publish `v0.8.0-next.8` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e3a898..3b24493 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stage1", - "version": "0.8.0-next.7", + "version": "0.8.0-next.8", "type": "module", "description": "High-performance JavaScript micro framework", "repository": "maxmilton/stage1", From 073dccdd72d068baeceef823f1528994ef5832be Mon Sep 17 00:00:00 2001 From: Max Milton Date: Tue, 30 Jan 2024 11:18:28 +1100 Subject: [PATCH 091/169] chore: Use semgrep pro in CI --- .github/workflows/semgrep-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/semgrep-analysis.yml b/.github/workflows/semgrep-analysis.yml index f03d6c5..ed6af3c 100644 --- a/.github/workflows/semgrep-analysis.yml +++ b/.github/workflows/semgrep-analysis.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 - run: semgrep ci --sarif > semgrep.sarif env: - SEMGREP_RULES: p/default + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - uses: github/codeql-action/upload-sarif@v3 if: always() with: From c1dba1ecb86bcc5f1ddcd5c3b6c8423f7c19f814 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 10 Feb 2024 08:47:10 +1100 Subject: [PATCH 092/169] chore: Migrate from `prettier` to `biome` for code formatting --- .eslintrc.cjs | 13 ++++-- .prettierrc | 14 ------- .vscode/extensions.json | 4 +- .vscode/settings.json | 10 +++-- biome.json | 92 +++++++++++++++++++++++++++++++++++++++++ package.json | 7 ++-- 6 files changed, 113 insertions(+), 27 deletions(-) delete mode 100644 .prettierrc create mode 100644 biome.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 592e48f..26caf16 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -20,16 +20,12 @@ module.exports = { 'plugin:@typescript-eslint/strict-type-checked', 'plugin:@typescript-eslint/stylistic-type-checked', 'plugin:unicorn/recommended', - 'prettier', ], - plugins: ['prettier'], rules: { '@typescript-eslint/explicit-module-boundary-types': ERROR, '@typescript-eslint/no-non-null-assertion': WARN, 'import/prefer-default-export': OFF, - 'import/order': OFF, // broken with prettier 'no-restricted-syntax': OFF, - 'prettier/prettier': WARN, 'unicorn/filename-case': OFF, 'unicorn/no-abusive-eslint-disable': WARN, 'unicorn/no-null': OFF, @@ -37,6 +33,15 @@ module.exports = { 'unicorn/prefer-top-level-await': WARN, 'unicorn/prevent-abbreviations': OFF, + /* Covered by biome formatter */ + '@typescript-eslint/indent': OFF, + 'function-paren-newline': OFF, + 'implicit-arrow-linebreak': OFF, + 'max-len': OFF, + 'object-curly-newline': OFF, + 'operator-linebreak': OFF, + 'unicorn/no-nested-ternary': OFF, + /* Performance and byte savings */ // byte savings '@typescript-eslint/no-confusing-void-expression': OFF, diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 4c3ca9b..0000000 --- a/.prettierrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "arrowParens": "always", - "endOfLine": "lf", - "singleQuote": true, - "trailingComma": "all", - "overrides": [ - { - "files": ["*.spec.ts", "*.test.ts"], - "options": { - "printWidth": 100 - } - } - ] -} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index cd965d4..47f9707 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ { "recommendations": [ + "biomejs.biome", "oven.bun-vscode", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode" + "dbaeumer.vscode-eslint" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 1de004a..0ec6cbe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,19 +2,23 @@ "editor.codeActionsOnSave": { "source.fixAll": "explicit" }, - "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnPaste": false, "editor.formatOnSave": true, "editor.formatOnType": false, "eslint.lintTask.options": "--ignore-path .gitignore", "git.branchProtection": ["master", "next"], "js/ts.implicitProjectConfig.checkJs": true, - "prettier.ignorePath": ".gitignore", + "prettier.enable": false, // use biome instead "typescript.tsdk": "node_modules/typescript/lib", + + "[json][jsonc][markdown]": { + "editor.defaultFormatter": "biomejs.biome" + }, "[javascript][typescript]": { "editor.codeActionsOnSave": { "source.sortImports": "explicit", "source.fixAll": "explicit" - } + }, + "editor.defaultFormatter": "biomejs.biome" } } diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..c2923d0 --- /dev/null +++ b/biome.json @@ -0,0 +1,92 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "organizeImports": { + "enabled": false + }, + "formatter": { + "formatWithErrors": true, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80 + }, + "javascript": { + "formatter": { + "semicolons": "always", + "trailingComma": "all", + "quoteStyle": "single" + } + }, + "linter": { + "ignore": ["bench/**", "src/reconcile/*.ts"], + "rules": { + "recommended": true, + "complexity": { + "noForEach": "off", + "useSimplifiedLogicExpression": "warn" + }, + "style": { + "noNamespace": "error", + "noNegationElse": "error", + "noNonNullAssertion": "off", + "noParameterProperties": "error", + "noRestrictedGlobals": "error", + "noShoutyConstants": "error", + "useCollapsedElseIf": "error", + "useEnumInitializers": "off", + "useNamingConvention": { + "level": "error", + "options": { "strictCase": false } + }, + "useShorthandArrayType": "error", + "useShorthandAssign": "error", + "useSingleCaseStatement": "off", + "useTemplate": "off" + }, + "suspicious": { + "noApproximativeNumericConstant": "error", + "noAssignInExpressions": "off", + "noConfusingVoidType": "off", + "noConsoleLog": "warn", + "noConstEnum": "off", + "noExplicitAny": "off", + "noMisrefactoredShorthandAssign": "error" + } + } + }, + "overrides": [ + { + "include": [".vscode/**"], + "json": { + "parser": { + "allowComments": true, + "allowTrailingCommas": true + } + } + }, + { + "include": ["**/*.spec.ts", "**/*.test.ts", "test/**/*.ts"], + "formatter": { + "lineWidth": 100 + } + }, + { + "include": ["build.ts"], + "linter": { + "rules": { + "style": { + "useNamingConvention": "off" + }, + "suspicious": { + "noConsoleLog": "off" + } + } + } + } + ] +} diff --git a/package.json b/package.json index 3b24493..5de2175 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ ], "scripts": { "build": "bun build.ts", - "lint": "bun run lint:js && bun run lint:ts", + "lint": "bun run lint:fmt && bun run lint:js && bun run lint:ts", + "lint:fmt": "biome format .", "lint:js": "eslint --ignore-path .gitignore --ignore-pattern bench --ext .ts,.mjs,.js,.cjs .", "lint:ts": "tsc --noEmit", "prebuild": "rm -rf dist", @@ -53,6 +54,7 @@ "test:e2e": "TZ=UTC playwright test" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "@playwright/test": "1.41.1", "@types/bun": "1.0.3", "@typescript-eslint/eslint-plugin": "6.19.1", @@ -61,12 +63,9 @@ "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", - "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-prettier": "5.1.3", "eslint-plugin-unicorn": "50.0.1", "happy-dom": "13.2.1", - "prettier": "3.2.4", "rollup": "4.9.6", "terser": "5.27.0", "typescript": "5.3.3" From 3071c8e0f2096e97fa1ec2f3b8781ef0e2cc4545 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 10 Feb 2024 08:49:33 +1100 Subject: [PATCH 093/169] chore: Fix new lint issues + run formatting --- package.json | 5 +---- src/browser/runtime.ts | 6 +++--- src/events.ts | 1 + src/runtime.ts | 2 +- test/setup.ts | 6 ++++-- test/unit/events.test.ts | 1 + test/unit/exports.test.ts | 22 +++++++++++----------- test/unit/macro.test.ts | 4 ++-- test/unit/store.test.ts | 4 ++-- test/unit/utils.ts | 17 +++++++++-------- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 5de2175..245bbf5 100644 --- a/package.json +++ b/package.json @@ -39,10 +39,7 @@ "./dist/*": "./dist/*", "./package.json": "./package.json" }, - "files": [ - "dist", - "src" - ], + "files": ["dist", "src"], "scripts": { "build": "bun build.ts", "lint": "bun run lint:fmt && bun run lint:js && bun run lint:ts", diff --git a/src/browser/runtime.ts b/src/browser/runtime.ts index 249cca6..417a673 100644 --- a/src/browser/runtime.ts +++ b/src/browser/runtime.ts @@ -15,7 +15,7 @@ export interface View extends Node, ChildNode { const compilerTemplate = create('template'); const treeWalker = document.createTreeWalker(compilerTemplate); -let str; +let str: string | null | undefined; const collector = (node: Node): string | undefined => { // 1 = Node.ELEMENT_NODE @@ -93,8 +93,8 @@ export const collect = ( const refs: Refs = {}; const len = view.$$refs.length; let index = 0; - let metadata; - let distance; + let metadata: RefMeta; + let distance: number; walker.currentNode = root; for (; index < len; index++) { diff --git a/src/events.ts b/src/events.ts index d55e241..68fe5f5 100644 --- a/src/events.ts +++ b/src/events.ts @@ -18,6 +18,7 @@ const nativeToSyntheticEvent = (event: Event) => { export const setupSyntheticEvent = (type: keyof DocumentEventMap): void => { configuredEvents[type] ??= + // biome-ignore lint/style/noCommaOperator: code compactness (document.addEventListener(type, nativeToSyntheticEvent), true); }; diff --git a/src/runtime.ts b/src/runtime.ts index c67a16e..1629073 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -31,7 +31,7 @@ export const collect = ( const refs: Refs = {}; const len = k.length; let index = 0; - let distance; + let distance: number; walker.currentNode = root; for (; index < len; index++) { diff --git a/test/setup.ts b/test/setup.ts index a60776f..0a3c520 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,13 +1,15 @@ import { expect } from 'bun:test'; import { GlobalWindow, type Window } from 'happy-dom'; +/* eslint-disable no-var, vars-on-top */ declare global { /** Real bun console. `console` is mapped to happy-dom's virtual console. */ - // eslint-disable-next-line no-var, vars-on-top + // biome-ignore lint/style/noVar: define global var console2: Console; - // eslint-disable-next-line no-var, vars-on-top + // biome-ignore lint/style/noVar: define global var happyDOM: Window['happyDOM']; } +/* eslint-enable */ declare module 'bun:test' { interface Matchers { diff --git a/test/unit/events.test.ts b/test/unit/events.test.ts index bf0465a..f407d33 100644 --- a/test/unit/events.test.ts +++ b/test/unit/events.test.ts @@ -66,6 +66,7 @@ describe('setupSyntheticEvent', () => { button.click(); expect(callback).toHaveBeenCalledTimes(1); deleteSyntheticEvent('click'); + // biome-ignore lint/performance/noDelete: cleanup delete document.body.__click; }); diff --git a/test/unit/exports.test.ts b/test/unit/exports.test.ts index af823db..67df17d 100644 --- a/test/unit/exports.test.ts +++ b/test/unit/exports.test.ts @@ -9,7 +9,7 @@ import * as nonKeyedExports from '../../src/reconcile/non-keyed'; import * as reuseNodesExports from '../../src/reconcile/reuse-nodes'; describe('browser', () => { - const PUBLIC_EXPORTS = [ + const publicExports = [ ['h', Function], ['html', Function], ['collect', Function], @@ -25,7 +25,7 @@ describe('browser', () => { ['store', Function], ] as const; - for (const [name, type] of PUBLIC_EXPORTS) { + for (const [name, type] of publicExports) { test(`exports public "${name}" ${type.name}`, () => { expect(browserExports).toHaveProperty(name); expect(browserExports[name]).toBeInstanceOf(type); @@ -33,7 +33,7 @@ describe('browser', () => { } test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + const publicExportNames = publicExports.map((x) => x[0]); for (const name in browserExports) { expect(publicExportNames).toContain(name); } @@ -46,7 +46,7 @@ describe('browser', () => { }); describe('index', () => { - const PUBLIC_EXPORTS = [ + const publicExports = [ ['h', Function], ['collect', Function], ['setupSyntheticEvent', Function], @@ -61,7 +61,7 @@ describe('index', () => { ['store', Function], ] as const; - for (const [name, type] of PUBLIC_EXPORTS) { + for (const [name, type] of publicExports) { test(`exports public "${name}" ${type.name}`, () => { expect(indexExports).toHaveProperty(name); expect(indexExports[name]).toBeInstanceOf(type); @@ -69,7 +69,7 @@ describe('index', () => { } test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + const publicExportNames = publicExports.map((x) => x[0]); for (const name in indexExports) { expect(publicExportNames).toContain(name); } @@ -82,9 +82,9 @@ describe('index', () => { }); describe('macro', () => { - const PUBLIC_EXPORTS = [['compile', Function]] as const; + const publicExports = [['compile', Function]] as const; - for (const [name, type] of PUBLIC_EXPORTS) { + for (const [name, type] of publicExports) { test(`exports public "${name}" ${type.name}`, () => { expect(macroExports).toHaveProperty(name); expect(macroExports[name]).toBeInstanceOf(type); @@ -92,7 +92,7 @@ describe('macro', () => { } test('does not export any private internals', () => { - const publicExportNames = PUBLIC_EXPORTS.map((x) => x[0]); + const publicExportNames = publicExports.map((x) => x[0]); for (const name in macroExports) { expect(publicExportNames).toContain(name); } @@ -104,13 +104,13 @@ describe('macro', () => { }); }); -const RECONSILERS = [ +const reconsilers = [ ['keyed', keyedExports], ['non-keyed', nonKeyedExports], ['reuse-nodes', reuseNodesExports], ] as const; -for (const [reconsiler, exports] of RECONSILERS) { +for (const [reconsiler, exports] of reconsilers) { describe(`reconcile/${reconsiler}`, () => { test('exports public "reconcile" Function', () => { expect(exports).toHaveProperty('reconcile'); diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index 7ae892b..f83ada9 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -71,7 +71,7 @@ describe('compile', () => { // TODO: Add documentation about this since it differs from the default compile.ts h() behaviour test('has 1 k and d properties when 1 text ref with whitespace', () => { - const meta = compile(`
@a
`); + const meta = compile('
@a
'); expect(meta.k).toHaveLength(1); expect(meta.d).toHaveLength(1); }); @@ -162,7 +162,7 @@ describe('compile', () => { `); - expect(meta.html).toBe(``); + expect(meta.html).toBe(''); }); describe('keepComments option', () => { diff --git a/test/unit/store.test.ts b/test/unit/store.test.ts index 99840e9..0bb89ba 100644 --- a/test/unit/store.test.ts +++ b/test/unit/store.test.ts @@ -45,8 +45,8 @@ describe('store', () => { v: new TestClass(), w: TestClass, x: /test/, - // eslint-disable-next-line prefer-regex-literals - y: new RegExp('test'), + // biome-ignore lint/complexity/useRegexLiterals: + y: new RegExp('test'), // eslint-disable-line prefer-regex-literals z: window, }; const state = store(initialState); diff --git a/test/unit/utils.ts b/test/unit/utils.ts index d3154f9..857cd51 100644 --- a/test/unit/utils.ts +++ b/test/unit/utils.ts @@ -8,7 +8,7 @@ export interface RenderResult { * * @param element - An element to inspect. Default is the mounted container. */ - debug(element?: Element): Promise; + debug(element?: Element): void; unmount(): void; } @@ -24,10 +24,13 @@ export function render(component: Node): RenderResult { return { container, - async debug(el = container) { - const { format } = await import('prettier'); - const html = await format(el.innerHTML, { parser: 'html' }); - console2.log(`DEBUG:\n${html}`); + debug(el = container) { + // const { format } = await import('prettier'); + // const html = await format(el.innerHTML, { parser: 'html' }); + // console2.log(`DEBUG:\n${html}`); + + // FIXME: Replace with biome once it has a HTML parser + console2.log(`DEBUG:\n${el.innerHTML}`); }, unmount() { // eslint-disable-next-line unicorn/prefer-dom-node-remove @@ -38,9 +41,7 @@ export function render(component: Node): RenderResult { export function cleanup(): void { if (mountedContainers.size === 0) { - throw new Error( - 'No mounted components exist, did you forget to call render()?', - ); + throw new Error('No components mounted, did you forget to call render()?'); } mountedContainers.forEach((container) => { From 94a4851151b4e0e39a32ec9bc841ee4044eb3c0e Mon Sep 17 00:00:00 2001 From: Max Milton Date: Sat, 10 Feb 2024 08:50:27 +1100 Subject: [PATCH 094/169] chore: Update and clean up dependencies --- bun.lockb | Bin 128842 -> 130514 bytes package.json | 15 ++++++--------- tsconfig.json | 8 -------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/bun.lockb b/bun.lockb index c7fac0cd1ef37d66cbce2e6329ae06cd09b0f26c..01e5a966246919bfefa0d57ea934c568f4e53966 100755 GIT binary patch delta 30294 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 F{|7dU133Ty delta 28977 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�*8U4fGLwEeVY7fA)uL|96*aEEuLfu8RiR+M`=+l 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 Date: Wed, 20 Mar 2024 13:26:59 +1100 Subject: [PATCH 095/169] chore: Update dependencies --- bun.lockb | Bin 130514 -> 134320 bytes package.json | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bun.lockb b/bun.lockb index 01e5a966246919bfefa0d57ea934c568f4e53966..b6f8fa187e46b88e8c273d3be715915583d0782c 100755 GIT binary patch delta 32985 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 delta 30562 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 Date: Wed, 20 Mar 2024 13:27:22 +1100 Subject: [PATCH 096/169] chore: Tweak tooling configs --- .vscode/settings.json | 2 +- biome.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0ec6cbe..11dc18d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,7 +11,7 @@ "prettier.enable": false, // use biome instead "typescript.tsdk": "node_modules/typescript/lib", - "[json][jsonc][markdown]": { + "[css][html][json][jsonc][markdown][xml]": { "editor.defaultFormatter": "biomejs.biome" }, "[javascript][typescript]": { diff --git a/biome.json b/biome.json index c2923d0..e3d653c 100644 --- a/biome.json +++ b/biome.json @@ -56,12 +56,15 @@ "noConstEnum": "off", "noExplicitAny": "off", "noMisrefactoredShorthandAssign": "error" + }, + "nursery": { + "noFocusedTests": "error" } } }, "overrides": [ { - "include": [".vscode/**"], + "include": [".vscode/**", "tsconfig.json", "tsconfig.node.json"], "json": { "parser": { "allowComments": true, From ad046bc613c30374a99ced0d2dbbe05031529222 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 20 Mar 2024 13:27:45 +1100 Subject: [PATCH 097/169] chore: Fix new lint errors --- src/reconcile/keyed.ts | 12 ++++++------ src/reconcile/non-keyed.ts | 12 ++++++------ src/reconcile/reuse-nodes.ts | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/reconcile/keyed.ts b/src/reconcile/keyed.ts index 1e75a8c..3bfac79 100644 --- a/src/reconcile/keyed.ts +++ b/src/reconcile/keyed.ts @@ -136,7 +136,7 @@ export const reconcile = ( a = renderedData[prevStart]; b = data[newStart]; while (a[key] === b[key]) { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevStartNode type updateFn(prevStartNode, b); prevStart++; newStart++; @@ -150,7 +150,7 @@ export const reconcile = ( a = renderedData[prevEnd]; b = data[newEnd]; while (a[key] === b[key]) { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevEndNode type updateFn(prevEndNode, b); prevEnd--; newEnd--; @@ -166,7 +166,7 @@ export const reconcile = ( b = data[newStart]; while (a[key] === b[key]) { loop = true; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevEndNode type updateFn(prevEndNode, b); tmpNode = prevEndNode!.previousSibling; parent.insertBefore(prevEndNode!, newStartNode); @@ -183,7 +183,7 @@ export const reconcile = ( b = data[newEnd]; while (a[key] === b[key]) { loop = true; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevStartNode type updateFn(prevStartNode, b); tmpNode = prevStartNode!.nextSibling; parent.insertBefore(prevStartNode!, afterNode!); @@ -306,7 +306,7 @@ export const reconcile = ( for (let i = newEnd; i >= newStart; i--) { if (longestSeq[lisIdx] === i) { afterNode = nodes[P[longestSeq[lisIdx]]]; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: afterNode type updateFn(afterNode, data[i]); lisIdx--; } else { @@ -314,7 +314,7 @@ export const reconcile = ( tmpD = createFn(data[i]); } else { tmpD = nodes[P[i]]!; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: tmpD type updateFn(tmpD, data[i]); } parent.insertBefore(tmpD, afterNode!); diff --git a/src/reconcile/non-keyed.ts b/src/reconcile/non-keyed.ts index f733b19..b6a52d6 100644 --- a/src/reconcile/non-keyed.ts +++ b/src/reconcile/non-keyed.ts @@ -132,7 +132,7 @@ export const reconcile = ( a = renderedData[prevStart]; b = data[newStart]; while (a === b) { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevStartNode type updateFn(prevStartNode, b); prevStart++; newStart++; @@ -146,7 +146,7 @@ export const reconcile = ( a = renderedData[prevEnd]; b = data[newEnd]; while (a === b) { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevEndNode type updateFn(prevEndNode, b); prevEnd--; newEnd--; @@ -162,7 +162,7 @@ export const reconcile = ( b = data[newStart]; while (a === b) { loop = true; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevEndNode type updateFn(prevEndNode, b); tmpNode = prevEndNode!.previousSibling; parent.insertBefore(prevEndNode!, newStartNode); @@ -179,7 +179,7 @@ export const reconcile = ( b = data[newEnd]; while (a === b) { loop = true; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: prevStartNode type updateFn(prevStartNode, b); tmpNode = prevStartNode!.nextSibling; parent.insertBefore(prevStartNode!, afterNode!); @@ -302,7 +302,7 @@ export const reconcile = ( for (let i = newEnd; i >= newStart; i--) { if (longestSeq[lisIdx] === i) { afterNode = nodes[P[longestSeq[lisIdx]]]; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: afterNode type updateFn(afterNode, data[i]); lisIdx--; } else { @@ -310,7 +310,7 @@ export const reconcile = ( tmpD = createFn(data[i]); } else { tmpD = nodes[P[i]]!; - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: tmpD type updateFn(tmpD, data[i]); } parent.insertBefore(tmpD, afterNode!); diff --git a/src/reconcile/reuse-nodes.ts b/src/reconcile/reuse-nodes.ts index 2c9a359..2fa3c20 100644 --- a/src/reconcile/reuse-nodes.ts +++ b/src/reconcile/reuse-nodes.ts @@ -49,10 +49,10 @@ export const reconcile = ( for (; index < len; index++) { item = data[index]; if (head) { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: head type updateFn(head, item); } else { - // @ts-expect-error - FIXME:! + // @ts-expect-error - FIXME: head type head = createFn(item); if (mode) { parent.insertBefore(head!, afterNode!); From ab30538cc335b129b0da8ecedb67add5caab7214 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 20 Mar 2024 13:27:58 +1100 Subject: [PATCH 098/169] chore: Add option to e2e in CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a91d14..0340816 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - run: bun install --frozen-lockfile - run: bun playwright install chromium - run: bun run build - - run: bun run test:e2e --reporter=dot,html + - run: bun run test:e2e --reporter=dot,html --forbid-only - uses: actions/upload-artifact@v4 if: always() with: From 794ae45427f04621c426fdad7e6b5f77c757da21 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 20 Mar 2024 13:29:40 +1100 Subject: [PATCH 099/169] test: Add workaround for happy-dom bug --- test/setup.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/setup.ts b/test/setup.ts index 0a3c520..941003b 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -50,6 +50,14 @@ function setupMocks(): void { global.performance.mark = noop; // @ts-expect-error - noop stub global.performance.measure = noop; + + // TODO: Remove once happy-dom supports `HTMLLIElement` again. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (window.HTMLLIElement) { + throw new TypeError('HTMLLIElement already defined'); + } + // @ts-expect-error - mock element + window.HTMLLIElement = window.HTMLElement; } export async function reset(): Promise { From 68a59504a3b7e172c9e8a91864b7d0ac47e502b1 Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 20 Mar 2024 13:30:05 +1100 Subject: [PATCH 100/169] text: Comment out broken test --- test/unit/macro.test.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/unit/macro.test.ts b/test/unit/macro.test.ts index f83ada9..493e3ed 100644 --- a/test/unit/macro.test.ts +++ b/test/unit/macro.test.ts @@ -115,11 +115,13 @@ describe('compile', () => { ); }); - test('does not escape HTML entities', () => { - const template = '
<span>Foo</span>
'; - const meta = compile(template); - expect(meta.html).toBe(template); - }); + // FIXME: Uncomment once bun string handling in macros bug is fixed. + // test('does not escape HTML entities', () => { + // expect.assertions(1); + // const template = '
<span>Foo</span>
'; + // const meta = compile(template); + // expect(meta.html).toBe(template); + // }); test('logs error when more than one root element', () => { const spy = spyOn(console, 'error').mockImplementation(() => {}); From 5e8c4b3eed9abd63c4483b9cdfe7849d91ed4d2d Mon Sep 17 00:00:00 2001 From: Max Milton Date: Wed, 20 Mar 2024 13:30:49 +1100 Subject: [PATCH 101/169] test: Add expect.assertions to all unit tests --- test/unit/browser-compile.test.ts | 10 ++++++++++ test/unit/events.test.ts | 14 ++++++++++++++ test/unit/exports.test.ts | 12 ++++++++++++ test/unit/macro.test.ts | 31 +++++++++++++++++++++++++++++++ test/unit/runtime.test.ts | 17 +++++++++++++++++ test/unit/store.test.ts | 13 +++++++++++++ test/unit/utils.test.ts | 30 ++++++++++++++++++++++++++++++ 7 files changed, 127 insertions(+) diff --git a/test/unit/browser-compile.test.ts b/test/unit/browser-compile.test.ts index 0c0027d..39ccb55 100644 --- a/test/unit/browser-compile.test.ts +++ b/test/unit/browser-compile.test.ts @@ -8,6 +8,7 @@ describe('h', () => { afterEach(cleanup); test('renders basic template', () => { + expect.assertions(1); const view = h(`