diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
new file mode 100644
index 00000000000..3f501600878
--- /dev/null
+++ b/.github/workflows/check.yml
@@ -0,0 +1,25 @@
+name: Check
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - Makefile
+ - elm.json
+ - package.json
+ - pnpm-lock.yaml
+ - 'src/**'
+ workflow_dispatch: {}
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - run: pnpm install
+ - name: Setup Elm
+ uses: mpizenberg/elm-tooling-action@1.6
+ with:
+ cache-key: elm-home-${{ hashFiles('elm-tooling.json', 'elm.json') }}
+ - run: make --always-make check
diff --git a/Makefile b/Makefile
index d58ea77160f..c00c0dbd66e 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,10 @@ all: docs/index.html NikumaruFont.en.woff2 COPYING
src/Translations.elm: public/translations/en.json
pnpx elm-i18next-gen --source public/translations/en.json --target src/ --type both --overwrite
-docs/index.html: fonts elm.json src/Translations.elm src/*.elm src/*/*.elm src/*/*/*.elm
+src/Main.elm.d.ts: src/InteropDefinitions.elm
+ pnpx elm-ts-interop --output src/Main.elm.d.ts
+
+docs/index.html: fonts elm.json src/Translations.elm src/Main.elm.d.ts src/*.elm src/*/*.elm src/*/*/*.elm
pnpx vite build --base ''
fonts: public/NikumaruFont.en.woff2 public/NikumaruFont.ja.woff2
@@ -22,6 +25,15 @@ COPYING: scripts/collect_licenses.sh src/COPYING.in elm.json docs/index.html
cp src/COPYING.in COPYING
./scripts/collect_licenses.sh >> COPYING
+check: check-elm check-ts
+
+check-elm:
+ elm make --output=/dev/null src/Main.elm
+
+check-ts: src/Main.elm.d.ts
+ pnpx eslint src/index.ts
+ tsc --noEmit
+
clean:
rm -r docs || true
rm public/NikumaruFont.en.woff2 || true
diff --git a/elm.json b/elm.json
index f3c34db2310..1fa3640571a 100644
--- a/elm.json
+++ b/elm.json
@@ -7,6 +7,7 @@
"dependencies": {
"direct": {
"ChristophP/elm-i18next": "4.2.1",
+ "dillonkearns/elm-ts-json": "2.1.1",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
@@ -24,7 +25,8 @@
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
- "elm/virtual-dom": "1.0.3"
+ "elm/virtual-dom": "1.0.3",
+ "elm-community/dict-extra": "2.4.0"
}
},
"test-dependencies": {
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 00000000000..55341fe97a7
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,23 @@
+import globals from "globals";
+import pluginJs from "@eslint/js";
+import tseslint from "typescript-eslint";
+
+
+export default [
+ {
+ files: ["**/*.{js,mjs,cjs,ts}"],
+ rules: {
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
+ },
+ },
+ {
+ languageOptions: {
+ globals: globals.browser,
+ parserOptions: {
+ project: true,
+ }
+ }
+ },
+ pluginJs.configs.recommended,
+ ...tseslint.configs.recommended,
+];
diff --git a/index.html b/index.html
index 80f6159bd0a..e9697a6563a 100644
--- a/index.html
+++ b/index.html
@@ -20,7 +20,7 @@
-
+
diff --git a/package.json b/package.json
index 21f9dd977bd..8904c10bfaf 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,12 @@
},
"license": "GPL-3.0-only",
"devDependencies": {
+ "@eslint/js": "^9.7.0",
"elm-i18next-gen": "^1.1.0",
"elm-tooling": "^1.8.0",
+ "eslint": "9.x",
+ "globals": "^15.8.0",
+ "typescript-eslint": "^7.16.1",
"vite": "^5.3.3",
"vite-plugin-elm": "^3.0.1",
"vite-plugin-html": "^3.2.2"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7c31e40c6ba..ac528a7db57 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,12 +8,24 @@ importers:
.:
devDependencies:
+ '@eslint/js':
+ specifier: ^9.7.0
+ version: 9.7.0
elm-i18next-gen:
specifier: ^1.1.0
version: 1.1.0
elm-tooling:
specifier: ^1.8.0
version: 1.15.1
+ eslint:
+ specifier: 9.x
+ version: 9.7.0
+ globals:
+ specifier: ^15.8.0
+ version: 15.8.0
+ typescript-eslint:
+ specifier: ^7.16.1
+ version: 7.16.1(eslint@9.7.0)(typescript@5.5.3)
vite:
specifier: ^5.3.3
version: 5.3.3(terser@5.31.2)
@@ -164,6 +176,40 @@ packages:
cpu: [x64]
os: [win32]
+ '@eslint-community/eslint-utils@4.4.0':
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.11.0':
+ resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.17.0':
+ resolution: {integrity: sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.1.0':
+ resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.7.0':
+ resolution: {integrity: sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.4':
+ resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.3.0':
+ resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
+ engines: {node: '>=18.18'}
+
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -284,6 +330,69 @@ packages:
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+ '@typescript-eslint/eslint-plugin@7.16.1':
+ resolution: {integrity: sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^7.0.0
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/parser@7.16.1':
+ resolution: {integrity: sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/scope-manager@7.16.1':
+ resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+
+ '@typescript-eslint/type-utils@7.16.1':
+ resolution: {integrity: sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/types@7.16.1':
+ resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+
+ '@typescript-eslint/typescript-estree@7.16.1':
+ resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/utils@7.16.1':
+ resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+
+ '@typescript-eslint/visitor-keys@7.16.1':
+ resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
acorn-walk@8.3.3:
resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==}
engines: {node: '>=0.4.0'}
@@ -293,10 +402,24 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
async@3.2.5:
resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
@@ -323,6 +446,10 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
camel-case@4.1.2:
resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
@@ -369,6 +496,10 @@ packages:
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
engines: {node: '>=4.8'}
+ cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+
css-select@4.3.0:
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
@@ -376,6 +507,22 @@ packages:
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
engines: {node: '>= 6'}
+ debug@4.3.5:
+ resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
@@ -425,16 +572,70 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-scope@8.0.2:
+ resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.0.0:
+ resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.7.0:
+ resolution: {integrity: sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+
+ espree@10.1.0:
+ resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ 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==}
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
filelist@1.0.4:
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
@@ -447,6 +648,10 @@ packages:
engines: {node: '>=4.0.0'}
hasBin: true
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
find-up@7.0.0:
resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
engines: {node: '>=18'}
@@ -455,6 +660,13 @@ packages:
resolution: {integrity: sha512-ycwgqtoxujz1dm0kjkBFOPQMESxB9uKc/PlD951dQDIG+tBXRpYZC2UmJb0gDxopQ1ZX6oyRQN3goRczYu7Deg==}
engines: {node: '>=6.4.0'}
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@@ -475,13 +687,32 @@ packages:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@15.8.0:
+ resolution: {integrity: sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==}
+ engines: {node: '>=18'}
+
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -495,6 +726,18 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ ignore@5.3.1:
+ resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
@@ -514,6 +757,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -522,13 +769,40 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
locate-path@7.2.0:
resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -550,6 +824,10 @@ packages:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@@ -557,11 +835,17 @@ packages:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
+ ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
nice-try@1.0.5:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
@@ -581,10 +865,22 @@ packages:
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
p-limit@4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
p-locate@6.0.0:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -592,9 +888,17 @@ packages:
param-case@3.0.4:
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
pascal-case@3.1.2:
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
path-exists@5.0.0:
resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -607,6 +911,14 @@ packages:
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
engines: {node: '>=4'}
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
pathe@0.2.0:
resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
@@ -621,6 +933,14 @@ packages:
resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
engines: {node: ^10 || ^12 || >=14}
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -628,6 +948,10 @@ packages:
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
engines: {node: '>= 0.10'}
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -649,14 +973,31 @@ packages:
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
hasBin: true
+ semver@7.6.2:
+ resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+ engines: {node: '>=10'}
+ hasBin: true
+
shebang-command@1.2.0:
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
engines: {node: '>=0.10.0'}
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
shebang-regex@1.0.0:
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
engines: {node: '>=0.10.0'}
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
@@ -668,6 +1009,14 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -681,13 +1030,41 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ ts-api-utils@1.3.0:
+ resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ typescript: '>=4.2.0'
+
tslib@2.6.3:
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ typescript-eslint@7.16.1:
+ resolution: {integrity: sha512-889oE5qELj65q/tGeOSvlreNKhimitFwZqQ0o7PcWC7/lgRkAMknznsCsV8J8mZGTP/Z+cIbX8accf2DE33hrA==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ typescript@5.5.3:
+ resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
unicorn-magic@0.1.0:
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
engines: {node: '>=18'}
@@ -696,6 +1073,9 @@ packages:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
vite-plugin-elm@3.0.1:
resolution: {integrity: sha512-xdIJ4SCrSfdcjsyvFOicn3xFq3wNXobX+OOnU4z24/7n/XGMJO3k70gUrH30tusdApOPQpIPM50wynoG3F35HQ==}
peerDependencies:
@@ -743,9 +1123,17 @@ packages:
engines: {node: '>= 8'}
hasBin: true
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
yocto-queue@1.1.1:
resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
engines: {node: '>=12.20'}
@@ -821,6 +1209,43 @@ snapshots:
'@esbuild/win32-x64@0.21.5':
optional: true
+ '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)':
+ dependencies:
+ eslint: 9.7.0
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.11.0': {}
+
+ '@eslint/config-array@0.17.0':
+ dependencies:
+ '@eslint/object-schema': 2.1.4
+ debug: 4.3.5
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/eslintrc@3.1.0':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.5
+ espree: 10.1.0
+ globals: 14.0.0
+ ignore: 5.3.1
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.7.0': {}
+
+ '@eslint/object-schema@2.1.4': {}
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.3.0': {}
+
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
@@ -910,16 +1335,114 @@ snapshots:
'@types/estree@1.0.5': {}
+ '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.11.0
+ '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ '@typescript-eslint/scope-manager': 7.16.1
+ '@typescript-eslint/type-utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ '@typescript-eslint/visitor-keys': 7.16.1
+ eslint: 9.7.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ natural-compare: 1.4.0
+ ts-api-utils: 1.3.0(typescript@5.5.3)
+ optionalDependencies:
+ typescript: 5.5.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 7.16.1
+ '@typescript-eslint/types': 7.16.1
+ '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3)
+ '@typescript-eslint/visitor-keys': 7.16.1
+ debug: 4.3.5
+ eslint: 9.7.0
+ optionalDependencies:
+ typescript: 5.5.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@7.16.1':
+ dependencies:
+ '@typescript-eslint/types': 7.16.1
+ '@typescript-eslint/visitor-keys': 7.16.1
+
+ '@typescript-eslint/type-utils@7.16.1(eslint@9.7.0)(typescript@5.5.3)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3)
+ '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ debug: 4.3.5
+ eslint: 9.7.0
+ ts-api-utils: 1.3.0(typescript@5.5.3)
+ optionalDependencies:
+ typescript: 5.5.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@7.16.1': {}
+
+ '@typescript-eslint/typescript-estree@7.16.1(typescript@5.5.3)':
+ dependencies:
+ '@typescript-eslint/types': 7.16.1
+ '@typescript-eslint/visitor-keys': 7.16.1
+ debug: 4.3.5
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.6.2
+ ts-api-utils: 1.3.0(typescript@5.5.3)
+ optionalDependencies:
+ typescript: 5.5.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@7.16.1(eslint@9.7.0)(typescript@5.5.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0)
+ '@typescript-eslint/scope-manager': 7.16.1
+ '@typescript-eslint/types': 7.16.1
+ '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3)
+ eslint: 9.7.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@typescript-eslint/visitor-keys@7.16.1':
+ dependencies:
+ '@typescript-eslint/types': 7.16.1
+ eslint-visitor-keys: 3.4.3
+
+ acorn-jsx@5.3.2(acorn@8.12.1):
+ dependencies:
+ acorn: 8.12.1
+
acorn-walk@8.3.3:
dependencies:
acorn: 8.12.1
acorn@8.12.1: {}
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-regex@5.0.1: {}
+
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
+ argparse@2.0.1: {}
+
+ array-union@2.1.0: {}
+
async@3.2.5: {}
at-least-node@1.0.0: {}
@@ -943,6 +1466,8 @@ snapshots:
buffer-from@1.1.2: {}
+ callsites@3.1.0: {}
+
camel-case@4.1.2:
dependencies:
pascal-case: 3.1.2
@@ -985,6 +1510,12 @@ snapshots:
shebang-command: 1.2.0
which: 1.3.1
+ cross-spawn@7.0.3:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
css-select@4.3.0:
dependencies:
boolbase: 1.0.0
@@ -995,6 +1526,16 @@ snapshots:
css-what@6.1.0: {}
+ debug@4.3.5:
+ dependencies:
+ ms: 2.1.2
+
+ deep-is@0.1.4: {}
+
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
dom-serializer@1.4.1:
dependencies:
domelementtype: 2.3.0
@@ -1065,8 +1606,78 @@ snapshots:
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
+ escape-string-regexp@4.0.0: {}
+
+ eslint-scope@8.0.2:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.0.0: {}
+
+ eslint@9.7.0:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0)
+ '@eslint-community/regexpp': 4.11.0
+ '@eslint/config-array': 0.17.0
+ '@eslint/eslintrc': 3.1.0
+ '@eslint/js': 9.7.0
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.3.0
+ '@nodelib/fs.walk': 1.2.8
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.5
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.0.2
+ eslint-visitor-keys: 4.0.0
+ espree: 10.1.0
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.1
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.1.0:
+ dependencies:
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
+ eslint-visitor-keys: 4.0.0
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
estree-walker@2.0.2: {}
+ esutils@2.0.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -1075,10 +1686,18 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.7
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
fastq@1.17.1:
dependencies:
reusify: 1.0.4
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
filelist@1.0.4:
dependencies:
minimatch: 5.1.6
@@ -1092,6 +1711,11 @@ snapshots:
firstline: 1.3.1
lodash: 4.17.21
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
find-up@7.0.0:
dependencies:
locate-path: 7.2.0
@@ -1100,6 +1724,13 @@ snapshots:
firstline@1.3.1: {}
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+
+ flatted@3.3.1: {}
+
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
@@ -1122,6 +1753,10 @@ snapshots:
dependencies:
is-glob: 4.0.3
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -1131,8 +1766,23 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
+ globals@14.0.0: {}
+
+ globals@15.8.0: {}
+
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 3.0.0
+
graceful-fs@4.2.11: {}
+ graphemer@1.4.0: {}
+
has-flag@4.0.0: {}
he@1.2.0: {}
@@ -1147,6 +1797,15 @@ snapshots:
relateurl: 0.2.7
terser: 5.31.2
+ ignore@5.3.1: {}
+
+ import-fresh@3.3.0:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
inflight@1.0.6:
dependencies:
once: 1.4.0
@@ -1162,6 +1821,8 @@ snapshots:
is-number@7.0.0: {}
+ is-path-inside@3.0.3: {}
+
isexe@2.0.0: {}
jake@10.9.1:
@@ -1171,16 +1832,41 @@ snapshots:
filelist: 1.0.4
minimatch: 3.1.2
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
jsonfile@6.1.0:
dependencies:
universalify: 2.0.1
optionalDependencies:
graceful-fs: 4.2.11
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
locate-path@7.2.0:
dependencies:
p-locate: 6.0.0
+ lodash.merge@4.6.2: {}
+
lodash@4.17.21: {}
lower-case@2.0.2:
@@ -1202,14 +1888,22 @@ snapshots:
dependencies:
brace-expansion: 2.0.1
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimist@1.2.8: {}
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
+ ms@2.1.2: {}
+
nanoid@3.3.7: {}
+ natural-compare@1.4.0: {}
+
nice-try@1.0.5: {}
no-case@3.0.4:
@@ -1237,10 +1931,27 @@ snapshots:
dependencies:
wrappy: 1.0.2
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
p-limit@4.0.0:
dependencies:
yocto-queue: 1.1.1
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
p-locate@6.0.0:
dependencies:
p-limit: 4.0.0
@@ -1250,17 +1961,27 @@ snapshots:
dot-case: 3.0.4
tslib: 2.6.3
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
pascal-case@3.1.2:
dependencies:
no-case: 3.0.4
tslib: 2.6.3
+ path-exists@4.0.0: {}
+
path-exists@5.0.0: {}
path-is-absolute@1.0.1: {}
path-key@2.0.1: {}
+ path-key@3.1.1: {}
+
+ path-type@4.0.0: {}
+
pathe@0.2.0: {}
picocolors@1.0.1: {}
@@ -1273,10 +1994,16 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
+ prelude-ls@1.2.1: {}
+
+ punycode@2.3.1: {}
+
queue-microtask@1.2.3: {}
relateurl@0.2.7: {}
+ resolve-from@4.0.0: {}
+
reusify@1.0.4: {}
rimraf@2.6.3:
@@ -1311,12 +2038,22 @@ snapshots:
semver@5.7.2: {}
+ semver@7.6.2: {}
+
shebang-command@1.2.0:
dependencies:
shebang-regex: 1.0.0
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
shebang-regex@1.0.0: {}
+ shebang-regex@3.0.0: {}
+
+ slash@3.0.0: {}
+
source-map-js@1.2.0: {}
source-map-support@0.5.21:
@@ -1326,6 +2063,12 @@ snapshots:
source-map@0.6.1: {}
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-json-comments@3.1.1: {}
+
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -1342,16 +2085,43 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
+ text-table@0.2.0: {}
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
+ ts-api-utils@1.3.0(typescript@5.5.3):
+ dependencies:
+ typescript: 5.5.3
+
tslib@2.6.3: {}
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ typescript-eslint@7.16.1(eslint@9.7.0)(typescript@5.5.3):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 7.16.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)
+ '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3)
+ eslint: 9.7.0
+ optionalDependencies:
+ typescript: 5.5.3
+ transitivePeerDependencies:
+ - supports-color
+
+ typescript@5.5.3: {}
+
unicorn-magic@0.1.0: {}
universalify@2.0.1: {}
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
vite-plugin-elm@3.0.1(vite@5.3.3(terser@5.31.2)):
dependencies:
acorn: 8.12.1
@@ -1394,6 +2164,10 @@ snapshots:
dependencies:
isexe: 2.0.0
+ word-wrap@1.2.5: {}
+
wrappy@1.0.2: {}
+ yocto-queue@0.1.0: {}
+
yocto-queue@1.1.1: {}
diff --git a/src/Feed.elm b/src/Feed.elm
index 6f9cbce7e3a..ce3552a3bc5 100644
--- a/src/Feed.elm
+++ b/src/Feed.elm
@@ -1,4 +1,4 @@
-module Feed exposing (Feed, Meta, Preset, decoder)
+module Feed exposing (Feed, Meta, decoder)
import EventCore as Event exposing (Event)
import Json.Decode as D
@@ -18,14 +18,6 @@ type alias Meta =
}
-type alias Preset =
- { id : String
- , title : String
- , lang : String
- , icon : String
- }
-
-
decoder : D.Decoder Feed
decoder =
D.map3 Feed
diff --git a/src/Filter.elm b/src/Filter.elm
index d2f5385229f..fef79c88c87 100644
--- a/src/Filter.elm
+++ b/src/Filter.elm
@@ -10,6 +10,7 @@ module Filter exposing
)
import Feed
+import InteropDefinitions exposing (PresetFeedMeta)
import List.Extra as List
import Url.Builder
@@ -17,7 +18,7 @@ import Url.Builder
type alias Feed =
{ checked : Bool
, alternate : String
- , preset : Feed.Preset
+ , preset : PresetFeedMeta
}
diff --git a/src/InteropDefinitions.elm b/src/InteropDefinitions.elm
new file mode 100644
index 00000000000..2f09196ff31
--- /dev/null
+++ b/src/InteropDefinitions.elm
@@ -0,0 +1,139 @@
+module InteropDefinitions exposing (Features, Flags, FromElm(..), PresetFeedMeta, ShareData, ToElm(..), interop)
+
+import Json.Decode
+import TsJson.Decode as D exposing (Decoder)
+import TsJson.Encode as E exposing (Encoder)
+
+
+interop :
+ { toElm : Decoder ToElm
+ , fromElm : Encoder FromElm
+ , flags : Decoder Flags
+ }
+interop =
+ { toElm = toElm
+ , fromElm = fromElm
+ , flags = flagsDecoder
+ }
+
+
+type FromElm
+ = Close String
+ | Copy String
+ | PreventScrollFocus String
+ | RemoveScrollEventListener
+ | SetLang String
+ | Share ShareData
+ | ShowModal String
+ | SlideViewportInto String
+
+
+type alias ShareData =
+ { title : String
+ , url : Maybe String
+ }
+
+
+type ToElm
+ = OnScrollToBottom
+
+
+type alias Flags =
+ { features : Features
+ , languages : List String
+ , feeds : List PresetFeedMeta
+ , observances : Json.Decode.Value
+ }
+
+
+type alias Features =
+ { copy : Bool
+ , share : Bool
+ }
+
+
+type alias PresetFeedMeta =
+ { id : String
+ , title : String
+ , lang : String
+ , icon : String
+ }
+
+
+fromElm : Encoder FromElm
+fromElm =
+ E.union
+ (\vClose vCopy vPreventScrollFocus vRemoveScrollEventListener vSetLang vShare vShowModal vSlideViewportInto value ->
+ case value of
+ Close id ->
+ vClose id
+
+ Copy text ->
+ vCopy text
+
+ PreventScrollFocus id ->
+ vPreventScrollFocus id
+
+ RemoveScrollEventListener ->
+ vRemoveScrollEventListener
+
+ SetLang lang ->
+ vSetLang lang
+
+ Share data ->
+ vShare data
+
+ ShowModal id ->
+ vShowModal id
+
+ SlideViewportInto id ->
+ vSlideViewportInto id
+ )
+ |> E.variantTagged "close" E.string
+ |> E.variantTagged "copy" E.string
+ |> E.variantTagged "preventScrollFocus" E.string
+ |> E.variant0 "removeScrollEventListener"
+ |> E.variantTagged "setLang" E.string
+ |> E.variantTagged "share"
+ (E.object
+ [ E.required "title" .title E.string
+ , E.optional "url" .url E.string
+ ]
+ )
+ |> E.variantTagged "showModal" E.string
+ |> E.variantTagged "slideViewportInto" E.string
+ |> E.buildUnion
+
+
+toElm : Decoder ToElm
+toElm =
+ D.discriminatedUnion "tag"
+ [ ( "OnScrollToBottom"
+ , D.succeed OnScrollToBottom
+ )
+ ]
+
+
+flagsDecoder : Decoder Flags
+flagsDecoder =
+ D.map4 Flags
+ (D.field "features" <| featuresDecoder)
+ (D.field "languages" <| D.list <| D.string)
+ (D.field "feeds" <| D.list <| presetFeedMetaDecoder)
+ (D.field "observances" D.value)
+
+
+featuresDecoder : Decoder Features
+featuresDecoder =
+ D.map2 Features
+ (D.field "copy" D.bool)
+ (D.field "share" D.bool)
+
+
+presetFeedMetaDecoder : Decoder PresetFeedMeta
+presetFeedMetaDecoder =
+ D.map4 PresetFeedMeta
+ (D.field "id" D.string)
+ (D.field "title" D.string)
+ (D.field "lang" D.string)
+ (D.field "icon" D.string)
diff --git a/src/InteropPorts.elm b/src/InteropPorts.elm
new file mode 100644
index 00000000000..eafefa7294c
--- /dev/null
+++ b/src/InteropPorts.elm
@@ -0,0 +1,49 @@
+port module InteropPorts exposing (fromElm, toElm, decodeFlags)
+
+{-| This file was generated by elm-ts-interop init. You can manually edit this file,
+just avoid exposing the low-level ports to ensure that only the FromElm and ToElm types
+can be sent/received by your ports.
+
+@docs fromElm, toElm, decodeFlags
+
+-}
+
+import InteropDefinitions
+import Json.Decode
+import Json.Encode
+import TsJson.Decode as TsDecode
+import TsJson.Encode as TsEncode
+
+
+{-| -}
+fromElm : InteropDefinitions.FromElm -> Cmd msg
+fromElm value =
+ value
+ |> (InteropDefinitions.interop.fromElm |> TsEncode.encoder)
+ |> interopFromElm
+
+
+{-| -}
+toElm : Sub (Result Json.Decode.Error InteropDefinitions.ToElm)
+toElm =
+ (InteropDefinitions.interop.toElm |> TsDecode.decoder)
+ |> Json.Decode.decodeValue
+ |> interopToElm
+
+
+{-| -}
+decodeFlags : Json.Decode.Value -> Result Json.Decode.Error InteropDefinitions.Flags
+decodeFlags flags =
+ Json.Decode.decodeValue
+ (InteropDefinitions.interop.flags |> TsDecode.decoder)
+ flags
+
+
+
+-- internals - do not expose
+
+
+port interopFromElm : Json.Encode.Value -> Cmd msg
+
+
+port interopToElm : (Json.Decode.Value -> msg) -> Sub msg
diff --git a/src/Main.elm b/src/Main.elm
index f819e9b8806..b1afec2075f 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,4 +1,4 @@
-port module Main exposing (main)
+module Main exposing (main)
import Attributes exposing (..)
import Browser exposing (Document)
@@ -19,7 +19,10 @@ import Html.Lazy exposing (..)
import Http
import I18Next exposing (Translations, translationsDecoder)
import Icon
+import InteropDefinitions as ID exposing (Features, Flags, ShareData)
+import InteropPorts as IP exposing (decodeFlags)
import Json.Decode as D
+import Json.Encode as E
import KeyboardEvent
import List.Extra as List
import Markdown
@@ -46,7 +49,7 @@ import Util.List as List
import Util.String as String
-main : Program Flags Model Msg
+main : Program D.Value Model Msg
main =
Browser.application
{ init = init
@@ -59,43 +62,6 @@ main =
--- PORTS
-
-
-port setLang : String -> Cmd msg
-
-
-port preventScrollFocus : String -> Cmd msg
-
-
-port slideViewportInto : String -> Cmd msg
-
-
-port showModal : String -> Cmd msg
-
-
-port close : String -> Cmd msg
-
-
-port copy : String -> Cmd msg
-
-
-port share : ShareData -> Cmd msg
-
-
-port onScrollToBottom : (D.Value -> msg) -> Sub msg
-
-
-port removeScrollEventListener : () -> Cmd msg
-
-
-type alias ShareData =
- { title : String
- , url : Maybe String
- }
-
-
-
-- MODEL
@@ -180,17 +146,17 @@ type Error
| Unexpected String
-type alias Flags =
- { features : Features
- , languages : List String
- , feeds : List Feed.Preset
- , observances : D.Value
- }
+init : D.Value -> Url -> Nav.Key -> ( Model, Cmd Msg )
+init flagsJson url key =
+ let
+ flags =
+ case decodeFlags flagsJson of
+ Err _ ->
+ Flags (Features False False) [] [] (E.list E.object [])
+ Ok f ->
+ f
-init : Flags -> Url -> Nav.Key -> ( Model, Cmd Msg )
-init flags url key =
- let
query =
Query.parseUrl url
@@ -457,7 +423,9 @@ update msg model =
env =
model.env
in
- ( { model | env = { env | translations = translations } }, setLang lang )
+ ( { model | env = { env | translations = translations } }
+ , ID.SetLang lang |> IP.fromElm
+ )
Err err ->
model |> update (ReportError (TranslationsHttpError lang err))
@@ -544,8 +512,8 @@ update msg model =
, Cmd.batch
[ -- Set `preventScroll` to avoid halting the sliding
-- animation.
- preventScrollFocus nowSectionId
- , slideViewportInto nowSectionId
+ ID.PreventScrollFocus nowSectionId |> IP.fromElm
+ , ID.SlideViewportInto nowSectionId |> IP.fromElm
]
)
@@ -637,7 +605,7 @@ update msg model =
( About _, None ) ->
Cmd.batch
- [ close aboutDialogId
+ [ ID.Close aboutDialogId |> IP.fromElm
, Dom.focus aboutButtonId |> Task.attempt handleDomResult
]
@@ -651,23 +619,23 @@ update msg model =
Cmd.none
About _ ->
- close aboutDialogId
+ ID.Close aboutDialogId |> IP.fromElm
Help ->
- close helpDialogId
+ ID.Close helpDialogId |> IP.fromElm
, case mode of
None ->
Cmd.none
About _ ->
Cmd.batch
- [ showModal aboutDialogId
+ [ ID.ShowModal aboutDialogId |> IP.fromElm
, Dom.focus aboutCloseButtonId |> Task.attempt handleDomResult
]
Help ->
Cmd.batch
- [ showModal helpDialogId
+ [ ID.ShowModal helpDialogId |> IP.fromElm
, Dom.focus helpCloseButtonId |> Task.attempt handleDomResult
]
]
@@ -788,7 +756,7 @@ update msg model =
[]
Nothing ->
- [ removeScrollEventListener () ]
+ [ ID.RemoveScrollEventListener |> IP.fromElm ]
cmds2 =
if
@@ -821,7 +789,7 @@ update msg model =
-- is large enough to contain current time. If KemoV becomes big enough to fill up
-- the first page with upcoming streams in the future, then we should revisit this!
( { model2 | initialized = True }
- , Cmd.batch [ cmd, slideViewportInto nowSectionId ]
+ , Cmd.batch [ cmd, ID.SlideViewportInto nowSectionId |> IP.fromElm ]
)
RetryGetFeed url ->
@@ -842,10 +810,10 @@ update msg model =
}
Copy text ->
- ( model, copy text )
+ ( model, ID.Copy text |> IP.fromElm )
Share title url ->
- ( model, share <| ShareData title url )
+ ( model, ShareData title url |> ID.Share |> IP.fromElm )
NoOp ->
( model, Cmd.none )
@@ -936,7 +904,18 @@ subscriptions model =
subs2 =
case model.pendingFeed of
OneMore url ->
- onScrollToBottom (always <| GetFeed url) :: subs
+ (IP.toElm
+ |> Sub.map
+ (\result ->
+ case result of
+ Ok ID.OnScrollToBottom ->
+ GetFeed url
+
+ Err e ->
+ ReportError <| Unexpected <| D.errorToString e
+ )
+ )
+ :: subs
_ ->
subs
diff --git a/src/Main.elm.d.ts b/src/Main.elm.d.ts
new file mode 100644
index 00000000000..7f38ba25622
--- /dev/null
+++ b/src/Main.elm.d.ts
@@ -0,0 +1,45 @@
+export type JsonObject = { [Key in string]?: JsonValue };
+export type JsonArray = JsonValue[];
+
+/**
+Matches any valid JSON value.
+Source: https://github.com/sindresorhus/type-fest/blob/master/source/basic.d.ts
+*/
+export type JsonValue =
+ | string
+ | number
+ | boolean
+ | null
+ | JsonObject
+ | JsonArray;
+
+export interface ElmApp {
+ ports: {
+ interopFromElm: PortFromElm;
+ interopToElm: PortToElm;
+ [key: string]: UnknownPort;
+ };
+}
+
+export type FromElm = { data : string; tag : "slideViewportInto" } | { data : string; tag : "showModal" } | { data : { title : string; url? : string }; tag : "share" } | { data : string; tag : "setLang" } | { tag : "removeScrollEventListener" } | { data : string; tag : "preventScrollFocus" } | { data : string; tag : "copy" } | { data : string; tag : "close" };
+
+export type ToElm = { tag : "OnScrollToBottom" };
+
+export type Flags = ({ features : { copy : boolean; share : boolean } } & { languages : string[] } & { feeds : ({ id : string } & { title : string } & { lang : string } & { icon : string })[] } & { observances : JsonValue });
+
+export namespace Main {
+ function init(options: { node?: HTMLElement | null; flags: Flags }): ElmApp;
+}
+
+export as namespace Elm;
+
+export { Elm };
+
+export type UnknownPort = PortFromElm | PortToElm | undefined;
+
+export type PortFromElm = {
+ subscribe(callback: (fromElm: Data) => void): void;
+ unsubscribe(callback: (fromElm: Data) => void): void;
+};
+
+export type PortToElm = { send(data: Data): void };
diff --git a/src/TranslationsExt.elm b/src/TranslationsExt.elm
index 0ce4de53f8e..de8c9f6e4e4 100644
--- a/src/TranslationsExt.elm
+++ b/src/TranslationsExt.elm
@@ -1,11 +1,11 @@
module TranslationsExt exposing (members)
-import Feed
import I18Next exposing (Translations)
+import InteropDefinitions exposing (PresetFeedMeta)
import Translations.Event.Description as TED
-members : Translations -> Feed.Preset -> List Feed.Preset -> String
+members : Translations -> PresetFeedMeta -> List PresetFeedMeta -> String
members translations author guests =
case guests of
[] ->
diff --git a/src/customElements.js b/src/customElements.ts
similarity index 84%
rename from src/customElements.js
rename to src/customElements.ts
index 66ba7e335c3..8d1e49ae49c 100644
--- a/src/customElements.js
+++ b/src/customElements.ts
@@ -23,23 +23,25 @@ customElements.define('intl-date', class extends HTMLElement {
return;
}
- const year = this.dataset.year;
- const month = this.dataset.month;
- const day = this.dataset.day;
- const date = new Date(year, month, day);
+ // The custom element is only created by `Elements.elm`, which always sets these properties.
+ const year = this.dataset.year!;
+ const month = this.dataset.month!;
+ const day = this.dataset.day!;
+ const date = new Date(+year, +month, +day);
const lang = this.getAttribute('lang');
- const opts = {
+ const opts: Intl.DateTimeFormatOptions = {
month: 'long',
day: 'numeric',
weekday: 'short',
};
- if (new Date().getYear() != date.getYear()) {
+ if (new Date().getFullYear() != date.getFullYear()) {
opts.year = 'numeric';
}
const fmt = new Intl.DateTimeFormat(lang ?? 'default', opts);
- const time = this.firstChild;
+ // The only child of the custom element is `