diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..0e8f13b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint", "unused-imports"], + "ignorePatterns": ["dist/", "tailwind.config.js"], + "rules": { + "@typescript-eslint/no-explicit-any": ["off"], + "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ] + } +} diff --git a/index.html b/index.html index 71558be..08dd3eb 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,9 @@ <!DOCTYPE html> -<html lang="en" class="sidebar-visible no-js light"> +<html + lang="en" + class="sidebar-visible js navy" + style="background-color: #161923" +> <head> <meta charset="UTF-8" /> <title>Subxt Explorer</title> diff --git a/package-lock.json b/package-lock.json index 90cc52c..8426288 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,11 @@ "vite-plugin-wasm": "^3.2.2" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.9.0", + "@typescript-eslint/parser": "^6.9.0", "autoprefixer": "^10.4.15", + "eslint": "^8.52.0", + "eslint-plugin-unused-imports": "^3.0.0", "postcss": "^8.4.29", "solid-devtools": "^0.27.3", "tailwindcss": "^3.3.3", @@ -36,6 +40,15 @@ "name": "subxt_example_codegen", "version": "0.1.0" }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -860,6 +873,110 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1443,6 +1560,358 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", + "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", + "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", + "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", + "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -1480,6 +1949,21 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/autoprefixer": { "version": "10.4.15", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz", @@ -1626,6 +2110,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1744,8 +2237,22 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, - "node_modules/cssesc": { - "version": "3.0.0", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, @@ -1778,18 +2285,48 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.513", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", @@ -1850,6 +2387,281 @@ "node": ">=0.8.0" } }, + "node_modules/eslint": { + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", + "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0", + "eslint": "^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -1878,6 +2690,18 @@ "node": ">= 6" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -1887,6 +2711,18 @@ "reusify": "^1.0.4" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1899,6 +2735,42 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, "node_modules/fraction.js": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", @@ -1932,10 +2804,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -1987,18 +2862,32 @@ "node": ">=4" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.4.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -2008,6 +2897,18 @@ "node": ">=4" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/highlight.js": { "version": "11.8.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz", @@ -2022,6 +2923,40 @@ "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "dev": true }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2051,12 +2986,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2092,6 +3027,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-what": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz", @@ -2104,6 +3048,12 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "node_modules/jiti": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", @@ -2119,6 +3069,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2131,6 +3093,24 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -2143,6 +3123,28 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -2158,6 +3160,27 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2261,6 +3284,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", @@ -2312,6 +3341,74 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2321,12 +3418,30 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2492,6 +3607,24 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2550,6 +3683,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -2560,6 +3702,21 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "3.29.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.1.tgz", @@ -2615,6 +3772,36 @@ "node": ">=10" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/solid-devtools": { "version": "0.27.7", "resolved": "https://registry.npmjs.org/solid-devtools/-/solid-devtools-0.27.7.tgz", @@ -2672,6 +3859,30 @@ "node": ">=0.10.0" } }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/subxt_example_codegen": { "resolved": "codegen/pkg", "link": true @@ -2759,6 +3970,12 @@ "node": ">=14.0.0" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2801,12 +4018,48 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", @@ -2850,6 +4103,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2978,6 +4240,21 @@ } } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2998,6 +4275,18 @@ "engines": { "node": ">= 14" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 7b6ddf6..1ff57bc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,11 @@ }, "license": "MIT", "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.9.0", + "@typescript-eslint/parser": "^6.9.0", "autoprefixer": "^10.4.15", + "eslint": "^8.52.0", + "eslint-plugin-unused-imports": "^3.0.0", "postcss": "^8.4.29", "solid-devtools": "^0.27.3", "tailwindcss": "^3.3.3", diff --git a/src/App.tsx b/src/App.tsx index 45aa1f9..88cb5d9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,29 +1,13 @@ -import { - Switch, - type Component, - Match, - createResource, - Suspense, - Show, - createEffect, - useTransition, - useContext, -} from "solid-js"; +import { type Component, createEffect } from "solid-js"; import { MdBookWrapper } from "./components/MdBookWrapper"; import { HomePage, HomePageState } from "./pages/Home"; import { - Navigate, Route, Router, Routes, hashIntegration, - memoryIntegration, - pathIntegration, - useBeforeLeave, useLocation, useNavigate, - useRouteData, - useSearchParams, } from "@solidjs/router"; import { RuntimeApisPage } from "./pages/RuntimeApis"; import { CustomValuesPage } from "./pages/CustomValues"; @@ -33,50 +17,57 @@ import { StoragePage } from "./pages/Storage"; import { ConstantsPage } from "./pages/Constants"; import { RuntimeApiMethodsPage } from "./pages/RuntimeApiMethods"; import { EventsPage } from "./pages/Events"; -import { Sidebar } from "./components/Sidebar"; -import { ClientKind, initAppState } from "./state/client_wrapper"; -import { wait } from "./utils"; -import { DebugComponent } from "./components/DebugComponent"; -import { AppConfig, paramsToString } from "./state/app_config"; +import { + AppConfig, + clientKindFromParams, + clientKindsEqual, +} from "./state/app_config"; import { RedirectToHome } from "./components/RedirectToHome"; +import { findSideBarItemByPath, setActiveItem } from "./state/sidebar"; const App: Component = () => { - // this happens only once on page load: + return ( + <Router source={hashIntegration()}> + <AppInRouter /> + </Router> + ); +}; + +export default App; + +const AppInRouter: Component = () => { + // On page load, create a new AppConfig from the URL params. + // Note: This code is only called ONCE at the start of the application lifecycle. const location = useLocation(); - let config = AppConfig.fromParams(location.query); - HomePageState.instance.appConfig = config; + + AppConfig.instance.updateWithParams(location.query); // listen to all client side solid router route change events: // If the url params indicate a different app config, reload the web app with that config. createEffect(() => { - let pathname = location.pathname; - let params = location.query; + const pathname = location.pathname; - let configFromParams = AppConfig.fromParams(params); - console.log( - "CreateEffect: ", - pathname, - Object.entries(params), - configFromParams - ); - if (!configFromParams.equals(HomePageState.instance.appConfig)) { - console.log( - "CreateEffect: config changed to", - configFromParams, - location.pathname - ); - HomePageState.instance.appConfig = configFromParams; + if (pathname == "/" && HomePageState.instance.generating) { + // we do not want anything here to trigger if the home page is currently generating some client connection. + return; + } + + const newItem = findSideBarItemByPath(pathname); + if (newItem) { + setActiveItem(newItem); + } + + const paramsClientKind = clientKindFromParams(location.query); + if (!clientKindsEqual(paramsClientKind, AppConfig.instance.clientKind)) { + AppConfig.instance.updateWith(paramsClientKind); if (pathname === "/" || pathname === "") { - console.log("HOME"); // if already on homepage adjust its UI to the new config: - HomePageState.instance.onHomePageLoad(); + HomePageState.instance.adjustUiToAppConfigInstance(); } else { - console.log("NOT HOME:", pathname); // otherwise navigate to homepage and set redirect hook: - let redirectUrl = `/?${configFromParams.toParamsString()}`; - console.log("WAS NOT AT HOME: redirecting to", redirectUrl); + const redirectUrl = `/?${AppConfig.instance.toParamsString()}`; HomePageState.instance.setRedirectPath(pathname); - let navigate = useNavigate(); + const navigate = useNavigate(); navigate(redirectUrl, { replace: true }); } } @@ -85,37 +76,28 @@ const App: Component = () => { return ( <MdBookWrapper> <Routes> - <Route path="/debug" component={DebugComponent}></Route> - <Route path="/" component={HomePage}></Route> - <Route path="/runtime_apis" component={RuntimeApisPage}></Route> + <Route path="/" component={HomePage} /> + <Route path="/runtime_apis" component={RuntimeApisPage} /> <Route path="/runtime_apis/:runtime_api" component={RuntimeApiMethodsPage} - ></Route> - <Route path="/custom_values" component={CustomValuesPage}></Route> - <Route path="/pallets/:pallet" component={PalletPage}></Route> - <Route path="/pallets/:pallet/calls" component={CallsPage}></Route> - <Route path="/pallets/:pallet/events" component={EventsPage}></Route> + /> + <Route path="/custom_values" component={CustomValuesPage} /> + <Route path="/pallets/:pallet" component={PalletPage} /> + <Route path="/pallets/:pallet/calls" component={CallsPage} /> + <Route path="/pallets/:pallet/events" component={EventsPage} /> <Route path="/pallets/:pallet/storage_entries" component={StoragePage} - ></Route> - <Route - path="/pallets/:pallet/constants" - component={ConstantsPage} - ></Route> - + /> + <Route path="/pallets/:pallet/constants" component={ConstantsPage} /> <Route path={"*"} component={() => { return <RedirectToHome></RedirectToHome>; }} - > - {/* */} - </Route> + /> </Routes> </MdBookWrapper> ); }; - -export default App; diff --git a/src/components/AnchoredH2.tsx b/src/components/AnchoredH2.tsx index 3faa8a5..793887a 100644 --- a/src/components/AnchoredH2.tsx +++ b/src/components/AnchoredH2.tsx @@ -3,14 +3,17 @@ import { JSX } from "solid-js"; export function AnchoredH2({ title, id, + children, }: { title: string; id?: string; + children?: JSX.Element; }): JSX.Element { return ( <h2 class="mt-12 relative"> <div class="heading-anchor" id={id ?? title}></div> {title} + {children} </h2> ); } diff --git a/src/components/Code.tsx b/src/components/Code.tsx index 28f6951..ca42bf7 100644 --- a/src/components/Code.tsx +++ b/src/components/Code.tsx @@ -8,7 +8,7 @@ hljs.registerLanguage("rust", rust); export const Code = ({ code }: { code: string }): JSX.Element => { const [showBoring, setShowBoring] = createSignal<boolean>(false); - let codeSegments = sliceCodeIntoBoringInterestingBoring(code); + const codeSegments = sliceCodeIntoBoringInterestingBoring(code); let highlightedWithBoring: string; let highlightedNoBoring: string; @@ -22,7 +22,7 @@ export const Code = ({ code }: { code: string }): JSX.Element => { highlightedNoBoring = highlightedWithBoring; } - let highlightedCode = () => + const highlightedCode = () => showBoring() ? highlightedWithBoring : highlightedNoBoring; return ( diff --git a/src/components/ConfigAwareLink.tsx b/src/components/ConfigAwareLink.tsx new file mode 100644 index 0000000..da39d74 --- /dev/null +++ b/src/components/ConfigAwareLink.tsx @@ -0,0 +1,31 @@ +import { AnchorProps, Link } from "@solidjs/router"; +import { JSX } from "solid-js"; +import { AppConfig } from "../state/app_config"; +import { findInSidebarItems, setActiveItem } from "../state/sidebar"; + +/** + * A wrapper around the solid-js Link/A component that does two things: + * 1. It uses AppConfig.instance to heep the query params in the href updated to the current config. + * 2. It sets the active item in the sidebar to the item that is being linked to. + */ +export const ConfigAwareLink = (props: AnchorProps): JSX.Element => { + const href = () => + props.href + "?" + AppConfig.instance.appConfigParamString(); + return ( + <Link + {...props} + activeClass="" + href={href()} + onClick={() => { + const splitPath = props.href.split("#")[0]; + const found = findInSidebarItems((e) => e.path == splitPath); + if (found) { + setActiveItem(found); + } + }} + style={{ "text-decoration": "none" }} + > + <span class="text-gray-300 hover:text-pink-500">{props.children}</span> + </Link> + ); +}; diff --git a/src/components/DebugComponent.tsx b/src/components/DebugComponent.tsx deleted file mode 100644 index 3204a4e..0000000 --- a/src/components/DebugComponent.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useRouteData, useSearchParams } from "@solidjs/router"; -import { JSX } from "solid-js"; - -export const DebugComponent = (): JSX.Element => { - const [searchParams, setSearchParams] = useSearchParams(); - - return ( - <> - <button - onClick={() => { - let searchParams = new URLSearchParams(window.location.search); - searchParams.set("foo", Math.random().toString()); - // setSearchParams({ hello: }); - }} - > - Press - </button> - </> - ); -}; diff --git a/src/components/Docs.tsx b/src/components/Docs.tsx index 03df4d6..4a0a5b2 100644 --- a/src/components/Docs.tsx +++ b/src/components/Docs.tsx @@ -2,7 +2,7 @@ import { marked } from "marked"; import { JSX } from "solid-js"; export const Docs = ({ mdDocs }: { mdDocs: string[] }): JSX.Element => { - let md = mdDocs + const md = mdDocs .filter((e) => e.length != 0) .map((e) => e.trim()) .join("\n") diff --git a/src/components/KeyValueTypesLayout.tsx b/src/components/KeyValueTypesLayout.tsx index 894b096..94b2bfe 100644 --- a/src/components/KeyValueTypesLayout.tsx +++ b/src/components/KeyValueTypesLayout.tsx @@ -1,6 +1,5 @@ import { Component, JSX, Show, createSignal } from "solid-js"; -import { highlight } from "./Code"; -import { NameAndType, TypeDescription } from "../state/client_wrapper"; +import { NameAndType, TypeDescription } from "../state/client"; export interface Props { keyTypes?: KeyTypesSection; valueType?: ValueTypeSection; @@ -25,14 +24,6 @@ interface ValueSection { } export const KeyValueTypesLayout: Component<Props> = (props: Props) => { - let [valueTypeMode, setValueTypeMode] = createSignal<"path" | "structure">( - "structure" - ); - - let [keyTypeMode, setKeyTypeMode] = createSignal<"path" | "structure">( - "structure" - ); - let keyTypes: { name?: string; type_description: TypeDescription; @@ -90,7 +81,9 @@ function TypeDisplay(props: { type_description: TypeDescription; }[]; }) { - let [typeMode, setTypeMode] = createSignal<"path" | "structure">("structure"); + const [typeMode, setTypeMode] = createSignal<"path" | "structure">( + "structure" + ); return ( <div> diff --git a/src/components/MdBookWrapper.tsx b/src/components/MdBookWrapper.tsx index 4f554bc..baf5558 100644 --- a/src/components/MdBookWrapper.tsx +++ b/src/components/MdBookWrapper.tsx @@ -3,7 +3,7 @@ import { Sidebar } from "./Sidebar"; import { NavWrapper } from "./NavWrapper"; import { NavWideWrapper } from "./NavWideWrapper"; import { MenuBar } from "./MenuBar"; -import { activeItem } from "../state/sidebar_state"; +import { activeItem } from "../state/sidebar"; interface Props { children?: JSX.Element; diff --git a/src/components/MenuBar.tsx b/src/components/MenuBar.tsx index 0d6c9ce..b9d720e 100644 --- a/src/components/MenuBar.tsx +++ b/src/components/MenuBar.tsx @@ -1,7 +1,7 @@ -import { Component, onMount } from "solid-js"; -import { setSidebarVisibility, toggleSidebar } from "../state/visual_state"; -interface Props {} -export const MenuBar: Component<Props> = (props: Props) => { +import { Component } from "solid-js"; +import { toggleSidebar } from "../state/sidebar"; + +export const MenuBar: Component = () => { return ( <> <div id="menu-bar-hover-placeholder"></div> diff --git a/src/components/NavWideWrapper.tsx b/src/components/NavWideWrapper.tsx index 7b1accb..c0f67e8 100644 --- a/src/components/NavWideWrapper.tsx +++ b/src/components/NavWideWrapper.tsx @@ -1,7 +1,6 @@ import { Component, Show } from "solid-js"; -import { SidebarItem, activeItem, setActiveItem } from "../state/sidebar_state"; -import { Link } from "@solidjs/router"; -import { HomePageState } from "../pages/Home"; +import { SidebarItem } from "../state/sidebar"; +import { ConfigAwareLink } from "./ConfigAwareLink"; interface Props { activeItem: SidebarItem; } @@ -9,39 +8,29 @@ export const NavWideWrapper: Component<Props> = (props: Props) => { return ( <nav class="nav-wide-wrapper" aria-label="Page navigation"> <Show when={props.activeItem.prev !== undefined}> - <Link + <ConfigAwareLink rel="prev" - href={`${ - props.activeItem.prev!.path - }?${HomePageState.instance.appConfigParamString()}`} + href={props.activeItem.prev!.path} class="nav-chapters previous" title={props.activeItem.prev!.title} - aria-label="Previous chapter" + aria-label="Previous Page" aria-keyshortcuts="Left" - onClick={() => { - setActiveItem(props.activeItem.prev!); - }} > <i class="fa fa-angle-left"></i> - </Link> + </ConfigAwareLink> </Show> <Show when={props.activeItem.next !== undefined}> - <Link + <ConfigAwareLink rel="next" - href={`${ - props.activeItem.next!.path - }?${HomePageState.instance.appConfigParamString()}`} + href={props.activeItem.next!.path} class="nav-chapters next" title={props.activeItem.next!.title} - aria-label="Next chapter" + aria-label="Next Page" aria-keyshortcuts="Right" - onClick={() => { - setActiveItem(props.activeItem.next!); - }} > <i class="fa fa-angle-right"></i> - </Link> + </ConfigAwareLink> </Show> </nav> ); diff --git a/src/components/NavWrapper.tsx b/src/components/NavWrapper.tsx index cbb0aca..79f0cf7 100644 --- a/src/components/NavWrapper.tsx +++ b/src/components/NavWrapper.tsx @@ -1,7 +1,6 @@ -import { Link } from "@solidjs/router"; import { Component, Show } from "solid-js"; -import { SidebarItem, activeItem, setActiveItem } from "../state/sidebar_state"; -import { HomePageState } from "../pages/Home"; +import { SidebarItem } from "../state/sidebar"; +import { ConfigAwareLink } from "./ConfigAwareLink"; interface Props { activeItem: SidebarItem; } @@ -9,39 +8,29 @@ export const NavWrapper: Component<Props> = (props: Props) => { return ( <nav class="nav-wrapper" aria-label="Page navigation"> <Show when={props.activeItem.prev !== undefined}> - <Link + <ConfigAwareLink rel="prev" - href={`${ - props.activeItem.prev!.path - }?${HomePageState.instance.appConfigParamString()}`} + href={props.activeItem.prev!.path} class="mobile-nav-chapters previous" title={props.activeItem.prev!.title} - aria-label="Previous chapter" + aria-label="Previous Page" aria-keyshortcuts="Left" - onClick={() => { - setActiveItem(props.activeItem.prev!); - }} > <i class="fa fa-angle-left"></i> - </Link> + </ConfigAwareLink> </Show> <Show when={props.activeItem.next !== undefined}> - <Link + <ConfigAwareLink rel="next" - href={`${ - props.activeItem.next!.path - }?${HomePageState.instance.appConfigParamString()}`} + href={props.activeItem.next!.path} class="mobile-nav-chapters next" title={props.activeItem.next!.title} - aria-label="Next chapter" + aria-label="Next Page" aria-keyshortcuts="Right" - onClick={() => { - setActiveItem(props.activeItem.next!); - }} > <i class="fa fa-angle-right"></i> - </Link> + </ConfigAwareLink> </Show> <div style="clear: both"></div> diff --git a/src/components/RedirectToHome.tsx b/src/components/RedirectToHome.tsx index 1765aa5..bdde362 100644 --- a/src/components/RedirectToHome.tsx +++ b/src/components/RedirectToHome.tsx @@ -1,12 +1,17 @@ import { Navigate, useLocation } from "@solidjs/router"; -import { AppConfig, paramsToString } from "../state/app_config"; +import { + clientKindFromParams, + clientKindToParams, + paramsToString, +} from "../state/app_config"; import { JSX } from "solid-js"; import { HomePageState } from "../pages/Home"; export function RedirectToHome(): JSX.Element { const location = useLocation(); - let config = AppConfig.fromParams(location.query); - let redirectUrl = `/?${config.toParamsString()}`; + const clientKind = clientKindFromParams(location.query); + const params = clientKindToParams(clientKind); + const redirectUrl = `/?${paramsToString(params)}`; HomePageState.instance.setRedirectPath(location.pathname); return <Navigate href={redirectUrl} />; } diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index ad52014..b1f62b3 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,31 +1,20 @@ -import { Component, For, JSX, createSignal } from "solid-js"; -import { ClientKind, clientWrapper } from "../state/client_wrapper"; -import { Link } from "@solidjs/router"; +import { Component, For, JSX } from "solid-js"; +import { ClientKind, client } from "../state/client"; import { HOME_ITEM, SidebarItem, activeItem, - newItem, - setActiveItem, sidebarItems, -} from "../state/sidebar_state"; -import { HomePageState } from "../pages/Home"; -interface Props {} +} from "../state/sidebar"; +import { ConfigAwareLink } from "./ConfigAwareLink"; -export const Sidebar: Component<Props> = (props: Props) => { +export const Sidebar: Component = () => { return ( <nav id="sidebar" class="sidebar" aria-label="Table of contents"> <div class="sidebar-scrollbox"> <ol class="chapter"> <li class="chapter-item expanded affix"> - <Link - href={`/?${HomePageState.instance.appConfigParamString()}`} - activeClass="" - onClick={() => { - setActiveItem(HOME_ITEM); - }} - class="p-0" - > + <ConfigAwareLink href={"/"} class="p-0"> <h1 class={`my-0 ${ activeItem().path == HOME_ITEM.path && "text-pink-500" @@ -33,15 +22,15 @@ export const Sidebar: Component<Props> = (props: Props) => { > Subxt Explorer </h1> - </Link> + </ConfigAwareLink> </li> - {clientWrapper() && ( + {client() && ( <li class="part-title leading-6 pt-6 pb-3"> - {metadataSourceSpan(clientWrapper()!.clientKindInCreation!)} + {metadataSourceSpan(client()!.clientKindInCreation!)} </li> )} - <For each={sidebarItems()}>{(item, i) => sideBarItem(item)}</For> + <For each={sidebarItems()}>{(item) => <SideBarItem {...item} />}</For> </ol> </div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> @@ -49,10 +38,12 @@ export const Sidebar: Component<Props> = (props: Props) => { ); }; -function sideBarItem(item: SidebarItem): JSX.Element { - // let params = useParams<{ path?: string }>(); +function SideBarItem(item: SidebarItem): JSX.Element { + if (item.kind.tag === "home") { + return; + } - let topLevel = + const topLevel = item.kind.tag === "runtime_apis" || item.kind.tag === "pallet" || item.kind.tag === "custom_values"; @@ -60,16 +51,7 @@ function sideBarItem(item: SidebarItem): JSX.Element { return ( <> <li class="chapter-item expanded "> - <Link - href={`${item.path}?${HomePageState.instance.appConfigParamString()}`} - activeClass="" - onClick={() => { - setActiveItem(item); - }} - // class={activeItem().path === item.path ? "active" : ""} - // class="text-gray-300 hover:text-pink-500" - style={{}} - > + <ConfigAwareLink href={item.path}> <span class={`${ activeItem().path === item.path @@ -87,12 +69,12 @@ function sideBarItem(item: SidebarItem): JSX.Element { </span> )} </span> - </Link> + </ConfigAwareLink> </li> {item.children.length != 0 && ( <li> <ol class="section"> - {item.children.map((subitem) => sideBarItem(subitem))} + {item.children.map((subitem) => SideBarItem(subitem))} </ol> </li> )} @@ -121,8 +103,8 @@ function metadataSourceSpan(ck: ClientKind): JSX.Element { /* - -The scrolling code above is adapted from this, which is from some md book js snippet +Todo: +In MdBook there is some code to scroll the sidebar to the correct item, we probably need something similar: <!-- Track and set sidebar scroll position --> <script> diff --git a/src/components/TryLinkTo.tsx b/src/components/TryLinkTo.tsx deleted file mode 100644 index fa5e5ae..0000000 --- a/src/components/TryLinkTo.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Link } from "@solidjs/router"; -import { JSX } from "solid-js"; -import { findInSidebarItems, setActiveItem } from "../state/sidebar_state"; - -// a Link component that tries to find the correct sidebar item and sets the active side bar item if the href matches. -export const TryToLink = (props: { - href: string; - children: JSX.Element; -}): JSX.Element => { - return ( - <Link - activeClass="" - href={props.href} - onClick={() => { - let splitPath = props.href.split("#")[0]; - let found = findInSidebarItems((e) => e.path == splitPath); - if (found) { - setActiveItem(found); - } - }} - style={{ "text-decoration": "none" }} - > - <span class="text-gray-300 hover:text-pink-500">{props.children}</span> - </Link> - ); -}; diff --git a/src/index.tsx b/src/index.tsx index 156a16a..ae1f1fa 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,9 +1,7 @@ import { render } from "solid-js/web"; import App from "./App"; -import { Router, hashIntegration } from "@solidjs/router"; -// body container is a special id used for styling in md-book const root = document.getElementById("body-container"); if (import.meta.env.DEV && !(root instanceof HTMLElement)) { @@ -12,11 +10,4 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) { ); } -render( - () => ( - <Router source={hashIntegration()}> - <App />{" "} - </Router> - ), - root! -); +render(() => <App />, root!); diff --git a/src/pages/Calls.tsx b/src/pages/Calls.tsx index 920cafd..83cab42 100644 --- a/src/pages/Calls.tsx +++ b/src/pages/Calls.tsx @@ -1,22 +1,15 @@ -import { Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - CallContent, - clientWrapper, -} from "../state/client_wrapper"; +import { useParams } from "@solidjs/router"; +import { CallContent, client } from "../state/client"; import { JSX } from "solid-js"; -import { marked } from "marked"; -import { Code } from "../components/Code"; import { Docs } from "../components/Docs"; import { CodeTabLayout } from "../components/CodeTabLayout"; import { KeyValueTypesLayout } from "../components/KeyValueTypesLayout"; import { AnchoredH2 } from "../components/AnchoredH2"; import { RedirectToHome } from "../components/RedirectToHome"; export const CallsPage = () => { - let props = () => { - let pallet = useParams<{ pallet: string }>().pallet; - let calls = clientWrapper()?.palletCalls(pallet); + const props = () => { + const pallet = useParams<{ pallet: string }>().pallet; + const calls = client()?.palletCalls(pallet); return { pallet, calls, @@ -36,10 +29,15 @@ export const CallsPage = () => { ); }; -function callContent(call: CallContent): JSX.Element { +function callContent(call: CallContent, index: number): JSX.Element { return ( <> - <AnchoredH2 title={call.name}></AnchoredH2> + <AnchoredH2 title={call.name}> + <span class="text-gray-500 text-xl float-right mt-5"> + {" "} + index = {index} + </span> + </AnchoredH2> <Docs mdDocs={call.docs}></Docs> <KeyValueTypesLayout keyTypes={ diff --git a/src/pages/Constants.tsx b/src/pages/Constants.tsx index 927a022..e4b52b0 100644 --- a/src/pages/Constants.tsx +++ b/src/pages/Constants.tsx @@ -1,23 +1,15 @@ -import { Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - CallContent, - ConstantContent, - clientWrapper, -} from "../state/client_wrapper"; +import { useParams } from "@solidjs/router"; +import { ConstantContent, client } from "../state/client"; import { JSX } from "solid-js"; -import { marked } from "marked"; -import { Code } from "../components/Code"; import { Docs } from "../components/Docs"; import { CodeTabLayout } from "../components/CodeTabLayout"; import { KeyValueTypesLayout } from "../components/KeyValueTypesLayout"; import { AnchoredH2 } from "../components/AnchoredH2"; import { RedirectToHome } from "../components/RedirectToHome"; export const ConstantsPage = () => { - let props = () => { - let pallet = useParams<{ pallet: string }>().pallet; - let constants = clientWrapper()?.palletConstants(pallet); + const props = () => { + const pallet = useParams<{ pallet: string }>().pallet; + const constants = client()?.palletConstants(pallet); return { pallet, constants, diff --git a/src/pages/CustomValues.tsx b/src/pages/CustomValues.tsx index ffe5046..997f225 100644 --- a/src/pages/CustomValues.tsx +++ b/src/pages/CustomValues.tsx @@ -1,4 +1,3 @@ -import { MdBookWrapper } from "../components/MdBookWrapper"; export const CustomValuesPage = () => { return ( <> diff --git a/src/pages/Events.tsx b/src/pages/Events.tsx index dc5894a..9bebb38 100644 --- a/src/pages/Events.tsx +++ b/src/pages/Events.tsx @@ -1,24 +1,15 @@ -import { Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - CallContent, - EventContent, - clientWrapper, -} from "../state/client_wrapper"; +import { useParams } from "@solidjs/router"; +import { EventContent, client } from "../state/client"; import { JSX } from "solid-js"; -import { marked } from "marked"; -import { Code } from "../components/Code"; import { Docs } from "../components/Docs"; -import { CodeTabLayout } from "../components/CodeTabLayout"; import { KeyValueTypesLayout } from "../components/KeyValueTypesLayout"; import { AnchoredH2 } from "../components/AnchoredH2"; import { RedirectToHome } from "../components/RedirectToHome"; export const EventsPage = () => { - let props = () => { - let pallet = useParams<{ pallet: string }>().pallet; - let events = clientWrapper()?.palletEvents(pallet); + const props = () => { + const pallet = useParams<{ pallet: string }>().pallet; + const events = client()?.palletEvents(pallet); return { pallet, events, diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 4036726..b67bb35 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,34 +1,16 @@ -import { - Accessor, - Component, - JSX, - Ref, - Setter, - createEffect, - createSignal, - onMount, -} from "solid-js"; +import { Accessor, Component, JSX, Setter, createSignal } from "solid-js"; import { DEFAULT_WS_URL } from "../constants"; -import { - ClientKind, - clientWrapper, - initAppState, - setClientWrapper, -} from "../state/client_wrapper"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { DebugComponent } from "../components/DebugComponent"; +import { ClientKind, client, initAppState } from "../state/client"; import { FileUploadArea } from "../components/FileUploadArea"; import { TabLayout, TabWithContent } from "../components/TabLayout"; import { useNavigate, useSearchParams } from "@solidjs/router"; import { AppConfig, clientKindsEqual } from "../state/app_config"; -import { setSidebarVisibility } from "../state/visual_state"; import { - findInSidebarItems, findSideBarItemByPath, itemKindToPath, setActiveItem, -} from "../state/sidebar_state"; -// import { appConfig } from "../state/app_config"; + setSidebarVisibility, +} from "../state/sidebar"; /** * A singleton class for the HomePage State. @@ -36,20 +18,7 @@ import { * Makes it easy to set fields from other locations. */ export class HomePageState { - _appConfig: AppConfig; - get appConfig(): AppConfig { - return this._appConfig; - } - - set appConfig(config: AppConfig) { - console.log("app config got changed", config); - this._appConfig = config; - this.#setAppConfigParamString(config.toParamsString()); - } - - #setAppConfigParamString: Setter<string>; - appConfigParamString: Accessor<string>; - + // UI state of the home page: file: Accessor<File | undefined>; setFile: Setter<File | undefined>; error: Accessor<string | undefined>; @@ -61,6 +30,7 @@ export class HomePageState { loadingState: Accessor<"none" | "loading">; setLoadingState: Setter<"none" | "loading">; + // infused by a scope that has access to the router. #setSearchParams?: (params: Record<string, string>) => void; #navigate?: (path: string) => void; @@ -73,32 +43,26 @@ export class HomePageState { } constructor() { - this._appConfig = new AppConfig(undefined); - let [file, setFile] = createSignal<File | undefined>(undefined); + const [file, setFile] = createSignal<File | undefined>(undefined); this.file = file; this.setFile = setFile; - let [error, setError] = createSignal<string | undefined>(undefined); + const [error, setError] = createSignal<string | undefined>(undefined); this.error = error; this.setError = setError; - let [tab, setTab] = createSignal<"file" | "url">("url"); + const [tab, setTab] = createSignal<"file" | "url">("url"); this.tab = tab; this.setTab = setTab; - let [url, setUrl] = createSignal<string>(DEFAULT_WS_URL); + const [url, setUrl] = createSignal<string>(DEFAULT_WS_URL); this.url = url; this.setUrl = setUrl; - let [loadingState, setLoadingState] = createSignal<"none" | "loading">( + const [loadingState, setLoadingState] = createSignal<"none" | "loading">( "none" ); this.loadingState = loadingState; this.setLoadingState = setLoadingState; - - let [appConfigParamString, setAppConfigParamString] = createSignal<string>( - this._appConfig.toParamsString() - ); - this.appConfigParamString = appConfigParamString; - this.#setAppConfigParamString = setAppConfigParamString; } + // singleton pattern static #instance: HomePageState; static get instance(): HomePageState { if (HomePageState.#instance === undefined) { @@ -107,6 +71,12 @@ export class HomePageState { return HomePageState.#instance; } + #generating = false; + get generating() { + return this.#generating; + } + + // takes the state of the ui elements and translates that into a clientKind that can be used to create a client. clientKindFromTab = (): ClientKind | undefined => { if (this.error() !== undefined) { return undefined; @@ -119,24 +89,28 @@ export class HomePageState { return undefined; }; + // a signal that is true if the generate button is clickable. generateButtonClickable = (): boolean => { return this.loadingState() === "none" && !!this.clientKindFromTab(); }; - async generateDocsAndUpdateAppConfig() { - let clientKind = this.clientKindFromTab(); + async generateAndUpdateAppConfig() { + const clientKind = this.clientKindFromTab(); if (clientKind === undefined || this.#setSearchParams === undefined) { return; } - this.appConfig = new AppConfig(clientKind); - this.#setSearchParams!(this.appConfig.toParams()); + AppConfig.instance.updateWith(clientKind); + this.#setSearchParams!(AppConfig.instance.toParams()); await this.#generate(clientKind); } async #generate(clientKind: ClientKind) { + this.#generating = true; this.setError(undefined); - console.log("GENERATE:", this.appConfig); - console.log("GENERATE:", this.appConfig.toParamsString()); + console.log( + "Kick off Generate Client for the current AppConfig:", + AppConfig.instance + ); this.setLoadingState("loading"); try { await initAppState(clientKind); @@ -146,43 +120,49 @@ export class HomePageState { this.setError(ex.toString()); } this.setLoadingState("none"); + this.#generating = false; } + // if the redirectPath is set, redirect to that path. maybeRedirect() { - if (this.redirectPath) { + if (this.#redirectPath) { // if redirect query param set, navigate to the correct page: - let sidebarItem = findSideBarItemByPath(this.redirectPath); - console.log("wants to redirect to", this.redirectPath, sidebarItem); + const sidebarItem = findSideBarItemByPath(this.#redirectPath); if (sidebarItem === null) { this.setError( - `Cannot redirect to ${this.redirectPath}. It is not a valid page.` + `Cannot redirect to ${this.#redirectPath}. It is not a valid page.` ); } else { setActiveItem(sidebarItem!); - let sanitizedRedirectPath = itemKindToPath(sidebarItem!.kind); - let paramsString = this.appConfig.toParamsString(); - console.log("paramsString", paramsString); - let completeRedirectPath = `${sanitizedRedirectPath}?${paramsString}`; - console.log("GENERATE REDIRECT: redirecting to", completeRedirectPath); + const sanitizedRedirectPath = itemKindToPath(sidebarItem!.kind); + const paramsString = AppConfig.instance.toParamsString(); + const completeRedirectPath = `${sanitizedRedirectPath}?${paramsString}`; + console.log( + "Home is done generating and redirects to", + completeRedirectPath + ); this.#navigate!(completeRedirectPath); } - this.redirectPath = undefined; + this.#redirectPath = undefined; } } - redirectPath: string | undefined = undefined; + #redirectPath: string | undefined = undefined; setRedirectPath = (path: string) => { - this.redirectPath = path; + this.#redirectPath = path; }; - onHomePageLoad() { - let configClientKind = this.appConfig.clientKind; + // used on: + // - page load + // - when the url params change and the AppConfig changes as a result. + adjustUiToAppConfigInstance() { + const configClientKind = AppConfig.instance.clientKind; if ( configClientKind != undefined && - !clientKindsEqual(configClientKind, clientWrapper()?.clientKindInCreation) + !clientKindsEqual(configClientKind, client()?.clientKindInCreation) ) { - this.#setSearchParams!(this.appConfig.toParams()); + this.#setSearchParams!(AppConfig.instance.toParams()); switch (configClientKind.tag) { case "url": this.setUrl(configClientKind.url); @@ -201,17 +181,16 @@ export class HomePageState { } } -interface Props {} -export const HomePage: Component<Props> = (props: Props) => { - let state = HomePageState.instance; - const [_searchParams, setSearchParams] = useSearchParams(); +export const HomePage: Component = () => { + const state = HomePageState.instance; + const setSearchParams = useSearchParams()[1]; const navigate = useNavigate(); state.infuseNavigationFns(setSearchParams, navigate); - let [isDraggingOnUpload, setIsDraggingOnUpload] = + const [isDraggingOnUpload, setIsDraggingOnUpload] = createSignal<boolean>(false); - state.onHomePageLoad(); + state.adjustUiToAppConfigInstance(); const urlTabContent = ( <input @@ -244,7 +223,7 @@ export const HomePage: Component<Props> = (props: Props) => { state.setFile(files[0]); state.setError(undefined); // directly generate new docs as soon as it it dragged in. - state.generateDocsAndUpdateAppConfig(); + state.generateAndUpdateAppConfig(); } }} ></FileUploadArea> @@ -277,7 +256,6 @@ export const HomePage: Component<Props> = (props: Props) => { }, ]; - /// JSX return ( <> <h1>Subxt Explorer</h1> @@ -299,7 +277,7 @@ export const HomePage: Component<Props> = (props: Props) => { disabled={!state.generateButtonClickable()} onClick={() => { // assumption: Button is only clickable if homeScreenClientKind() is a valid value. - state.generateDocsAndUpdateAppConfig(); + state.generateAndUpdateAppConfig(); }} > {state.loadingState() === "loading" ? ( @@ -307,7 +285,7 @@ export const HomePage: Component<Props> = (props: Props) => { ) : ( <span class="fa fa-play mr-4"></span> )} - Generate Docs{" "} + Generate Docs </button> </div> <SubxtExplanationSection /> diff --git a/src/pages/Pallet.tsx b/src/pages/Pallet.tsx index 0895064..3516fb1 100644 --- a/src/pages/Pallet.tsx +++ b/src/pages/Pallet.tsx @@ -1,42 +1,17 @@ -import { A, Link, Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - PalletContent, - clientWrapper, -} from "../state/client_wrapper"; -import { For, JSX, createEffect, createSignal } from "solid-js"; -import { - activeItem, - findInSidebarItems, - setActiveItem, - sidebarItems, -} from "../state/sidebar_state"; -import { TryToLink } from "../components/TryLinkTo"; -import { HomePageState } from "./Home"; -import { RedirectToHome } from "../components/RedirectToHome"; - -// // refetch pallet when -// let props = () => { -// let _a = activeItem(); -// let pallet = useParams<{ pallet: string }>().pallet; -// let docs = appState()?.palletDocs(pallet); -// let content = appState()?.palletContent(pallet); -// return { -// pallet, -// docs, -// content, -// }; -// }; +import { useParams } from "@solidjs/router"; +import { client } from "../state/client"; +import { For, JSX } from "solid-js"; -// return <PalletPageInternal {...props()}></PalletPageInternal>; +import { RedirectToHome } from "../components/RedirectToHome"; +import { AppConfig } from "../state/app_config"; +import { ConfigAwareLink } from "../components/ConfigAwareLink"; export const PalletPage = () => { - let props = () => { - let pallet = useParams<{ pallet: string }>().pallet; + const props = () => { + const pallet = useParams<{ pallet: string }>().pallet; return { - docs: clientWrapper()?.palletDocs(pallet), - content: clientWrapper()?.palletContent(pallet), + docs: client()?.palletDocs(pallet), + content: client()?.palletContent(pallet), pallet, }; }; @@ -60,17 +35,29 @@ export const PalletPage = () => { {props().content!.storage_entries.length > 0 && ( <PalletItemSection title="Storage Entries" - titleHref={`/pallets/${props().pallet}/storage_entries`} + titleHref={AppConfig.instance.href( + `/pallets/${props().pallet}/storage_entries` + )()} items={props().content!.storage_entries} - itemToHref={(e) => `/pallets/${props().pallet}/storage_entries#${e}`} + itemToHref={(e) => + AppConfig.instance.href( + `/pallets/${props().pallet}/constants#${e}` + )() + } ></PalletItemSection> )} {props().content!.constants.length > 0 && ( <PalletItemSection title="Constants" - titleHref={`/pallets/${props().pallet}/constants`} + titleHref={AppConfig.instance.href( + `/pallets/${props().pallet}/constants` + )()} items={props().content!.constants} - itemToHref={(e) => `/pallets/${props().pallet}/constants#${e}`} + itemToHref={(e) => + AppConfig.instance.href( + `/pallets/${props().pallet}/constants#${e}` + )() + } ></PalletItemSection> )} {props().content!.events.length > 0 && ( @@ -95,24 +82,16 @@ type PalletItemSectionProps = { function PalletItemSection(props: PalletItemSectionProps): JSX.Element { return ( <> - <TryToLink - href={`${ - props.titleHref - }?${HomePageState.instance.appConfigParamString()}`} - > + <ConfigAwareLink href={props.titleHref}> <h2 class="mt-12 text-gray-300 hover:text-pink-500">{props.title}</h2> - </TryToLink> + </ConfigAwareLink> <ul> <For each={props.items}> {(item) => ( <li class="text-gray-300 hover:text-pink-500"> - <TryToLink - href={`${props.itemToHref( - item - )}?${HomePageState.instance.appConfigParamString()}`} - > + <ConfigAwareLink href={props.itemToHref(item)}> {item} - </TryToLink> + </ConfigAwareLink> </li> )} </For> diff --git a/src/pages/RuntimeApiMethods.tsx b/src/pages/RuntimeApiMethods.tsx index 6217ab8..377f279 100644 --- a/src/pages/RuntimeApiMethods.tsx +++ b/src/pages/RuntimeApiMethods.tsx @@ -1,10 +1,5 @@ -import { Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - RuntimeApiMethodContent, - clientWrapper, -} from "../state/client_wrapper"; +import { useParams } from "@solidjs/router"; +import { RuntimeApiMethodContent, client } from "../state/client"; import { JSX } from "solid-js"; import { Docs } from "../components/Docs"; import { CodeTabLayout } from "../components/CodeTabLayout"; @@ -13,10 +8,10 @@ import { AnchoredH2 } from "../components/AnchoredH2"; import { RedirectToHome } from "../components/RedirectToHome"; export const RuntimeApiMethodsPage = () => { - let props = () => { - let runtimeApi = useParams<{ runtime_api: string }>().runtime_api; - let docs = clientWrapper()?.runtimeApiDocs(runtimeApi); - let methods = clientWrapper()?.runtimeApiMethods(runtimeApi); + const props = () => { + const runtimeApi = useParams<{ runtime_api: string }>().runtime_api; + const docs = client()?.runtimeApiDocs(runtimeApi); + const methods = client()?.runtimeApiMethods(runtimeApi); return { runtimeApi, docs, diff --git a/src/pages/RuntimeApis.tsx b/src/pages/RuntimeApis.tsx index 31bab62..a5c2676 100644 --- a/src/pages/RuntimeApis.tsx +++ b/src/pages/RuntimeApis.tsx @@ -1,39 +1,29 @@ -import { A, Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { ClientWrapper, clientWrapper } from "../state/client_wrapper"; -import { JSX } from "solid-js"; -import { TryToLink } from "../components/TryLinkTo"; +import { client } from "../state/client"; import { RedirectToHome } from "../components/RedirectToHome"; -import { HomePageState } from "./Home"; +import { ConfigAwareLink } from "../components/ConfigAwareLink"; export const RuntimeApisPage = () => { - if (!clientWrapper()?.content.runtime_apis.length) { + if (!client()?.content.runtime_apis.length) { return <RedirectToHome />; } return ( <> <h1>Runtime APIs</h1> - {clientWrapper()!.content.runtime_apis.map((runtimeApi) => ( + {client()!.content.runtime_apis.map((runtimeApi) => ( <> <h2 class="mt-12"> - <TryToLink - href={`/runtime_apis/${ - runtimeApi.name - }?${HomePageState.instance.appConfigParamString()}`} - > + <ConfigAwareLink href={`/runtime_apis/${runtimeApi.name}`}> {runtimeApi.name} - </TryToLink> + </ConfigAwareLink> </h2> <ul> {runtimeApi.methods.map((method) => ( <li> - <TryToLink - href={`/runtime_apis/${ - runtimeApi.name - }#${method}?${HomePageState.instance.appConfigParamString()}`} + <ConfigAwareLink + href={`/runtime_apis/${runtimeApi.name}#${method}`} > {method} - </TryToLink> + </ConfigAwareLink> </li> ))} </ul> diff --git a/src/pages/Storage.tsx b/src/pages/Storage.tsx index 33bb7cc..c3aac08 100644 --- a/src/pages/Storage.tsx +++ b/src/pages/Storage.tsx @@ -1,13 +1,6 @@ -import { Navigate, useParams } from "@solidjs/router"; -import { MdBookWrapper } from "../components/MdBookWrapper"; -import { - ClientWrapper, - StorageEntryContent, - clientWrapper, -} from "../state/client_wrapper"; +import { useParams } from "@solidjs/router"; +import { Client, StorageEntryContent, client } from "../state/client"; import { JSX, Show, createSignal } from "solid-js"; -import { marked } from "marked"; -import { Code } from "../components/Code"; import { Docs } from "../components/Docs"; import { CodeTabLayout } from "../components/CodeTabLayout"; import { @@ -16,10 +9,11 @@ import { } from "../components/KeyValueTypesLayout"; import { AnchoredH2 } from "../components/AnchoredH2"; import { RedirectToHome } from "../components/RedirectToHome"; + export const StoragePage = () => { - let props = () => { - let pallet = useParams<{ pallet: string }>().pallet; - let entries = clientWrapper()?.palletStorageEntries(pallet); + const props = () => { + const pallet = useParams<{ pallet: string }>().pallet; + const entries = client()?.palletStorageEntries(pallet); return { pallet, entries, @@ -34,9 +28,7 @@ export const StoragePage = () => { <h1>{props().pallet} Pallet: Storage Entries</h1> There are {props().entries!.length} storage entries on the{" "} {props().pallet} Pallet. - {props().entries!.map((entry) => - storageEntryContent(clientWrapper()!, entry) - )} + {props().entries!.map((entry) => storageEntryContent(client()!, entry))} </> ); } @@ -50,10 +42,10 @@ type StorageValueState = | { tag: "value"; value: string }; function storageEntryContent( - state: ClientWrapper, + state: Client, entry: StorageEntryContent ): JSX.Element { - let [storageValue, setStorageValue] = createSignal<StorageValueState>(); + const [storageValue, setStorageValue] = createSignal<StorageValueState>(); async function fetchStorageValue() { setStorageValue({ tag: "loading" }); @@ -68,10 +60,7 @@ function storageEntryContent( } } // fetch the value in storage when the component is loaded - if ( - entry.key_types.length === 0 && - clientWrapper()?.hasOnlineCapabilities() - ) { + if (entry.key_types.length === 0 && client()?.hasOnlineCapabilities()) { fetchStorageValue(); } diff --git a/src/state/README.md b/src/state/README.md deleted file mode 100644 index 57b4791..0000000 --- a/src/state/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Warning: DEPRECATED / OUTDATED - -## Application State explained - -There are a few state islands that dictate the state of the App. They are all implemented as SolidJs Signals. - -### [App Config](app_config.ts) - -``` -appState: AppConfig | undefined -``` - -### [App State](app_state.ts) - -``` -appState: { - clientKind: ClientKind | undefined -} -``` - -### [Sidebar State](sidebar_state.ts) - -```ts -sidebarItems: SidebarItem[] -activeItem: SidebarItem -sidebarVisibility: "visible" | "hidden" -``` - -# State flow of the application - -## On Page load - -On page load we extract some information from the url and direct the user always to the homepage. We have access to the following information before rendering anything (but being inside the Router Component): - -- path -- query params - -1. Construct the AppConfig from query params. Set the signal to this value. This should happen before anything is rendered. - -2. Check the path. If... - - - path is already `/` (pointing to home) route to `/` the Home page. - - path is pointing somewhere else, route to `/?redirect=$PATH` which is also the Home page. - -3. Render the home page. The home page contains a few local variables that might need to get configured by the app config. E.g. what tab to show (url, metadata file, lightclient) and what content is in that tab. - 1. If the `redirect` query param is set, cache it in a local variable `redirectAfterGenerate`. - 1. If the clientKind field of the AppConfig is set to some value, we show the respective tab and tabContent (e.g. tab: url, content: "wss://rpc.polkadot.io"). Also we start the generation/client building immediately. The user will see a grayed out "Generate" Button with a loading spinner. - 1. ERROR CASE: "Generate" action causes an exception: show an error message on the Home Screen - 1. SUCCESS CASE: If `redirect` variable is set, use Router to navigate to that path + the url params that the config requires. - -## On hitting Generate Button on Home Screen manually - -1. Construct the clientKind from the respective tab on the home screen. Example: if the active tab is url and the user entered "wss://rpc.polkadot.io", we get the clientKind `{tag: "url", url: "wss://rpc.polkadot.io"}`. -2. Update the AppConfig state signal. -3. Update the query params in the URL (should now match the AppConfig state signal). -4. initAppState with the clientKind: - - this makes a call to the Rust code in WASM handing the clientKind over. - - the rust code constructs a client (including metadata) and hands all that back to the JS. - - the JS now keeps this client object around ([appState](app_state.ts) is all about wrapping the client) for future function calls on it (e.g. requesting code examples or storage values) - - the sidebar UI elements are computed and the respective signals updated, such that the sidebar is rendered with all the links. - -Error Case (catch all exceptions during process above): - -- An error message is set in the state of the Home Page. -- The "Generate" Button is unlocked again and the user can use the Home Page to start all over again. - -## On Navigate to a different page (using SPA router navigation) - -After the initial page load, the user stays conceptually on a single html page. All routing and query params are hash based (root url does not change). -This means, that if a user changes a part of the URL after the hash, no page reload is triggered. Changes to the URL therefore need to be handled by listeing to signals the Router emits. - -On navigate: - -- Extract an AppConfig from the new url we navigate to. -- Compare that to the AppConfig that is currently set. -- If there are differences, redirect to the home screen like on a first page load. - -### Notes: - -All links everywhere should be appended with the query params constructed from the AppConfig. Otherwise a user can run into cases where they cannot simply copy the URL and paste it somewhere else. There should be a memoized signal `appConfigSearchParamString` that computes this appendix every time the app config changes. diff --git a/src/state/app_config.ts b/src/state/app_config.ts index b1554ab..f858883 100644 --- a/src/state/app_config.ts +++ b/src/state/app_config.ts @@ -1,27 +1,44 @@ -import { createMemo, createSignal, from } from "solid-js"; -import { ClientKind } from "./client_wrapper"; -import { Location, useSearchParams } from "@solidjs/router"; +import { Accessor, Setter, createSignal } from "solid-js"; +import { ClientKind } from "./client"; +/** + * A config object that is created at the start of the application lifecycle and can be updated at runtime. + */ export class AppConfig { clientKind: ClientKind | undefined; + // Signal used mainly in href of links. + #setAppConfigParamString: Setter<string>; + appConfigParamString: Accessor<string>; + + static #instance: AppConfig; + static get instance(): AppConfig { + if (AppConfig.#instance === undefined) { + AppConfig.#instance = new AppConfig(undefined); + } + return AppConfig.#instance; + } + + updateWith(clientKind: ClientKind | undefined) { + this.clientKind = clientKind; + this.#setAppConfigParamString(this.toParamsString()); + } + constructor(clientKind: ClientKind | undefined) { this.clientKind = clientKind; + const [appConfigParamString, setAppConfigParamString] = + createSignal<string>(this.toParamsString()); + this.appConfigParamString = appConfigParamString; + this.#setAppConfigParamString = setAppConfigParamString; } - toParams(): Record<string, string> { - let params: Record<string, string> = {}; - - switch (this.clientKind?.tag) { - case undefined: - break; - case "url": - params["url"] = this.clientKind.url; - break; - case "file": - break; - } + /// Returns a signal that contains an href to a local path with the current app config as a query string. + href(path: string): Accessor<string> { + return () => `${path}?${this.appConfigParamString()}`; + } + toParams(): Record<string, string> { + const params: Record<string, string> = clientKindToParams(this.clientKind); return params; } @@ -29,16 +46,8 @@ export class AppConfig { return paramsToString(this.toParams()); } - static fromParams(params: Record<string, string>): AppConfig { - let clientKind: ClientKind | undefined = undefined; - let url = params["url"]; - if (url) { - clientKind = { - tag: "url", - url: decodeURI(url), - }; - } - return new AppConfig(clientKind); + updateWithParams(params: Record<string, string>) { + this.clientKind = clientKindFromParams(params); } equals(other: AppConfig): boolean { @@ -46,27 +55,28 @@ export class AppConfig { } } -/** - * AppConfig contains some basic settings, is initially created from - * the browser url and local storage and can be updated at runtime. - */ -// export const [appConfig, setAppConfig] = createSignal<AppConfig>({ -// clientKind: undefined, -// }); - -// export const [ -// latestSuccessfulClientCreation, -// setLatestSuccessfulClientCreation, -// ] = createSignal<ClientKind | undefined>(undefined); - -// export function homeRedirectUrl(fromPath: string): string { -// // let config = appConfig(); -// let params: Record<string, string> = appConfigToSearchParams(config); -// params.redirect = fromPath; -// return `/${paramsToString(params)}`; -// } +export function clientKindFromParams( + params: Record<string, string> +): ClientKind | undefined { + const url = params["url"]; + if (url) { + return { + tag: "url", + url: decodeURI(url), + }; + } + return undefined; +} -//createMemo(); +export function clientKindToParams( + clientKind: ClientKind | undefined +): Record<string, string> { + const params: Record<string, string> = {}; + if (clientKind?.tag === "url") { + params["url"] = clientKind.url; + } + return params; +} export function paramsToString(params: Record<string, string>): string { return new URLSearchParams(Object.entries(params)).toString(); @@ -90,7 +100,7 @@ export function clientKindsEqual( switch (c1.tag) { case "url": - return c1.url === (c2 as any).url; + return c1.url === (c2 as { tag: "url"; url: string }).url; case "file": return true; } diff --git a/src/state/client_wrapper.ts b/src/state/client.ts similarity index 82% rename from src/state/client_wrapper.ts rename to src/state/client.ts index 445af62..733e779 100644 --- a/src/state/client_wrapper.ts +++ b/src/state/client.ts @@ -1,13 +1,6 @@ import { createSignal } from "solid-js"; -import { Client } from "subxt_example_codegen"; -import { - HOME_ITEM, - SidebarItem, - ItemKind, - itemKindToPath, - newItem, - setSidebarItems, -} from "./sidebar_state"; +import { Client as WASMClient } from "subxt_example_codegen"; +import { SidebarItem, newItem, setSidebarItems } from "./sidebar"; import { readFileAsBytes } from "../utils"; export type ClientKind = @@ -20,35 +13,32 @@ export type ClientKind = file: File; }; -export const [clientWrapper, setClientWrapper] = createSignal< - ClientWrapper | undefined ->(undefined); +export const [client, setClient] = createSignal<Client | undefined>(undefined); -export class ClientWrapper { - client: Client; +export class Client { + client: WASMClient; clientKindInCreation: ClientKind; content: MetadataContent; - constructor(client: Client, clientKindInCreation: ClientKind) { + constructor(client: WASMClient, clientKindInCreation: ClientKind) { this.client = client; this.clientKindInCreation = clientKindInCreation; this.content = client.metadataContent() as MetadataContent; } - static async createSelfWithClient( - clientKind: ClientKind - ): Promise<ClientWrapper> { - let client: Client; + static async createSelfWithClient(clientKind: ClientKind): Promise<Client> { + let client: WASMClient; switch (clientKind.tag) { case "url": - client = await Client.fromUrl(clientKind.url); + client = await WASMClient.fromUrl(clientKind.url); break; - case "file": - let bytes = await readFileAsBytes(clientKind.file); - client = Client.fromBytes(clientKind.file.name, bytes); + case "file": { + const bytes = await readFileAsBytes(clientKind.file); + client = WASMClient.fromBytes(clientKind.file.name, bytes); break; + } } - return new ClientWrapper(client, clientKind); + return new Client(client, clientKind); } hasOnlineCapabilities(): boolean { @@ -56,10 +46,10 @@ export class ClientWrapper { } constructSidebarItems(): SidebarItem[] { - let items: SidebarItem[] = []; + const items: SidebarItem[] = [newItem({ tag: "home" })]; // runtime apis if (this.content.runtime_apis.length != 0) { - let item = newItem({ tag: "runtime_apis" }); + const item = newItem({ tag: "runtime_apis" }); for (const runtimeAPI of this.content.runtime_apis) { item.children.push( newItem({ tag: "runtime_api", runtime_api: runtimeAPI.name }) @@ -73,7 +63,7 @@ export class ClientWrapper { } // pallets for (const pallet of this.content.pallets) { - let item = newItem({ + const item = newItem({ tag: "pallet", pallet: pallet.name, index: pallet.index, @@ -95,7 +85,7 @@ export class ClientWrapper { items.push(item); } // go over items to set next and prev items (for navigation): - let flattened: SidebarItem[] = []; + const flattened: SidebarItem[] = []; function add_to_flattened(item: SidebarItem) { flattened.push(item); for (const child of item.children) { @@ -139,7 +129,7 @@ export class ClientWrapper { const items: CallContent[] = []; for (const callName of pallet.calls) { - let content = this.client.callContent(palletName, callName) as + const content = this.client.callContent(palletName, callName) as | CallContent | undefined; if (content !== undefined) { @@ -161,7 +151,7 @@ export class ClientWrapper { const items: StorageEntryContent[] = []; for (const entryName of pallet.storage_entries) { - let content = this.client.storageEntryContent(palletName, entryName) as + const content = this.client.storageEntryContent(palletName, entryName) as | StorageEntryContent | undefined; if (content !== undefined) { @@ -183,7 +173,7 @@ export class ClientWrapper { const items: ConstantContent[] = []; for (const entryName of pallet.constants) { - let content = this.client.constantContent(palletName, entryName) as + const content = this.client.constantContent(palletName, entryName) as | ConstantContent | undefined; if (content !== undefined) { @@ -205,7 +195,7 @@ export class ClientWrapper { const items: EventContent[] = []; for (const eventName of pallet.events) { - let content = this.client.eventContent(palletName, eventName) as + const content = this.client.eventContent(palletName, eventName) as | EventContent | undefined; if (content !== undefined) { @@ -227,14 +217,14 @@ export class ClientWrapper { runtimeApiMethods( runtimeApiTraitName: string ): RuntimeApiMethodContent[] | undefined { - let runtimeApi = this.runtimeApiTraitContent(runtimeApiTraitName); + const runtimeApi = this.runtimeApiTraitContent(runtimeApiTraitName); if (runtimeApi === undefined) { return undefined; } - let methodContents: RuntimeApiMethodContent[] = []; + const methodContents: RuntimeApiMethodContent[] = []; for (const methodName of runtimeApi.methods) { - let content = this.client.runtimeApiMethodContent( + const content = this.client.runtimeApiMethodContent( runtimeApiTraitName, methodName ) as RuntimeApiMethodContent | undefined; @@ -260,7 +250,7 @@ export class ClientWrapper { palletName: string, storageEntryName: string ): Promise<string | undefined> { - let valueString = await this.client.fetchKeylessStorageValue( + const valueString = await this.client.fetchKeylessStorageValue( palletName, storageEntryName ); @@ -269,12 +259,12 @@ export class ClientWrapper { } export async function initAppState(clientKind: ClientKind): Promise<void> { - setClientWrapper(undefined); + setClient(undefined); setSidebarItems([]); - let state = await ClientWrapper.createSelfWithClient(clientKind); - let items = state.constructSidebarItems(); + const state = await Client.createSelfWithClient(clientKind); + const items = state.constructSidebarItems(); setSidebarItems(items); - setClientWrapper(state); + setClient(state); } export interface MetadataContent { diff --git a/src/state/sidebar_state.ts b/src/state/sidebar.ts similarity index 73% rename from src/state/sidebar_state.ts rename to src/state/sidebar.ts index d556ffa..e74fede 100644 --- a/src/state/sidebar_state.ts +++ b/src/state/sidebar.ts @@ -1,11 +1,12 @@ -import { createSignal } from "solid-js"; +import { Signal, createEffect, createSignal } from "solid-js"; export const [sidebarItems, setSidebarItems] = createSignal<SidebarItem[]>([]); + export const HOME_ITEM: SidebarItem = newItem({ tag: "home" }); export const [activeItem, setActiveItem] = createSignal<SidebarItem>(HOME_ITEM); export function findSideBarItemByPath(path: string): SidebarItem | null { - let itemKind = pathToItemKind(path); + const itemKind = pathToItemKind(path); if (itemKind === undefined) { return null; } @@ -26,7 +27,7 @@ function recursiveFind( if (fn(e)) { return e; } - let childFound = recursiveFind(e.children, fn); + const childFound = recursiveFind(e.children, fn); if (childFound !== null) { return childFound; } @@ -106,7 +107,7 @@ function itemKindEquals(a: ItemKind, b: ItemKind): boolean { // Note: currently not necessary export function pathToItemKind(path: string): ItemKind | undefined { - let segs = path.split("/").filter((e) => e.length > 0); + const segs = path.split("/").filter((e) => e.length > 0); if (segs.length == 0) { return { tag: "home" }; } @@ -119,21 +120,26 @@ export function pathToItemKind(path: string): ItemKind | undefined { } case "custom_values": return { tag: "custom_values" }; - case "pallets": - if (segs[1]) { + case "pallets": { + const pallet = segs[1]; + if (pallet) { switch (segs[2]) { case "calls": - return { tag: "calls", pallet: segs[1] }; + return { tag: "calls", pallet }; case "storage_entries": - return { tag: "storage_entries", pallet: segs[1] }; + return { tag: "storage_entries", pallet }; case "constants": - return { tag: "constants", pallet: segs[1] }; + return { tag: "constants", pallet }; + case "events": + return { tag: "events", pallet }; default: - return { tag: "pallet", pallet: segs[1], index: -1 }; + // note: index can currently not be parsed from url + return { tag: "pallet", pallet, index: -1 }; } } else { return undefined; } + } default: return undefined; } @@ -184,3 +190,29 @@ export function itemKindToTitle(item: ItemKind): string { return "Events"; } } + +const HTML = document.querySelector("html")!; + +export type SidebarState = "visible" | "hidden"; + +export const [sidebarVisibility, setSidebarVisibility]: Signal<SidebarState> = + createSignal<SidebarState>("hidden"); +export function toggleSidebar() { + setSidebarVisibility((prev) => { + switch (prev) { + case "visible": + return "hidden"; + case "hidden": + return "visible"; + } + }); +} + +// Whenever the sidebar signal changes, we also want to adjust the class on the html. +// This is some baggage from MdBook but we keep it for now. +createEffect((prevSidebar: SidebarState) => { + const currentSidebar = sidebarVisibility(); + HTML.classList.remove(`sidebar-${prevSidebar}`); + HTML.classList.add(`sidebar-${currentSidebar}`); + return currentSidebar; +}, "visible" as SidebarState); diff --git a/src/state/visual_state.ts b/src/state/visual_state.ts deleted file mode 100644 index f9aaecb..0000000 --- a/src/state/visual_state.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Signal, createEffect, createSignal } from "solid-js"; - -export const HTML = document.querySelector("html")!; -export const STORAGE_ADDR_THEME = "mdbook-theme"; -export const STORAGE_ADDR_SIDEBAR = "mdbook-sidebar"; -export const STORAGE_ADDR_SIDEBAR_SCROLL = "sidebar-scroll"; - -// Work around some values being stored in localStorage wrapped in quotes. -function localStorageQuoteWorkaround() { - try { - var theme = localStorage.getItem("mdbook-theme"); - var sidebar = localStorage.getItem("mdbook-sidebar"); - - if (theme?.startsWith('"') && theme.endsWith('"')) { - localStorage.setItem( - STORAGE_ADDR_THEME, - theme.slice(1, theme.length - 1) - ); - } - - if (sidebar?.startsWith('"') && sidebar.endsWith('"')) { - localStorage.setItem( - STORAGE_ADDR_SIDEBAR, - sidebar.slice(1, sidebar.length - 1) - ); - } - } catch (e) {} -} -localStorageQuoteWorkaround(); - -export type SidebarState = "visible" | "hidden"; - -export const [sidebarVisibility, setSidebarVisibility]: Signal<SidebarState> = - createSignal(initSidebarVisibilitySignal()); -export function toggleSidebar() { - setSidebarVisibility((prev) => { - switch (prev) { - case "visible": - return "hidden"; - case "hidden": - return "visible"; - } - }); -} - -function initSidebarVisibilitySignal(): SidebarState { - return "hidden"; - // todo!: reintroduce this local storage stuff later. For now it is okay if sidebar is closed in the beginning and opens on generate. - var sidebar = null; - if (document.body.clientWidth >= 1080) { - try { - sidebar = localStorage.getItem(STORAGE_ADDR_SIDEBAR); - } catch (e) {} - sidebar = sidebar || "visible"; - } else { - sidebar = "hidden"; - } - return sidebar as SidebarState; -} - -// Whenever the sidebar signal changes, we also want to adjust the class on the html. -createEffect((prevSidebar: SidebarState) => { - let currentSidebar = sidebarVisibility(); - HTML.classList.remove(`sidebar-${prevSidebar}`); - HTML.classList.add(`sidebar-${currentSidebar}`); - return currentSidebar; -}, "visible" as SidebarState); - -export type Theme = "light" | "rust" | "coal" | "navy" | "ayu"; - -export const [theme, setTheme]: Signal<Theme> = createSignal(initThemeSignal()); - -function initThemeSignal(): Theme { - let default_theme = "navy"; - - // Note: this is how MdBook does theming: currently not used. - // window.matchMedia("(prefers-color-scheme: dark)").matches - // ? "navy" - // : "light"; - let themeUnvalidated = undefined; - try { - themeUnvalidated = localStorage.getItem(STORAGE_ADDR_THEME); - } catch (e) {} - if ( - themeUnvalidated === null || - themeUnvalidated === undefined || - !["light", "rust", "coal", "navy", "ayu"].includes(themeUnvalidated) - ) { - themeUnvalidated = default_theme; - } - - let theme = themeUnvalidated as Theme; - - // the the theme on the html - HTML.classList.remove("no-js"); - HTML.classList.add("js"); - return theme as Theme; -} - -// whenever theme changes, add/remove the respective class in the html. -createEffect((prevTheme: Theme) => { - let currentTheme = theme(); - HTML.classList.remove(prevTheme); - HTML.classList.add(currentTheme); - return currentTheme; -}, "light" as Theme);