From ef02942e7dfb6a9765669a20c77e9e8370a6e7f1 Mon Sep 17 00:00:00 2001 From: Mike Cousins Date: Tue, 27 Dec 2022 14:31:28 -0600 Subject: [PATCH] feat(www): add initial tracespace view page --- pnpm-lock.yaml | 539 ++++++++++-------- www/src/components/file-input.tsx | 18 + www/src/components/icon.tsx | 30 + www/src/components/log-slider.tsx | 35 ++ www/src/components/types.ts | 1 + www/src/components/use-pan-zoom.ts | 213 +++++++ .../__tests__/use-dark-mode.test.tsx | 61 ++ www/src/dark-mode/dark-mode-toggle.tsx | 26 + www/src/dark-mode/index.ts | 2 + www/src/dark-mode/use-dark-mode.ts | 32 ++ www/src/pages/_default.page.server.tsx | 22 +- www/src/pages/index.page.tsx | 5 +- www/src/pages/view/__tests__/view.test.tsx | 62 ++ www/src/pages/view/index.page.tsx | 56 ++ www/src/pages/view/render-viewer.tsx | 159 ++++++ www/src/pages/view/store.ts | 57 ++ www/src/render/__tests__/render.test.ts | 26 + www/src/render/__tests__/worker.test.ts | 96 ++++ www/src/render/actions.ts | 8 + www/src/render/call-worker.ts | 46 ++ www/src/render/index.ts | 8 + www/src/render/worker-shell.ts | 17 + www/src/render/worker.ts | 14 + www/typings/jsx.d.ts | 1 + www/typings/preact.d.ts | 10 +- www/typings/windicss.d.ts | 2 +- www/windi.config.ts | 13 + 27 files changed, 1305 insertions(+), 254 deletions(-) create mode 100644 www/src/components/file-input.tsx create mode 100644 www/src/components/icon.tsx create mode 100644 www/src/components/log-slider.tsx create mode 100644 www/src/components/types.ts create mode 100644 www/src/components/use-pan-zoom.ts create mode 100644 www/src/dark-mode/__tests__/use-dark-mode.test.tsx create mode 100644 www/src/dark-mode/dark-mode-toggle.tsx create mode 100644 www/src/dark-mode/index.ts create mode 100644 www/src/dark-mode/use-dark-mode.ts create mode 100644 www/src/pages/view/__tests__/view.test.tsx create mode 100644 www/src/pages/view/index.page.tsx create mode 100644 www/src/pages/view/render-viewer.tsx create mode 100644 www/src/pages/view/store.ts create mode 100644 www/src/render/__tests__/render.test.ts create mode 100644 www/src/render/__tests__/worker.test.ts create mode 100644 www/src/render/actions.ts create mode 100644 www/src/render/call-worker.ts create mode 100644 www/src/render/index.ts create mode 100644 www/src/render/worker-shell.ts create mode 100644 www/src/render/worker.ts create mode 100644 www/typings/jsx.d.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfd75106..89a877ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -203,8 +203,8 @@ importers: packages: - /@adobe/css-tools/4.0.1: - resolution: {integrity: sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==} + /@adobe/css-tools/4.0.2: + resolution: {integrity: sha512-Fx6tYjk2wKUgLi8uMANZr8GNZx05u44ArIJldn9VxLvolzlJVgHbTUCbwhMd6bcYky178+WUSxPHO3DAtGLWpw==} dev: true /@ampproject/remapping/2.2.0: @@ -423,13 +423,6 @@ packages: '@babel/types': 7.20.7 dev: true - /@babel/runtime/7.19.4: - resolution: {integrity: sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.10 - dev: true - /@babel/runtime/7.20.7: resolution: {integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==} engines: {node: '>=6.9.0'} @@ -687,8 +680,8 @@ packages: dev: true optional: true - /@eslint/eslintrc/1.4.0: - resolution: {integrity: sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==} + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -755,8 +748,8 @@ packages: engines: {node: '>=8'} dev: true - /@jest/expect-utils/29.2.1: - resolution: {integrity: sha512-yr4aHNg5Z1CjKby5ozm7sKjgBlCOorlAoFcvrOQ/4rbZRfgZQdnmh7cth192PYIgiPZo2bBXvqdOApnAMWFJZg==} + /@jest/expect-utils/29.3.1: + resolution: {integrity: sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-get-type: 29.2.0 @@ -766,11 +759,11 @@ packages: resolution: {integrity: sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@sinclair/typebox': 0.24.48 + '@sinclair/typebox': 0.24.51 dev: true - /@jest/types/29.2.1: - resolution: {integrity: sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==} + /@jest/types/29.3.1: + resolution: {integrity: sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.0.0 @@ -824,11 +817,11 @@ packages: dependencies: '@types/estree-jsx': 1.0.0 '@types/mdx': 2.0.3 - estree-util-build-jsx: 2.2.0 + estree-util-build-jsx: 2.2.2 estree-util-is-identifier-name: 2.0.1 estree-util-to-js: 1.1.0 - estree-walker: 3.0.1 - hast-util-to-estree: 2.1.0 + estree-walker: 3.0.2 + hast-util-to-estree: 2.2.0 markdown-extensions: 1.1.1 periscopic: 3.0.4 remark-mdx: 2.2.1 @@ -973,8 +966,8 @@ packages: picomatch: 2.3.1 dev: true - /@sinclair/typebox/0.24.48: - resolution: {integrity: sha512-WPGpRNHbkOsfBDmh8QHU7a5NWzEuYNThST8x1cISvX0RpP+1+V8zjuJqNwGJkHGIlhdIIhv6qVYqXz2q5/gjAA==} + /@sinclair/typebox/0.24.51: + resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: true /@testing-library/dom/8.19.1: @@ -986,7 +979,7 @@ packages: '@types/aria-query': 5.0.1 aria-query: 5.1.3 chalk: 4.1.2 - dom-accessibility-api: 0.5.14 + dom-accessibility-api: 0.5.15 lz-string: 1.4.4 pretty-format: 27.5.1 dev: true @@ -995,13 +988,13 @@ packages: resolution: {integrity: sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==} engines: {node: '>=8', npm: '>=6', yarn: '>=1'} dependencies: - '@adobe/css-tools': 4.0.1 - '@babel/runtime': 7.19.4 + '@adobe/css-tools': 4.0.2 + '@babel/runtime': 7.20.7 '@types/testing-library__jest-dom': 5.14.5 - aria-query: 5.0.2 + aria-query: 5.1.3 chalk: 3.0.0 css.escape: 1.5.1 - dom-accessibility-api: 0.5.14 + dom-accessibility-api: 0.5.15 lodash: 4.17.21 redent: 3.0.0 dev: true @@ -1098,11 +1091,11 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/29.2.0: - resolution: {integrity: sha512-KO7bPV21d65PKwv3LLsD8Jn3E05pjNjRZvkm+YTacWhVmykAb07wW6IkZUmQAltwQafNcDUEUrMO2h3jeBSisg==} + /@types/jest/29.2.5: + resolution: {integrity: sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==} dependencies: - expect: 29.2.1 - pretty-format: 29.2.1 + expect: 29.3.1 + pretty-format: 29.3.1 dev: true /@types/json-schema/7.0.11: @@ -1166,7 +1159,7 @@ packages: /@types/testing-library__jest-dom/5.14.5: resolution: {integrity: sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==} dependencies: - '@types/jest': 29.2.0 + '@types/jest': 29.2.5 dev: true /@types/unist/2.0.6: @@ -1182,8 +1175,8 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin/5.47.0_ncmi6noazr3nzas7jxykisekym: - resolution: {integrity: sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==} + /@typescript-eslint/eslint-plugin/5.48.1_3jon24igvnqaqexgwtxk6nkpse: + resolution: {integrity: sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1193,12 +1186,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa - '@typescript-eslint/scope-manager': 5.47.0 - '@typescript-eslint/type-utils': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa - '@typescript-eslint/utils': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa + '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/type-utils': 5.48.1_iukboom6ndih5an6iafl45j2fe + '@typescript-eslint/utils': 5.48.1_iukboom6ndih5an6iafl45j2fe debug: 4.3.4 - eslint: 8.30.0 + eslint: 8.31.0 ignore: 5.2.4 natural-compare-lite: 1.4.0 regexpp: 3.2.0 @@ -1209,8 +1202,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.47.0_lzzuuodtsqwxnvqeq4g4likcqa: - resolution: {integrity: sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==} + /@typescript-eslint/parser/5.48.1_iukboom6ndih5an6iafl45j2fe: + resolution: {integrity: sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1219,26 +1212,26 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.47.0 - '@typescript-eslint/types': 5.47.0 - '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.4 + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4 debug: 4.3.4 - eslint: 8.30.0 + eslint: 8.31.0 typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.47.0: - resolution: {integrity: sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==} + /@typescript-eslint/scope-manager/5.48.1: + resolution: {integrity: sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.47.0 - '@typescript-eslint/visitor-keys': 5.47.0 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/visitor-keys': 5.48.1 dev: true - /@typescript-eslint/type-utils/5.47.0_lzzuuodtsqwxnvqeq4g4likcqa: - resolution: {integrity: sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==} + /@typescript-eslint/type-utils/5.48.1_iukboom6ndih5an6iafl45j2fe: + resolution: {integrity: sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1247,23 +1240,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.4 - '@typescript-eslint/utils': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa + '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4 + '@typescript-eslint/utils': 5.48.1_iukboom6ndih5an6iafl45j2fe debug: 4.3.4 - eslint: 8.30.0 + eslint: 8.31.0 tsutils: 3.21.0_typescript@4.9.4 typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types/5.47.0: - resolution: {integrity: sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==} + /@typescript-eslint/types/5.48.1: + resolution: {integrity: sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.47.0_typescript@4.9.4: - resolution: {integrity: sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==} + /@typescript-eslint/typescript-estree/5.48.1_typescript@4.9.4: + resolution: {integrity: sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1271,8 +1264,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.47.0 - '@typescript-eslint/visitor-keys': 5.47.0 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/visitor-keys': 5.48.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1283,31 +1276,31 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.47.0_lzzuuodtsqwxnvqeq4g4likcqa: - resolution: {integrity: sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==} + /@typescript-eslint/utils/5.48.1_iukboom6ndih5an6iafl45j2fe: + resolution: {integrity: sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.47.0 - '@typescript-eslint/types': 5.47.0 - '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.4 - eslint: 8.30.0 + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4 + eslint: 8.31.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@8.30.0 + eslint-utils: 3.0.0_eslint@8.31.0 semver: 7.3.8 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys/5.47.0: - resolution: {integrity: sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==} + /@typescript-eslint/visitor-keys/5.48.1: + resolution: {integrity: sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/types': 5.48.1 eslint-visitor-keys: 3.3.0 dev: true @@ -1334,7 +1327,7 @@ packages: resolution: {integrity: sha512-O9SsC110b1Ik3YYa4Ck/0TWuCo7YFfA9KDrwD5sAeqscT5COIGK1HszdCT3oh0MJFej2wNrvpfyW9h6yQaW6PA==} dependencies: debug: 4.3.4 - jiti: 1.16.0 + jiti: 1.16.2 windicss: 3.5.6 transitivePeerDependencies: - supports-color @@ -1435,15 +1428,10 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-query/5.0.2: - resolution: {integrity: sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==} - engines: {node: '>=6.0'} - dev: true - /aria-query/5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} dependencies: - deep-equal: 2.1.0 + deep-equal: 2.2.0 dev: true /array-find/1.0.0: @@ -1456,7 +1444,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 get-intrinsic: 1.1.3 is-string: 1.0.7 dev: true @@ -1472,7 +1460,17 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 + 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.1.4 + es-abstract: 1.21.1 es-shim-unscopables: 1.0.0 dev: true @@ -1490,8 +1488,8 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true - /astring/1.8.3: - resolution: {integrity: sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A==} + /astring/1.8.4: + resolution: {integrity: sha512-97a+l2LBU3Op3bBQEff79i/E4jMD2ZLFD8rHx9B6mXyB2uQwhJQYfiDqUwtfjF4QA1F2qs//N6Cw8LetMbQjcw==} hasBin: true dev: true @@ -1677,12 +1675,8 @@ packages: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true - /ci-info/3.5.0: - resolution: {integrity: sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==} - dev: true - - /ci-info/3.7.0: - resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} + /ci-info/3.7.1: + resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==} engines: {node: '>=8'} dev: true @@ -1830,17 +1824,6 @@ packages: engines: {node: '>=0.11'} dev: true - /debug/2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: true - /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -1899,15 +1882,17 @@ packages: type-detect: 4.0.8 dev: true - /deep-equal/2.1.0: - resolution: {integrity: sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==} + /deep-equal/2.2.0: + resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} dependencies: call-bind: 1.0.2 - es-get-iterator: 1.1.2 + es-get-iterator: 1.1.3 get-intrinsic: 1.1.3 is-arguments: 1.1.1 + is-array-buffer: 3.0.1 is-date-object: 1.0.5 is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 isarray: 2.0.5 object-is: 1.1.5 object-keys: 1.1.1 @@ -1951,8 +1936,8 @@ packages: engines: {node: '>=6'} dev: true - /diff-sequences/29.2.0: - resolution: {integrity: sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==} + /diff-sequences/29.3.1: + resolution: {integrity: sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true @@ -1982,8 +1967,8 @@ packages: esutils: 2.0.3 dev: true - /dom-accessibility-api/0.5.14: - resolution: {integrity: sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==} + /dom-accessibility-api/0.5.15: + resolution: {integrity: sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==} dev: true /domexception/4.0.0: @@ -2032,39 +2017,47 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract/1.20.5: - resolution: {integrity: sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==} + /es-abstract/1.21.1: + resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} engines: {node: '>= 0.4'} dependencies: + available-typed-arrays: 1.0.5 call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 es-to-primitive: 1.2.1 function-bind: 1.1.1 function.prototype.name: 1.1.5 get-intrinsic: 1.1.3 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.4 + is-array-buffer: 3.0.1 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.2 + object-inspect: 1.12.3 object-keys: 1.1.1 object.assign: 4.1.4 regexp.prototype.flags: 1.4.3 safe-regex-test: 1.0.0 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-get-iterator/1.1.2: - resolution: {integrity: sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==} + /es-get-iterator/1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.3 @@ -2074,12 +2067,22 @@ packages: is-set: 2.0.2 is-string: 1.0.7 isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 dev: true /es-module-lexer/0.10.5: resolution: {integrity: sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==} dev: true + /es-set-tostringtag/2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.1.3 + has: 1.0.3 + has-tostringtag: 1.0.0 + dev: true + /es-shim-unscopables/1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: @@ -2157,16 +2160,16 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-prettier/8.5.0_eslint@8.30.0: - resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + /eslint-config-prettier/8.6.0_eslint@8.31.0: + resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.30.0 + eslint: 8.31.0 dev: true - /eslint-config-xo-typescript/0.55.1_qbm5x4mewwucm77gjb5cop3dfi: + /eslint-config-xo-typescript/0.55.1_ddkuuvdrd7nn3bjshfkuqupluq: resolution: {integrity: sha512-iXua+7n9fOp7LzGzvXlcZG0w6cdtscjASGTrAHMj0Rn9voayxF2oRoMIK1QS6ZJb4fMVEQZdU2D6gTKmWhcCQQ==} engines: {node: '>=12'} peerDependencies: @@ -2175,20 +2178,20 @@ packages: eslint: '>=8.0.0' typescript: '>=4.4' dependencies: - '@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym - '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa - eslint: 8.30.0 + '@typescript-eslint/eslint-plugin': 5.48.1_3jon24igvnqaqexgwtxk6nkpse + '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe + eslint: 8.31.0 typescript: 4.9.4 dev: true - /eslint-config-xo/0.43.1_eslint@8.30.0: + /eslint-config-xo/0.43.1_eslint@8.31.0: resolution: {integrity: sha512-azv1L2PysRA0NkZOgbndUpN+581L7wPqkgJOgxxw3hxwXAbJgD6Hqb/SjHRiACifXt/AvxCzE/jIKFAlI7XjvQ==} engines: {node: '>=12'} peerDependencies: eslint: '>=8.27.0' dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.30.0 + eslint: 8.31.0 dev: true /eslint-formatter-pretty/4.1.0: @@ -2205,16 +2208,17 @@ packages: supports-hyperlinks: 2.3.0 dev: true - /eslint-import-resolver-node/0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + /eslint-import-resolver-node/0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} dependencies: debug: 3.2.7 + is-core-module: 2.11.0 resolve: 1.22.1 transitivePeerDependencies: - supports-color dev: true - /eslint-import-resolver-webpack/0.13.2_fkfqfehjtk7sk2efaqbgxsuasa: + /eslint-import-resolver-webpack/0.13.2_xwyoujhv2zz5pj5vdvbnv64eri: resolution: {integrity: sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==} engines: {node: '>= 6'} peerDependencies: @@ -2227,7 +2231,7 @@ packages: array-find: 1.0.0 debug: 3.2.7 enhanced-resolve: 0.9.1 - eslint-plugin-import: 2.26.0_yyrepad25urm4u4e2pvzah4jey + eslint-plugin-import: 2.27.4_jdpvvnd5kfmzpspui5rywveqlq find-root: 1.1.0 has: 1.0.3 interpret: 1.4.0 @@ -2240,7 +2244,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_gsirn7wil62idnhsoviflbzkqa: + /eslint-module-utils/2.7.4_k2wrozg4airpbchlinet5l6rae: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -2261,24 +2265,24 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa + '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe debug: 3.2.7 - eslint: 8.30.0 - eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-webpack: 0.13.2_fkfqfehjtk7sk2efaqbgxsuasa + eslint: 8.31.0 + eslint-import-resolver-node: 0.3.7 + eslint-import-resolver-webpack: 0.13.2_xwyoujhv2zz5pj5vdvbnv64eri transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-ava/13.2.0_eslint@8.30.0: + /eslint-plugin-ava/13.2.0_eslint@8.31.0: resolution: {integrity: sha512-i5B5izsEdERKQLruk1nIWzTTE7C26/ju8qQf7JeyRv32XT2lRMW0zMFZNhIrEf5/5VvpSz2rqrV7UcjClGbKsw==} engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4'} peerDependencies: eslint: '>=7.22.0' dependencies: enhance-visitors: 1.0.0 - eslint: 8.30.0 - eslint-utils: 3.0.0_eslint@8.30.0 + eslint: 8.31.0 + eslint-utils: 3.0.0_eslint@8.31.0 espree: 9.4.1 espurify: 2.1.1 import-modules: 2.1.0 @@ -2287,30 +2291,30 @@ packages: resolve-from: 5.0.0 dev: true - /eslint-plugin-es/4.1.0_eslint@8.30.0: + /eslint-plugin-es/4.1.0_eslint@8.31.0: resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=4.19.1' dependencies: - eslint: 8.30.0 + eslint: 8.31.0 eslint-utils: 2.1.0 regexpp: 3.2.0 dev: true - /eslint-plugin-eslint-comments/3.2.0_eslint@8.30.0: + /eslint-plugin-eslint-comments/3.2.0_eslint@8.31.0: resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} peerDependencies: eslint: '>=4.19.1' dependencies: escape-string-regexp: 1.0.5 - eslint: 8.30.0 + eslint: 8.31.0 ignore: 5.2.4 dev: true - /eslint-plugin-import/2.26.0_yyrepad25urm4u4e2pvzah4jey: - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + /eslint-plugin-import/2.27.4_jdpvvnd5kfmzpspui5rywveqlq: + resolution: {integrity: sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -2319,20 +2323,22 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa + '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe array-includes: 3.1.6 array.prototype.flat: 1.3.1 - debug: 2.6.9 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.30.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_gsirn7wil62idnhsoviflbzkqa + eslint: 8.31.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4_k2wrozg4airpbchlinet5l6rae has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 minimatch: 3.1.2 object.values: 1.1.6 resolve: 1.22.1 + semver: 6.3.0 tsconfig-paths: 3.14.1 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -2340,16 +2346,16 @@ packages: - supports-color dev: true - /eslint-plugin-n/15.6.0_eslint@8.30.0: - resolution: {integrity: sha512-Hd/F7wz4Mj44Jp0H6Jtty13NcE69GNTY0rVlgTIj1XBnGGVI6UTdDrpE6vqu3AHo07bygq/N+7OH/lgz1emUJw==} + /eslint-plugin-n/15.6.1_eslint@8.31.0: + resolution: {integrity: sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==} engines: {node: '>=12.22.0'} peerDependencies: eslint: '>=7.0.0' dependencies: builtins: 5.0.1 - eslint: 8.30.0 - eslint-plugin-es: 4.1.0_eslint@8.30.0 - eslint-utils: 3.0.0_eslint@8.30.0 + eslint: 8.31.0 + eslint-plugin-es: 4.1.0_eslint@8.31.0 + eslint-utils: 3.0.0_eslint@8.31.0 ignore: 5.2.4 is-core-module: 2.11.0 minimatch: 3.1.2 @@ -2367,7 +2373,7 @@ packages: is-proto-prop: 2.0.0 dev: true - /eslint-plugin-prettier/4.2.1_bxtqutsr77kdjupoaxnvecwq24: + /eslint-plugin-prettier/4.2.1_do5yx3dogbskqc4h5x5ilvlwyy: resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -2378,23 +2384,23 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.30.0 - eslint-config-prettier: 8.5.0_eslint@8.30.0 + eslint: 8.31.0 + eslint-config-prettier: 8.6.0_eslint@8.31.0 prettier: 2.8.3 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-unicorn/44.0.2_eslint@8.30.0: + /eslint-plugin-unicorn/44.0.2_eslint@8.31.0: resolution: {integrity: sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==} engines: {node: '>=14.18'} peerDependencies: eslint: '>=8.23.1' dependencies: '@babel/helper-validator-identifier': 7.19.1 - ci-info: 3.7.0 + ci-info: 3.7.1 clean-regexp: 1.0.0 - eslint: 8.30.0 - eslint-utils: 3.0.0_eslint@8.30.0 + eslint: 8.31.0 + eslint-utils: 3.0.0_eslint@8.31.0 esquery: 1.4.0 indent-string: 4.0.0 is-builtin-module: 3.2.0 @@ -2434,13 +2440,13 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.30.0: + /eslint-utils/3.0.0_eslint@8.31.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.30.0 + eslint: 8.31.0 eslint-visitor-keys: 2.1.0 dev: true @@ -2459,12 +2465,12 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.30.0: - resolution: {integrity: sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==} + /eslint/8.31.0: + resolution: {integrity: sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.4.0 + '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.11.8 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -2475,7 +2481,7 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.30.0 + eslint-utils: 3.0.0_eslint@8.31.0 eslint-visitor-keys: 3.3.0 espree: 9.4.1 esquery: 1.4.0 @@ -2563,12 +2569,12 @@ packages: '@types/estree': 1.0.0 dev: true - /estree-util-build-jsx/2.2.0: - resolution: {integrity: sha512-apsfRxF9uLrqosApvHVtYZjISPvTJ+lBiIydpC+9wE6cF6ssbhnjyQLqaIjgzGxvC2Hbmec1M7g91PoBayYoQQ==} + /estree-util-build-jsx/2.2.2: + resolution: {integrity: sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg==} dependencies: '@types/estree-jsx': 1.0.0 estree-util-is-identifier-name: 2.0.1 - estree-walker: 3.0.1 + estree-walker: 3.0.2 dev: true /estree-util-is-identifier-name/2.0.1: @@ -2579,7 +2585,7 @@ packages: resolution: {integrity: sha512-490lbfCcpLk+ofK6HCgqDfYs4KAfq6QVvDw3+Bm1YoKRgiOjKiKYGAVQE1uwh7zVxBgWhqp4FDtp5SqunpUk1A==} dependencies: '@types/estree-jsx': 1.0.0 - astring: 1.8.3 + astring: 1.8.4 source-map: 0.7.4 dev: true @@ -2594,8 +2600,8 @@ packages: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true - /estree-walker/3.0.1: - resolution: {integrity: sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g==} + /estree-walker/3.0.2: + resolution: {integrity: sha512-C03BvXCQIH/po+PNPONx/zSM9ziPr9weX8xNhYb/IJtdJ9z+L4z9VKPTB+UTHdmhnIopA2kc419ueyVyHVktwA==} dev: true /esutils/2.0.3: @@ -2618,15 +2624,15 @@ packages: strip-final-newline: 2.0.0 dev: true - /expect/29.2.1: - resolution: {integrity: sha512-BJtA754Fba0YWRWHgjKUMTA3ltWarKgITXHQnbZ2mTxTXC4yMQlR0FI7HkB3fJYkhWBf4qjNiqvg3LDtXCcVRQ==} + /expect/29.3.1: + resolution: {integrity: sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/expect-utils': 29.2.1 + '@jest/expect-utils': 29.3.1 jest-get-type: 29.2.0 - jest-matcher-utils: 29.2.1 - jest-message-util: 29.2.1 - jest-util: 29.2.1 + jest-matcher-utils: 29.3.1 + jest-message-util: 29.3.1 + jest-util: 29.3.1 dev: true /extend/3.0.2: @@ -2773,7 +2779,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 functions-have-names: 1.2.3 dev: true @@ -2862,6 +2868,13 @@ packages: 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.1.4 + dev: true + /globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2924,6 +2937,11 @@ packages: get-intrinsic: 1.1.3 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'} @@ -2988,8 +3006,8 @@ packages: zwitch: 2.0.4 dev: true - /hast-util-to-estree/2.1.0: - resolution: {integrity: sha512-Vwch1etMRmm89xGgz+voWXvVHba2iiMdGMKmaMfYt35rbVtFDq8JNwwAIvi8zHMkO6Gvqo9oTMwJTmzVRfXh4g==} + /hast-util-to-estree/2.2.0: + resolution: {integrity: sha512-QFMTJsd3+lr0TKiObJ6PWwpWqFjD+T28dVSazcPAslHjHGMXxs5xFvjLbUf6e6O3/dfHb9iourepMlSh5x7lIA==} dependencies: '@types/estree': 1.0.0 '@types/estree-jsx': 1.0.0 @@ -3003,7 +3021,7 @@ packages: mdast-util-mdxjs-esm: 1.3.0 property-information: 6.2.0 space-separated-tokens: 2.0.2 - style-to-object: 0.3.0 + style-to-object: 0.4.0 unist-util-position: 4.0.3 zwitch: 2.0.4 transitivePeerDependencies: @@ -3023,7 +3041,6 @@ packages: property-information: 6.2.0 space-separated-tokens: 2.0.2 stringify-entities: 4.0.3 - unist-util-is: 5.1.1 zwitch: 2.0.4 dev: true @@ -3215,6 +3232,14 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-array-buffer/3.0.1: + resolution: {integrity: sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + is-typed-array: 1.1.10 + dev: true + /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -3365,8 +3390,8 @@ packages: proto-props: 2.0.0 dev: true - /is-reference/3.0.0: - resolution: {integrity: sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==} + /is-reference/3.0.1: + resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} dependencies: '@types/estree': 1.0.0 dev: true @@ -3507,14 +3532,14 @@ packages: istanbul-lib-report: 3.0.0 dev: true - /jest-diff/29.2.1: - resolution: {integrity: sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA==} + /jest-diff/29.3.1: + resolution: {integrity: sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - diff-sequences: 29.2.0 + diff-sequences: 29.3.1 jest-get-type: 29.2.0 - pretty-format: 29.2.1 + pretty-format: 29.3.1 dev: true /jest-get-type/29.2.0: @@ -3522,45 +3547,45 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-matcher-utils/29.2.1: - resolution: {integrity: sha512-hUTBh7H/Mnb6GTpihbLh8uF5rjAMdekfW/oZNXUMAXi7bbmym2HiRpzgqf/zzkjgejMrVAkPdVSQj+32enlUww==} + /jest-matcher-utils/29.3.1: + resolution: {integrity: sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - jest-diff: 29.2.1 + jest-diff: 29.3.1 jest-get-type: 29.2.0 - pretty-format: 29.2.1 + pretty-format: 29.3.1 dev: true - /jest-message-util/29.2.1: - resolution: {integrity: sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw==} + /jest-message-util/29.3.1: + resolution: {integrity: sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/code-frame': 7.18.6 - '@jest/types': 29.2.1 + '@jest/types': 29.3.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.10 micromatch: 4.0.5 - pretty-format: 29.2.1 + pretty-format: 29.3.1 slash: 3.0.0 - stack-utils: 2.0.5 + stack-utils: 2.0.6 dev: true - /jest-util/29.2.1: - resolution: {integrity: sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==} + /jest-util/29.3.1: + resolution: {integrity: sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.2.1 + '@jest/types': 29.3.1 '@types/node': 18.11.18 chalk: 4.1.2 - ci-info: 3.5.0 + ci-info: 3.7.1 graceful-fs: 4.2.10 picomatch: 2.3.1 dev: true - /jiti/1.16.0: - resolution: {integrity: sha512-L3BJStEf5NAqNuzrpfbN71dp43mYIcBUlCRea/vdyv5dW/AYa1d4bpelko4SHdY3I6eN9Wzyasxirj1/vv5kmg==} + /jiti/1.16.2: + resolution: {integrity: sha512-OKBOVWmU3FxDt/UH4zSwiKPuc1nihFZiOD722FuJlngvLz2glX1v2/TJIgoA4+mrpnXxHV6dSAoCvPcYQtoG5A==} hasBin: true dev: true @@ -3697,12 +3722,6 @@ packages: minimist: 1.2.7 dev: true - /json5/2.2.2: - resolution: {integrity: sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==} - engines: {node: '>=6'} - hasBin: true - dev: true - /json5/2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3901,7 +3920,7 @@ packages: '@types/hast': 2.3.4 '@types/mdast': 3.0.10 mdast-util-from-markdown: 1.2.0 - mdast-util-to-markdown: 1.4.0 + mdast-util-to-markdown: 1.5.0 transitivePeerDependencies: - supports-color dev: true @@ -3913,7 +3932,7 @@ packages: '@types/hast': 2.3.4 '@types/mdast': 3.0.10 ccount: 2.0.1 - mdast-util-to-markdown: 1.4.0 + mdast-util-to-markdown: 1.5.0 parse-entities: 4.0.0 stringify-entities: 4.0.3 unist-util-remove-position: 4.0.1 @@ -3938,13 +3957,20 @@ packages: '@types/hast': 2.3.4 '@types/mdast': 3.0.10 mdast-util-from-markdown: 1.2.0 - mdast-util-to-markdown: 1.4.0 + mdast-util-to-markdown: 1.5.0 transitivePeerDependencies: - supports-color dev: true - /mdast-util-to-hast/12.2.4: - resolution: {integrity: sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==} + /mdast-util-phrasing/3.0.0: + resolution: {integrity: sha512-S+QYsDRLkGi8U7o5JF1agKa/sdP+CNGXXLqC17pdTVL8FHHgQEiwFGa9yE5aYtUxNiFGYoaDy9V1kC85Sz86Gg==} + dependencies: + '@types/mdast': 3.0.10 + unist-util-is: 5.1.1 + dev: true + + /mdast-util-to-hast/12.2.5: + resolution: {integrity: sha512-EFNhT35ZR/VZ85/EedDdCNTq0oFM+NM/+qBomVGQ0+Lcg0nhI8xIwmdCzNMlVlCJNXRprpobtKP/IUh8cfz6zQ==} dependencies: '@types/hast': 2.3.4 '@types/mdast': 3.0.10 @@ -3957,12 +3983,13 @@ packages: unist-util-visit: 4.1.1 dev: true - /mdast-util-to-markdown/1.4.0: - resolution: {integrity: sha512-IjXARf/O8VGx/pc5SZ7syfydq1DYL9vd92orsG5U0b4GNCmAvXzu+n7sbzfIKrXwB0AVrYk3NV2kXl0AIi9LCA==} + /mdast-util-to-markdown/1.5.0: + resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==} dependencies: '@types/mdast': 3.0.10 '@types/unist': 2.0.6 longest-streak: 3.1.0 + mdast-util-phrasing: 3.0.0 mdast-util-to-string: 3.1.0 micromark-util-decode-string: 1.0.2 unist-util-visit: 4.1.1 @@ -3991,7 +4018,7 @@ packages: read-pkg-up: 9.1.0 redent: 4.0.0 trim-newlines: 4.0.2 - type-fest: 3.4.0 + type-fest: 3.5.1 yargs-parser: 21.1.1 dev: true @@ -4338,10 +4365,6 @@ packages: engines: {node: '>=10'} dev: true - /ms/2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true @@ -4413,8 +4436,8 @@ packages: engines: {node: '>=0.10.0'} dev: true - /object-inspect/1.12.2: - resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-inspect/1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: true /object-is/1.1.5: @@ -4446,7 +4469,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 dev: true /once/1.4.0: @@ -4636,8 +4659,8 @@ packages: /periscopic/3.0.4: resolution: {integrity: sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==} dependencies: - estree-walker: 3.0.1 - is-reference: 3.0.0 + estree-walker: 3.0.2 + is-reference: 3.0.1 dev: true /picocolors/1.0.0: @@ -4736,8 +4759,8 @@ packages: react-is: 17.0.2 dev: true - /pretty-format/29.2.1: - resolution: {integrity: sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA==} + /pretty-format/29.3.1: + resolution: {integrity: sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.0.0 @@ -4849,10 +4872,6 @@ packages: strip-indent: 4.0.0 dev: true - /regenerator-runtime/0.13.10: - resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==} - dev: true - /regenerator-runtime/0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} dev: true @@ -4900,7 +4919,7 @@ packages: dependencies: '@types/hast': 2.3.4 '@types/mdast': 3.0.10 - mdast-util-to-hast: 12.2.4 + mdast-util-to-hast: 12.2.5 unified: 10.1.2 dev: true @@ -5034,7 +5053,7 @@ packages: dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.3 - object-inspect: 1.12.2 + object-inspect: 1.12.3 dev: true /siginfo/2.0.0: @@ -5084,7 +5103,6 @@ packages: /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - requiresBuild: true dev: true /source-map/0.7.4: @@ -5121,8 +5139,8 @@ packages: resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} dev: true - /stack-utils/2.0.5: - resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} + /stack-utils/2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 @@ -5132,6 +5150,13 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true + /stop-iteration-iterator/1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + dependencies: + internal-slot: 1.0.4 + dev: true + /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -5145,7 +5170,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 dev: true /string.prototype.trimstart/1.0.6: @@ -5153,7 +5178,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.5 + es-abstract: 1.21.1 dev: true /stringify-entities/4.0.3: @@ -5218,6 +5243,12 @@ packages: inline-style-parser: 0.1.1 dev: true + /style-to-object/0.4.0: + resolution: {integrity: sha512-dAjq2m87tPn/TcYTeqMhXJRhu96WYWcxMFQxs3Y9jfYpq2jG+38u4tj0Lst6DOiYXmDuNxVJ2b1Z2uPC6wTEeg==} + dependencies: + inline-style-parser: 0.1.1 + dev: true + /supports-color/5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -5463,11 +5494,19 @@ packages: engines: {node: '>=12.20'} dev: true - /type-fest/3.4.0: - resolution: {integrity: sha512-PEPg6RHlB9cFwoTMNENNrQFL0cXX04voWr2UPwQBJ3pVs7Mt8Y1oLWdUeMdGEwZE8HFFlujq8gS9enmyiQ8pLg==} + /type-fest/3.5.1: + resolution: {integrity: sha512-70T99cpILFk2fzwuljwWxmazSphFrdOe3gRHbp6bqs71pxFBbJwFqnmkLO2lQL6aLHxHmYAnP/sL+AJWpT70jA==} engines: {node: '>=14.16'} 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/4.9.4: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'} @@ -5932,25 +5971,25 @@ packages: webpack: optional: true dependencies: - '@eslint/eslintrc': 1.4.0 - '@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym - '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa + '@eslint/eslintrc': 1.4.1 + '@typescript-eslint/eslint-plugin': 5.48.1_3jon24igvnqaqexgwtxk6nkpse + '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe arrify: 3.0.0 cosmiconfig: 7.1.0 define-lazy-prop: 3.0.0 - eslint: 8.30.0 - eslint-config-prettier: 8.5.0_eslint@8.30.0 - eslint-config-xo: 0.43.1_eslint@8.30.0 - eslint-config-xo-typescript: 0.55.1_qbm5x4mewwucm77gjb5cop3dfi + eslint: 8.31.0 + eslint-config-prettier: 8.6.0_eslint@8.31.0 + eslint-config-xo: 0.43.1_eslint@8.31.0 + eslint-config-xo-typescript: 0.55.1_ddkuuvdrd7nn3bjshfkuqupluq eslint-formatter-pretty: 4.1.0 - eslint-import-resolver-webpack: 0.13.2_fkfqfehjtk7sk2efaqbgxsuasa - eslint-plugin-ava: 13.2.0_eslint@8.30.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.30.0 - eslint-plugin-import: 2.26.0_yyrepad25urm4u4e2pvzah4jey - eslint-plugin-n: 15.6.0_eslint@8.30.0 + eslint-import-resolver-webpack: 0.13.2_xwyoujhv2zz5pj5vdvbnv64eri + eslint-plugin-ava: 13.2.0_eslint@8.31.0 + eslint-plugin-eslint-comments: 3.2.0_eslint@8.31.0 + eslint-plugin-import: 2.27.4_jdpvvnd5kfmzpspui5rywveqlq + eslint-plugin-n: 15.6.1_eslint@8.31.0 eslint-plugin-no-use-extend-native: 0.5.0 - eslint-plugin-prettier: 4.2.1_bxtqutsr77kdjupoaxnvecwq24 - eslint-plugin-unicorn: 44.0.2_eslint@8.30.0 + eslint-plugin-prettier: 4.2.1_do5yx3dogbskqc4h5x5ilvlwyy + eslint-plugin-unicorn: 44.0.2_eslint@8.31.0 esm-utils: 4.1.1 find-cache-dir: 4.0.0 find-up: 6.3.0 @@ -5958,7 +5997,7 @@ packages: globby: 13.1.3 imurmurhash: 0.1.4 json-stable-stringify-without-jsonify: 1.0.1 - json5: 2.2.2 + json5: 2.2.3 lodash-es: 4.17.21 meow: 11.0.0 micromatch: 4.0.5 diff --git a/www/src/components/file-input.tsx b/www/src/components/file-input.tsx new file mode 100644 index 00000000..0242ca68 --- /dev/null +++ b/www/src/components/file-input.tsx @@ -0,0 +1,18 @@ +import type {ComponentChildren} from 'preact' +import type {StylableComponentProps} from './types' + +export interface FileInputProps extends StylableComponentProps { + children: ComponentChildren + onChange: JSX.DOMAttributes['onChange'] +} + +export function FileInput(props: FileInputProps): JSX.Element { + const {children, onChange, ...styleAttributes} = props + + return ( + + ) +} diff --git a/www/src/components/icon.tsx b/www/src/components/icon.tsx new file mode 100644 index 00000000..346222fb --- /dev/null +++ b/www/src/components/icon.tsx @@ -0,0 +1,30 @@ +import type {IconDefinition} from '@fortawesome/fontawesome-svg-core' + +import type {StylableComponentProps} from './types' + +export interface IconProps extends StylableComponentProps { + data: IconDefinition +} + +export function Icon(props: IconProps) { + const {data, ...styleAttributes} = props + const [width, height, _ligatures, _unicode, pathData] = data.icon + const viewBox = `0 0 ${width} ${height}` + const path = typeof pathData === 'string' ? pathData : pathData.join('') + + return ( + + + + ) +} diff --git a/www/src/components/log-slider.tsx b/www/src/components/log-slider.tsx new file mode 100644 index 00000000..f547dc4c --- /dev/null +++ b/www/src/components/log-slider.tsx @@ -0,0 +1,35 @@ +import type {StylableComponentProps} from './types' + +export interface Props extends StylableComponentProps { + value: number + valueText: string + min: number + max: number + onChange: (value: number) => unknown +} + +export function LogSlider(props: Props): JSX.Element { + const {value, valueText, min, max, onChange, ...styleProps} = props + + return ( + { + if (event.target instanceof HTMLInputElement) { + onChange(Math.E ** Number(event.target.value)) + } + }} + {...styleProps} + /> + ) +} diff --git a/www/src/components/types.ts b/www/src/components/types.ts new file mode 100644 index 00000000..de08774b --- /dev/null +++ b/www/src/components/types.ts @@ -0,0 +1 @@ +export type {AttributifyAttributes as StylableComponentProps} from 'windicss/types/jsx' diff --git a/www/src/components/use-pan-zoom.ts b/www/src/components/use-pan-zoom.ts new file mode 100644 index 00000000..f3f71709 --- /dev/null +++ b/www/src/components/use-pan-zoom.ts @@ -0,0 +1,213 @@ +import {useRef, useEffect} from 'preact/hooks' +import type {Ref} from 'preact/hooks' + +export interface PanZoomOptions { + initialScale?: number + minScale?: number + maxScale?: number + onChange?: (state: PanZoomState) => unknown +} + +export type PanZoomState = [scale: number, panX: number, panY: number] + +export type PanZoom = [ref: Ref, zoom?: PanZoomer] + +export function usePanZoom(options: PanZoomOptions = {}): PanZoom { + const viewportRef = useRef(null) + const panZoomerRef = useRef() + + useEffect(() => { + if (viewportRef.current !== null) { + const [cleanup, panZoomer] = initializePanZoom( + viewportRef.current, + options + ) + panZoomerRef.current = panZoomer + return cleanup + } + }, []) + + return [viewportRef, panZoomerRef.current] +} + +interface PanZoomer { + container: SVGSVGElement + options: PanZoomOptions + state: PanZoomState + create(container: SVGSVGElement, options: PanZoomOptions): PanZoomer + reset(): void + pan(deltaX: number, deltaY: number): void + zoom(deltaZ: number, centerX?: number, centerY?: number): void + zoomTo(scale: number, centerX?: number, centerY?: number): void +} + +const PanZoomerPrototype: PanZoomer = { + container: undefined as unknown as SVGSVGElement, + options: undefined as unknown as PanZoomOptions, + state: undefined as unknown as PanZoomState, + + create(container: SVGSVGElement, options: PanZoomOptions): PanZoomer { + const panZoomer = Object.assign(Object.create(PanZoomerPrototype), { + container, + options, + state: [1, 0, 0], + }) + + return panZoomer.reset() + }, + + reset(): PanZoomer { + const initialScale = this.options.initialScale ?? 1 + const initialPanX = 0.5 * this.container.clientWidth * (1 - initialScale) + const initialPanY = 0.5 * this.container.clientHeight * (1 - initialScale) + const state = [initialScale, initialPanX, initialPanY] + + Object.assign(this, {state}) + this.options.onChange?.(this.state) + return this + }, + + pan(deltaX: number, deltaY: number): void { + this.state[1] += deltaX + this.state[2] += deltaY + + this.options.onChange?.(this.state) + }, + + zoom(deltaZ: number, centerX?: number, centerY?: number): void { + const [scale] = this.state + this.zoomTo(scale * (1 - deltaZ), centerX, centerY) + }, + + zoomTo(scale: number, centerX?: number, centerY?: number): void { + centerX = centerX ?? 0.5 * this.container.clientWidth + centerY = centerY ?? 0.5 * this.container.clientHeight + + const [previousScale, panX, panY] = this.state + const nextScale = clamp(scale, this.options.minScale, this.options.maxScale) + + const zoom = nextScale / previousScale + const originX = centerX - panX + const originY = centerY - panY + + this.state[0] = nextScale + this.state[1] += originX * (1 - zoom) + this.state[2] += originY * (1 - zoom) + + this.options.onChange?.(this.state) + }, +} + +function initializePanZoom( + viewport: SVGGElement, + options: PanZoomOptions +): [cleanup: () => void, panZoomer: PanZoomer] { + const updateViewport = throttle((state: PanZoomState) => { + const [scale, panX, panY] = state + viewport.style.transform = `translate(${panX}px,${panY}px) scale(${scale})` + options.onChange?.([scale, panX, panY]) + }) + + const container = viewport.parentElement as unknown as SVGSVGElement + const panZoomer = PanZoomerPrototype.create(container, { + ...options, + onChange: updateViewport, + }) + + let mouseLocation: [x: number, y: number] | undefined + + const handleMouseDown = (event: MouseEvent) => { + // eslint-disable-next-line no-bitwise + if ((event.buttons & 1) === 1) { + mouseLocation = [event.clientX, event.clientY] + } + } + + const handleMouseUp = () => { + mouseLocation = undefined + } + + const handleMouseMove = throttle((event: MouseEvent) => { + if (mouseLocation !== undefined) { + const movementX = event.clientX - mouseLocation[0] + const movementY = event.clientY - mouseLocation[1] + + mouseLocation[0] = event.clientX + mouseLocation[1] = event.clientY + panZoomer.pan(movementX, movementY) + } + }) + + const handleWheel = (event: WheelEvent) => { + panZoomer.zoom(event.deltaY / 1000, event.clientX, event.clientY) + event.preventDefault() + } + + const cleanup = () => { + updateViewport.cancel() + handleMouseMove.cancel() + container.removeEventListener('mousedown', handleMouseDown) + container.removeEventListener('mouseenter', handleMouseDown) + container.removeEventListener('mouseup', handleMouseUp) + container.removeEventListener('mouseleave', handleMouseUp) + container.removeEventListener('mousemove', handleMouseMove) + container.removeEventListener('wheel', handleWheel) + } + + container.addEventListener('mousedown', handleMouseDown, {passive: true}) + container.addEventListener('mouseenter', handleMouseDown, {passive: true}) + container.addEventListener('mouseup', handleMouseUp, {passive: true}) + container.addEventListener('mouseleave', handleMouseUp, {passive: true}) + container.addEventListener('mousemove', handleMouseMove, {passive: true}) + container.addEventListener('wheel', handleWheel, {passive: false}) + + return [cleanup, panZoomer] +} + +export type Callback = (...args: A) => void + +export interface ThrottledCallback extends Callback { + cancel: () => void +} + +function throttle( + callback: Callback +): ThrottledCallback { + let requestId: number | undefined + let latestArgs: ArgsType | undefined + + return Object.assign(throttledCallback, {cancel}) + + function throttledCallback(...args: ArgsType): void { + latestArgs = args + + if (requestId === undefined) { + requestId = requestAnimationFrame(doCallback) + } + } + + function doCallback() { + if (latestArgs !== undefined) { + callback(...latestArgs) + requestId = undefined + latestArgs = undefined + } + } + + function cancel() { + if (requestId !== undefined) { + cancelAnimationFrame(requestId) + requestId = undefined + } + } +} + +function clamp( + value: number, + min: number | undefined, + max: number | undefined +): number { + if (min !== undefined && value < min) return min + if (max !== undefined && value > max) return max + return value +} diff --git a/www/src/dark-mode/__tests__/use-dark-mode.test.tsx b/www/src/dark-mode/__tests__/use-dark-mode.test.tsx new file mode 100644 index 00000000..fe230485 --- /dev/null +++ b/www/src/dark-mode/__tests__/use-dark-mode.test.tsx @@ -0,0 +1,61 @@ +// @vitest-environment jsdom +import {describe, it, afterEach, expect} from 'vitest' +import {renderHook, act, cleanup} from '@testing-library/preact' + +import {useDarkMode as subject} from '..' + +describe('useDarkMode', () => { + afterEach(async () => { + document.querySelector('html')?.classList.remove('dark') + cleanup() + }) + + it('should initialize to false by default', () => { + const {result} = renderHook(() => subject()) + expect(result.current?.[0]).toEqual(false) + }) + + it('should initialize to true if dark class present', () => { + document.querySelector('html')?.classList.add('dark') + + const {result} = renderHook(() => subject()) + + expect(result.current?.[0]).toEqual(true) + }) + + it('should toggle dark mode', async () => { + const {result} = renderHook(() => subject()) + + expect(result.current?.[0]).toEqual(false) + + await act(() => { + result.current?.[1]() + }) + + expect(result.current?.[0]).toEqual(true) + + await act(() => { + result.current?.[1]() + }) + + expect(result.current?.[0]).toEqual(false) + }) + + it('should add html class and persist to localstorage', async () => { + const {result} = renderHook(() => subject()) + + await act(() => { + result.current?.[1]() + }) + + expect(document.querySelector('html')).toHaveClass('dark') + expect(localStorage.getItem('tracespace:darkModeEnabled')).toEqual('true') + + await act(() => { + result.current?.[1]() + }) + + expect(document.querySelector('html')).not.toHaveClass('dark') + expect(localStorage.getItem('tracespace:darkModeEnabled')).toEqual('false') + }) +}) diff --git a/www/src/dark-mode/dark-mode-toggle.tsx b/www/src/dark-mode/dark-mode-toggle.tsx new file mode 100644 index 00000000..2d50fc74 --- /dev/null +++ b/www/src/dark-mode/dark-mode-toggle.tsx @@ -0,0 +1,26 @@ +import {useState, useEffect} from 'preact/hooks' +import {faSun} from '@fortawesome/free-solid-svg-icons/faSun' +import {faMoon} from '@fortawesome/free-solid-svg-icons/faMoon' + +import {Icon} from '../components/icon' +import type {StylableComponentProps} from '../components/types' +import {useDarkMode} from './use-dark-mode' + +export interface DarkModeToggleProps extends StylableComponentProps {} + +export function DarkModeToggle(props: DarkModeToggleProps): JSX.Element { + const [isDark, toggleIsDark] = useDarkMode() + const iconData = isDark ? faMoon : faSun + const labelText = `Switch to ${isDark ? 'light' : 'dark'} mode` + + return ( + + ) +} diff --git a/www/src/dark-mode/index.ts b/www/src/dark-mode/index.ts new file mode 100644 index 00000000..0820429d --- /dev/null +++ b/www/src/dark-mode/index.ts @@ -0,0 +1,2 @@ +export * from './dark-mode-toggle' +export * from './use-dark-mode' diff --git a/www/src/dark-mode/use-dark-mode.ts b/www/src/dark-mode/use-dark-mode.ts new file mode 100644 index 00000000..b0aff96f --- /dev/null +++ b/www/src/dark-mode/use-dark-mode.ts @@ -0,0 +1,32 @@ +import {useState, useLayoutEffect, useEffect} from 'preact/hooks' + +export const DARK_MODE_STORAGE_KEY = 'tracespace:darkModeEnabled' +export const DARK_MODE_CLASSNAME = 'dark' + +export type DarkModeResults = [isDark: boolean, toggleIsDark: () => unknown] + +export function useDarkMode(): DarkModeResults { + const [isDark, setIsDark] = useState(false) + + useLayoutEffect(() => { + if (document.documentElement.classList.contains(DARK_MODE_CLASSNAME)) { + setIsDark(true) + } + }, []) + + useEffect(() => { + localStorage.setItem(DARK_MODE_STORAGE_KEY, JSON.stringify(isDark)) + + if (isDark) { + document.documentElement.classList.add(DARK_MODE_CLASSNAME) + } else { + document.documentElement.classList.remove(DARK_MODE_CLASSNAME) + } + }, [isDark]) + + const toggleIsDark = () => { + setIsDark(!isDark) + } + + return [isDark, toggleIsDark] +} diff --git a/www/src/pages/_default.page.server.tsx b/www/src/pages/_default.page.server.tsx index 81586094..eec3fc73 100644 --- a/www/src/pages/_default.page.server.tsx +++ b/www/src/pages/_default.page.server.tsx @@ -1,6 +1,7 @@ import {render as renderToString} from 'preact-render-to-string' import {escapeInject as html, dangerouslySkipEscape} from 'vite-plugin-ssr' +import {DARK_MODE_STORAGE_KEY, DARK_MODE_CLASSNAME} from '../dark-mode' import type {PageContext} from './_page-context' export function render(pageContext: PageContext): unknown { @@ -14,8 +15,27 @@ export function render(pageContext: PageContext): unknown { tracespace + - + ${dangerouslySkipEscape(pageHtml)} diff --git a/www/src/pages/index.page.tsx b/www/src/pages/index.page.tsx index 17f1d2a0..c85df19a 100644 --- a/www/src/pages/index.page.tsx +++ b/www/src/pages/index.page.tsx @@ -40,6 +40,9 @@ const SECTIONS = SECTION_NAMES.map(sectionName => { export function Page(): JSX.Element { return (
+ + tracespace view {'>'} +

tracespace render test

{SECTIONS.map(({sectionName, fixtures}) => (
-
+

{sectionName}/{name}

diff --git a/www/src/pages/view/__tests__/view.test.tsx b/www/src/pages/view/__tests__/view.test.tsx new file mode 100644 index 00000000..30326a51 --- /dev/null +++ b/www/src/pages/view/__tests__/view.test.tsx @@ -0,0 +1,62 @@ +// @vitest-environment jsdom +// Tests for the index page +import {describe, it, beforeEach, afterEach, expect} from 'vitest' +import {render, screen, within, cleanup} from '@testing-library/preact' +import userEvent from '@testing-library/user-event' +import * as td from 'testdouble' +import {replaceEsm, reset} from 'testdouble-vitest' + +describe('view page', () => { + let renderer: typeof import('../../../render') + let subject: typeof import('../index.page') + + beforeEach(async () => { + renderer = await replaceEsm('../../../render') + subject = await import('../index.page') + td.when(renderer.render(td.matchers.anything())).thenResolve({}) + }) + + afterEach(() => { + cleanup() + reset() + }) + + it('should have a title', () => { + render() + + const result = screen.getByRole('heading', {level: 1}) + expect(result).toHaveTextContent('tracespace view') + }) + + it.skip('should have a file input', async () => { + const files = [ + new File(['hello'], 'hello.gbr', {type: 'application/vnd.gerber'}), + new File(['world'], 'world.gbr', {type: 'application/vnd.gerber'}), + ] + + render() + + const input = screen.getByLabelText(/select your.+files/i) + await userEvent.upload(input, files) + + const results = within(screen.getByRole('list')).getAllByRole('listitem') + + expect(results).toHaveLength(2) + expect(results[0]).toHaveTextContent('hello.gbr') + expect(results[1]).toHaveTextContent('world.gbr') + }) + + it('should toggle dark mode', async () => { + render() + + let result = screen.getByRole('button', {name: /switch to dark/i}) + await userEvent.click(result) + + expect(screen.queryByRole('button', {name: /switch to dark/i})).toBeNull() + + result = screen.getByRole('button', {name: /switch to light/i}) + await userEvent.click(result) + + expect(screen.queryByRole('button', {name: /switch to light/i})).toBeNull() + }) +}) diff --git a/www/src/pages/view/index.page.tsx b/www/src/pages/view/index.page.tsx new file mode 100644 index 00000000..3ccf6f5b --- /dev/null +++ b/www/src/pages/view/index.page.tsx @@ -0,0 +1,56 @@ +import {faPlus} from '@fortawesome/free-solid-svg-icons/faPlus' + +import {Icon} from '../../components/icon' +import {FileInput} from '../../components/file-input' +import {DarkModeToggle} from '../../dark-mode' + +import {useAddFiles, useRenderResult} from './store' + +import {RenderViewer} from './render-viewer' + +export function Page(): JSX.Element { + const renderResult = useRenderResult() + const addFiles = useAddFiles() + + return ( +
+ + {renderResult === undefined ? ( + { + const inputFiles = event.currentTarget.files + + if (inputFiles !== null && inputFiles.length > 0) { + const files = [...inputFiles] + addFiles(files) + } + }} + > + + Select your Gerber and drill files to render your PCB + + ) : ( + + )} +
+ ) +} diff --git a/www/src/pages/view/render-viewer.tsx b/www/src/pages/view/render-viewer.tsx new file mode 100644 index 00000000..b6b93848 --- /dev/null +++ b/www/src/pages/view/render-viewer.tsx @@ -0,0 +1,159 @@ +import {BASE_IMAGE_PROPS} from '@tracespace/renderer' + +import type {RenderFragmentsResult} from '@tracespace/core' + +import {usePanZoom} from '../../components/use-pan-zoom' +import {LogSlider} from '../../components/log-slider' +import {useZoomScale, useUpdateZoomScale} from './store' + +export interface LayersRenderProps { + render: RenderFragmentsResult +} + +const ZOOM_SCALE_INITIAL = 0.8 +const ZOOM_SCALE_LIMIT_FACTOR = 24 +const ZOOM_SCALE_MIN = ZOOM_SCALE_INITIAL / ZOOM_SCALE_LIMIT_FACTOR +const ZOOM_SCALE_MAX = ZOOM_SCALE_INITIAL * ZOOM_SCALE_LIMIT_FACTOR + +export function RenderViewer(props: LayersRenderProps): JSX.Element { + const { + layers, + bottomLayers, + mechanicalLayers, + outlineRender, + svgFragmentsById, + } = props.render + const {viewBox, svgFragment: outlineSvgFragment} = outlineRender + + const onPanZoomed = useUpdateZoomScale() + const [renderContainerRef, panZoomer] = usePanZoom({ + initialScale: ZOOM_SCALE_INITIAL, + minScale: ZOOM_SCALE_MIN, + maxScale: ZOOM_SCALE_MAX, + onChange: onPanZoomed, + }) + + const fillRectProps = { + x: viewBox[0], + y: viewBox[1], + width: viewBox[2], + height: viewBox[3], + } + + return ( +
+ + + + + + + {mechanicalLayers.drill.map(id => ( + + ))} + + + + {bottomLayers.solderMask.map(id => ( + + ))} + + {outlineSvgFragment ? ( + + ) : null} + + + + + {bottomLayers.copper.map(id => ( + + ))} + + + {bottomLayers.solderMask.length > 0 ? ( + + ) : null} + {bottomLayers.silkScreen.map(id => ( + + ))} + + {bottomLayers.solderPaste.map(id => ( + + ))} + + {layers.map(({id, side, type}) => ( + + ))} + + + + +
+ ) +} + +function PanZoomControls(props: { + zoomTo?: (scale: number) => unknown +}): JSX.Element | null { + const scale = useZoomScale() + + if (scale === undefined) { + return null + } + + return ( +
+ props.zoomTo?.(nextScale)} + w="full" + /> +
+ ) +} diff --git a/www/src/pages/view/store.ts b/www/src/pages/view/store.ts new file mode 100644 index 00000000..8add16e9 --- /dev/null +++ b/www/src/pages/view/store.ts @@ -0,0 +1,57 @@ +import {atom, useAtom} from 'jotai' + +import type {RenderFragmentsResult} from '@tracespace/core' + +import {render} from '../../render' +import type {PanZoomState} from '../../components/use-pan-zoom' + +export const FILES_ADDED = 'filesAdded' + +export const LAYER_RENDERED = 'layerRendered' + +export interface LayerRender { + filename: string + svg?: SvgRender +} + +export interface SvgRender { + svgFragment: string +} + +const renderResultAtom = atom(undefined) +const zoomScaleAtom = atom(undefined) + +const writeZoomScaleAtom = atom( + undefined, + (get, set, panZoomState) => { + set(zoomScaleAtom, panZoomState[0]) + } +) + +const writeInitialRenderAtom = atom( + undefined, + async (get, set, files) => { + const renderResult = await render(files) + set(renderResultAtom, renderResult) + } +) + +export function useAddFiles(): (files: File[]) => void { + const [, addFiles] = useAtom(writeInitialRenderAtom) + return addFiles +} + +export function useUpdateZoomScale(): (panZoomState: PanZoomState) => void { + const [, updatePanZoom] = useAtom(writeZoomScaleAtom) + return updatePanZoom +} + +export function useRenderResult(): RenderFragmentsResult | undefined { + const [renderResult] = useAtom(renderResultAtom) + return renderResult +} + +export function useZoomScale(): number | undefined { + const [scale] = useAtom(zoomScaleAtom) + return scale +} diff --git a/www/src/render/__tests__/render.test.ts b/www/src/render/__tests__/render.test.ts new file mode 100644 index 00000000..b07670d2 --- /dev/null +++ b/www/src/render/__tests__/render.test.ts @@ -0,0 +1,26 @@ +// @vitest-environment jsdom +import {vi, describe, it, expect, afterEach} from 'vitest' +import * as td from 'testdouble' + +import {callWorker} from '../call-worker' + +import * as subject from '..' + +vi.mock('../call-worker', () => td.object()) + +describe('render files', () => { + afterEach(() => { + td.reset() + }) + + it('should pass files in a message the worker', async () => { + const files = [new File(['foo'], 'foo.gbr')] + + td.when(callWorker({type: 'initialRender', files})).thenResolve({ + layers: [], + }) + + const result = await subject.render(files) + expect(result).to.eql({layers: []}) + }) +}) diff --git a/www/src/render/__tests__/worker.test.ts b/www/src/render/__tests__/worker.test.ts new file mode 100644 index 00000000..0a37008c --- /dev/null +++ b/www/src/render/__tests__/worker.test.ts @@ -0,0 +1,96 @@ +// @vitest-environment jsdom +import {describe, beforeEach, afterEach, it, expect} from 'vitest' +import {replaceEsm, reset} from 'testdouble-vitest' +import * as td from 'testdouble' + +import {TYPE_COPPER, SIDE_TOP} from '@tracespace/identify-layers' +import {ROOT} from '@tracespace/parser' +import type {GerberTree} from '@tracespace/parser' +import {IMAGE} from '@tracespace/plotter' +import type {ImageTree} from '@tracespace/plotter' + +import {INITIAL_RENDER} from '../actions' + +const parseTree = {type: ROOT} as GerberTree +const plotTree = {type: IMAGE} as ImageTree +const layerType = {type: TYPE_COPPER, side: SIDE_TOP} as const + +describe('render worker', () => { + let core: typeof import('@tracespace/core') + let subject: typeof import('../worker') + + beforeEach(async () => { + core = await replaceEsm('@tracespace/core') + subject = await import('../worker') + }) + + afterEach(() => { + reset() + }) + + it('should read and render files', async () => { + const files = [new File(['foo'], 'foo.gbr')] + + td.when(core.read(files)).thenResolve({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + parseTreesById: {'id-1': parseTree}, + }) + + td.when( + core.plot({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + parseTreesById: {'id-1': parseTree}, + }) + ).thenReturn({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + size: [1, 2, 3, 4], + plotTreesById: {'id-1': plotTree}, + }) + + td.when( + core.renderFragments({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + size: [1, 2, 3, 4], + plotTreesById: {'id-1': plotTree}, + }) + ).thenReturn({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + topLayers: { + copper: ['id-1'], + solderMask: [], + silkScreen: [], + solderPaste: [], + }, + bottomLayers: { + copper: [], + solderMask: [], + silkScreen: [], + solderPaste: [], + }, + mechanicalLayers: {drill: [], outline: undefined}, + outlineRender: {svgFragment: '', viewBox: [5, 6, 7, 8]}, + svgFragmentsById: {'id-1': ''}, + }) + + const result = await subject.call({type: INITIAL_RENDER, files}) + + expect(result).to.eql({ + layers: [{id: 'id-1', filename: 'foo.gbr', ...layerType}], + topLayers: { + copper: ['id-1'], + solderMask: [], + silkScreen: [], + solderPaste: [], + }, + bottomLayers: { + copper: [], + solderMask: [], + silkScreen: [], + solderPaste: [], + }, + mechanicalLayers: {drill: [], outline: undefined}, + outlineRender: {svgFragment: '', viewBox: [5, 6, 7, 8]}, + svgFragmentsById: {'id-1': ''}, + }) + }) +}) diff --git a/www/src/render/actions.ts b/www/src/render/actions.ts new file mode 100644 index 00000000..7be54c74 --- /dev/null +++ b/www/src/render/actions.ts @@ -0,0 +1,8 @@ +export const INITIAL_RENDER = 'initialRender' + +export interface InitialRenderAction { + type: typeof INITIAL_RENDER + files: File[] +} + +export type WorkerAction = InitialRenderAction diff --git a/www/src/render/call-worker.ts b/www/src/render/call-worker.ts new file mode 100644 index 00000000..8e80d4da --- /dev/null +++ b/www/src/render/call-worker.ts @@ -0,0 +1,46 @@ +import WorkerShell from './worker-shell?worker' + +import type {WorkerAction} from './actions' +import type {WorkerResponse} from './worker' +import type {MessageId} from './worker-shell' + +export interface WorkerWrapper { + call(request: WorkerAction): Promise +} + +let worker: Worker + +export async function callWorker( + request: WorkerAction +): Promise { + return new Promise((resolve, reject) => { + const id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16) + + worker = worker ?? new WorkerShell() + worker.addEventListener('message', handleMessage) + worker.addEventListener('error', handleError) + worker.postMessage({id, ...request}) + + function handleMessage( + event: MessageEvent + ): void { + const {id: responseId, ...response} = event.data + + if (responseId === id) { + removeListeners() + resolve(response) + } + } + + function handleError(event: Event): void { + removeListeners() + console.error('Render worker encountered an error', event) + reject(new Error('Render worker encountered an error')) + } + + function removeListeners() { + worker.removeEventListener('message', handleMessage) + worker.removeEventListener('error', handleError) + } + }) +} diff --git a/www/src/render/index.ts b/www/src/render/index.ts new file mode 100644 index 00000000..43052c56 --- /dev/null +++ b/www/src/render/index.ts @@ -0,0 +1,8 @@ +import type {RenderFragmentsResult} from '@tracespace/core' + +import {INITIAL_RENDER} from './actions' +import {callWorker} from './call-worker' + +export async function render(files: File[]): Promise { + return callWorker({type: INITIAL_RENDER, files}) +} diff --git a/www/src/render/worker-shell.ts b/www/src/render/worker-shell.ts new file mode 100644 index 00000000..b11d5029 --- /dev/null +++ b/www/src/render/worker-shell.ts @@ -0,0 +1,17 @@ +import {call} from './worker' +import type {WorkerAction} from './actions' + +export interface MessageId { + id: string +} + +async function handleMessage( + event: MessageEvent +): Promise { + const {id, ...request} = event.data + const response = await call(request) + + self.postMessage({id, ...response}) +} + +self.addEventListener('message', handleMessage) diff --git a/www/src/render/worker.ts b/www/src/render/worker.ts new file mode 100644 index 00000000..74b635f5 --- /dev/null +++ b/www/src/render/worker.ts @@ -0,0 +1,14 @@ +import {read, plot, renderFragments} from '@tracespace/core' +import type {RenderFragmentsResult} from '@tracespace/core' + +import type {WorkerAction} from './actions' + +export type WorkerResponse = RenderFragmentsResult + +export async function call(action: WorkerAction): Promise { + const readResult = await read(action.files) + const plotResult = plot(readResult) + const renderResult = renderFragments(plotResult) + + return renderResult +} diff --git a/www/typings/jsx.d.ts b/www/typings/jsx.d.ts new file mode 100644 index 00000000..ac79d62a --- /dev/null +++ b/www/typings/jsx.d.ts @@ -0,0 +1 @@ +import JSX = preact.JSX diff --git a/www/typings/preact.d.ts b/www/typings/preact.d.ts index ac79d62a..deeb77fa 100644 --- a/www/typings/preact.d.ts +++ b/www/typings/preact.d.ts @@ -1 +1,9 @@ -import JSX = preact.JSX +import 'preact' + +declare module 'preact' { + namespace JSX { + interface HTMLAttributes { + color?: string + } + } +} diff --git a/www/typings/windicss.d.ts b/www/typings/windicss.d.ts index ef021d92..2b0cb697 100644 --- a/www/typings/windicss.d.ts +++ b/www/typings/windicss.d.ts @@ -1,7 +1,7 @@ import type {AttributifyAttributes} from 'windicss/types/jsx' declare module 'windicss/types/jsx' { - type MissingAttributes = 'sr' | 'pointer' + type MissingAttributes = 'sr' | 'pointer' | 'appearance' interface AttributifyAttributes extends Partial> {} diff --git a/www/windi.config.ts b/www/windi.config.ts index bbffba89..f80ccda8 100644 --- a/www/windi.config.ts +++ b/www/windi.config.ts @@ -1,5 +1,6 @@ import {defineConfig} from 'windicss/helpers' import defaultTheme from 'windicss/defaultTheme' +import plugin from 'windicss/plugin' export default defineConfig({ attributify: true, @@ -9,6 +10,18 @@ export default defineConfig({ fontFamily: { sans: ['Open SansVariable', ...defaultTheme.fontFamily.sans], }, + cursor: { + grab: 'grab', + }, }, }, + plugins: [ + plugin(({addVariant}) => { + addVariant('slider-thumb', ({modifySelectors}) => { + return modifySelectors(({className}) => { + return `input[type=range]${className}::-webkit-slider-thumb` + }) + }) + }), + ], })