From 7c4df5234a101857b4ab74b69614f3b44aa491a0 Mon Sep 17 00:00:00 2001 From: John Jenkins Date: Fri, 10 Jul 2026 00:06:36 +0100 Subject: [PATCH 1/3] feat: participate in v5 cli wizards --- .gitignore | 6 +- package.json | 30 +- pnpm-lock.yaml | 444 +++++++++++++++++++++++++++ pnpm-workspace.yaml | 2 + rolldown.config.ts | 8 +- src/configs/index.ts | 2 + src/configs/oxlint.ts | 19 ++ src/wizard.ts | 140 +++++++++ tests/wizard-playground/package.json | 15 + tests/wizard.test.ts | 146 +++++++++ tsconfig.json | 3 +- 11 files changed, 809 insertions(+), 6 deletions(-) create mode 100644 pnpm-workspace.yaml create mode 100644 src/configs/oxlint.ts create mode 100644 src/wizard.ts create mode 100644 tests/wizard-playground/package.json create mode 100644 tests/wizard.test.ts diff --git a/.gitignore b/.gitignore index 6ffcce2..24c67de 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ node_modules dist report *.tgz -coverage \ No newline at end of file +coverage + +# scratch output from running `stencil init`/`generate` against the dev wizard +tests/wizard-playground/* +!tests/wizard-playground/package.json \ No newline at end of file diff --git a/package.json b/package.json index 94da65b..48dd0be 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "Jack Woodward ", "Ionic Team ", "d0whc3r ", - "Christian Bromann " + "Christian Bromann ", + "John Jenkins " ], "repository": { "type": "git", @@ -49,6 +50,7 @@ "tsutils": "^3.21.0" }, "devDependencies": { + "@stencil/cli": "^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", "@types/eslint": "9.6.1", "@types/eslint-utils": "^3.0.5", "@types/estree": "^1.0.8", @@ -67,14 +69,36 @@ "vitest": "^4.0.5" }, "peerDependencies": { + "@stencil/core": "^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", "@typescript-eslint/eslint-plugin": "^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0", "eslint-plugin-react": "^7.37.4", - "typescript": "^4.9.4 || ^5.0.0" + "oxlint": "^1.73.0", + "typescript": "^4.9.4 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + }, + "eslint": { + "optional": true + }, + "eslint-plugin-react": { + "optional": true + }, + "oxlint": { + "optional": true + } }, "engines": { "node": ">=22.0.0" }, - "packageManager": "pnpm@11.10.0" + "packageManager": "pnpm@11.10.0", + "stencil": { + "wizard": "./dist/wizard.js" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33b245c..21b4239 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@stencil/core': + specifier: ^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 + version: 4.43.5 eslint-utils: specifier: ^3.0.0 version: 3.0.0(eslint@9.38.0) @@ -18,6 +21,9 @@ importers: specifier: ^3.21.0 version: 3.21.0(typescript@5.9.3) devDependencies: + '@stencil/cli': + specifier: ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 + version: 5.0.0-alpha.19(@stencil/core@4.43.5) '@types/eslint': specifier: 9.6.1 version: 9.6.1 @@ -67,6 +73,18 @@ importers: specifier: ^4.0.5 version: 4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)) + tests/wizard-playground: + devDependencies: + '@stencil/cli': + specifier: ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 + version: 5.0.0-alpha.19(@stencil/core@4.43.5) + '@stencil/core': + specifier: ^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 + version: 4.43.5 + '@stencil/eslint-plugin': + specifier: workspace:* + version: link:../.. + packages: '@asamuzakjp/css-color@4.0.5': @@ -120,6 +138,14 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.7.0': + resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} + engines: {node: '>= 20.12.0'} + '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} @@ -589,9 +615,72 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/rollup-darwin-arm64@4.44.0': + resolution: {integrity: sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.44.0': + resolution: {integrity: sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm64-gnu@4.44.0': + resolution: {integrity: sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.44.0': + resolution: {integrity: sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-x64-gnu@4.44.0': + resolution: {integrity: sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.44.0': + resolution: {integrity: sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-win32-arm64-msvc@4.44.0': + resolution: {integrity: sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.44.0': + resolution: {integrity: sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==} + cpu: [x64] + os: [win32] + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stencil/cli@5.0.0-alpha.19': + resolution: {integrity: sha512-tcgadbU0afcILLZB70YO2AJFKJEQqqJcPYR2Uc7a/EGupNpiI/PC75iQSlEq2qYHu8cLFRTjHsPcK7GCT+ktFQ==} + hasBin: true + peerDependencies: + '@stencil/core': ^5.0.0-0 + + '@stencil/core@4.43.5': + resolution: {integrity: sha512-cgWD+GeuvJpTe1WQn40p02+BJ2j0j1YJ17GdkF2qKIQ23s2e3Zivq5yISXS3dcuV6oUJFN93jprdk+nk/sq99Q==} + engines: {node: '>=16.0.0', npm: '>=7.10.0'} + hasBin: true + + '@stencil/dev-server@5.0.0-alpha.19': + resolution: {integrity: sha512-LTCBuYuZkPU106kxC+j10AtQgzFp1jMmTFNohYZabGD7ED/aIJSYrDt7C7+nTBjlMwF4YgJNBQpD0r6z3uPdKw==} + peerDependencies: + '@stencil/core': ^5.0.0-0 + + '@stencil/templates@5.0.0-alpha.19': + resolution: {integrity: sha512-bZpOx5RUlq46QOAnZPx7YdtH2nCVAPLzeDRUA9s7pLpfx2khqux67S4APN7f2QdJo+DjPF8RSbkXbx3vAEmCpQ==} + '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} @@ -732,6 +821,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -813,6 +907,10 @@ packages: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -837,6 +935,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -847,6 +948,13 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -893,10 +1001,22 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -1034,6 +1154,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -1047,6 +1171,15 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1098,6 +1231,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -1164,6 +1301,10 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -1220,6 +1361,11 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + 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 + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1236,6 +1382,15 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -1259,6 +1414,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -1283,6 +1442,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -1345,6 +1508,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + launch-editor@2.14.1: + resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1455,6 +1621,13 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -1462,6 +1635,9 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1473,6 +1649,15 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + nypm@0.3.12: + resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1504,6 +1689,14 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1564,9 +1757,16 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -1577,6 +1777,9 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -1585,6 +1788,10 @@ packages: resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -1649,6 +1856,10 @@ packages: rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -1697,6 +1908,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.9.0: + resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -1716,6 +1931,13 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1723,6 +1945,9 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} @@ -1745,6 +1970,10 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1837,6 +2066,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -1994,6 +2226,10 @@ packages: utf-8-validate: optional: true + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -2062,6 +2298,18 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@clack/core@1.4.3': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.7.0': + dependencies: + '@clack/core': 1.4.3 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + '@csstools/color-helpers@5.1.0': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -2353,8 +2601,68 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@rollup/rollup-darwin-arm64@4.44.0': + optional: true + + '@rollup/rollup-darwin-x64@4.44.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.44.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.44.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.44.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.44.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.44.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.44.0': + optional: true + '@standard-schema/spec@1.1.0': {} + '@stencil/cli@5.0.0-alpha.19(@stencil/core@4.43.5)': + dependencies: + '@clack/prompts': 1.7.0 + '@stencil/core': 4.43.5 + '@stencil/dev-server': 5.0.0-alpha.19(@stencil/core@4.43.5) + '@stencil/templates': 5.0.0-alpha.19 + nypm: 0.3.12 + std-env: 3.10.0 + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@stencil/core@4.43.5': + optionalDependencies: + '@rollup/rollup-darwin-arm64': 4.44.0 + '@rollup/rollup-darwin-x64': 4.44.0 + '@rollup/rollup-linux-arm64-gnu': 4.44.0 + '@rollup/rollup-linux-arm64-musl': 4.44.0 + '@rollup/rollup-linux-x64-gnu': 4.44.0 + '@rollup/rollup-linux-x64-musl': 4.44.0 + '@rollup/rollup-win32-arm64-msvc': 4.44.0 + '@rollup/rollup-win32-x64-msvc': 4.44.0 + + '@stencil/dev-server@5.0.0-alpha.19(@stencil/core@4.43.5)': + dependencies: + '@stencil/core': 4.43.5 + launch-editor: 2.14.1 + open: 11.0.0 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@stencil/templates@5.0.0-alpha.19': {} + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 @@ -2547,6 +2855,8 @@ snapshots: acorn@8.15.0: {} + acorn@8.17.0: {} + agent-base@7.1.4: {} ajv@6.15.0: @@ -2656,6 +2966,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2682,6 +2996,10 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + citty@0.1.6: + dependencies: + consola: 3.4.2 + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2690,6 +3008,10 @@ snapshots: concat-map@0.0.1: {} + confbox@0.1.8: {} + + consola@3.4.2: {} + convert-source-map@2.0.0: {} cross-spawn@7.0.6: @@ -2742,12 +3064,21 @@ snapshots: deep-is@0.1.4: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -2975,6 +3306,18 @@ snapshots: esutils@2.0.3: {} + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + expect-type@1.3.0: {} fast-deep-equal@3.1.3: {} @@ -2983,6 +3326,16 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -3041,6 +3394,8 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@8.0.1: {} + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -3106,6 +3461,8 @@ snapshots: transitivePeerDependencies: - supports-color + human-signals@5.0.0: {} + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -3167,6 +3524,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -3184,6 +3543,12 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-map@2.0.3: {} is-number-object@1.1.1: @@ -3206,6 +3571,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-stream@3.0.0: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -3232,6 +3599,10 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} isexe@2.0.0: {} @@ -3313,6 +3684,11 @@ snapshots: dependencies: json-buffer: 3.0.1 + launch-editor@2.14.1: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.9.0 + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -3397,6 +3773,10 @@ snapshots: mdn-data@2.12.2: {} + merge-stream@2.0.0: {} + + mimic-fn@4.0.0: {} + minimatch@10.2.5: dependencies: brace-expansion: 5.0.6 @@ -3405,12 +3785,32 @@ snapshots: dependencies: brace-expansion: 1.1.15 + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + ms@2.1.3: {} nanoid@3.3.12: {} natural-compare@1.4.0: {} + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + nypm@0.3.12: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + execa: 8.0.1 + pathe: 1.1.2 + pkg-types: 1.3.1 + ufo: 1.6.4 + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -3449,6 +3849,19 @@ snapshots: obug@2.1.1: {} + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3534,14 +3947,24 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + path-parse@1.0.7: {} + pathe@1.1.2: {} + pathe@2.0.3: {} picocolors@1.1.1: {} picomatch@4.0.4: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + possible-typed-array-names@1.1.0: {} postcss@8.5.15: @@ -3550,6 +3973,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + prelude-ls@1.2.1: {} prop-types@15.8.1: @@ -3633,6 +4058,8 @@ snapshots: rrweb-cssom@0.8.0: {} + run-applescript@7.1.0: {} + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -3690,6 +4117,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.9.0: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -3720,10 +4149,16 @@ snapshots: siginfo@2.0.0: {} + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + source-map-js@1.2.1: {} stackback@0.0.2: {} + std-env@3.10.0: {} + std-env@4.1.0: {} string.prototype.matchall@4.0.12: @@ -3770,6 +4205,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + strip-final-newline@3.0.0: {} + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -3860,6 +4297,8 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.4: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -3983,6 +4422,11 @@ snapshots: ws@8.21.0: {} + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..c80bf3f --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - tests/wizard-playground diff --git a/rolldown.config.ts b/rolldown.config.ts index 839f5bc..8dc7538 100644 --- a/rolldown.config.ts +++ b/rolldown.config.ts @@ -8,9 +8,14 @@ const external = [ "jsdom", "eslint-utils", "eslint-plugin-react", + "@stencil/cli", + /^node:/, ]; -const input = "src/index.ts"; +const input = { + index: "src/index.ts", + wizard: "src/wizard.ts", +}; const sourcemap = true; export default defineConfig({ @@ -19,6 +24,7 @@ export default defineConfig({ dir: "dist", format: "esm", sourcemap, + entryFileNames: "[name].js", }, external, plugins: [dts({ sourcemap: true })], diff --git a/src/configs/index.ts b/src/configs/index.ts index eb6da14..816e0ef 100644 --- a/src/configs/index.ts +++ b/src/configs/index.ts @@ -1,6 +1,7 @@ import type { Linter } from "eslint"; import base from "./base"; +import oxlint from "./oxlint"; import recommended from "./recommended"; import strict from "./strict"; @@ -8,6 +9,7 @@ export default { base, recommended, strict, + oxlint, /** * will be populated in `/src/index.ts` * For backward compatibility diff --git a/src/configs/oxlint.ts b/src/configs/oxlint.ts new file mode 100644 index 0000000..ab9cc69 --- /dev/null +++ b/src/configs/oxlint.ts @@ -0,0 +1,19 @@ +import base from "./base"; +import recommended from "./recommended"; + +type OxlintRuleEntry = number | [number, ...unknown[]]; + +/** + * Rule set for oxlint's `.oxlintrc.json`, loaded via `jsPlugins`. Unlike the + * ESLint flat configs, this only carries `stencil/*` rules - oxlint has its + * own built-in `react` plugin, so `eslint-plugin-react` rules from + * {@link recommended} are not applicable here. + */ +function stencilRulesOf(rules: Record): Record { + return Object.fromEntries(Object.entries(rules).filter(([name]) => name.startsWith("stencil/"))); +} + +export default { + ...stencilRulesOf(base.overrides[0].rules), + ...stencilRulesOf(recommended.rules), +} satisfies Record; diff --git a/src/wizard.ts b/src/wizard.ts new file mode 100644 index 0000000..4255e45 --- /dev/null +++ b/src/wizard.ts @@ -0,0 +1,140 @@ +import type { StencilWizardPlugin, WizardContext } from "@stencil/cli"; +import { access, readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; + +import configs from "./configs"; + +type Runner = "eslint" | "oxlint"; +type Preset = "recommended" | "strict"; + +async function fileExists(path: string): Promise { + try { + await access(path); + return true; + } catch { + return false; + } +} + +function configFileName(runner: Runner): string { + return runner === "eslint" ? "eslint.config.js" : ".oxlintrc.json"; +} + +function eslintConfigContent(preset: Preset): string { + return `import stencil from '@stencil/eslint-plugin'; + +export default [stencil.configs.flat.${preset}]; +`; +} + +function oxlintConfigContent(): string { + return ( + JSON.stringify( + { + $schema: "./node_modules/oxlint/configuration_schema.json", + jsPlugins: ["@stencil/eslint-plugin"], + rules: configs.oxlint, + }, + null, + 2, + ) + "\n" + ); +} + +async function updatePackageJsonScripts(rootDir: string, runner: Runner): Promise { + const pkgPath = join(rootDir, "package.json"); + const pkg = JSON.parse(await readFile(pkgPath, "utf8")) as Record; + + pkg["scripts"] ??= {}; + pkg["scripts"]["lint"] ??= runner === "eslint" ? "eslint ." : "oxlint ."; + pkg["scripts"]["lint:fix"] ??= runner === "eslint" ? "eslint . --fix" : "oxlint . --fix"; + + await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8"); +} + +export const wizard: StencilWizardPlugin = { + init: { + id: "@stencil/eslint-plugin", + displayName: "ESLint Plugin", + description: "Stencil-specific lint rules, via ESLint or oxlint", + + async run({ config, prompts, nypm }: WizardContext): Promise { + const { intro, outro, select, confirm, isCancel, cancel, spinner } = prompts; + const rootDir = config.rootDir; + + intro("@stencil/eslint-plugin - Stencil-specific lint rules"); + + const runner = await select({ + message: "Which linter do you want to run Stencil rules with?", + options: [ + { + value: "oxlint", + label: "oxlint", + hint: "fast, Rust-based - a few type-aware rules run type-blind (JS plugins are alpha)", + }, + { + value: "eslint", + label: "ESLint", + hint: "full rule coverage, including type-aware rules", + }, + ], + }); + if (isCancel(runner)) { + cancel("Setup cancelled."); + process.exit(0); + } + + const configPath = join(rootDir, configFileName(runner as Runner)); + if (await fileExists(configPath)) { + const overwrite = await confirm({ + message: `${configFileName(runner as Runner)} already exists. Overwrite it?`, + initialValue: false, + }); + if (isCancel(overwrite) || !overwrite) { + cancel("Skipping lint setup - existing config kept."); + return; + } + } + + let preset: Preset = "recommended"; + if (runner === "eslint") { + const chosenPreset = await select({ + message: "Which rule preset?", + options: [ + { value: "recommended", label: "Recommended", hint: "sensible defaults" }, + { value: "strict", label: "Strict", hint: "recommended + formatting/style rules" }, + ], + }); + if (isCancel(chosenPreset)) { + cancel("Setup cancelled."); + process.exit(0); + } + preset = chosenPreset as Preset; + } + + const deps = + runner === "eslint" + ? [ + "eslint", + "@typescript-eslint/parser", + "@typescript-eslint/eslint-plugin", + "eslint-plugin-react", + ] + : ["oxlint"]; + + const s = spinner(); + s.start("Installing dependencies"); + await nypm.addDependency(deps, { cwd: rootDir, dev: true }); + s.stop("Dependencies installed"); + + await writeFile( + configPath, + runner === "eslint" ? eslintConfigContent(preset) : oxlintConfigContent(), + "utf8", + ); + await updatePackageJsonScripts(rootDir, runner as Runner); + + outro(`${runner === "eslint" ? "ESLint" : "oxlint"} configured with Stencil rules`); + }, + }, +}; diff --git a/tests/wizard-playground/package.json b/tests/wizard-playground/package.json new file mode 100644 index 0000000..ba1e432 --- /dev/null +++ b/tests/wizard-playground/package.json @@ -0,0 +1,15 @@ +{ + "name": "wizard-playground", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "init": "STENCIL_WIZARD_DEV=../../dist/wizard.js stencil init", + "add": "STENCIL_WIZARD_DEV=../../dist/wizard.js stencil init" + }, + "devDependencies": { + "@stencil/cli": "^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", + "@stencil/core": "^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", + "@stencil/eslint-plugin": "workspace:*" + } +} diff --git a/tests/wizard.test.ts b/tests/wizard.test.ts new file mode 100644 index 0000000..793fe0f --- /dev/null +++ b/tests/wizard.test.ts @@ -0,0 +1,146 @@ +import { beforeEach, describe, expect, test, vi } from "vitest"; + +vi.mock("node:fs/promises", () => ({ + access: vi.fn(), + readFile: vi.fn(), + writeFile: vi.fn(), +})); + +import { access, readFile, writeFile } from "node:fs/promises"; +import configs from "../src/configs"; +import { wizard } from "../src/wizard"; + +const CANCEL = Symbol("cancel"); + +function fakePrompts(overrides: { select?: unknown; confirm?: unknown } = {}) { + return { + intro: vi.fn(), + outro: vi.fn(), + log: { warn: vi.fn() }, + select: overrides.select ?? vi.fn(), + confirm: overrides.confirm ?? vi.fn(), + isCancel: (v: unknown) => v === CANCEL, + cancel: vi.fn(), + spinner: () => ({ start: vi.fn(), stop: vi.fn() }), + }; +} + +function fakeContext(prompts: ReturnType) { + return { + config: { rootDir: "/proj" }, + isNewProject: false, + prompts, + nypm: { addDependency: vi.fn() }, + } as any; +} + +describe("eslint plugin wizard", () => { + beforeEach(() => { + vi.mocked(access).mockReset(); + vi.mocked(readFile).mockReset(); + vi.mocked(writeFile).mockReset(); + vi.mocked(readFile).mockResolvedValue('{"scripts":{}}'); + }); + + test("exports a stable id for de-duplication", () => { + expect(wizard.init?.id).toBe("@stencil/eslint-plugin"); + }); + + test("cancelling the runner prompt exits without installing anything", async () => { + const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); + const select = vi.fn().mockResolvedValueOnce(CANCEL); + const prompts = fakePrompts({ select }); + vi.mocked(access).mockRejectedValue(new Error("missing")); + + await wizard.init!.run(fakeContext(prompts)); + + expect(prompts.cancel).toHaveBeenCalled(); + expect(exitSpy).toHaveBeenCalledWith(0); + exitSpy.mockRestore(); + }); + + test("declining to overwrite an existing config skips setup", async () => { + const select = vi.fn().mockResolvedValueOnce("oxlint"); + const confirm = vi.fn().mockResolvedValueOnce(false); + const prompts = fakePrompts({ select, confirm }); + const ctx = fakeContext(prompts); + vi.mocked(access).mockResolvedValue(undefined); + + await wizard.init!.run(ctx); + + expect(confirm).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.stringContaining(".oxlintrc.json") }), + ); + expect(ctx.nypm.addDependency).not.toHaveBeenCalled(); + expect(vi.mocked(writeFile)).not.toHaveBeenCalled(); + }); + + test("oxlint runner installs oxlint and writes .oxlintrc.json with only stencil rules", async () => { + const select = vi.fn().mockResolvedValueOnce("oxlint"); + const prompts = fakePrompts({ select }); + const ctx = fakeContext(prompts); + vi.mocked(access).mockRejectedValue(new Error("missing")); + + await wizard.init!.run(ctx); + + expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: "/proj", dev: true }); + + const [configPath, configContent] = vi.mocked(writeFile).mock.calls[0]; + expect(configPath).toBe("/proj/.oxlintrc.json"); + const written = JSON.parse(configContent as string); + expect(written.jsPlugins).toEqual(["@stencil/eslint-plugin"]); + expect(written.rules).toEqual(configs.oxlint); + expect(Object.keys(written.rules).every((name) => name.startsWith("stencil/"))).toBe(true); + + const [pkgPath, pkgContent] = vi.mocked(writeFile).mock.calls[1]; + expect(pkgPath).toBe("/proj/package.json"); + expect(JSON.parse(pkgContent as string).scripts).toEqual({ + lint: "oxlint .", + "lint:fix": "oxlint . --fix", + }); + }); + + test("eslint runner prompts for a preset and writes eslint.config.js", async () => { + const select = vi.fn().mockResolvedValueOnce("eslint").mockResolvedValueOnce("strict"); + const prompts = fakePrompts({ select }); + const ctx = fakeContext(prompts); + vi.mocked(access).mockRejectedValue(new Error("missing")); + + await wizard.init!.run(ctx); + + expect(ctx.nypm.addDependency).toHaveBeenCalledWith( + [ + "eslint", + "@typescript-eslint/parser", + "@typescript-eslint/eslint-plugin", + "eslint-plugin-react", + ], + { cwd: "/proj", dev: true }, + ); + + const [configPath, configContent] = vi.mocked(writeFile).mock.calls[0]; + expect(configPath).toBe("/proj/eslint.config.js"); + expect(configContent).toContain("stencil.configs.flat.strict"); + + const [, pkgContent] = vi.mocked(writeFile).mock.calls[1]; + expect(JSON.parse(pkgContent as string).scripts).toEqual({ + lint: "eslint .", + "lint:fix": "eslint . --fix", + }); + }); + + test("does not clobber pre-existing lint scripts", async () => { + vi.mocked(readFile).mockResolvedValue('{"scripts":{"lint":"custom-lint"}}'); + const select = vi.fn().mockResolvedValueOnce("oxlint"); + const prompts = fakePrompts({ select }); + const ctx = fakeContext(prompts); + vi.mocked(access).mockRejectedValue(new Error("missing")); + + await wizard.init!.run(ctx); + + const [, pkgContent] = vi.mocked(writeFile).mock.calls[1]; + const scripts = JSON.parse(pkgContent as string).scripts; + expect(scripts.lint).toBe("custom-lint"); + expect(scripts["lint:fix"]).toBe("oxlint . --fix"); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 4484ef7..7d35888 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,8 +11,9 @@ "moduleResolution": "bundler", "strict": true, "target": "es2022", + "rootDir": ".", "outDir": "dist/build", "lib": ["es2022"] }, - "files": ["src/index.ts"] + "files": ["src/index.ts", "src/wizard.ts"] } From 22d998d591254ac951441220e32567246e90acd1 Mon Sep 17 00:00:00 2001 From: John Jenkins Date: Fri, 10 Jul 2026 17:12:48 +0100 Subject: [PATCH 2/3] chore: make `add` reconfigure correctly. --- .gitignore | 7 +- README.md | 46 ++- pnpm-lock.yaml | 499 ++++++++++++++++++++++++--- pnpm-workspace.yaml | 2 + src/configs/oxlint.ts | 31 +- src/configs/strict.ts | 38 +- src/index.ts | 82 +++-- src/wizard.ts | 80 +++-- tests/wizard-playground/package.json | 2 +- tests/wizard.test.ts | 62 +++- 10 files changed, 688 insertions(+), 161 deletions(-) diff --git a/.gitignore b/.gitignore index 24c67de..f5ac5f8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ dist report *.tgz coverage - -# scratch output from running `stencil init`/`generate` against the dev wizard -tests/wizard-playground/* -!tests/wizard-playground/package.json \ No newline at end of file +www +loader +.stencil diff --git a/README.md b/README.md index 3348d52..05f4616 100644 --- a/README.md +++ b/README.md @@ -44,14 +44,14 @@ module.exports = [ ]; ``` -By default, ESLint will ignore your `node_modules/` directory. Consider adding a `.eslintignore` file at the root of -your project with any output target directories to avoid false positive errors from ESLint. +Exclude +directories created by the Stencil compilation process with an `ignores` entry instead: -``` -# place any directories created by the Stencil compilation process here -dist -loader -www +```js +// eslint.config.js +import stencil from "@stencil/eslint-plugin"; + +export default [{ ignores: ["dist", "loader", "www"] }, stencil.configs.flat.recommended]; ``` Lint all your project: @@ -60,8 +60,40 @@ Lint all your project: npm run lint ``` +### Configuration (oxlint) + +This plugin can also run under [oxlint](https://oxc.rs/docs/guide/usage/linter.html) via its `jsPlugins` +support, instead of ESLint: + +```bash +npm i --save-dev oxlint @stencil/eslint-plugin +``` + +```json +// .oxlintrc.json +{ + "jsPlugins": [{ "name": "stencil", "specifier": "@stencil/eslint-plugin" }], + "rules": { + "stencil/async-methods": "error", + "stencil/methods-must-be-public": "error" + } +} +``` + +TypeScript type information (e.g. type-aware checks in `async-methods`) run in a degraded, type-blind +mode under oxlint, since oxlint doesn't do type resolution. + +```sh +npx oxlint . +``` + ### Configuration (legacy: .eslintrc*) +Only works on ESLint 8, or ESLint 9 with the `ESLINT_USE_FLAT_CONFIG=false` environment variable set - +ESLint no longer reads `.eslintrc.*` files by default, and that escape hatch is removed entirely in +ESLint 10. Use the [flat config](#configuration-new-eslintconfig) above unless you have a specific +reason not to. + `.eslintrc.json` configuration file: ```json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21b4239..dcf0acd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 4.43.5 eslint-utils: specifier: ^3.0.0 - version: 3.0.0(eslint@9.38.0) + version: 3.0.0(eslint@9.38.0(jiti@2.7.0)) jsdom: specifier: ^27.0.1 version: 27.0.1(postcss@8.5.15) @@ -41,19 +41,19 @@ importers: version: 24.9.2 '@typescript-eslint/eslint-plugin': specifier: ^8.46.2 - version: 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.38.0)(typescript@5.9.3))(eslint@9.38.0)(typescript@5.9.3) + version: 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.46.2 - version: 8.60.1(eslint@9.38.0)(typescript@5.9.3) + version: 8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@vitest/coverage-v8': specifier: ^4.0.5 version: 4.1.8(vitest@4.1.8) eslint: specifier: ^9.38.0 - version: 9.38.0 + version: 9.38.0(jiti@2.7.0) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.38.0) + version: 7.37.5(eslint@9.38.0(jiti@2.7.0)) oxfmt: specifier: ^0.58.0 version: 0.58.0 @@ -71,16 +71,16 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.5 - version: 4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)) + version: 4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0)) tests/wizard-playground: devDependencies: '@stencil/cli': specifier: ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 - version: 5.0.0-alpha.19(@stencil/core@4.43.5) + version: 5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19) '@stencil/core': - specifier: ^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 - version: 4.43.5 + specifier: ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0 + version: 5.0.0-alpha.19 '@stencil/eslint-plugin': specifier: workspace:* version: link:../.. @@ -258,6 +258,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -517,6 +520,97 @@ packages: cpu: [x64] os: [win32] + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@preact/signals-core@1.14.4': + resolution: {integrity: sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA==} + '@rolldown/binding-android-arm64@1.0.3': resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -615,6 +709,15 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-darwin-arm64@4.44.0': resolution: {integrity: sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==} cpu: [arm64] @@ -673,11 +776,18 @@ packages: engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true + '@stencil/core@5.0.0-alpha.19': + resolution: {integrity: sha512-49E9ZOVTjwfZHayE+f1WSqWYIuGKam44OuuEvT3f9Pnlj3cFgx+bLnw1MYXj3sijE9/z5gYJcd1jhgw2AdWVyA==} + hasBin: true + '@stencil/dev-server@5.0.0-alpha.19': resolution: {integrity: sha512-LTCBuYuZkPU106kxC+j10AtQgzFp1jMmTFNohYZabGD7ED/aIJSYrDt7C7+nTBjlMwF4YgJNBQpD0r6z3uPdKw==} peerDependencies: '@stencil/core': ^5.0.0-0 + '@stencil/mock-doc@5.0.0-alpha.19': + resolution: {integrity: sha512-TJEhxuTnM3xR2flYH0irneBF2dvd0Q2etWmyHcuyDqlM5pfU/6f+47bGqofNPGiP7aEvjiAJ+tSBNXGwtb18fw==} + '@stencil/templates@5.0.0-alpha.19': resolution: {integrity: sha512-bZpOx5RUlq46QOAnZPx7YdtH2nCVAPLzeDRUA9s7pLpfx2khqux67S4APN7f2QdJo+DjPF8RSbkXbx3vAEmCpQ==} @@ -816,11 +926,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.17.0: resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} @@ -894,6 +999,11 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + baseline-browser-mapping@2.10.42: + resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==} + engines: {node: '>=6.0.0'} + hasBin: true + bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -907,6 +1017,14 @@ packages: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} + browserslist@4.28.5: + resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -927,6 +1045,9 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + caniuse-lite@1.0.30001803: + resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -935,6 +1056,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -945,6 +1070,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -966,6 +1094,15 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + cssstyle@5.3.1: resolution: {integrity: sha512-g5PC9Aiph9eiczFpcgUhd9S4UUO3F+LHGRIi5NUMZ+4xtoIYbHNZwZnWA2JsFGe8OU8nl4WyaEFiZuGuxlutJQ==} engines: {node: '>=20'} @@ -1042,6 +1179,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + electron-to-chromium@1.5.389: + resolution: {integrity: sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1085,6 +1225,10 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1147,6 +1291,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -1468,6 +1615,10 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -1649,10 +1800,20 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-releases@2.0.51: + resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + engines: {node: '>=18'} + npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + nwsapi@2.2.24: + resolution: {integrity: sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==} + nypm@0.3.12: resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} engines: {node: ^14.16.0 || >=16.10.0} @@ -1784,6 +1945,16 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-selector-parser@7.1.4: + resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} + engines: {node: '>=4'} + postcss@8.5.15: resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} @@ -1825,6 +1996,11 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true @@ -1942,6 +2118,13 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1989,6 +2172,11 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + terser@5.49.0: + resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} + engines: {node: '>=10'} + hasBin: true + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -2076,9 +2264,18 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite@8.0.16: resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2350,9 +2547,9 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0)': + '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0(jiti@2.7.0))': dependencies: - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -2420,6 +2617,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -2550,6 +2752,68 @@ snapshots: '@oxlint/binding-win32-x64-msvc@1.73.0': optional: true + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.4 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@preact/signals-core@1.14.4': {} + '@rolldown/binding-android-arm64@1.0.3': optional: true @@ -2601,6 +2865,12 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@rollup/pluginutils@5.4.0': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.4 + '@rollup/rollup-darwin-arm64@4.44.0': optional: true @@ -2640,6 +2910,19 @@ snapshots: - bufferutil - utf-8-validate + '@stencil/cli@5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19)': + dependencies: + '@clack/prompts': 1.7.0 + '@stencil/core': 5.0.0-alpha.19 + '@stencil/dev-server': 5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19) + '@stencil/templates': 5.0.0-alpha.19 + nypm: 0.3.12 + std-env: 3.10.0 + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@stencil/core@4.43.5': optionalDependencies: '@rollup/rollup-darwin-arm64': 4.44.0 @@ -2651,6 +2934,35 @@ snapshots: '@rollup/rollup-win32-arm64-msvc': 4.44.0 '@rollup/rollup-win32-x64-msvc': 4.44.0 + '@stencil/core@5.0.0-alpha.19': + dependencies: + '@parcel/watcher': 2.5.6 + '@preact/signals-core': 1.14.4 + '@rollup/pluginutils': 5.4.0 + '@stencil/cli': 5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19) + '@stencil/dev-server': 5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19) + '@stencil/mock-doc': 5.0.0-alpha.19 + browserslist: 4.28.5 + chalk: 5.6.2 + css-what: 7.0.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + picomatch: 4.0.4 + postcss: 8.5.15 + postcss-safe-parser: 7.0.1(postcss@8.5.15) + postcss-selector-parser: 7.1.4 + resolve: 1.22.12 + rolldown: 1.0.3 + semver: 7.7.3 + terser: 5.49.0 + tinyglobby: 0.2.17 + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - rollup + - utf-8-validate + '@stencil/dev-server@5.0.0-alpha.19(@stencil/core@4.43.5)': dependencies: '@stencil/core': 4.43.5 @@ -2661,6 +2973,21 @@ snapshots: - bufferutil - utf-8-validate + '@stencil/dev-server@5.0.0-alpha.19(@stencil/core@5.0.0-alpha.19)': + dependencies: + '@stencil/core': 5.0.0-alpha.19 + launch-editor: 2.14.1 + open: 11.0.0 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@stencil/mock-doc@5.0.0-alpha.19': + dependencies: + nwsapi: 2.2.24 + parse5: 8.0.0 + '@stencil/templates@5.0.0-alpha.19': {} '@tybys/wasm-util@0.10.2': @@ -2703,15 +3030,15 @@ snapshots: '@types/tough-cookie@4.0.5': {} - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.38.0)(typescript@5.9.3))(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@9.38.0)(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.60.1 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -2719,14 +3046,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/parser@8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2749,13 +3076,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.60.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -2778,13 +3105,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/utils@8.60.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2806,7 +3133,7 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)) + vitest: 4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0)) '@vitest/expect@4.1.8': dependencies: @@ -2817,13 +3144,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@24.9.2))': + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0))': dependencies: '@vitest/spy': 4.1.8 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.16(@types/node@24.9.2) + vite: 8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0) '@vitest/pretty-format@4.1.8': dependencies: @@ -2849,11 +3176,9 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} + acorn: 8.17.0 acorn@8.17.0: {} @@ -2951,6 +3276,8 @@ snapshots: balanced-match@4.0.4: {} + baseline-browser-mapping@2.10.42: {} + bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -2966,6 +3293,16 @@ snapshots: dependencies: balanced-match: 4.0.4 + browserslist@4.28.5: + dependencies: + baseline-browser-mapping: 2.10.42 + caniuse-lite: 1.0.30001803 + electron-to-chromium: 1.5.389 + node-releases: 2.0.51 + update-browserslist-db: 1.2.3(browserslist@4.28.5) + + buffer-from@1.1.2: {} + bundle-name@4.1.0: dependencies: run-applescript: 7.1.0 @@ -2989,6 +3326,8 @@ snapshots: callsites@3.1.0: {} + caniuse-lite@1.0.30001803: {} + chai@6.2.2: {} chalk@4.1.2: @@ -2996,6 +3335,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + citty@0.1.6: dependencies: consola: 3.4.2 @@ -3006,6 +3347,8 @@ snapshots: color-name@1.1.4: {} + commander@2.20.3: {} + concat-map@0.0.1: {} confbox@0.1.8: {} @@ -3025,6 +3368,10 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 + css-what@7.0.0: {} + + cssesc@3.0.0: {} + cssstyle@5.3.1(postcss@8.5.15): dependencies: '@asamuzakjp/css-color': 4.0.5 @@ -3099,6 +3446,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + electron-to-chromium@1.5.389: {} + entities@4.5.0: {} entities@6.0.1: {} @@ -3203,9 +3552,11 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} - eslint-plugin-react@7.37.5(eslint@9.38.0): + eslint-plugin-react@7.37.5(eslint@9.38.0(jiti@2.7.0)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -3213,7 +3564,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -3232,9 +3583,9 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@3.0.0(eslint@9.38.0): + eslint-utils@3.0.0(eslint@9.38.0(jiti@2.7.0)): dependencies: - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.7.0) eslint-visitor-keys: 2.1.0 eslint-visitor-keys@2.1.0: {} @@ -3245,9 +3596,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.38.0: + eslint@9.38.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -3281,13 +3632,15 @@ snapshots: minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 transitivePeerDependencies: - supports-color espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) eslint-visitor-keys: 4.2.1 esquery@1.6.0: @@ -3300,6 +3653,8 @@ snapshots: estraverse@5.3.0: {} + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 @@ -3629,6 +3984,8 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 + jiti@2.7.0: {} + js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -3798,10 +4155,16 @@ snapshots: natural-compare@1.4.0: {} + node-addon-api@7.1.1: {} + + node-releases@2.0.51: {} + npm-run-path@5.3.0: dependencies: path-key: 4.0.0 + nwsapi@2.2.24: {} + nypm@0.3.12: dependencies: citty: 0.1.6 @@ -3967,6 +4330,15 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-safe-parser@7.0.1(postcss@8.5.15): + dependencies: + postcss: 8.5.15 + + postcss-selector-parser@7.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.15: dependencies: nanoid: 3.3.12 @@ -4013,6 +4385,13 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@2.0.0-next.5: dependencies: is-core-module: 2.16.1 @@ -4155,6 +4534,13 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + stackback@0.0.2: {} std-env@3.10.0: {} @@ -4217,6 +4603,13 @@ snapshots: symbol-tree@3.2.4: {} + terser@5.49.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.17.0 + commander: 2.20.3 + source-map-support: 0.5.21 + tinybench@2.9.0: {} tinyexec@1.2.4: {} @@ -4308,11 +4701,19 @@ snapshots: undici-types@7.16.0: {} + update-browserslist-db@1.2.3(browserslist@4.28.5): + dependencies: + browserslist: 4.28.5 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 - vite@8.0.16(@types/node@24.9.2): + util-deprecate@1.0.2: {} + + vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -4322,11 +4723,13 @@ snapshots: optionalDependencies: '@types/node': 24.9.2 fsevents: 2.3.3 + jiti: 2.7.0 + terser: 5.49.0 - vitest@4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)): + vitest@4.1.8(@types/node@24.9.2)(@vitest/coverage-v8@4.1.8)(jsdom@27.0.1(postcss@8.5.15))(vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0)): dependencies: '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.9.2)) + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0)) '@vitest/pretty-format': 4.1.8 '@vitest/runner': 4.1.8 '@vitest/snapshot': 4.1.8 @@ -4343,7 +4746,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.16(@types/node@24.9.2) + vite: 8.0.16(@types/node@24.9.2)(jiti@2.7.0)(terser@5.49.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.9.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c80bf3f..db56884 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,4 @@ packages: - tests/wizard-playground +allowBuilds: + "@parcel/watcher": true diff --git a/src/configs/oxlint.ts b/src/configs/oxlint.ts index ab9cc69..b45fb17 100644 --- a/src/configs/oxlint.ts +++ b/src/configs/oxlint.ts @@ -1,16 +1,39 @@ import base from "./base"; import recommended from "./recommended"; -type OxlintRuleEntry = number | [number, ...unknown[]]; +type Severity = "off" | "warn" | "error"; +type RawRuleEntry = number | string | [number | string, ...unknown[]]; +type OxlintRuleEntry = Severity | [Severity, ...unknown[]]; + +const SEVERITY_BY_NUMBER: Record = { 0: "off", 1: "warn", 2: "error" }; + +function toSeverity(value: number | string): Severity { + return typeof value === "string" ? (value as Severity) : SEVERITY_BY_NUMBER[value]; +} + +function normalize(entry: RawRuleEntry): OxlintRuleEntry { + if (Array.isArray(entry)) { + const [severity, ...options] = entry; + return [toSeverity(severity), ...options]; + } + return toSeverity(entry); +} /** * Rule set for oxlint's `.oxlintrc.json`, loaded via `jsPlugins`. Unlike the * ESLint flat configs, this only carries `stencil/*` rules - oxlint has its * own built-in `react` plugin, so `eslint-plugin-react` rules from - * {@link recommended} are not applicable here. + * {@link recommended} are not applicable here. Severities are normalized to + * oxlint's string form ("off"/"warn"/"error") rather than the numeric form + * the legacy `.eslintrc` configs use, since oxlint users read them directly + * out of `.oxlintrc.json`. */ -function stencilRulesOf(rules: Record): Record { - return Object.fromEntries(Object.entries(rules).filter(([name]) => name.startsWith("stencil/"))); +function stencilRulesOf(rules: Record): Record { + return Object.fromEntries( + Object.entries(rules) + .filter(([name]) => name.startsWith("stencil/")) + .map(([name, entry]) => [name, normalize(entry)]), + ); } export default { diff --git a/src/configs/strict.ts b/src/configs/strict.ts index 759d8ff..54192db 100644 --- a/src/configs/strict.ts +++ b/src/configs/strict.ts @@ -11,17 +11,15 @@ export default { "stencil/ban-default-true": 2, "stencil/strict-boolean-conditions": 2, - // Resets - "@typescript-eslint/camelcase": 0, + // Resets - the recommended-tier defaults from `@typescript-eslint/recommended` are too + // aggressive for typical Stencil component code. "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/ban-ts-ignore": 0, "@typescript-eslint/no-this-alias": 0, "@typescript-eslint/no-non-null-assertion": 0, "@typescript-eslint/no-unused-vars": 0, "@typescript-eslint/no-empty-interface": 0, "@typescript-eslint/no-use-before-define": 0, "@typescript-eslint/no-explicit-any": 0, - "no-constant-condition": 0, // Best practices "no-shadow": 2, @@ -29,38 +27,6 @@ export default { "prefer-object-spread": 2, "no-nested-ternary": 2, "no-duplicate-imports": 2, - - // General formatting - indent: [2, 2], - "no-trailing-spaces": 2, curly: [2, "all"], - "comma-spacing": 2, - "comma-style": 2, - "computed-property-spacing": 2, - "comma-dangle": [ - 2, - { - objects: "always-multiline", - }, - ], - "func-style": [2, "expression", { allowArrowFunctions: true }], - "multiline-ternary": [2, "always-multiline"], - "operator-linebreak": [2, "after", { overrides: { "?": "before", ":": "before" } }], - "linebreak-style": 2, - "space-in-parens": 2, - "@typescript-eslint/semi": 2, - "@typescript-eslint/brace-style": 2, - "@typescript-eslint/func-call-spacing": 2, - - // JSX formatting - "react/jsx-closing-tag-location": 2, - "react/jsx-curly-newline": [2, "never"], - "react/jsx-closing-bracket-location": 2, - "react/jsx-curly-spacing": [2, { when: "never", children: true }], - "react/jsx-boolean-value": [2, "never"], - "react/jsx-child-element-spacing": 2, - "react/jsx-indent-props": [2, "first"], - "react/jsx-props-no-multi-spaces": 2, - "react/jsx-equals-spacing": [2, "never"], }, } satisfies Linter.BaseConfig; diff --git a/src/index.ts b/src/index.ts index 55f5c32..7545fac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,8 +3,8 @@ * @author Tom Chinery <tom.chinery@addtoevent.co.uk> */ +import { createRequire } from "node:module"; import type { Linter } from "eslint"; -import react from "eslint-plugin-react"; import rules from "./rules"; import configs from "./configs"; @@ -13,34 +13,62 @@ const plugin = { configs, }; -const flatBase: Linter.Config = { - plugins: { stencil: plugin }, - rules: configs.base.overrides[0].rules, - languageOptions: { parserOptions: configs.base.overrides[0].parserOptions }, -}; +const FLAT_FILES = ["**/*.ts", "**/*.tsx"]; -const flatRecommended: Linter.Config = { - plugins: { - react: react, - stencil: plugin, - }, - rules: configs.recommended.rules, - languageOptions: { parserOptions: configs.base.overrides[0].parserOptions }, -}; +let flat: Record | undefined; -const flatStrict: Linter.Config = { - plugins: { - react: react, - stencil: plugin, - }, - rules: configs.strict.rules, - languageOptions: { parserOptions: configs.base.overrides[0].parserOptions }, -}; +// `eslint-plugin-react` and `@typescript-eslint/parser` are only needed by the flat +// ESLint configs below - resolved lazily so that consumers who only need `rules`/`configs` +// (e.g. oxlint's `jsPlugins` loader, which imports this same module) aren't forced to have +// ESLint's peer deps installed just to load the plugin. +Object.defineProperty(configs, "flat", { + enumerable: true, + configurable: true, + get(): Record { + if (!flat) { + const require = createRequire(import.meta.url); + const react = require("eslint-plugin-react"); + // Only `strict` references `@typescript-eslint/*` rule IDs (semi, brace-style, + // func-call-spacing, plus a handful reset to "off") - ESLint's flat config validates + // every rule key against a registered plugin regardless of severity, so this has to be + // registered under the `@typescript-eslint` namespace even for the "off" entries. + const typescriptEslint = require("@typescript-eslint/eslint-plugin"); -configs.flat = { - base: flatBase, - recommended: flatRecommended, - strict: flatStrict, -}; + const languageOptions: Linter.Config["languageOptions"] = { + parser: require("@typescript-eslint/parser"), + parserOptions: configs.base.overrides[0].parserOptions, + }; + + // Flat config has no equivalent of the legacy `extends: ["plugin:stencil/base"]` + // chain, so each tier's rules are merged in here to preserve the same + // base -> recommended -> strict cascade the .eslintrc configs describe. + const baseRules = configs.base.overrides[0].rules; + const recommendedRules = { ...baseRules, ...configs.recommended.rules }; + const strictRules = { ...recommendedRules, ...configs.strict.rules }; + + flat = { + base: { + files: FLAT_FILES, + plugins: { stencil: plugin }, + rules: baseRules, + languageOptions, + }, + recommended: { + files: FLAT_FILES, + plugins: { react, stencil: plugin }, + rules: recommendedRules, + languageOptions, + }, + strict: { + files: FLAT_FILES, + plugins: { react, stencil: plugin, "@typescript-eslint": typescriptEslint }, + rules: strictRules, + languageOptions, + }, + }; + } + return flat; + }, +}); export default plugin; diff --git a/src/wizard.ts b/src/wizard.ts index 4255e45..5951afe 100644 --- a/src/wizard.ts +++ b/src/wizard.ts @@ -1,5 +1,5 @@ import type { StencilWizardPlugin, WizardContext } from "@stencil/cli"; -import { access, readFile, writeFile } from "node:fs/promises"; +import { access, readFile, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; import configs from "./configs"; @@ -7,6 +7,9 @@ import configs from "./configs"; type Runner = "eslint" | "oxlint"; type Preset = "recommended" | "strict"; +const ESLINT_CONFIG_FILE = "eslint.config.js"; +const OXLINT_CONFIG_FILE = ".oxlintrc.json"; + async function fileExists(path: string): Promise { try { await access(path); @@ -16,10 +19,6 @@ async function fileExists(path: string): Promise { } } -function configFileName(runner: Runner): string { - return runner === "eslint" ? "eslint.config.js" : ".oxlintrc.json"; -} - function eslintConfigContent(preset: Preset): string { return `import stencil from '@stencil/eslint-plugin'; @@ -32,7 +31,10 @@ function oxlintConfigContent(): string { JSON.stringify( { $schema: "./node_modules/oxlint/configuration_schema.json", - jsPlugins: ["@stencil/eslint-plugin"], + // Aliased to "stencil" - `@stencil/eslint-plugin` has no `meta.name`, so without an + // alias oxlint derives the plugin name from the package name instead (`@stencil`), + // which wouldn't match the `stencil/*` rule keys below. + jsPlugins: [{ name: "stencil", specifier: "@stencil/eslint-plugin" }], rules: configs.oxlint, }, null, @@ -41,13 +43,25 @@ function oxlintConfigContent(): string { ); } -async function updatePackageJsonScripts(rootDir: string, runner: Runner): Promise { +async function updatePackageJsonScripts( + rootDir: string, + runner: Runner, + force: boolean, +): Promise { const pkgPath = join(rootDir, "package.json"); const pkg = JSON.parse(await readFile(pkgPath, "utf8")) as Record; pkg["scripts"] ??= {}; - pkg["scripts"]["lint"] ??= runner === "eslint" ? "eslint ." : "oxlint ."; - pkg["scripts"]["lint:fix"] ??= runner === "eslint" ? "eslint . --fix" : "oxlint . --fix"; + const lint = runner === "eslint" ? "eslint ." : "oxlint ."; + const lintFix = runner === "eslint" ? "eslint . --fix" : "oxlint . --fix"; + + if (force) { + pkg["scripts"]["lint"] = lint; + pkg["scripts"]["lint:fix"] = lintFix; + } else { + pkg["scripts"]["lint"] ??= lint; + pkg["scripts"]["lint:fix"] ??= lintFix; + } await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8"); } @@ -64,18 +78,47 @@ export const wizard: StencilWizardPlugin = { intro("@stencil/eslint-plugin - Stencil-specific lint rules"); + const eslintConfigPath = join(rootDir, ESLINT_CONFIG_FILE); + const oxlintConfigPath = join(rootDir, OXLINT_CONFIG_FILE); + const [hasEslintConfig, hasOxlintConfig] = await Promise.all([ + fileExists(eslintConfigPath), + fileExists(oxlintConfigPath), + ]); + const isReconfigure = hasEslintConfig || hasOxlintConfig; + + if (isReconfigure) { + const existing = [ + hasEslintConfig && ESLINT_CONFIG_FILE, + hasOxlintConfig && OXLINT_CONFIG_FILE, + ] + .filter((name): name is string => Boolean(name)) + .join(" and "); + const reconfigure = await confirm({ + message: `Lint is already configured (${existing}). Reconfigure?`, + initialValue: false, + }); + if (isCancel(reconfigure) || !reconfigure) { + cancel("Lint setup left unchanged."); + return; + } + // Clear out both, regardless of which runner is picked next - otherwise switching + // runners leaves the old runner's config behind alongside the new one. + if (hasEslintConfig) await rm(eslintConfigPath); + if (hasOxlintConfig) await rm(oxlintConfigPath); + } + const runner = await select({ message: "Which linter do you want to run Stencil rules with?", options: [ { value: "oxlint", label: "oxlint", - hint: "fast, Rust-based - a few type-aware rules run type-blind (JS plugins are alpha)", + hint: "fast, Rust-based - a few type-aware rules cannot run at-present", }, { value: "eslint", label: "ESLint", - hint: "full rule coverage, including type-aware rules", + hint: "slower, JS-based - full rule coverage, including type-aware rules", }, ], }); @@ -84,18 +127,6 @@ export const wizard: StencilWizardPlugin = { process.exit(0); } - const configPath = join(rootDir, configFileName(runner as Runner)); - if (await fileExists(configPath)) { - const overwrite = await confirm({ - message: `${configFileName(runner as Runner)} already exists. Overwrite it?`, - initialValue: false, - }); - if (isCancel(overwrite) || !overwrite) { - cancel("Skipping lint setup - existing config kept."); - return; - } - } - let preset: Preset = "recommended"; if (runner === "eslint") { const chosenPreset = await select({ @@ -127,12 +158,13 @@ export const wizard: StencilWizardPlugin = { await nypm.addDependency(deps, { cwd: rootDir, dev: true }); s.stop("Dependencies installed"); + const configPath = runner === "eslint" ? eslintConfigPath : oxlintConfigPath; await writeFile( configPath, runner === "eslint" ? eslintConfigContent(preset) : oxlintConfigContent(), "utf8", ); - await updatePackageJsonScripts(rootDir, runner as Runner); + await updatePackageJsonScripts(rootDir, runner as Runner, isReconfigure); outro(`${runner === "eslint" ? "ESLint" : "oxlint"} configured with Stencil rules`); }, diff --git a/tests/wizard-playground/package.json b/tests/wizard-playground/package.json index ba1e432..9fada6f 100644 --- a/tests/wizard-playground/package.json +++ b/tests/wizard-playground/package.json @@ -9,7 +9,7 @@ }, "devDependencies": { "@stencil/cli": "^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", - "@stencil/core": "^4.0.0 || ^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", + "@stencil/core": "^5.0.0 || >=5.0.0-alpha.19 <5.0.0-next.0", "@stencil/eslint-plugin": "workspace:*" } } diff --git a/tests/wizard.test.ts b/tests/wizard.test.ts index 793fe0f..07492a0 100644 --- a/tests/wizard.test.ts +++ b/tests/wizard.test.ts @@ -4,9 +4,10 @@ vi.mock("node:fs/promises", () => ({ access: vi.fn(), readFile: vi.fn(), writeFile: vi.fn(), + rm: vi.fn(), })); -import { access, readFile, writeFile } from "node:fs/promises"; +import { access, readFile, rm, writeFile } from "node:fs/promises"; import configs from "../src/configs"; import { wizard } from "../src/wizard"; @@ -34,11 +35,25 @@ function fakeContext(prompts: ReturnType) { } as any; } +// By default neither config file exists - individual tests override via mockImplementation +// for the "reconfigure" scenarios. +function mockNoExistingConfig() { + vi.mocked(access).mockRejectedValue(new Error("missing")); +} + +function mockExistingConfig(...paths: string[]) { + vi.mocked(access).mockImplementation(async (path) => { + if (paths.includes(path as string)) return undefined; + throw new Error("missing"); + }); +} + describe("eslint plugin wizard", () => { beforeEach(() => { vi.mocked(access).mockReset(); vi.mocked(readFile).mockReset(); vi.mocked(writeFile).mockReset(); + vi.mocked(rm).mockReset(); vi.mocked(readFile).mockResolvedValue('{"scripts":{}}'); }); @@ -50,7 +65,7 @@ describe("eslint plugin wizard", () => { const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); const select = vi.fn().mockResolvedValueOnce(CANCEL); const prompts = fakePrompts({ select }); - vi.mocked(access).mockRejectedValue(new Error("missing")); + mockNoExistingConfig(); await wizard.init!.run(fakeContext(prompts)); @@ -59,27 +74,54 @@ describe("eslint plugin wizard", () => { exitSpy.mockRestore(); }); - test("declining to overwrite an existing config skips setup", async () => { - const select = vi.fn().mockResolvedValueOnce("oxlint"); + test("declining to reconfigure an existing setup leaves it unchanged", async () => { + const select = vi.fn(); const confirm = vi.fn().mockResolvedValueOnce(false); const prompts = fakePrompts({ select, confirm }); const ctx = fakeContext(prompts); - vi.mocked(access).mockResolvedValue(undefined); + mockExistingConfig("/proj/.oxlintrc.json"); await wizard.init!.run(ctx); expect(confirm).toHaveBeenCalledWith( expect.objectContaining({ message: expect.stringContaining(".oxlintrc.json") }), ); + expect(select).not.toHaveBeenCalled(); + expect(vi.mocked(rm)).not.toHaveBeenCalled(); expect(ctx.nypm.addDependency).not.toHaveBeenCalled(); expect(vi.mocked(writeFile)).not.toHaveBeenCalled(); }); + test("reconfiguring removes a stale config from the other runner and force-overwrites scripts", async () => { + vi.mocked(readFile).mockResolvedValue( + '{"scripts":{"lint":"custom-lint","lint:fix":"custom-fix"}}', + ); + const select = vi.fn().mockResolvedValueOnce("oxlint"); + const confirm = vi.fn().mockResolvedValueOnce(true); + const prompts = fakePrompts({ select, confirm }); + const ctx = fakeContext(prompts); + mockExistingConfig("/proj/eslint.config.js"); + + await wizard.init!.run(ctx); + + expect(vi.mocked(rm)).toHaveBeenCalledWith("/proj/eslint.config.js"); + expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: "/proj", dev: true }); + + const [configPath] = vi.mocked(writeFile).mock.calls[0]; + expect(configPath).toBe("/proj/.oxlintrc.json"); + + const [, pkgContent] = vi.mocked(writeFile).mock.calls[1]; + expect(JSON.parse(pkgContent as string).scripts).toEqual({ + lint: "oxlint .", + "lint:fix": "oxlint . --fix", + }); + }); + test("oxlint runner installs oxlint and writes .oxlintrc.json with only stencil rules", async () => { const select = vi.fn().mockResolvedValueOnce("oxlint"); const prompts = fakePrompts({ select }); const ctx = fakeContext(prompts); - vi.mocked(access).mockRejectedValue(new Error("missing")); + mockNoExistingConfig(); await wizard.init!.run(ctx); @@ -88,7 +130,7 @@ describe("eslint plugin wizard", () => { const [configPath, configContent] = vi.mocked(writeFile).mock.calls[0]; expect(configPath).toBe("/proj/.oxlintrc.json"); const written = JSON.parse(configContent as string); - expect(written.jsPlugins).toEqual(["@stencil/eslint-plugin"]); + expect(written.jsPlugins).toEqual([{ name: "stencil", specifier: "@stencil/eslint-plugin" }]); expect(written.rules).toEqual(configs.oxlint); expect(Object.keys(written.rules).every((name) => name.startsWith("stencil/"))).toBe(true); @@ -104,7 +146,7 @@ describe("eslint plugin wizard", () => { const select = vi.fn().mockResolvedValueOnce("eslint").mockResolvedValueOnce("strict"); const prompts = fakePrompts({ select }); const ctx = fakeContext(prompts); - vi.mocked(access).mockRejectedValue(new Error("missing")); + mockNoExistingConfig(); await wizard.init!.run(ctx); @@ -129,12 +171,12 @@ describe("eslint plugin wizard", () => { }); }); - test("does not clobber pre-existing lint scripts", async () => { + test("first-time setup does not clobber pre-existing unrelated lint scripts", async () => { vi.mocked(readFile).mockResolvedValue('{"scripts":{"lint":"custom-lint"}}'); const select = vi.fn().mockResolvedValueOnce("oxlint"); const prompts = fakePrompts({ select }); const ctx = fakeContext(prompts); - vi.mocked(access).mockRejectedValue(new Error("missing")); + mockNoExistingConfig(); await wizard.init!.run(ctx); From b3cd0698c67b807406fa8ef07e7ef1cd31ca4bc6 Mon Sep 17 00:00:00 2001 From: John Jenkins Date: Fri, 10 Jul 2026 17:16:00 +0100 Subject: [PATCH 3/3] chore: normalise test paths --- tests/wizard.test.ts | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tests/wizard.test.ts b/tests/wizard.test.ts index 07492a0..5a4956a 100644 --- a/tests/wizard.test.ts +++ b/tests/wizard.test.ts @@ -1,3 +1,4 @@ +import { join } from "node:path"; import { beforeEach, describe, expect, test, vi } from "vitest"; vi.mock("node:fs/promises", () => ({ @@ -12,6 +13,10 @@ import configs from "../src/configs"; import { wizard } from "../src/wizard"; const CANCEL = Symbol("cancel"); +const ROOT = "/proj"; +const ESLINT_CONFIG_PATH = join(ROOT, "eslint.config.js"); +const OXLINT_CONFIG_PATH = join(ROOT, ".oxlintrc.json"); +const PKG_PATH = join(ROOT, "package.json"); function fakePrompts(overrides: { select?: unknown; confirm?: unknown } = {}) { return { @@ -28,7 +33,7 @@ function fakePrompts(overrides: { select?: unknown; confirm?: unknown } = {}) { function fakeContext(prompts: ReturnType) { return { - config: { rootDir: "/proj" }, + config: { rootDir: ROOT }, isNewProject: false, prompts, nypm: { addDependency: vi.fn() }, @@ -79,7 +84,7 @@ describe("eslint plugin wizard", () => { const confirm = vi.fn().mockResolvedValueOnce(false); const prompts = fakePrompts({ select, confirm }); const ctx = fakeContext(prompts); - mockExistingConfig("/proj/.oxlintrc.json"); + mockExistingConfig(OXLINT_CONFIG_PATH); await wizard.init!.run(ctx); @@ -100,15 +105,15 @@ describe("eslint plugin wizard", () => { const confirm = vi.fn().mockResolvedValueOnce(true); const prompts = fakePrompts({ select, confirm }); const ctx = fakeContext(prompts); - mockExistingConfig("/proj/eslint.config.js"); + mockExistingConfig(ESLINT_CONFIG_PATH); await wizard.init!.run(ctx); - expect(vi.mocked(rm)).toHaveBeenCalledWith("/proj/eslint.config.js"); - expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: "/proj", dev: true }); + expect(vi.mocked(rm)).toHaveBeenCalledWith(ESLINT_CONFIG_PATH); + expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: ROOT, dev: true }); const [configPath] = vi.mocked(writeFile).mock.calls[0]; - expect(configPath).toBe("/proj/.oxlintrc.json"); + expect(configPath).toBe(OXLINT_CONFIG_PATH); const [, pkgContent] = vi.mocked(writeFile).mock.calls[1]; expect(JSON.parse(pkgContent as string).scripts).toEqual({ @@ -125,17 +130,17 @@ describe("eslint plugin wizard", () => { await wizard.init!.run(ctx); - expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: "/proj", dev: true }); + expect(ctx.nypm.addDependency).toHaveBeenCalledWith(["oxlint"], { cwd: ROOT, dev: true }); const [configPath, configContent] = vi.mocked(writeFile).mock.calls[0]; - expect(configPath).toBe("/proj/.oxlintrc.json"); + expect(configPath).toBe(OXLINT_CONFIG_PATH); const written = JSON.parse(configContent as string); expect(written.jsPlugins).toEqual([{ name: "stencil", specifier: "@stencil/eslint-plugin" }]); expect(written.rules).toEqual(configs.oxlint); expect(Object.keys(written.rules).every((name) => name.startsWith("stencil/"))).toBe(true); const [pkgPath, pkgContent] = vi.mocked(writeFile).mock.calls[1]; - expect(pkgPath).toBe("/proj/package.json"); + expect(pkgPath).toBe(PKG_PATH); expect(JSON.parse(pkgContent as string).scripts).toEqual({ lint: "oxlint .", "lint:fix": "oxlint . --fix", @@ -157,11 +162,11 @@ describe("eslint plugin wizard", () => { "@typescript-eslint/eslint-plugin", "eslint-plugin-react", ], - { cwd: "/proj", dev: true }, + { cwd: ROOT, dev: true }, ); const [configPath, configContent] = vi.mocked(writeFile).mock.calls[0]; - expect(configPath).toBe("/proj/eslint.config.js"); + expect(configPath).toBe(ESLINT_CONFIG_PATH); expect(configContent).toContain("stencil.configs.flat.strict"); const [, pkgContent] = vi.mocked(writeFile).mock.calls[1];