diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7fa505c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +storybook-static +dist \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index c8546d6..927c5ab 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,158 @@ { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "airbnb", + "airbnb/hooks", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 12, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "plugins": [ + "react", + "@typescript-eslint", + "prettier" + ], + "rules": { + "import/no-unresolved": "off", + "@typescript-eslint/no-explicit-any": "off", + "prettier/prettier": "error", + "import/no-extraneous-dependencies": "off", + "object-curly-newline": "off", + "jsx-a11y/href-no-hash": "off", + + "jsx-a11y/label-has-for": "warn", + + "react/jsx-filename-extension": ["error", { "extensions": [".js", ".jsx"] }], + + "react/prefer-stateless-function": "off", + + "max-len": ["error", { "code": 130, "tabWidth": 2 }], + "jsx-a11y/no-static-element-interactions": "off", + "jsx-a11y/no-noninteractive-element-interactions": "off", + "jsx-a11y/anchor-has-content": "off", + "react/jsx-no-target-blank": "off", + "react/forbid-prop-types": "off", + "no-console": "off", + "import/prefer-default-export": "off", + "no-plusplus": "off", + "func-names": "off", + "no-case-declarations": "off", + "no-param-reassign": "off", + "react/no-array-index-key": "off", + "no-use-before-define": "off", + "react/no-did-update-set-state": "off", + "react-hooks/exhaustive-deps": "off", + "react/destructuring-assignment": "off", + "react/static-property-placement": "off", + "jsx-a11y/click-events-have-key-events": "off", + "react/jsx-props-no-spreading": "off", + "react/require-default-props": "off", + "react/button-has-type": "off", + "import/extensions": [ + "error", + "always", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never", + "mjs": "never" + } + ] + }, "settings": { "import/resolver": { - "typescript": {} + "typescript": {}, + "node": { + "moduleDirectory": ["node_modules", "src"], + "extensions": [".js", ".jsx", ".ts", ".tsx"], + "typescript": { + "alwaysTryTypes": true + } + } } - } -} \ No newline at end of file + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + + "@typescript-eslint/no-explicit-any": "off" + } + }, + { + "files": ["**/*.ts", "**/*.tsx"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier"], + "parserOptions": { + "sourceType": "module", + "project": null + }, + "extends": ["airbnb", "plugin:@typescript-eslint/recommended", "prettier"], + "rules": { + "prettier/prettier": ["error"], + "object-curly-newline": "off", + "max-len": ["error", { "code": 130, "tabWidth": 2 }], + "react/require-default-props": "off", + "no-use-before-define": "off", + "@typescript-eslint/no-use-before-define": "off", + "jsx-a11y/anchor-has-content": "off", + "import/prefer-default-export": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/await-thenable": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/no-for-in-array": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "class-methods-use-this": "off", + "react/prop-types": "off", + "no-plusplus": "off", + "react/jsx-props-no-spreading": "off", + "react/jsx-filename-extension": ["error", { "extensions": [".js", ".jsx", "tsx"] }], + "import/extensions": [ + "error", + "always", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never", + "mjs": "never" + } + ] + }, + "settings": { + "import/resolver": { + "typescript": {}, + "node": { + "moduleDirectory": ["node_modules", "src"], + "extensions": [".js", ".jsx", ".ts", ".tsx"], + "typescript": { + "alwaysTryTypes": true, + } + } + } + } + } + ] +} diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..cb2c84d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..7fa505c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +node_modules +storybook-static +dist \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e1a8e64 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "tabWidth": 2, + "printWidth": 130, + "trailingComma": "all" +} diff --git a/package.json b/package.json index d213901..4ff8a12 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,25 @@ { "name": "schema-builder", - "version": "1.0.0", + "version": "0.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "prepare": "husky install", + "lint": "eslint 'src/**/*.{js,ts,jsx,tsx}'", + "lint:fix": "eslint 'src/**/*.{js,ts,jsx,tsx}' --fix", + "format": "prettier --write 'src/**/*.{js,ts,jsx,tsx,json,css,scss,md}'", + "postinstall": "husky install", + "prepack": "pinst --disable", + "postpack": "pinst --enable" + }, + "lint-staged": { + "src/**/*.{js,ts,jsx,tsx}": [ + "eslint --fix", + "prettier --write" + ] }, "keywords": [], "author": "", @@ -40,11 +53,23 @@ "@storybook/test": "^8.1.6", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", "eslint": "^9.4.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.2", + "eslint-plugin-react-hooks": "^4.6.2", "globals": "^15.4.0", + "husky": "^8.0.0", + "lint-staged": "^15.2.7", + "pinst": "^3.0.0", + "prettier": "^3.3.2", + "shiki": "^1.10.3", "storybook": "^8.1.6", "typescript": "^5.4.5", "typescript-eslint": "^7.12.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9368056..070a0f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,7 +57,7 @@ devDependencies: version: 9.4.0 '@storybook/addon-essentials': specifier: ^8.1.6 - version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) + version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) '@storybook/addon-interactions': specifier: ^8.1.6 version: 8.1.6 @@ -69,13 +69,13 @@ devDependencies: version: 8.1.6(react@18.3.1) '@storybook/blocks': specifier: ^8.1.6 - version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) + version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) '@storybook/react': specifier: ^8.1.6 - version: 8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5) + version: 8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5) '@storybook/react-vite': specifier: ^8.1.6 - version: 8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(vite@5.2.13) + version: 8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(vite@5.2.13) '@storybook/test': specifier: ^8.1.6 version: 8.1.6 @@ -85,21 +85,57 @@ devDependencies: '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 + '@typescript-eslint/eslint-plugin': + specifier: ^7.16.0 + version: 7.16.0(@typescript-eslint/parser@7.16.0)(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/parser': + specifier: ^7.16.0 + version: 7.16.0(eslint@9.4.0)(typescript@5.4.5) eslint: specifier: ^9.4.0 version: 9.4.0 + eslint-config-airbnb: + specifier: ^19.0.4 + version: 19.0.4(eslint-plugin-import@2.29.1)(eslint-plugin-jsx-a11y@6.9.0)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.34.2)(eslint@9.4.0) + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@9.4.0) eslint-import-resolver-typescript: specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.12.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0) + version: 3.6.1(@typescript-eslint/parser@7.16.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + version: 2.29.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint-plugin-jsx-a11y: + specifier: ^6.9.0 + version: 6.9.0(eslint@9.4.0) + eslint-plugin-prettier: + specifier: ^5.1.3 + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.4.0)(prettier@3.3.2) eslint-plugin-react: specifier: ^7.34.2 version: 7.34.2(eslint@9.4.0) + eslint-plugin-react-hooks: + specifier: ^4.6.2 + version: 4.6.2(eslint@9.4.0) globals: specifier: ^15.4.0 version: 15.4.0 + husky: + specifier: ^8.0.0 + version: 8.0.3 + lint-staged: + specifier: ^15.2.7 + version: 15.2.7 + pinst: + specifier: ^3.0.0 + version: 3.0.0 + prettier: + specifier: ^3.3.2 + version: 3.3.2 + shiki: + specifier: ^1.10.3 + version: 1.10.3 storybook: specifier: ^8.1.6 version: 8.1.6(react-dom@18.3.1)(react@18.3.1) @@ -2213,6 +2249,11 @@ packages: dev: true optional: true + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + /@popperjs/core@2.11.8: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false @@ -2705,6 +2746,12 @@ packages: dev: true optional: true + /@shikijs/core@1.10.3: + resolution: {integrity: sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==} + dependencies: + '@types/hast': 3.0.4 + dev: true + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -2733,10 +2780,10 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/addon-controls@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1): + /@storybook/addon-controls@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-hDMsu4yRP/ySb/G7hbd7nSFhVNz+F9hnizJGJX4XGuiSx7rAEYjvfKQKkawxTP+VeAw6iZPj1fukvOrMCQ0xxQ==} dependencies: - '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) + '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) dequal: 2.0.3 lodash: 4.17.21 ts-dedent: 2.2.0 @@ -2750,12 +2797,12 @@ packages: - supports-color dev: true - /@storybook/addon-docs@8.1.6(@types/react-dom@18.3.0)(prettier@3.3.1): + /@storybook/addon-docs@8.1.6(@types/react-dom@18.3.0)(prettier@3.3.2): resolution: {integrity: sha512-ejTbjDhaHn6IeTma/pwn8OutDzIqbMJKNhZx24W4FE/qvYInZIK/9gYPU9/oLKZ7FImqP3s1e4+RxDBgsq21lA==} dependencies: '@babel/core': 7.24.7 '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1) - '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) + '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) '@storybook/client-logger': 8.1.6 '@storybook/components': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) '@storybook/csf-plugin': 8.1.6 @@ -2780,19 +2827,19 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1): + /@storybook/addon-essentials@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-8ve9eM9dL6JsC5hV98unXtADvwyhIZoa3iWSeTicxWab49tvAfIM9ExwcWmUyPaB4m5q45jBSBXg66bzW2+TFw==} dependencies: '@storybook/addon-actions': 8.1.6 '@storybook/addon-backgrounds': 8.1.6 - '@storybook/addon-controls': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) - '@storybook/addon-docs': 8.1.6(@types/react-dom@18.3.0)(prettier@3.3.1) + '@storybook/addon-controls': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) + '@storybook/addon-docs': 8.1.6(@types/react-dom@18.3.0)(prettier@3.3.2) '@storybook/addon-highlight': 8.1.6 '@storybook/addon-measure': 8.1.6 '@storybook/addon-outline': 8.1.6 '@storybook/addon-toolbars': 8.1.6 '@storybook/addon-viewport': 8.1.6 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/manager-api': 8.1.6(react-dom@18.3.1)(react@18.3.1) '@storybook/node-logger': 8.1.6 '@storybook/preview-api': 8.1.6 @@ -2876,7 +2923,7 @@ packages: memoizerific: 1.11.3 dev: true - /@storybook/blocks@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1): + /@storybook/blocks@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-HBp80G9puOejqlBA0iNlV3gUxc7TkBlNIVG2rmhjcvPZUueldxTUGIGvEfTLdEM6nqzNVZT+duXwqeHHnDcynA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -2892,7 +2939,7 @@ packages: '@storybook/components': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) '@storybook/core-events': 8.1.6 '@storybook/csf': 0.1.8 - '@storybook/docs-tools': 8.1.6(prettier@3.3.1) + '@storybook/docs-tools': 8.1.6(prettier@3.3.2) '@storybook/global': 5.0.0 '@storybook/icons': 1.2.9(react-dom@18.3.1)(react@18.3.1) '@storybook/manager-api': 8.1.6(react-dom@18.3.1)(react@18.3.1) @@ -2921,11 +2968,11 @@ packages: - supports-color dev: true - /@storybook/builder-manager@8.1.6(prettier@3.3.1): + /@storybook/builder-manager@8.1.6(prettier@3.3.2): resolution: {integrity: sha512-Y5d+dikKnUuCYyh4VLEF6A+AbWughEgtipVkDKOddSTzn04trClIOKqfhQqEUObydCpgvvfdjGXJa/zDRV/UQA==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/manager': 8.1.6 '@storybook/node-logger': 8.1.6 '@types/ejs': 3.1.5 @@ -2944,7 +2991,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@8.1.6(prettier@3.3.1)(typescript@5.4.5)(vite@5.2.13): + /@storybook/builder-vite@8.1.6(prettier@3.3.2)(typescript@5.4.5)(vite@5.2.13): resolution: {integrity: sha512-xbGxI7aVMNuLcAB41Z+Vjr+M1Kznvw/jJ8HP9cfmUl1cO7ysF8R9opVG1C+kMIXUIQAVeND+DUZgmUg2zGzH6A==} peerDependencies: '@preact/preset-vite': '*' @@ -2961,7 +3008,7 @@ packages: dependencies: '@storybook/channels': 8.1.6 '@storybook/client-logger': 8.1.6 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/core-events': 8.1.6 '@storybook/csf-plugin': 8.1.6 '@storybook/node-logger': 8.1.6 @@ -3002,12 +3049,12 @@ packages: '@babel/types': 7.24.7 '@ndelangen/get-tarball': 3.0.9 '@storybook/codemod': 8.1.6 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/core-events': 8.1.6 - '@storybook/core-server': 8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1) + '@storybook/core-server': 8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1) '@storybook/csf-tools': 8.1.6 '@storybook/node-logger': 8.1.6 - '@storybook/telemetry': 8.1.6(prettier@3.3.1) + '@storybook/telemetry': 8.1.6(prettier@3.3.2) '@storybook/types': 8.1.6 '@types/semver': 7.5.8 '@yarnpkg/fslib': 2.10.3 @@ -3026,7 +3073,7 @@ packages: jscodeshift: 0.15.2(@babel/preset-env@7.24.7) leven: 3.1.0 ora: 5.4.1 - prettier: 3.3.1 + prettier: 3.3.2 prompts: 2.4.2 read-pkg-up: 7.0.1 semver: 7.6.2 @@ -3065,7 +3112,7 @@ packages: globby: 14.0.1 jscodeshift: 0.15.2(@babel/preset-env@7.24.7) lodash: 4.17.21 - prettier: 3.3.1 + prettier: 3.3.2 recast: 0.23.9 tiny-invariant: 1.3.3 transitivePeerDependencies: @@ -3095,7 +3142,7 @@ packages: - '@types/react-dom' dev: true - /@storybook/core-common@8.1.6(prettier@3.3.1): + /@storybook/core-common@8.1.6(prettier@3.3.2): resolution: {integrity: sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==} peerDependencies: prettier: ^2 || ^3 @@ -3124,8 +3171,8 @@ packages: node-fetch: 2.7.0 picomatch: 2.3.1 pkg-dir: 5.0.0 - prettier: 3.3.1 - prettier-fallback: /prettier@3.3.1 + prettier: 3.3.2 + prettier-fallback: /prettier@3.3.2 pretty-hrtime: 1.0.3 resolve-from: 5.0.0 semver: 7.6.2 @@ -3145,16 +3192,16 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/core-server@8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1): + /@storybook/core-server@8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-rgkeTG8V4emzhPqjlhchsjLay0WtgK7SrXNf1X40oTJIwmbgbReLJ5EmOXBe9rhWSXJ13aKL3l6JuTLAoptSkg==} dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@babel/core': 7.24.7 '@babel/parser': 7.24.7 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 8.1.6(prettier@3.3.1) + '@storybook/builder-manager': 8.1.6(prettier@3.3.2) '@storybook/channels': 8.1.6 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/core-events': 8.1.6 '@storybook/csf': 0.1.8 '@storybook/csf-tools': 8.1.6 @@ -3164,7 +3211,7 @@ packages: '@storybook/manager-api': 8.1.6(react-dom@18.3.1)(react@18.3.1) '@storybook/node-logger': 8.1.6 '@storybook/preview-api': 8.1.6 - '@storybook/telemetry': 8.1.6(prettier@3.3.1) + '@storybook/telemetry': 8.1.6(prettier@3.3.2) '@storybook/types': 8.1.6 '@types/detect-port': 1.3.5 '@types/diff': 5.2.1 @@ -3238,10 +3285,10 @@ packages: resolution: {integrity: sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==} dev: true - /@storybook/docs-tools@8.1.6(prettier@3.3.1): + /@storybook/docs-tools@8.1.6(prettier@3.3.2): resolution: {integrity: sha512-IhqQHSJ5nEBEJ162P/6/6c45toLinWpAkB7pwbAoP00djZSzfHNdQ4HfpZSGfD4GUJIvzsqMzUlyqCKLAoRPPA==} dependencies: - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/core-events': 8.1.6 '@storybook/preview-api': 8.1.6 '@storybook/types': 8.1.6 @@ -3346,7 +3393,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: true - /@storybook/react-vite@8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(vite@5.2.13): + /@storybook/react-vite@8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(vite@5.2.13): resolution: {integrity: sha512-aUrSOVVG/11v5FBWjxyVVYtL1MhFcGFvkHcT2tTUK2lN/EMNFugL5t5YYPv0FIi/DXxg8RBdJIV9vdNCd6tNOA==} engines: {node: '>=18.0.0'} peerDependencies: @@ -3356,9 +3403,9 @@ packages: dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.1(typescript@5.4.5)(vite@5.2.13) '@rollup/pluginutils': 5.1.0 - '@storybook/builder-vite': 8.1.6(prettier@3.3.1)(typescript@5.4.5)(vite@5.2.13) + '@storybook/builder-vite': 8.1.6(prettier@3.3.2)(typescript@5.4.5)(vite@5.2.13) '@storybook/node-logger': 8.1.6 - '@storybook/react': 8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5) + '@storybook/react': 8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5) '@storybook/types': 8.1.6 find-up: 5.0.0 magic-string: 0.30.10 @@ -3378,7 +3425,7 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@8.1.6(prettier@3.3.1)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5): + /@storybook/react@8.1.6(prettier@3.3.2)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5): resolution: {integrity: sha512-2CSc3MLeaY7QaYAQLwaXRboKkgQnWrSZAo/WTJcSHUr2YFxH5+iECB0Kci12GqaJklhhgmfTfVZ4Jo9ZJ6LQfg==} engines: {node: '>=18.0.0'} peerDependencies: @@ -3390,7 +3437,7 @@ packages: optional: true dependencies: '@storybook/client-logger': 8.1.6 - '@storybook/docs-tools': 8.1.6(prettier@3.3.1) + '@storybook/docs-tools': 8.1.6(prettier@3.3.2) '@storybook/global': 5.0.0 '@storybook/preview-api': 8.1.6 '@storybook/react-dom-shim': 8.1.6(react-dom@18.3.1)(react@18.3.1) @@ -3427,11 +3474,11 @@ packages: qs: 6.12.1 dev: true - /@storybook/telemetry@8.1.6(prettier@3.3.1): + /@storybook/telemetry@8.1.6(prettier@3.3.2): resolution: {integrity: sha512-qNWjQPF6ufRvLCAavulhNYoqldDIeBvioFuCjLlwbw3BZw3ck7pwh1vZg4AJ0SAfzbnpnXPGrHe31gnxV0D6tw==} dependencies: '@storybook/client-logger': 8.1.6 - '@storybook/core-common': 8.1.6(prettier@3.3.1) + '@storybook/core-common': 8.1.6(prettier@3.3.2) '@storybook/csf-tools': 8.1.6 chalk: 4.1.2 detect-package-manager: 2.0.1 @@ -3816,6 +3863,33 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0)(eslint@9.4.0)(typescript@5.4.5): + resolution: {integrity: sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.1 + '@typescript-eslint/parser': 7.16.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/type-utils': 7.16.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.16.0 + eslint: 9.4.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser@7.12.0(eslint@9.4.0)(typescript@5.4.5): resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3837,6 +3911,27 @@ packages: - supports-color dev: true + /@typescript-eslint/parser@7.16.0(eslint@9.4.0)(typescript@5.4.5): + resolution: {integrity: sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.16.0 + debug: 4.3.5 + eslint: 9.4.0 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@7.12.0: resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3845,6 +3940,14 @@ packages: '@typescript-eslint/visitor-keys': 7.12.0 dev: true + /@typescript-eslint/scope-manager@7.16.0: + resolution: {integrity: sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==} + engines: {node: ^18.18.0 || >=20.0.0} + dependencies: + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/visitor-keys': 7.16.0 + dev: true + /@typescript-eslint/type-utils@7.12.0(eslint@9.4.0)(typescript@5.4.5): resolution: {integrity: sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3865,11 +3968,36 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils@7.16.0(eslint@9.4.0)(typescript@5.4.5): + resolution: {integrity: sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.0(eslint@9.4.0)(typescript@5.4.5) + debug: 4.3.5 + eslint: 9.4.0 + ts-api-utils: 1.3.0(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@7.12.0: resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==} engines: {node: ^18.18.0 || >=20.0.0} dev: true + /@typescript-eslint/types@7.16.0: + resolution: {integrity: sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==} + engines: {node: ^18.18.0 || >=20.0.0} + dev: true + /@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5): resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3892,6 +4020,28 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@7.16.0(typescript@5.4.5): + resolution: {integrity: sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/visitor-keys': 7.16.0 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.4 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@7.12.0(eslint@9.4.0)(typescript@5.4.5): resolution: {integrity: sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3908,6 +4058,22 @@ packages: - typescript dev: true + /@typescript-eslint/utils@7.16.0(eslint@9.4.0)(typescript@5.4.5): + resolution: {integrity: sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.4.0) + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.4.5) + eslint: 9.4.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@7.12.0: resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -3916,6 +4082,14 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@typescript-eslint/visitor-keys@7.16.0: + resolution: {integrity: sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==} + engines: {node: ^18.18.0 || >=20.0.0} + dependencies: + '@typescript-eslint/types': 7.16.0 + eslint-visitor-keys: 3.4.3 + dev: true + /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true @@ -4059,6 +4233,11 @@ packages: uri-js: 4.4.1 dev: false + /ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4248,6 +4427,10 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + dev: true + /ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -4266,6 +4449,17 @@ packages: possible-typed-array-names: 1.0.0 dev: true + /axe-core@4.9.1: + resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==} + engines: {node: '>=4'} + dev: true + + /axobject-query@3.1.1: + resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} + dependencies: + deep-equal: 2.2.3 + dev: true + /babel-core@7.0.0-bridge.0(@babel/core@7.24.7): resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: @@ -4497,6 +4691,11 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} dependencies: @@ -4553,6 +4752,13 @@ packages: restore-cursor: 3.1.0 dev: true + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: true + /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -4567,6 +4773,14 @@ packages: '@colors/colors': 1.5.0 dev: true + /cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + dev: true + /clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -4605,6 +4819,15 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + dev: true + /commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} @@ -4657,6 +4880,10 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true + /confusing-browser-globals@1.0.11: + resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + dev: true + /consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} @@ -4735,6 +4962,10 @@ packages: /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + /damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + dev: true + /data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -4998,6 +5229,10 @@ packages: resolution: {integrity: sha512-NglN/xprcM+SHD2XCli4oC6bWe6kHoytcyLKCWXmRL854F0qhPhaYgUswUsglnPxYaNQIg2uMY4BvaomIf3kLA==} dev: true + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -5244,6 +5479,50 @@ packages: source-map: 0.6.1 dev: true + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@9.4.0): + resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.2 + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 9.4.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + object.assign: 4.1.5 + object.entries: 1.1.8 + semver: 6.3.1 + dev: true + + /eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1)(eslint-plugin-jsx-a11y@6.9.0)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.34.2)(eslint@9.4.0): + resolution: {integrity: sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==} + engines: {node: ^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.3 + eslint-plugin-jsx-a11y: ^6.5.1 + eslint-plugin-react: ^7.28.0 + eslint-plugin-react-hooks: ^4.3.0 + dependencies: + eslint: 9.4.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@9.4.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint-plugin-jsx-a11y: 6.9.0(eslint@9.4.0) + eslint-plugin-react: 7.34.2(eslint@9.4.0) + eslint-plugin-react-hooks: 4.6.2(eslint@9.4.0) + object.assign: 4.1.5 + object.entries: 1.1.8 + dev: true + + /eslint-config-prettier@9.1.0(eslint@9.4.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 9.4.0 + dev: true + /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: @@ -5254,7 +5533,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5264,8 +5543,8 @@ packages: debug: 4.3.5 enhanced-resolve: 5.17.0 eslint: 9.4.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -5277,7 +5556,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0): + /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: @@ -5298,16 +5577,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 7.12.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.16.0(eslint@9.4.0)(typescript@5.4.5) debug: 3.2.7 eslint: 9.4.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.0)(eslint-plugin-import@2.29.1)(eslint@9.4.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -5317,7 +5596,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 7.12.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.16.0(eslint@9.4.0)(typescript@5.4.5) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -5326,7 +5605,7 @@ packages: doctrine: 2.1.0 eslint: 9.4.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5342,6 +5621,61 @@ packages: - supports-color dev: true + /eslint-plugin-jsx-a11y@6.9.0(eslint@9.4.0): + resolution: {integrity: sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + aria-query: 5.1.3 + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.9.1 + axobject-query: 3.1.1 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + es-iterator-helpers: 1.0.19 + eslint: 9.4.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.0 + dev: true + + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@9.4.0)(prettier@3.3.2): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 9.4.0 + eslint-config-prettier: 9.1.0(eslint@9.4.0) + prettier: 3.3.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + dev: true + + /eslint-plugin-react-hooks@4.6.2(eslint@9.4.0): + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 9.4.0 + dev: true + /eslint-plugin-react@7.34.2(eslint@9.4.0): resolution: {integrity: sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==} engines: {node: '>=4'} @@ -5484,6 +5818,10 @@ packages: engines: {node: '>= 0.6'} dev: true + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: true + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -5556,6 +5894,10 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -5781,6 +6123,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: true + /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true @@ -6082,6 +6429,12 @@ packages: engines: {node: '>=16.17.0'} dev: true + /husky@8.0.3: + resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} + engines: {node: '>=14'} + hasBin: true + dev: true + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6253,6 +6606,18 @@ packages: engines: {node: '>=8'} dev: true + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + dependencies: + get-east-asian-width: 1.2.0 + dev: true + /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -6593,6 +6958,17 @@ packages: engines: {node: '>=6'} dev: true + /language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + dev: true + + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + dependencies: + language-subtag-registry: 0.3.23 + dev: true + /lazy-universal-dotenv@4.0.0: resolution: {integrity: sha512-aXpZJRnTkpK6gQ/z4nk+ZBLd/Qdp118cvPruLSIQzQNRhKwEcdXCOzXuF55VDqIiuAaY3UGZ10DJtvZzDcvsxg==} engines: {node: '>=14.0.0'} @@ -6615,9 +6991,45 @@ packages: type-check: 0.4.0 dev: true + /lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + dev: true + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /lint-staged@15.2.7: + resolution: {integrity: sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==} + engines: {node: '>=18.12.0'} + hasBin: true + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + debug: 4.3.5 + execa: 8.0.1 + lilconfig: 3.1.2 + listr2: 8.2.3 + micromatch: 4.0.7 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /listr2@8.2.3: + resolution: {integrity: sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==} + engines: {node: '>=18.0.0'} + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.0.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + dev: true + /lit-element@4.0.6: resolution: {integrity: sha512-U4sdJ3CSQip7sLGZ/uJskO5hGiqtlpxndsLr6mt3IQIjheg93UKYeGQjWMRql1s/cXNOaRrCzC2FQwjIwSUqkg==} dependencies: @@ -6685,6 +7097,17 @@ packages: is-unicode-supported: 0.1.0 dev: true + /log-update@6.0.0: + resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} + engines: {node: '>=18'} + dependencies: + ansi-escapes: 6.2.1 + cli-cursor: 4.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + dev: true + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -7274,11 +7697,23 @@ packages: engines: {node: '>=8.6'} dev: true + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} dev: true + /pinst@3.0.0: + resolution: {integrity: sha512-cengSmBxtCyaJqtRSvJorIIZXMXg+lJ3sIljGmtBGUVonMnMsVJbnzl6jGN1HkOWwxNuJynCJ2hXxxqCQrFDdw==} + engines: {node: '>=12.0.0'} + hasBin: true + dev: true + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -7331,8 +7766,15 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@3.3.1: - resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==} + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true dev: true @@ -7801,11 +8243,23 @@ packages: signal-exit: 3.0.7 dev: true + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true + /rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + dev: true + /rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -7976,6 +8430,13 @@ packages: engines: {node: '>=8'} dev: true + /shiki@1.10.3: + resolution: {integrity: sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==} + dependencies: + '@shikijs/core': 1.10.3 + '@types/hast': 3.0.4 + dev: true + /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -8009,6 +8470,22 @@ packages: engines: {node: '>=14.16'} dev: true + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + dev: true + /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -8092,6 +8569,11 @@ packages: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} dev: true + /string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8110,6 +8592,22 @@ packages: strip-ansi: 7.1.0 dev: true + /string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: true + /string.prototype.matchall@4.0.11: resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} engines: {node: '>= 0.4'} @@ -8236,6 +8734,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.3 + dev: true + /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -8864,6 +9370,15 @@ packages: strip-ansi: 7.1.0 dev: true + /wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true @@ -8907,6 +9422,12 @@ packages: engines: {node: '>= 6'} dev: false + /yaml@2.4.5: + resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/src/builder/JsonSchemaBuilder.ts b/src/builder/JsonSchemaBuilder.ts index 8c4656e..f968163 100644 --- a/src/builder/JsonSchemaBuilder.ts +++ b/src/builder/JsonSchemaBuilder.ts @@ -1,6 +1,5 @@ -import {JsonSchema, JsonSchemaType, Format} from "../types"; -import {deleteNestedPropertyByPath, generatePath, updateNestedObjectByPath} from "../utils"; - +import { Format, JsonSchema, JsonSchemaType } from '../types'; +import { deleteNestedPropertyByPath, updateNestedObjectByPath } from '../utils'; /** * Builder class for constructing JSON Schema objects. @@ -166,7 +165,7 @@ export class JsonSchemaBuilder { } deleteProperty(name: string): JsonSchemaBuilder { - this.schema = deleteNestedPropertyByPath(this.schema, name) + this.schema = deleteNestedPropertyByPath(this.schema, name); return this; } @@ -178,7 +177,7 @@ export class JsonSchemaBuilder { } editProperty(name: string, propSchema: JsonSchema): JsonSchemaBuilder { - this.schema = updateNestedObjectByPath(this.schema, name, propSchema) + this.schema = updateNestedObjectByPath(this.schema, name, propSchema); return this; } diff --git a/src/components/AddFieldModal.tsx b/src/components/AddFieldModal.tsx index 3cff384..75f48b8 100644 --- a/src/components/AddFieldModal.tsx +++ b/src/components/AddFieldModal.tsx @@ -1,114 +1,129 @@ -import { - Box, - Button, - Dialog, - FormControl, - IconButton, - InputLabel, - MenuItem, - Stack, - TextField, - Tooltip, -} from "@mui/material"; -import Form from "@rjsf/mui"; +import { Box, Button, Dialog, FormControl, IconButton, InputLabel, MenuItem, Stack, TextField, Tooltip } from '@mui/material'; +import Form from '@rjsf/mui'; -import validator from "@rjsf/validator-ajv8"; -import React from "react"; -import {useSchema} from "../providers/SchemaProvider"; -import {JsonSchemaType} from "../types"; -import {JsonSchemaField} from "../fields/JsonSchemaField"; -import Select from "@mui/material/Select"; -import {Add} from "@mui/icons-material"; -import {generatePath} from "../utils"; +import validator from '@rjsf/validator-ajv8'; +import React from 'react'; +import { useSchema } from '../providers/SchemaProvider'; +import { JsonSchemaType } from '../types'; +import { JsonSchemaField } from '../fields/JsonSchemaField'; +import Select from '@mui/material/Select'; +import { Add } from '@mui/icons-material'; +import { generatePath } from '../utils'; -const AddFieldModal = ({ parentPath }) => { - const [open, setOpen] = React.useState(false); - const [name, setName] = React.useState(null); - const [type, setType] = React.useState(null); - const [field, setField] = React.useState(null); - const {dispatch, fields} = useSchema(); - const [step, setStep] = React.useState(0); - - const SelectedFieldClass = fields.find(f => f.id === type)?.Class +type Props = { + parentPath: string; +}; - const handleSelectType = () => { - if (name && type && SelectedFieldClass) { - setField(new SelectedFieldClass(name)) - setStep(1); - } - } +const AddFieldModal = ({ parentPath }: Props) => { + const [open, setOpen] = React.useState(false); + const [name, setName] = React.useState(null); + const [type, setType] = React.useState(null); + const [field, setField] = React.useState(null); + const { dispatch, fields } = useSchema(); + const [step, setStep] = React.useState(0); + const SelectedFieldClass = fields.find((f) => f.id === type)?.Class; - const handleSubmit = (formData) => { - if (field) { - field.setSchema(formData); - dispatch({ - type: "ADD_PROPERTY", - payload: { - name: generatePath(parentPath, field.getName() || 'newField'), - schema: field.getSchema(), - }, - }); - if (field.getIsRequired()) { - dispatch({ - type: "ADD_REQUIRED", - payload: { - name: generatePath(parentPath, field.getName() || 'newField'), - }, - }) - } - setOpen(false); - setType(null); - setName(null); - setStep(0); - } + const handleSelectType = () => { + if (name && type && SelectedFieldClass) { + setField(new SelectedFieldClass(name)); + setStep(1); } + }; - - const handleTitleChanged = (e: React.ChangeEvent) => { - const input = e.target.value; - setName(input) + const handleSubmit = (formData) => { + if (field) { + field.setSchema(formData); + dispatch({ + type: 'ADD_PROPERTY', + payload: { + name: generatePath(parentPath, field.getName() || 'newField'), + schema: field.getSchema(), + }, + }); + if (field.getIsRequired()) { + dispatch({ + type: 'ADD_REQUIRED', + payload: { + name: generatePath(parentPath, field.getName() || 'newField'), + }, + }); + } + setOpen(false); + setType(null); + setName(null); + setStep(0); } + }; + + const handleTitleChanged = (e: React.ChangeEvent) => { + const input = e.target.value; + setName(input); + }; - return ( - <> - setOpen(true)}> - setOpen(false)}> - -

{step !== 0 && }Adding Field

- {step === 0 && ( - - + return ( + <> + + setOpen(true)}> + + + + setOpen(false)}> + +

+ {step !== 0 && } + Adding Field +

+ {step === 0 && ( + + - - Field Type - - + + Field Type + + - - - )} - {step === 1 && ( - <> -

Please complete the info for the name field

- {field && ( -
handleSubmit(formData)}/> - )} - - )} - -
- - ); + +
+ )} + {step === 1 && ( + <> +

+ Please complete the info for the name field +

+ {field && ( + handleSubmit(formData)} + /> + )} + + )} +
+
+ + ); }; export default AddFieldModal; diff --git a/src/components/FieldPreview.tsx b/src/components/FieldPreview.tsx index 1026a1a..9c1af7c 100644 --- a/src/components/FieldPreview.tsx +++ b/src/components/FieldPreview.tsx @@ -1,144 +1,116 @@ -import React from "react"; -import {RJSFSchema} from "@rjsf/utils"; -import AddFieldModal from "./AddFieldModal"; -import Numbers from '@mui/icons-material/Numbers'; -import { - Add, - Check, - Close, - DataArray, - DataObject, - ExpandLess, - ExpandMore, - TextSnippet, - ToggleOn -} from "@mui/icons-material"; -import { - Box, - Card, - Chip, - Collapse, - IconButton, - ListItem, - ListItemText, Table, TableBody, - TableCell, - TableRow, - Typography -} from "@mui/material"; -import {getSchemaFormatFromSchema} from "../utils"; -import {DataVisualizationType} from "../types"; -import {SchemaAction, useSchema} from "../providers/SchemaProvider"; +import React from 'react'; +import { RJSFSchema } from '@rjsf/utils'; +import { Check, Close, DataArray } from '@mui/icons-material'; +import { Card, ListItem, ListItemText, Table, TableBody, TableCell, TableRow, Typography } from '@mui/material'; +import { getSchemaFormatFromSchema } from '../utils'; +import { DataVisualizationType } from '../types'; type Props = { - schema: RJSFSchema; - data: unknown; - name: string; -} - + schema: RJSFSchema; + data: unknown; + name: string; +}; // TODO: refactor -const renderHeader = ({data, schema}: { - data: unknown, - schema: RJSFSchema, -}) => { - return ( - <> - - - {schema?.title} - {schema?.description && ( - {schema?.description} - )} - - )} - /> - - - ) -} +const renderHeader = ({ schema }: { data: unknown; schema: RJSFSchema }) => { + return ( + <> + + + {schema?.title} + {schema?.description && {schema?.description}} + + } + /> + + + ); +}; +const FieldPreview = ({ schema, data, name }: Props) => { + const FormPreview = getSchemaFormatFromSchema(schema, FieldPreview); + return ; +}; -const FieldPreview = ({schema, data, name}: Props) => { - const FormPreview = getSchemaFormatFromSchema(schema, FieldPreview) - return ( - - ) +FieldPreview.String = function String({ schema, data }: DataVisualizationType) { + return ( + + {schema?.title} + {data || '-'} + + ); }; -FieldPreview.String = function String({schema, data, name}: DataVisualizationType) { - return ( - - {schema?.title} - {data || '-'} - - ); +FieldPreview.Enum = function Enum({ schema, data }: DataVisualizationType) { + return ( + + {schema?.title} + {data || '-'} + + ); }; -FieldPreview.Enum = function Enum({schema, data, name}: DataVisualizationType) { - return ( - - {schema?.title} - {data || '-'} - - ); +FieldPreview.Number = function Number({ schema, data }: DataVisualizationType) { + return ( + + {schema?.title} + {data || '-'} + + ); }; -FieldPreview.Number = function Number({schema, name, data}: DataVisualizationType) { - return ( - - {schema?.title} - {data || '-'} - - ); +FieldPreview.Integer = function Integer({ schema, data }: DataVisualizationType) { + return ( + + {schema?.title} + {data || '-'} + + ); }; -FieldPreview.Boolean = function BooleanVisualization({schema, name, data}: DataVisualizationType) { - return ( - - {schema?.title} - {data ? : } - - ); +FieldPreview.Boolean = function BooleanVisualization({ schema, data }: DataVisualizationType) { + return ( + + {schema?.title} + {data ? : } + + ); }; -FieldPreview.Object = function ObjectVisualization({schema, data, name}: DataVisualizationType) { - const properties = Object.keys(schema?.properties || {}) - return ( - - {renderHeader({ - name, - schema, - })} - - {properties?.filter((property) => data[property] !== undefined)?.map((property) => ( - - ))} - -
- ); +FieldPreview.Object = function ObjectVisualization({ schema, data, name }: DataVisualizationType) { + const properties = Object.keys(schema?.properties || {}); + return ( + + {renderHeader({ + name, + schema, + })} + + {properties + ?.filter((property) => data[property] !== undefined) + ?.map((property) => ( + + ))} + +
+ ); }; -FieldPreview.Array = function ArrayVisualization({schema, data, name}: DataVisualizationType) { - return ( - <> - - {renderHeader({name, schema, icon: })} - - - - ); +FieldPreview.Array = function ArrayVisualization({ schema, name }: DataVisualizationType) { + return ( + <> + + {renderHeader({ name, schema, icon: })} + + + + ); }; FieldPreview.Unknown = function ArrayVisualization() { - return <>; + return <>; }; export default FieldPreview; diff --git a/src/components/SchemaBuilder.tsx b/src/components/SchemaBuilder.tsx index 9571ece..b5811bf 100644 --- a/src/components/SchemaBuilder.tsx +++ b/src/components/SchemaBuilder.tsx @@ -1,43 +1,53 @@ -import Form from "@rjsf/mui"; -import validator from "@rjsf/validator-ajv8"; -import React, {useState} from "react"; -import AddFieldModal from "./AddFieldModal"; -import {useSchema} from "../providers/SchemaProvider"; -import {Button, CssBaseline, ButtonGroup, Tabs, Tab} from "@mui/material"; -import SchemaPreview from "./SchemaPreview"; - +import Form from '@rjsf/mui'; +import validator from '@rjsf/validator-ajv8'; +import React, { useEffect, useState } from 'react'; +import { useSchema } from '../providers/SchemaProvider'; +import { Box, CssBaseline, Tab, Tabs } from '@mui/material'; +import SchemaPreview from './SchemaPreview'; +import { codeToHtml } from 'shiki'; const SchemaBuilder = () => { - const {schema} = useSchema(); - const [tab, setTab] = useState(0) - const TABS: Record<'BUILDER' | "SCHEMA" | "FORM_PREVIEW", number> = { - 'BUILDER': 0, "SCHEMA": 1, "FORM_PREVIEW": 2 - } - const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { - setTab(newValue); + const { schema } = useSchema(); + const [highlightedSchema, setHighlightedSchema] = useState(''); + const [tab, setTab] = useState(0); + const TABS: Record<'BUILDER' | 'SCHEMA' | 'FORM_PREVIEW', number> = { + BUILDER: 0, + SCHEMA: 1, + FORM_PREVIEW: 2, + }; + const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { + setTab(newValue); + }; + + useEffect(() => { + const getHighlightedCode = async (code: string) => { + const highlighted = await codeToHtml(code, { + lang: 'json', + theme: 'github-dark-default', + }); + + setHighlightedSchema(highlighted); }; - return ( - <> - -
- - - - - - {tab === TABS.BUILDER && ( - - )} - {tab === TABS.SCHEMA && ( -
{JSON.stringify(schema, null, 2)}
- )} - {tab === TABS.FORM_PREVIEW && ( - - )} -
- - ); + getHighlightedCode(JSON.stringify(schema, null, 2)); + }, [schema]); + + return ( + <> + +
+ + + + + + + {tab === TABS.BUILDER && } + {tab === TABS.SCHEMA && } + {tab === TABS.FORM_PREVIEW && } +
+ + ); }; export default SchemaBuilder; diff --git a/src/components/SchemaPreview.tsx b/src/components/SchemaPreview.tsx index 7e8a47e..aaac128 100644 --- a/src/components/SchemaPreview.tsx +++ b/src/components/SchemaPreview.tsx @@ -1,302 +1,346 @@ -import React, {useState} from "react"; -import {RJSFSchema} from "@rjsf/utils"; -import AddFieldModal from "./AddFieldModal"; +import React, { useState } from 'react'; +import { RJSFSchema } from '@rjsf/utils'; +import AddFieldModal from './AddFieldModal'; import Numbers from '@mui/icons-material/Numbers'; import { - Add, Checklist, - DataArray, - DataObject, - Delete, - Edit, - ExpandLess, - ExpandMore, - TextSnippet, - ToggleOn, Visibility -} from "@mui/icons-material"; + Add, + Checklist, + DataArray, + DataObject, + Delete, + Edit, + ExpandLess, + ExpandMore, + TextSnippet, + ToggleOn, + Visibility, +} from '@mui/icons-material'; import { - Box, Button, Card, Chip, - Collapse, - Dialog, DialogActions, DialogContent, DialogTitle, - IconButton, - ListItem, - ListItemIcon, - ListItemText, Paper, Stack, - Tooltip, - Typography, useTheme -} from "@mui/material"; -import {generatePath, getFieldId, getSchemaFormatFromSchema} from "../utils"; -import {DataVisualizationType} from "../types"; -import {SchemaAction, useSchema} from "../providers/SchemaProvider"; -import Form from "@rjsf/mui"; -import validator from "@rjsf/validator-ajv8"; -import FieldPreview from "./FieldPreview"; - -type Props = { - schema: RJSFSchema; - data: unknown; - name: string; - path?: string; -} + Box, + Button, + Chip, + Collapse, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + ListItem, + ListItemText, + Paper, + Stack, + Typography, +} from '@mui/material'; +import { generatePath, getFieldId, getSchemaFormatFromSchema } from '../utils'; +import { DataVisualizationType } from '../types'; +import { SchemaAction, useSchema } from '../providers/SchemaProvider'; +import Form from '@rjsf/mui'; +import validator from '@rjsf/validator-ajv8'; +import FieldPreview from './FieldPreview'; // TODO: refactor -const renderHeader = ({icon, schema, onDelete, name, path, description}: { - icon?: React.ReactNode, - schema: RJSFSchema, - description?: React.ReactNode, - path: string, - name?: string, - onDelete?: () => void, - collapse?: boolean; - onCollapse?: () => void +const renderHeader = ({ + icon, + schema, + onDelete, + name, + path, + description, +}: { + icon?: React.ReactNode; + schema: RJSFSchema; + description?: React.ReactNode; + path: string; + name?: string; + onDelete?: () => void; + collapse?: boolean; + onCollapse?: () => void; }) => { - const [showDeleteConfirmationModal, setShowDeleteConfirmationModal] = useState(false); - const [showEditModal, setShowEditModal] = useState(false); - const [showPreviewModal, setShowPreviewModal] = useState(false); - const {fields, dispatch} = useSchema(); - const SelectedFieldClass = fields.find(field => field.id === getFieldId(schema))?.Class + const [showDeleteConfirmationModal, setShowDeleteConfirmationModal] = useState(false); + const [showEditModal, setShowEditModal] = useState(false); + const [showPreviewModal, setShowPreviewModal] = useState(false); + const { fields, dispatch } = useSchema(); + const SelectedFieldClass = fields.find((field) => field.id === getFieldId(schema))?.Class; - let field; - if (SelectedFieldClass) { - field = new SelectedFieldClass(name) - } - return ( - <> - setShowEditModal(false)}> - Edit {name} Field - - { - handleEdit(dispatch, path, formData) - setShowEditModal(false); - }} schema={field?.getBuilderSchema()} formData={schema} validator={validator}/> - - + let field; + if (SelectedFieldClass) { + field = new SelectedFieldClass(name); + } + return ( + <> + setShowEditModal(false)}> + + Edit {name} Field + + + { + handleEdit(dispatch, path, formData); + setShowEditModal(false); + }} + schema={field?.getBuilderSchema()} + formData={schema} + validator={validator} + /> + + - setShowPreviewModal(false)}> - {name} Field {onDelete && - setShowDeleteConfirmationModal(true)}>} - setShowEditModal(true)} - > - - - - - - + setShowPreviewModal(false)}> + + {name} Field{' '} + + {onDelete && ( + setShowDeleteConfirmationModal(true)}> + + + )} + setShowEditModal(true)}> + + + + + + + + - setShowDeleteConfirmationModal(false)}> - Are you sure you want to delete this field? - - - - - - - - {schema?.title} - - {description && ( - {description} - )} - - )} + setShowDeleteConfirmationModal(false)}> + + Are you sure you want to delete this field? + + + + + + + + + + {schema?.title}{' '} + - {onDelete && setShowDeleteConfirmationModal(true)}>} - setShowEditModal(true)} - > - - - - setShowPreviewModal(true)} - > - - + + {description && {description}} + + } + /> + {onDelete && ( + setShowDeleteConfirmationModal(true)}> + + + )} + setShowEditModal(true)}> + + - - - ) -} + setShowPreviewModal(true)}> + + + + + ); +}; const handleDelete = (dispatch: React.Dispatch, name: string) => { - dispatch({type: "DELETE_PROPERTY", payload: {name}}); - dispatch({type: "DELETE_REQUIRED", payload: {name}}); -} + dispatch({ type: 'DELETE_PROPERTY', payload: { name } }); + dispatch({ type: 'DELETE_REQUIRED', payload: { name } }); +}; const handleEdit = (dispatch: React.Dispatch, name: string, schema: RJSFSchema) => { - dispatch({type: "UPDATE_PROPERTY", payload: {name, schema}}); -} + dispatch({ type: 'UPDATE_PROPERTY', payload: { name, schema } }); +}; -const SchemaPreview = ({schema, data, name, path}: Props) => { - const FormPreview = getSchemaFormatFromSchema(schema, SchemaPreview) - return ( - - ) +const SchemaPreview = ({ schema, data, name, path }: DataVisualizationType) => { + const FormPreview = getSchemaFormatFromSchema(schema, SchemaPreview); + return ; }; -SchemaPreview.String = function String({schema, path, data, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - return ( - - {renderHeader({ - description: schema.description, - name, - path, - schema, - icon: , - onDelete: () => handleDelete(dispatch, path) - })} - - ); +SchemaPreview.String = function String({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + ); }; -SchemaPreview.Enum = function Enum({schema, path, data, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - const enums = schema.enum - return ( - - {renderHeader({ - description: <>{schema.description} Options: {enums.map(e => ( - ))}, - name, - path, - schema, - icon: , - onDelete: () => handleDelete(dispatch, path) - })} - - ); +SchemaPreview.Enum = function Enum({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + const enums = schema.enum; + return ( + + {renderHeader({ + description: ( + <> + {schema.description} Options:{' '} + + {enums.map((e) => ( + + ))} + + + ), + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + ); }; -SchemaPreview.Number = function Number({schema, path, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - return ( - - {renderHeader({ - description: schema.description, - name, - path, - schema, - icon: , - onDelete: () => handleDelete(dispatch, path) - })} - - ); +SchemaPreview.Number = function Number({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + ); }; -SchemaPreview.Boolean = function BooleanVisualization({schema, path, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - return ( - - {renderHeader({ - description: schema.description, - name, - path, - schema, - icon: , - onDelete: () => handleDelete(dispatch, path) - })} - - ); +SchemaPreview.Integer = function Number({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + ); }; -SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - const properties = Object.keys(schema?.properties || {}) +SchemaPreview.Boolean = function BooleanVisualization({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + ); +}; - const [open, setOpen] = React.useState(true); +SchemaPreview.Object = function ObjectVisualization({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + const properties = Object.keys(schema?.properties || {}); - const handleCollapse = () => { - setOpen(!open); - }; + const [open, setOpen] = React.useState(true); - const theme = useTheme(); + const handleCollapse = () => { + setOpen(!open); + }; - return ( - - {renderHeader({ - description: schema.description, - name, - path, - schema, - icon: , - collapse: open, - onCollapse: handleCollapse, - onDelete: () => handleDelete(dispatch, path) - })} - - - Properties - - {open !== undefined && - {!open ? : - }} - - - - {properties?.length > 0 ? properties?.map((property) => ( - <> - - - )) : ( - - Click on button to add properties - - )} - - - - - ); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + collapse: open, + onCollapse: handleCollapse, + onDelete: () => handleDelete(dispatch, path), + })} + + + Properties + + {open !== undefined && ( + + {!open ? : } + + )} + + + + {properties?.length > 0 ? ( + properties?.map((property) => ( + <> + + + )) + ) : ( + + Click on button to add properties + + )} + + + + + ); }; -SchemaPreview.Array = function ArrayVisualization({schema, path, data, name}: DataVisualizationType) { - const {dispatch} = useSchema(); - const theme = useTheme(); - return ( - - {renderHeader({ - description: schema.description, - name, - path, - schema, - icon: , - onDelete: () => handleDelete(dispatch, path) - })} - - - - - ); +SchemaPreview.Array = function ArrayVisualization({ schema, path, name }: DataVisualizationType) { + const { dispatch } = useSchema(); + return ( + + {renderHeader({ + description: schema.description, + name, + path, + schema, + icon: , + onDelete: () => handleDelete(dispatch, path), + })} + + + + + ); }; SchemaPreview.Unknown = function ArrayVisualization() { - return <>; + return <>; }; export default SchemaPreview; diff --git a/src/constants.ts b/src/constants.ts index 1b44e0a..c316683 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,100 +1,106 @@ -import {StringField} from "./fields/primitives/StringField"; -import {IntegerField} from "./fields/primitives/IntegerField"; -import {BooleanField} from "./fields/primitives/BooleanField"; -import {NumberField} from "./fields/primitives/NumberField"; -import {ObjectField} from "./fields/containers/ObjectField"; -import {ArrayField} from "./fields/containers/ArrayField"; -import {DateField} from "./fields/widgets/DateField"; -import {TimeField} from "./fields/widgets/TimeField"; -import {DateTimeField} from "./fields/widgets/DateTimeField"; -import {FaqWidget} from "./fields/patterns/FaqWidget"; -import {FieldConfig} from "./types"; -import {SelectField} from "./fields/widgets/SelectField"; +import { StringField } from './fields/primitives/StringField'; +import { IntegerField } from './fields/primitives/IntegerField'; +import { BooleanField } from './fields/primitives/BooleanField'; +import { NumberField } from './fields/primitives/NumberField'; +import { ObjectField } from './fields/containers/ObjectField'; +import { ArrayField } from './fields/containers/ArrayField'; +import { DateField } from './fields/widgets/DateField'; +import { TimeField } from './fields/widgets/TimeField'; +import { DateTimeField } from './fields/widgets/DateTimeField'; +import { FaqWidget } from './fields/patterns/FaqWidget'; +import { FieldConfig } from './types'; +import { SelectField } from './fields/widgets/SelectField'; -export const PRIMITIVE_PROPERTIES: FieldConfig[] = [ - { - id: 'STRING', - title: 'String Field', - description: 'a string field', - Class: StringField, +export const SCHEMA_TYPE = { + STRING: 'string', + NUMBER: 'number', + INTEGER: 'integer', + OBJECT: 'object', + ARRAY: 'array', + BOOLEAN: 'boolean', +}; - }, - { - id: 'INTEGER', - title: 'Integer Field', - description: 'a integer field', - Class: IntegerField, - }, - { - id: 'NUMBER', - title: 'Number Field', - description: 'a number field', - Class: NumberField, - }, - { - id: 'BOOLEAN', - title: 'Boolean Field', - description: 'a boolean field', - Class: BooleanField, - }, +export const PRIMITIVE_PROPERTIES: FieldConfig[] = [ + { + id: 'STRING', + title: 'String Field', + description: 'a string field', + Class: StringField, + }, + { + id: 'INTEGER', + title: 'Integer Field', + description: 'a integer field', + Class: IntegerField, + }, + { + id: 'NUMBER', + title: 'Number Field', + description: 'a number field', + Class: NumberField, + }, + { + id: 'BOOLEAN', + title: 'Boolean Field', + description: 'a boolean field', + Class: BooleanField, + }, ]; export const CONTAINER_PROPERTIES: FieldConfig[] = [ - { - id: 'ARRAY', - title: 'Array Field', - description: 'a array field', - Class: ArrayField, - }, - { - id: 'OBJECT', - title: 'Object Field', - description: 'a object field', - Class: ObjectField, - }, + { + id: 'ARRAY', + title: 'Array Field', + description: 'a array field', + Class: ArrayField, + }, + { + id: 'OBJECT', + title: 'Object Field', + description: 'a object field', + Class: ObjectField, + }, ]; - export const STRING_WIDGETS: FieldConfig[] = [ - { - id: 'DATE', - title: 'Date Field', - description: 'a date field', - Class: DateField, - }, - { - id: 'DATE_TIME', - title: 'Date-Time Field', - description: 'a date-time field', - Class: DateTimeField, - }, - { - id: 'TIME', - title: 'Time Field', - description: 'a time field', - Class: TimeField, - }, - { - id: 'SELECT', - title: 'Select Field', - description: 'a select field with a list of options', - Class: SelectField, - } + { + id: 'DATE', + title: 'Date Field', + description: 'a date field', + Class: DateField, + }, + { + id: 'DATE_TIME', + title: 'Date-Time Field', + description: 'a date-time field', + Class: DateTimeField, + }, + { + id: 'TIME', + title: 'Time Field', + description: 'a time field', + Class: TimeField, + }, + { + id: 'SELECT', + title: 'Select Field', + description: 'a select field with a list of options', + Class: SelectField, + }, ]; export const PATTERNS: FieldConfig[] = [ - { - id: 'FAQ', - title: 'FAQ', - description: 'a FAQ form', - Class: FaqWidget, - } + { + id: 'FAQ', + title: 'FAQ', + description: 'a FAQ form', + Class: FaqWidget, + }, ]; export const PROPERTIES = [ - ...PRIMITIVE_PROPERTIES, - ...CONTAINER_PROPERTIES, - // ...STRING_WIDGETS, - // ...PATTERNS -] - + ...PRIMITIVE_PROPERTIES, + ...CONTAINER_PROPERTIES, + // ...STRING_WIDGETS, + // ...PATTERNS +]; diff --git a/src/fields/JsonSchemaField.ts b/src/fields/JsonSchemaField.ts index 7f42801..91d3e7c 100644 --- a/src/fields/JsonSchemaField.ts +++ b/src/fields/JsonSchemaField.ts @@ -1,180 +1,180 @@ -import {JsonSchemaType, JsonSchema, SchemaAnnotation} from "../types"; +import { JsonSchemaType, JsonSchema, SchemaAnnotation } from '../types'; +import { SCHEMA_TYPE } from '../constants'; export class JsonSchemaField { - protected name: string; - - protected isRequired: boolean = false; - - protected type: JsonSchemaType; - - protected title?: string; - - protected description?: string; - - protected default?: unknown; - - protected readOnly?: boolean; - - protected writeOnly?: boolean; - - protected enum?: string[]; - - protected enumNames?: string[]; - - - constructor(name: string) { - this.name = name; - this.type = 'object'; - } - - public getName(): string { - return this.name; - } - - public getIsRequired(): boolean { - return this.isRequired; - } - - - protected setType(type: JsonSchemaType): JsonSchemaField { - this.type = type; - return this; - } - - private setTitle(title: string): JsonSchemaField { - this.title = title; - return this; - } - - private setDescription(description: string): JsonSchemaField { - this.description = description; - return this; - } - - setEnum(_enum: string[]): this { - this.enum = _enum; - return this; - } - - setEnumNames(enumNames: string[]): this { - this.enumNames = enumNames; - return this; - } - - private setDefault(value: unknown): JsonSchemaField { - this.default = value; - return this; - } - - private setReadOnly(readOnly: boolean): JsonSchemaField { - this.readOnly = readOnly; - return this; - } - - private setWriteOnly(writeOnly: boolean): JsonSchemaField { - this.writeOnly = writeOnly; - return this; - } - - private setIsRequired(isRequired: boolean): JsonSchemaField { - this.isRequired = isRequired; - return this; - } - - public setSchema(schema: SchemaAnnotation & { - isRequired?: boolean, options: { - enum: string; - enumNames: string; - }[] - }): void { - if (schema.type) this.setType(schema.type) - if (schema.title) this.setTitle(schema.title) - if (schema.description) this.setDescription(schema.description) - if (schema.default) this.setDefault(schema.default) - if (schema.readOnly) this.setReadOnly(schema.readOnly) - if (schema.writeOnly) this.setWriteOnly(schema.writeOnly) - if (schema.isRequired) this.setIsRequired(schema.isRequired) - - const options = { - enum: schema.options?.map((option) => option.enum) || [], - enumNames: schema.options?.map((option) => option.enumNames) || [], - } - - if (options.enum?.length > 0) this.setEnum(options.enum) - if (options.enumNames?.length > 0) this.setEnumNames(options.enumNames) - } - - - public getSchema(): JsonSchema { - return { - type: this.type, - title: this.title, - description: this.description, - default: this.default, - readOnly: this.readOnly, - writeOnly: this.writeOnly, - enum: this.enum, - enumNames: this.enumNames - }; - - } - - public getBuilderSchema(): JsonSchema { - return { - type: 'object', + protected name: string; + + protected isRequired: boolean = false; + + protected type: JsonSchemaType; + + protected title?: string; + + protected description?: string; + + protected default?: unknown; + + protected readOnly?: boolean; + + protected writeOnly?: boolean; + + protected enum?: string[]; + + protected enumNames?: string[]; + + constructor(name: string) { + this.name = name; + this.type = 'object'; + } + + public getName(): string { + return this.name; + } + + public getIsRequired(): boolean { + return this.isRequired; + } + + protected setType(type: JsonSchemaType): JsonSchemaField { + this.type = type; + return this; + } + + private setTitle(title: string): JsonSchemaField { + this.title = title; + return this; + } + + private setDescription(description: string): JsonSchemaField { + this.description = description; + return this; + } + + setEnum(_enum: string[]): this { + this.enum = _enum; + return this; + } + + setEnumNames(enumNames: string[]): this { + this.enumNames = enumNames; + return this; + } + + private setDefault(value: unknown): JsonSchemaField { + this.default = value; + return this; + } + + private setReadOnly(readOnly: boolean): JsonSchemaField { + this.readOnly = readOnly; + return this; + } + + private setWriteOnly(writeOnly: boolean): JsonSchemaField { + this.writeOnly = writeOnly; + return this; + } + + private setIsRequired(isRequired: boolean): JsonSchemaField { + this.isRequired = isRequired; + return this; + } + + public setSchema( + schema: SchemaAnnotation & { + isRequired?: boolean; + options?: { + enum: string; + enumNames: string; + }[]; + }, + ): void { + if (schema.type) this.setType(schema.type); + if (schema.title) this.setTitle(schema.title); + if (schema.description) this.setDescription(schema.description); + if (schema.default) this.setDefault(schema.default); + if (schema.readOnly) this.setReadOnly(schema.readOnly); + if (schema.writeOnly) this.setWriteOnly(schema.writeOnly); + if (schema.isRequired) this.setIsRequired(schema.isRequired); + + const options = { + enum: schema.options?.map((option) => option.enum) || [], + enumNames: schema.options?.map((option) => option.enumNames) || [], + }; + + if (options.enum?.length > 0) this.setEnum(options.enum); + if (options.enumNames?.length > 0) this.setEnumNames(options.enumNames); + } + + public getSchema(): JsonSchema { + return { + type: this.type, + title: this.title, + description: this.description, + default: this.default, + readOnly: this.readOnly, + writeOnly: this.writeOnly, + enum: this.enum, + enumNames: this.enumNames, + }; + } + + public getBuilderSchema(): JsonSchema { + return { + type: SCHEMA_TYPE.OBJECT, + properties: { + type: { + type: SCHEMA_TYPE.STRING, + title: 'Field type', + enum: Object.values(SCHEMA_TYPE), + }, + title: { + type: SCHEMA_TYPE.STRING, + title: 'Field Title', + }, + description: { + type: SCHEMA_TYPE.STRING, + title: 'Field Description', + }, + default: { + type: SCHEMA_TYPE.STRING, + title: 'Field Default', + }, + readOnly: { + type: SCHEMA_TYPE.BOOLEAN, + title: 'Field is ReadOnly', + }, + writeOnly: { + type: SCHEMA_TYPE.BOOLEAN, + title: 'Field is WriteOnly', + }, + isRequired: { + type: SCHEMA_TYPE.BOOLEAN, + title: 'Field is required', + }, + options: { + type: SCHEMA_TYPE.ARRAY, + title: 'Options', + description: 'Here you can add options for the select field', + items: { + type: SCHEMA_TYPE.OBJECT, properties: { - type: { - type: 'string', - title: 'Field type', - enum: ['string', 'number', 'boolean', 'integer', 'array', 'object'] - }, - title: { - type: 'string', - title: 'Field Title' - }, - description: { - type: 'string', - title: 'Field Description' - }, - default: { - type: 'string', - title: 'Field Default' - }, - readOnly: { - type: 'boolean', - title: 'Field is ReadOnly' - }, - writeOnly: { - type: 'boolean', - title: 'Field is WriteOnly' - }, - isRequired: { - type: 'boolean', - title: 'Field is required' - }, - options: { - type: "array", - title: "Options", - description: "Here you can add options for the select field", - items: { - type: "object", - properties: { - enum: { - type: this.getSchema()?.type || 'string', - title: "Value of the option", - description: "The value that is going to be in the form", - }, - enumNames: { - type: "string", - title: "Title of the option", - description: "The title that is going to be shown to user", - }, - }, - required: ["enum", "enumNames"], - } - } + enum: { + type: this.getSchema()?.type || SCHEMA_TYPE.STRING, + title: 'Value of the option', + description: 'The value that is going to be in the form', + }, + enumNames: { + type: SCHEMA_TYPE.STRING, + title: 'Title of the option', + description: 'The title that is going to be shown to user', + }, }, - required: ['title', 'type'], - } - } -} \ No newline at end of file + required: ['enum', 'enumNames'], + }, + }, + }, + required: ['title', 'type'], + }; + } +} diff --git a/src/fields/containers/ArrayField.ts b/src/fields/containers/ArrayField.ts index cbc0242..17f3b6b 100644 --- a/src/fields/containers/ArrayField.ts +++ b/src/fields/containers/ArrayField.ts @@ -1,122 +1,123 @@ -import {JsonSchemaField} from "../JsonSchemaField"; -import {produce} from "immer"; -import {JsonSchema, JsonSchemaType, SchemaAnnotation} from "../../types"; +import { JsonSchemaField } from '../JsonSchemaField'; +import { produce } from 'immer'; +import { JsonSchema, JsonSchemaType, SchemaAnnotation } from '../../types'; +import { SCHEMA_TYPE } from '../../constants'; export type ArrayFieldType = SchemaAnnotation & { - items?: JsonSchema | JsonSchema[]; - itemsType?: JsonSchemaType; - prefixItems?: object; // TODO: fix type - unevaluatedItems?: boolean | object; - maxItems?: number; - minItems?: number; -} + items?: JsonSchema | JsonSchema[]; + itemsType?: JsonSchemaType; + prefixItems?: object; // TODO: fix type + unevaluatedItems?: boolean | object; + maxItems?: number; + minItems?: number; +}; export class ArrayField extends JsonSchemaField { - protected items?: JsonSchema | JsonSchema[]; - - protected itemsType?: JsonSchemaType; - - protected maxItems?: number; - - protected minItems?: number; - - protected prefixItems?: object; - - protected unevaluatedItems?: boolean | object; - - constructor(name: string) { - super(name); - this.type = "array"; - } - - setItems(items: JsonSchema | JsonSchema[]): this { - this.items = items; - return this; - } - - - setItemsType(itemsType: JsonSchemaType): this { - this.itemsType = itemsType; - return this; - } - - setMaxItems(maxItems: number): this { - this.maxItems = maxItems; - return this; - } - - setMinItems(minItems: number): this { - this.minItems = minItems; - return this; - } - - setPrefixItems(prefixItems: object): this { - this.prefixItems = prefixItems; - return this; - } - - setUnevaluatedItems(unevaluatedItems: boolean | object): this { - this.unevaluatedItems = unevaluatedItems; - return this; - } - - setSchema(schema: ArrayFieldType & { itemsType?: JsonSchema }) { - super.setSchema(schema as SchemaAnnotation); - if (schema.itemsType) this.setItemsType(schema.itemsType); - if (schema.items) this.setItems({...schema.items, ...(this.itemsType && {type: this.itemsType})}); - if (schema.maxItems) this.setMaxItems(schema.maxItems); - if (schema.minItems) this.setMinItems(schema.minItems); - if (schema.prefixItems) this.setPrefixItems(schema.prefixItems); - if (schema.unevaluatedItems) this.setUnevaluatedItems(schema.unevaluatedItems); - - } - - - getBuilderSchema(): JsonSchema { - const arraySchema: Record = { - itemsType: { - title: 'Items Type', - type: 'string', - enum: ['string', 'number', 'boolean', 'integer', 'array', 'object'] - }, - prefixItems: { - title: 'prefixItems', - type: 'object' - }, - unevaluatedItems: { - title: 'unevaluatedItems', - type: 'object' - }, - minItems: { - title: "minItems", - type: "number", - }, - maxItems: { - title: "maxItems", - type: "number", - }, - } - - return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - Object.keys(arraySchema).forEach(key => { - if (draft.properties) draft.properties[key] = arraySchema[key]; - }) - draft.required = [...(draft.required || []), 'items'] - }); - } - - public getSchema(): JsonSchema { - return { - ...super.getSchema(), - items: { - type: this.itemsType, - ...this.items, - }, - prefixItems: this.prefixItems, - unevaluatedItems: this.unevaluatedItems, - minItems: this.minItems, - maxItems: this.maxItems, - } - } - + protected items?: JsonSchema | JsonSchema[]; + + protected itemsType?: JsonSchemaType; + + protected maxItems?: number; + + protected minItems?: number; + + protected prefixItems?: object; + + protected unevaluatedItems?: boolean | object; + + constructor(name: string) { + super(name); + this.type = SCHEMA_TYPE.ARRAY; + } + + setItems(items: JsonSchema | JsonSchema[]): this { + this.items = items; + return this; + } + + setItemsType(itemsType: JsonSchemaType): this { + this.itemsType = itemsType; + return this; + } + + setMaxItems(maxItems: number): this { + this.maxItems = maxItems; + return this; + } + + setMinItems(minItems: number): this { + this.minItems = minItems; + return this; + } + + setPrefixItems(prefixItems: object): this { + this.prefixItems = prefixItems; + return this; + } + + setUnevaluatedItems(unevaluatedItems: boolean | object): this { + this.unevaluatedItems = unevaluatedItems; + return this; + } + + setSchema(schema: ArrayFieldType & { itemsType?: JsonSchema }) { + super.setSchema(schema as SchemaAnnotation); + if (schema.itemsType) this.setItemsType(schema.itemsType); + if (schema.items) + this.setItems({ + ...schema.items, + ...(this.itemsType && { type: this.itemsType }), + }); + if (schema.maxItems) this.setMaxItems(schema.maxItems); + if (schema.minItems) this.setMinItems(schema.minItems); + if (schema.prefixItems) this.setPrefixItems(schema.prefixItems); + if (schema.unevaluatedItems) this.setUnevaluatedItems(schema.unevaluatedItems); + } + + getBuilderSchema(): JsonSchema { + const arraySchema: Record = { + itemsType: { + title: 'Items Type', + type: SCHEMA_TYPE.STRING, + enum: Object.values(SCHEMA_TYPE.OBJECT), + }, + prefixItems: { + title: 'prefixItems', + type: SCHEMA_TYPE.OBJECT, + }, + unevaluatedItems: { + title: 'unevaluatedItems', + type: SCHEMA_TYPE.OBJECT, + }, + minItems: { + title: 'minItems', + type: SCHEMA_TYPE.NUMBER, + }, + maxItems: { + title: 'maxItems', + type: SCHEMA_TYPE.NUMBER, + }, + }; + + return produce(super.getBuilderSchema(), (draft: JsonSchema) => { + Object.keys(arraySchema).forEach((key) => { + if (draft.properties) draft.properties[key] = arraySchema[key]; + }); + draft.required = [...(draft.required || []), 'items']; + }); + } + + public getSchema(): JsonSchema { + return { + ...super.getSchema(), + items: { + type: this.itemsType, + ...this.items, + }, + prefixItems: this.prefixItems, + unevaluatedItems: this.unevaluatedItems, + minItems: this.minItems, + maxItems: this.maxItems, + }; + } } diff --git a/src/fields/containers/ObjectField.ts b/src/fields/containers/ObjectField.ts index 915806c..f0e5c8b 100644 --- a/src/fields/containers/ObjectField.ts +++ b/src/fields/containers/ObjectField.ts @@ -1,13 +1,14 @@ -import {JsonSchemaField} from "../JsonSchemaField"; -import {produce} from "immer"; -import {JsonSchema, SchemaAnnotation} from "../../types"; +import { JsonSchemaField } from '../JsonSchemaField'; +import { produce } from 'immer'; +import { JsonSchema, SchemaAnnotation } from '../../types'; +import { SCHEMA_TYPE } from '../../constants'; export type ObjectFieldType = SchemaAnnotation & { properties?: Record; required?: string[]; patternProperties?: object; // TODO: fix type additionalProperties?: object; // TODO: fix type -} +}; export class ObjectField extends JsonSchemaField { protected properties?: JsonSchema; @@ -15,16 +16,15 @@ export class ObjectField extends JsonSchemaField { protected patternProperties?: object; protected additionalProperties?: object; - constructor(name: string) { + constructor(name: string) { super(name); - this.type = "object"; + this.type = SCHEMA_TYPE.OBJECT; } addProperty(name: string, propSchema: JsonSchema): this { if (!this.properties) { this.properties = {}; } - // @ts-expect-error this.properties[name] = propSchema; return this; } @@ -48,35 +48,34 @@ export class ObjectField extends JsonSchemaField { } setSchema(schema: ObjectFieldType) { - super.setSchema(schema); - Object.keys(schema.properties || {}).forEach(property => { - if (schema.properties) this.addProperty(property, schema.properties[property]) - }) - if (schema.required) this.addRequired(...schema.required) - if (schema.patternProperties) this.setPatternProperties(schema.patternProperties) - if (schema.additionalProperties) this.setAdditionalProperties(schema.additionalProperties) + super.setSchema(schema); + Object.keys(schema.properties || {}).forEach((property) => { + if (schema.properties) this.addProperty(property, schema.properties[property]); + }); + if (schema.required) this.addRequired(...schema.required); + if (schema.patternProperties) this.setPatternProperties(schema.patternProperties); + if (schema.additionalProperties) this.setAdditionalProperties(schema.additionalProperties); } getBuilderSchema(): JsonSchema { const objectSchema: Record = { properties: { - type: "object", - title: "Properties", + type: SCHEMA_TYPE.OBJECT, + title: 'Properties', }, patternProperties: { - type: "object", - title: "Pattern Properties", + type: SCHEMA_TYPE.OBJECT, + title: 'Pattern Properties', }, additionalProperties: { - type: "object", - title: "Additional Properties", + type: SCHEMA_TYPE.OBJECT, + title: 'Additional Properties', }, - } + }; return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - Object.keys(objectSchema).forEach(key => { + Object.keys(objectSchema).forEach((key) => { if (draft.properties) draft.properties[key] = objectSchema[key]; - }) + }); }); } - } diff --git a/src/fields/patterns/FaqWidget.ts b/src/fields/patterns/FaqWidget.ts index 6a2e819..f53c1fa 100644 --- a/src/fields/patterns/FaqWidget.ts +++ b/src/fields/patterns/FaqWidget.ts @@ -1,42 +1,42 @@ -import {StringField} from "../primitives/StringField"; -import {ObjectField, ObjectFieldType} from "../containers/ObjectField"; -import {produce} from "immer"; -import {ArrayField} from "../containers/ArrayField"; -import {JsonSchema} from "../../types"; +import { StringField } from '../primitives/StringField'; +import { ObjectField, ObjectFieldType } from '../containers/ObjectField'; +import { produce } from 'immer'; +import { ArrayField } from '../containers/ArrayField'; +import { JsonSchema } from '../../types'; +import { SCHEMA_TYPE } from '../../constants'; export type FaqType = ObjectFieldType; export class FaqWidget extends ArrayField { - constructor(name: string) { - super(name); - this.title = "Frequently Asked Questions"; - this.setSchema({ - items: { - // @ts-expect-error TODO: fix - question: { - type: 'string', - title: 'FAQ Question', - }, - answer: { - type: 'string', - title: 'FAQ Answer', - } - } - }) - } - - getBuilderSchema(): JsonSchema { - // TODO: fix - return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - const items = new ObjectField('items'); - items.setSchema({ - properties: { - question: new StringField('question').getBuilderSchema(), - answers: new StringField('answers').getBuilderSchema(), - } - }) - if (draft?.items) draft.items = items.getBuilderSchema() - }) - } + constructor(name: string) { + super(name); + this.title = 'Frequently Asked Questions'; + this.setSchema({ + items: { + // @ts-expect-error TODO: fix + question: { + type: SCHEMA_TYPE.STRING, + title: 'FAQ Question', + }, + answer: { + type: SCHEMA_TYPE.STRING, + title: 'FAQ Answer', + }, + }, + }); + } + getBuilderSchema(): JsonSchema { + // TODO: fix + return produce(super.getBuilderSchema(), (draft: JsonSchema) => { + const items = new ObjectField('items'); + items.setSchema({ + properties: { + question: new StringField('question').getBuilderSchema(), + answers: new StringField('answers').getBuilderSchema(), + }, + }); + if (draft?.items) draft.items = items.getBuilderSchema(); + }); + } } diff --git a/src/fields/primitives/BooleanField.ts b/src/fields/primitives/BooleanField.ts index 8ac7c37..1a4f0af 100644 --- a/src/fields/primitives/BooleanField.ts +++ b/src/fields/primitives/BooleanField.ts @@ -1,11 +1,12 @@ -import {JsonSchemaField} from "../JsonSchemaField"; -import {SchemaAnnotation} from "../../types"; +import { JsonSchemaField } from '../JsonSchemaField'; +import { SchemaAnnotation } from '../../types'; +import { SCHEMA_TYPE } from '../../constants'; export type BooleanFieldType = SchemaAnnotation; export class BooleanField extends JsonSchemaField { constructor(name: string) { super(name); - this.type = "boolean"; + this.type = SCHEMA_TYPE.BOOLEAN; } } diff --git a/src/fields/primitives/IntegerField.ts b/src/fields/primitives/IntegerField.ts index 89930fb..bfbaccd 100644 --- a/src/fields/primitives/IntegerField.ts +++ b/src/fields/primitives/IntegerField.ts @@ -1,11 +1,12 @@ -import { JsonSchemaField } from "../JsonSchemaField"; -import {SchemaAnnotation} from "../../types"; +import { JsonSchemaField } from '../JsonSchemaField'; +import { SchemaAnnotation } from '../../types'; +import { SCHEMA_TYPE } from '../../constants'; export type IntegerFieldType = SchemaAnnotation; export class IntegerField extends JsonSchemaField { - constructor(name: string) { + constructor(name: string) { super(name); - this.type = "integer"; + this.type = SCHEMA_TYPE.INTEGER; } } diff --git a/src/fields/primitives/NumberField.ts b/src/fields/primitives/NumberField.ts index afdeda8..81ee926 100644 --- a/src/fields/primitives/NumberField.ts +++ b/src/fields/primitives/NumberField.ts @@ -1,6 +1,7 @@ -import {JsonSchemaField} from "../JsonSchemaField"; -import {JsonSchema, SchemaAnnotation} from "../../types"; -import {produce} from "immer"; +import { JsonSchemaField } from '../JsonSchemaField'; +import { JsonSchema, SchemaAnnotation } from '../../types'; +import { produce } from 'immer'; +import { SCHEMA_TYPE } from '../../constants'; export type NumberFieldType = SchemaAnnotation & { multipleOf?: number; @@ -8,7 +9,7 @@ export type NumberFieldType = SchemaAnnotation & { minimum?: number; exclusiveMaximum?: boolean; exclusiveMinimum?: boolean; -} +}; export class NumberField extends JsonSchemaField { protected multipleOf?: number; @@ -17,9 +18,9 @@ export class NumberField extends JsonSchemaField { protected exclusiveMaximum?: boolean; protected exclusiveMinimum?: boolean; - constructor(name: string) { + constructor(name: string) { super(name); - this.type = "number"; + this.type = SCHEMA_TYPE.NUMBER; } setMultipleOf(multipleOf: number): this { @@ -50,31 +51,31 @@ export class NumberField extends JsonSchemaField { getBuilderSchema(): JsonSchema { const numberSchema: Record = { multipleOf: { - type: "number", - title: "Multiple Of", + type: SCHEMA_TYPE.NUMBER, + title: 'Multiple Of', }, maximum: { - type: "number", - title: "Maximum", + type: SCHEMA_TYPE.NUMBER, + title: 'Maximum', }, minimum: { - type: "number", - title: "Minimum", + type: SCHEMA_TYPE.NUMBER, + title: 'Minimum', }, exclusiveMaximum: { - type: "boolean", - title: "Field has exclusive maximum", + type: SCHEMA_TYPE.BOOLEAN, + title: 'Field has exclusive maximum', }, exclusiveMinimum: { - type: "boolean", - title: "Field has exclusive minimum", + type: SCHEMA_TYPE.BOOLEAN, + title: 'Field has exclusive minimum', }, - } + }; return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - Object.keys(numberSchema).forEach(key => { + Object.keys(numberSchema).forEach((key) => { if (draft.properties) draft.properties[key] = numberSchema[key]; - }) + }); }); } @@ -86,15 +87,15 @@ export class NumberField extends JsonSchemaField { minimum: this.minimum, exclusiveMaximum: this.exclusiveMaximum, exclusiveMinimum: this.exclusiveMinimum, - } + }; } public setSchema(schema: NumberFieldType): void { super.setSchema(schema); - if (schema.multipleOf) this.setMultipleOf(schema.multipleOf) - if (schema.maximum) this.setMaximum(schema.maximum) - if (schema.minimum) this.setMinimum(schema.minimum) - if (schema.exclusiveMaximum) this.setExclusiveMaximum(schema.exclusiveMaximum) - if (schema.exclusiveMinimum) this.setExclusiveMinimum(schema.exclusiveMinimum) + if (schema.multipleOf) this.setMultipleOf(schema.multipleOf); + if (schema.maximum) this.setMaximum(schema.maximum); + if (schema.minimum) this.setMinimum(schema.minimum); + if (schema.exclusiveMaximum) this.setExclusiveMaximum(schema.exclusiveMaximum); + if (schema.exclusiveMinimum) this.setExclusiveMinimum(schema.exclusiveMinimum); } } diff --git a/src/fields/primitives/StringField.ts b/src/fields/primitives/StringField.ts index c845e71..f59bc0e 100644 --- a/src/fields/primitives/StringField.ts +++ b/src/fields/primitives/StringField.ts @@ -1,133 +1,132 @@ -import {JsonSchemaField} from "../JsonSchemaField"; -import {Format, SchemaAnnotation, JsonSchema} from "../../types"; -import {produce} from "immer" +import { JsonSchemaField } from '../JsonSchemaField'; +import { Format, SchemaAnnotation, JsonSchema } from '../../types'; +import { produce } from 'immer'; +import { SCHEMA_TYPE } from '../../constants'; export type StringFieldType = SchemaAnnotation & { - maxLength?: number; - minLength?: number; - pattern?: string; - format?: Format; - contentEncoding?: string; - contentMediaType?: string; -} + maxLength?: number; + minLength?: number; + pattern?: string; + format?: Format; + contentEncoding?: string; + contentMediaType?: string; +}; export class StringField extends JsonSchemaField { - protected maxLength?: number; - - protected minLength?: number; - - protected pattern?: string; - - protected format?: Format; - - protected contentEncoding?: string; - - protected contentMediaType?: string; - - constructor(name: string) { - super(name); - this.setType('string'); - } - - setMaxLength(maxLength: number): this { - this.maxLength = maxLength; - return this; - } - - setMinLength(minLength: number): this { - this.minLength = minLength; - return this; - } - - setPattern(pattern: string): this { - this.pattern = pattern; - return this; - } - - setFormat(format: Format): this { - this.format = format; - return this; - } - - setContentEncoding(contentEncoding: string): this { - this.contentEncoding = contentEncoding; - return this; - } - - setContentMediaType(contentMediaType: string): this { - this.contentMediaType = contentMediaType; - return this; - } - - getBuilderSchema(): JsonSchema { - - const stringSchema: Record = { - maxLength: { - type: "integer", - title: "Max Length", - }, - minLength: { - type: "integer", - title: "Min Length", - }, - pattern: { - type: "string", - title: "RegEx Pattern", - }, - format: { - type: "string", - title: "Format", - enum: [ - "date-time", - "time", - "date", - "duration", - "email", - "idn-email", - "hostname", - "idn-hostname", - "ipv4", - "ipv6", - "uuid", - "uri", - "uri-reference", - "iri", - "iri-reference", - "uri-template", - "json-pointer", - "relative-json-pointer", - "regex", - ], - }, - } - - return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - Object.keys(stringSchema).forEach(key => { - if (draft.properties) draft.properties[key] = stringSchema[key]; - }) - }); - } - - public setSchema(schema: StringFieldType): void { - super.setSchema(schema); - if (schema.maxLength) this.setMaxLength(schema.maxLength) - if (schema.minLength) this.setMinLength(schema.minLength) - if (schema.pattern) this.setPattern(schema.pattern) - if (schema.format) this.setFormat(schema.format) - if (schema.contentEncoding) this.setContentEncoding(schema.contentEncoding) - if (schema.contentMediaType) this.setContentMediaType(schema.contentMediaType) - } - - public getSchema(): JsonSchema { - return { - ...super.getSchema(), - maxLength: this.maxLength, - minLength: this.minLength, - pattern: this.pattern, - format: this.format, - contentEncoding: this.contentEncoding, - contentMediaType: this.contentMediaType, - } - } + protected maxLength?: number; + + protected minLength?: number; + + protected pattern?: string; + + protected format?: Format; + + protected contentEncoding?: string; + + protected contentMediaType?: string; + + constructor(name: string) { + super(name); + this.setType(SCHEMA_TYPE.STRING); + } + + setMaxLength(maxLength: number): this { + this.maxLength = maxLength; + return this; + } + + setMinLength(minLength: number): this { + this.minLength = minLength; + return this; + } + + setPattern(pattern: string): this { + this.pattern = pattern; + return this; + } + + setFormat(format: Format): this { + this.format = format; + return this; + } + + setContentEncoding(contentEncoding: string): this { + this.contentEncoding = contentEncoding; + return this; + } + + setContentMediaType(contentMediaType: string): this { + this.contentMediaType = contentMediaType; + return this; + } + + getBuilderSchema(): JsonSchema { + const stringSchema: Record = { + maxLength: { + type: SCHEMA_TYPE.INTEGER, + title: 'Max Length', + }, + minLength: { + type: SCHEMA_TYPE.INTEGER, + title: 'Min Length', + }, + pattern: { + type: SCHEMA_TYPE.STRING, + title: 'RegEx Pattern', + }, + format: { + type: SCHEMA_TYPE.STRING, + title: 'Format', + enum: [ + 'date-time', + 'time', + 'date', + 'duration', + 'email', + 'idn-email', + 'hostname', + 'idn-hostname', + 'ipv4', + 'ipv6', + 'uuid', + 'uri', + 'uri-reference', + 'iri', + 'iri-reference', + 'uri-template', + 'json-pointer', + 'relative-json-pointer', + 'regex', + ], + }, + }; + + return produce(super.getBuilderSchema(), (draft: JsonSchema) => { + Object.keys(stringSchema).forEach((key) => { + if (draft.properties) draft.properties[key] = stringSchema[key]; + }); + }); + } + + public setSchema(schema: StringFieldType): void { + super.setSchema(schema); + if (schema.maxLength) this.setMaxLength(schema.maxLength); + if (schema.minLength) this.setMinLength(schema.minLength); + if (schema.pattern) this.setPattern(schema.pattern); + if (schema.format) this.setFormat(schema.format); + if (schema.contentEncoding) this.setContentEncoding(schema.contentEncoding); + if (schema.contentMediaType) this.setContentMediaType(schema.contentMediaType); + } + + public getSchema(): JsonSchema { + return { + ...super.getSchema(), + maxLength: this.maxLength, + minLength: this.minLength, + pattern: this.pattern, + format: this.format, + contentEncoding: this.contentEncoding, + contentMediaType: this.contentMediaType, + }; + } } - \ No newline at end of file diff --git a/src/fields/widgets/DateField.ts b/src/fields/widgets/DateField.ts index d02559e..8147d43 100644 --- a/src/fields/widgets/DateField.ts +++ b/src/fields/widgets/DateField.ts @@ -1,11 +1,10 @@ -import {StringField, StringFieldType} from "../primitives/StringField"; +import { StringField, StringFieldType } from '../primitives/StringField'; export type DateType = StringFieldType; export class DateField extends StringField { - constructor(name: string) { + constructor(name: string) { super(name); - this.type = "string"; - this.format = "date" + this.format = 'date'; } } diff --git a/src/fields/widgets/DateTimeField.ts b/src/fields/widgets/DateTimeField.ts index a4c765c..cec05af 100644 --- a/src/fields/widgets/DateTimeField.ts +++ b/src/fields/widgets/DateTimeField.ts @@ -1,10 +1,10 @@ -import {StringField, StringFieldType} from "../primitives/StringField"; +import { StringField, StringFieldType } from '../primitives/StringField'; export type DateTimeType = StringFieldType; export class DateTimeField extends StringField { - constructor(name: string) { + constructor(name: string) { super(name); - this.format = "date-time" + this.format = 'date-time'; } } diff --git a/src/fields/widgets/SelectField.ts b/src/fields/widgets/SelectField.ts index 3bd78a7..87f8758 100644 --- a/src/fields/widgets/SelectField.ts +++ b/src/fields/widgets/SelectField.ts @@ -1,83 +1,84 @@ -import {StringField, StringFieldType} from "../primitives/StringField"; -import {JsonSchema} from "../../types"; -import {produce} from "immer"; +import { StringField, StringFieldType } from '../primitives/StringField'; +import { JsonSchema } from '../../types'; +import { produce } from 'immer'; +import { SCHEMA_TYPE } from '../../constants'; export type SelectFieldType = StringFieldType & { - options: { - enum: string; - enumNames: string; - }[] + options: { + enum: string; + enumNames: string; + }[]; }; export class SelectField extends StringField { - protected enum?: string[]; + protected enum?: string[]; - protected enumNames?: string[]; - - constructor(name: string) { - super(name); - } + protected enumNames?: string[]; - setEnum(_enum: string[]): this { - this.enum = _enum; - return this; - } + constructor(name: string) { + super(name); + } - setEnumNames(enumNames: string[]): this { - this.enumNames = enumNames; - return this; - } + setEnum(_enum: string[]): this { + this.enum = _enum; + return this; + } - getBuilderSchema(): JsonSchema { - const enumSchema: Record = { - options: { - type: "array", - title: "Options", - minItems: 1, - description: "Here you can add options for the select field", - items: { - type: "object", - properties: { - enum: { - type: "string", - title: "Value of the option", - description: "The value that is going to be in the form", - }, - enumNames: { - type: "string", - title: "Title of the option", - description: "The title that is going to be shown to user", - }, - }, - required: ["enum", "enumNames"], - } - } - } + setEnumNames(enumNames: string[]): this { + this.enumNames = enumNames; + return this; + } - return produce(super.getBuilderSchema(), (draft: JsonSchema) => { - Object.keys(enumSchema).forEach(key => { - if (draft.properties) draft.properties[key] = enumSchema[key]; - }) - }); - } + getBuilderSchema(): JsonSchema { + const enumSchema: Record = { + options: { + type: SCHEMA_TYPE.ARRAY, + title: 'Options', + minItems: 1, + description: 'Here you can add options for the select field', + items: { + type: SCHEMA_TYPE.OBJECT, + properties: { + enum: { + type: SCHEMA_TYPE.STRING, + title: 'Value of the option', + description: 'The value that is going to be in the form', + }, + enumNames: { + type: SCHEMA_TYPE.STRING, + title: 'Title of the option', + description: 'The title that is going to be shown to user', + }, + }, + required: ['enum', 'enumNames'], + }, + }, + }; - public getSchema(): JsonSchema { - return { - ...super.getSchema(), - enum: this.enum, - enumNames: this.enumNames, - } - } + return produce(super.getBuilderSchema(), (draft: JsonSchema) => { + Object.keys(enumSchema).forEach((key) => { + if (draft.properties) draft.properties[key] = enumSchema[key]; + }); + }); + } - public setSchema(schema: SelectFieldType): void { - super.setSchema(schema); + public getSchema(): JsonSchema { + return { + ...super.getSchema(), + enum: this.enum, + enumNames: this.enumNames, + }; + } - const options = { - enum: schema.options?.map((option) => option.enum) || [], - enumNames: schema.options?.map((option) => option.enumNames) || [], - } + public setSchema(schema: SelectFieldType): void { + super.setSchema(schema); - if (options.enum?.length > 0) this.setEnum(options.enum) - if (options.enumNames?.length > 0) this.setEnumNames(options.enumNames) - } + const options = { + enum: schema.options?.map((option) => option.enum) || [], + enumNames: schema.options?.map((option) => option.enumNames) || [], + }; + + if (options.enum?.length > 0) this.setEnum(options.enum); + if (options.enumNames?.length > 0) this.setEnumNames(options.enumNames); + } } diff --git a/src/fields/widgets/TimeField.ts b/src/fields/widgets/TimeField.ts index 17a7879..79df4ec 100644 --- a/src/fields/widgets/TimeField.ts +++ b/src/fields/widgets/TimeField.ts @@ -1,11 +1,10 @@ -import {StringField, StringFieldType} from "../primitives/StringField"; +import { StringField, StringFieldType } from '../primitives/StringField'; export type TimeType = StringFieldType; export class TimeField extends StringField { - constructor(name: string) { + constructor(name: string) { super(name); - this.type = "string"; - this.format = "time" + this.format = 'time'; } } diff --git a/src/providers/SchemaProvider.tsx b/src/providers/SchemaProvider.tsx index e936f2e..6e3b9e4 100644 --- a/src/providers/SchemaProvider.tsx +++ b/src/providers/SchemaProvider.tsx @@ -1,137 +1,121 @@ -import React, {createContext, Dispatch, ReactNode, useContext, useReducer} from "react"; -import {JsonSchemaBuilder} from "../builder/JsonSchemaBuilder"; -import {FieldConfig, JsonSchema} from "../types"; -import {PROPERTIES} from "../constants"; -import {RJSFSchema} from "@rjsf/utils"; - +import React, { createContext, Dispatch, ReactNode, useContext, useReducer } from 'react'; +import { JsonSchemaBuilder } from '../builder/JsonSchemaBuilder'; +import { FieldConfig, JsonSchema } from '../types'; +import { PROPERTIES, SCHEMA_TYPE } from '../constants'; +import { RJSFSchema } from '@rjsf/utils'; export interface SchemaAction { - type: "ADD_PROPERTY" | "UPDATE_PROPERTY" | "DELETE_PROPERTY" | "ADD_REQUIRED" | "DELETE_REQUIRED"; - payload: { name: string; schema?: JsonSchema; value?: any }; + type: 'ADD_PROPERTY' | 'UPDATE_PROPERTY' | 'DELETE_PROPERTY' | 'ADD_REQUIRED' | 'DELETE_REQUIRED'; + payload: { name: string; schema?: JsonSchema; value?: never }; } const addAnnotations = (builder: JsonSchemaBuilder, state: JsonSchema) => { - builder.setType(state.type || "object"); - if (state.title) builder.setTitle(state.title); - if (state.description) builder.setDescription(state.description); - if (state.default) builder.setDefault(state.default); - if (state.readOnly) builder.setReadOnly(state.readOnly); - if (state.writeOnly) builder.setWriteOnly(state.writeOnly); + builder.setType(state.type || 'object'); + if (state.title) builder.setTitle(state.title); + if (state.description) builder.setDescription(state.description); + if (state.default) builder.setDefault(state.default); + if (state.readOnly) builder.setReadOnly(state.readOnly); + if (state.writeOnly) builder.setWriteOnly(state.writeOnly); }; - export const SchemaContext = createContext<{ - schema: JsonSchema; - dispatch: Dispatch; - fields: FieldConfig[]; + schema: JsonSchema; + dispatch: Dispatch; + fields: FieldConfig[]; }>({ - schema: new JsonSchemaBuilder().setType("object").build(), - dispatch: () => null, - fields: [] + schema: new JsonSchemaBuilder().setType('object').build(), + dispatch: () => null, + fields: [], }); -const addSpecificProperties = ( - builder: JsonSchemaBuilder, - state: JsonSchema -) => { - switch (state.type) { - case "string": - if (state.maxLength) builder.setMaxLength(state.maxLength); - if (state.minLength) builder.setMinLength(state.minLength); - if (state.pattern) builder.setPattern(state.pattern); - if (state.format) builder.setFormat(state.format); - if (state.contentEncoding) - builder.setContentEncoding(state.contentEncoding); - if (state.contentMediaType) - builder.setContentMediaType(state.contentMediaType); - break; - case "number": - if (state.multipleOf) builder.setMultipleOf(state.multipleOf); - if (state.maximum) builder.setMaximum(state.maximum); - if (state.minimum) builder.setMinimum(state.minimum); - if (state.exclusiveMaximum) - builder.setExclusiveMaximum(state.exclusiveMaximum); - if (state.exclusiveMinimum) - builder.setExclusiveMinimum(state.exclusiveMinimum); - break; - case "object": - if (state.properties) { - Object.keys(state.properties).forEach((key) => { - if (state.properties?.[key]) - builder.addProperty(key, state.properties[key]); - }); - } - if (state.required) { - builder.addRequired(...state.required); - } - if (state.patternProperties) - builder.setPatternProperties(state.patternProperties); - if (state.additionalProperties) - builder.setAdditionalProperties(state.additionalProperties); - - break; - case "array": - if (state.items) builder.setItems(state.items); - if (state.prefixItems) builder.setPrefixItems(state.prefixItems); - if (state.unevaluatedItems) - builder.setUnevaluatedItems(state.unevaluatedItems); - if (state.maxItems) builder.setMaxItems(state.maxItems); - if (state.minItems) builder.setMinItems(state.minItems); - break; - default: - break; - } +const addSpecificProperties = (builder: JsonSchemaBuilder, state: JsonSchema) => { + switch (state.type) { + case SCHEMA_TYPE.STRING: + if (state.maxLength) builder.setMaxLength(state.maxLength); + if (state.minLength) builder.setMinLength(state.minLength); + if (state.pattern) builder.setPattern(state.pattern); + if (state.format) builder.setFormat(state.format); + if (state.contentEncoding) builder.setContentEncoding(state.contentEncoding); + if (state.contentMediaType) builder.setContentMediaType(state.contentMediaType); + break; + case SCHEMA_TYPE.NUMBER: + if (state.multipleOf) builder.setMultipleOf(state.multipleOf); + if (state.maximum) builder.setMaximum(state.maximum); + if (state.minimum) builder.setMinimum(state.minimum); + if (state.exclusiveMaximum) builder.setExclusiveMaximum(state.exclusiveMaximum); + if (state.exclusiveMinimum) builder.setExclusiveMinimum(state.exclusiveMinimum); + break; + case SCHEMA_TYPE.OBJECT: + if (state.properties) { + Object.keys(state.properties).forEach((key) => { + if (state.properties?.[key]) builder.addProperty(key, state.properties[key]); + }); + } + if (state.required) { + builder.addRequired(...state.required); + } + if (state.patternProperties) builder.setPatternProperties(state.patternProperties); + if (state.additionalProperties) builder.setAdditionalProperties(state.additionalProperties); + break; + + case SCHEMA_TYPE.ARRAY: + if (state.items) builder.setItems(state.items); + if (state.prefixItems) builder.setPrefixItems(state.prefixItems); + if (state.unevaluatedItems) builder.setUnevaluatedItems(state.unevaluatedItems); + if (state.maxItems) builder.setMaxItems(state.maxItems); + if (state.minItems) builder.setMinItems(state.minItems); + break; + default: + break; + } }; const schemaReducer = (state: JsonSchema, action: SchemaAction): JsonSchema => { - const builder = new JsonSchemaBuilder(); - - addAnnotations(builder, state); - addSpecificProperties(builder, state); - - if (state.enum) builder.setEnum(state.enum); - if (state.enumNames) builder.setEnumNames(state.enumNames); - - switch (action.type) { - case "ADD_PROPERTY": - builder.addNestedProperty(action.payload.name, action.payload.schema!); - break; - case "UPDATE_PROPERTY": - builder.editProperty(action.payload.name, action.payload.schema!); - break; - case "DELETE_PROPERTY": - builder.deleteProperty(action.payload.name); - break; - case "ADD_REQUIRED": - builder.addRequired(action.payload.name); - break; - case "DELETE_REQUIRED": - builder.deleteRequired(action.payload.name); - break; - default: - return state; - } - - return builder.build(); + const builder = new JsonSchemaBuilder(); + + addAnnotations(builder, state); + addSpecificProperties(builder, state); + + if (state.enum) builder.setEnum(state.enum); + if (state.enumNames) builder.setEnumNames(state.enumNames); + + switch (action.type) { + case 'ADD_PROPERTY': + builder.addNestedProperty(action.payload.name, action.payload.schema!); + break; + case 'UPDATE_PROPERTY': + builder.editProperty(action.payload.name, action.payload.schema!); + break; + case 'DELETE_PROPERTY': + builder.deleteProperty(action.payload.name); + break; + case 'ADD_REQUIRED': + builder.addRequired(action.payload.name); + break; + case 'DELETE_REQUIRED': + builder.deleteRequired(action.payload.name); + break; + default: + return state; + } + + return builder.build(); }; type Props = { - extraFields: FieldConfig[]; - children: ReactNode; - value?: RJSFSchema; + extraFields: FieldConfig[]; + children: ReactNode; + value?: RJSFSchema; }; -export const SchemaProvider = ({children, extraFields, value}: Props) => { - const [schema, dispatch] = useReducer( - schemaReducer, - value || new JsonSchemaBuilder().setType("object").build() - ); +export const SchemaProvider = ({ children, extraFields, value }: Props) => { + const [schema, dispatch] = useReducer(schemaReducer, value || new JsonSchemaBuilder().setType('object').build()); - return ( - - {children} - - ); + return ( + + {children} + + ); }; export const useSchema = () => useContext(SchemaContext); diff --git a/src/stories/SchemaBuilder.stories.tsx b/src/stories/SchemaBuilder.stories.tsx index 6cfc26b..3e6f65c 100644 --- a/src/stories/SchemaBuilder.stories.tsx +++ b/src/stories/SchemaBuilder.stories.tsx @@ -1,158 +1,157 @@ import React from 'react'; -import {Story, Meta} from '@storybook/react'; +import { Story, Meta } from '@storybook/react'; import SchemaBuilder from '../components/SchemaBuilder'; -import {STRING_WIDGETS} from "../constants"; -import {SchemaProvider} from "../providers/SchemaProvider"; -import {createTheme, ThemeProvider} from "@mui/material"; -import {RJSFSchema} from "@rjsf/utils"; +import { STRING_WIDGETS } from '../constants'; +import { SchemaProvider } from '../providers/SchemaProvider'; +import { createTheme, ThemeProvider } from '@mui/material'; +import { RJSFSchema } from '@rjsf/utils'; const sampleSchema: RJSFSchema = { - "title": "Example Schema", - "description": "A rich JSON schema example without dependencies and no nested objects.", - "type": "object", - "properties": { - "id": { - "title": "Identifier", - "description": "A unique identifier for the item.", - "type": "string", - "pattern": "^[a-zA-Z0-9-]+$" - }, - "name": { - "title": "Name", - "description": "The name of the item.", - "type": "string", - "minLength": 1 - }, - "type": { - "title": "Type", - "description": "The type of the item.", - "type": "string", - enum: ['grocery', 'cloths'], - enumNames: ['Grocery', 'Cloths'], - }, - "price": { - "title": "Price", - "description": "The price of the item.", - "type": "number", - "minimum": 0 - }, - "location": { - "title": "Location", - "description": "The coordination.", - "type": "object", - properties: { - lat: { - type: 'number', - title: "latitude" - }, - long: { - type: 'number', - title: "longitude" - }, - } - }, - "tags": { - "title": "Tags", - "description": "Tags associated with the item.", - "type": "array", - "items": { - "type": "string", - 'title': 'Tag Name' - }, - "uniqueItems": true + title: 'Example Schema', + description: 'A rich JSON schema example without dependencies and no nested objects.', + type: 'object', + properties: { + id: { + title: 'Identifier', + description: 'A unique identifier for the item.', + type: 'string', + pattern: '^[a-zA-Z0-9-]+$', + }, + name: { + title: 'Name', + description: 'The name of the item.', + type: 'string', + minLength: 1, + }, + type: { + title: 'Type', + description: 'The type of the item.', + type: 'string', + enum: ['grocery', 'cloths'], + enumNames: ['Grocery', 'Cloths'], + }, + price: { + title: 'Price', + description: 'The price of the item.', + type: 'number', + minimum: 0, + }, + location: { + title: 'Location', + description: 'The coordination.', + type: 'object', + properties: { + lat: { + type: 'number', + title: 'latitude', }, - "faq": { - "title": "FAQ", - "type": "array", - "items": { - "type": "object", - title: 'List of Questions', - properties: { - question: { - title: 'question', - type: 'string', - }, - answer: { - title: 'answer', - type: 'string', - } - } - }, - "uniqueItems": true + long: { + type: 'number', + title: 'longitude', }, - "birthday": { - "title": "Birthday Date", - "type": "string", - "minimum": 0, - "format": "date" + }, + }, + tags: { + title: 'Tags', + description: 'Tags associated with the item.', + type: 'array', + items: { + type: 'string', + title: 'Tag Name', + }, + uniqueItems: true, + }, + faq: { + title: 'FAQ', + type: 'array', + items: { + type: 'object', + title: 'List of Questions', + properties: { + question: { + title: 'question', + type: 'string', + }, + answer: { + title: 'answer', + type: 'string', + }, }, - "inStock": { - "title": "In Stock", - "description": "Indicates if the item is in stock.", - "type": "boolean" - } + }, + uniqueItems: true, + }, + birthday: { + title: 'Birthday Date', + type: 'string', + minimum: 0, + format: 'date', + }, + inStock: { + title: 'In Stock', + description: 'Indicates if the item is in stock.', + type: 'boolean', }, - "required": ["id", "name", "price"], - "additionalProperties": false + }, + required: ['id', 'name', 'price'], + additionalProperties: false, }; export default { - title: 'SchemaBuilder', - component: SchemaBuilder, + title: 'SchemaBuilder', + component: SchemaBuilder, } as Meta; const Template: Story = (args) => ( - - - + + + ); export const Primitives = Template.bind({}); Primitives.args = {}; - export const Formats = Template.bind({}); Formats.args = { - extraFields: [...STRING_WIDGETS] + extraFields: [...STRING_WIDGETS], }; const DefaultValueTemplate: Story = (args) => ( - - - + + + ); export const WithDefaultValue = DefaultValueTemplate.bind({}); WithDefaultValue.args = { - extraFields: [...STRING_WIDGETS] + extraFields: [...STRING_WIDGETS], }; const ThemedTemplate: Story = (args) => { - const theme = createTheme(args.theme) - return ( - - - - - - ) + const theme = createTheme(args.theme); + return ( + + + + + + ); }; export const Themed = ThemedTemplate.bind({}); Themed.args = { - extraFields: [...STRING_WIDGETS], - theme: { - palette: { - primary: { - main: '#ff5722' - }, - mode: 'dark' + extraFields: [...STRING_WIDGETS], + theme: { + palette: { + primary: { + main: '#ff5722', + }, + mode: 'dark', + }, + components: { + MuiInput: { + defaultProps: { + size: 'small', }, - components: { - MuiInput: { - defaultProps: { - size: 'small' - } - } - } - } -}; \ No newline at end of file + }, + }, + }, +}; diff --git a/src/types.ts b/src/types.ts index a3bba91..b2c72de 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,81 +1,70 @@ -import {StringFieldType} from "./fields/primitives/StringField"; -import {NumberFieldType} from "./fields/primitives/NumberField"; -import {ObjectFieldType} from "./fields/containers/ObjectField"; -import {ArrayFieldType} from "./fields/containers/ArrayField"; -import {IntegerFieldType} from "./fields/primitives/IntegerField"; -import {BooleanFieldType} from "./fields/primitives/BooleanField"; -import {JsonSchemaField} from "./fields/JsonSchemaField"; -import {RJSFSchema} from "@rjsf/utils"; +import { StringField, StringFieldType } from './fields/primitives/StringField'; +import { NumberField, NumberFieldType } from './fields/primitives/NumberField'; +import { ObjectField, ObjectFieldType } from './fields/containers/ObjectField'; +import { ArrayField, ArrayFieldType } from './fields/containers/ArrayField'; +import { IntegerField, IntegerFieldType } from './fields/primitives/IntegerField'; +import { BooleanField, BooleanFieldType } from './fields/primitives/BooleanField'; +import { JsonSchemaField } from './fields/JsonSchemaField'; +import { RJSFSchema } from '@rjsf/utils'; +import { SCHEMA_TYPE } from './constants'; export type BuiltInFormats = - | "date-time" - | "time" - | "date" - | "duration" - | "email" - | "idn-email" - | "hostname" - | "idn-hostname" - | "ipv4" - | "ipv6" - | "uuid" - | "uri" - | "uri-reference" - | "iri" - | "iri-reference" - | "uri-template" - | "json-pointer" - | "relative-json-pointer" - | "regex"; + | 'date-time' + | 'time' + | 'date' + | 'duration' + | 'email' + | 'idn-email' + | 'hostname' + | 'idn-hostname' + | 'ipv4' + | 'ipv6' + | 'uuid' + | 'uri' + | 'uri-reference' + | 'iri' + | 'iri-reference' + | 'uri-template' + | 'json-pointer' + | 'relative-json-pointer' + | 'regex'; // TODO: fix export type Format = BuiltInFormats | string; - -export type JsonSchemaType = - | "string" - | "number" - | "integer" - | "object" - | "array" - | "boolean"; - +export type JsonSchemaType = (typeof SCHEMA_TYPE)[keyof typeof SCHEMA_TYPE]; export interface SchemaAnnotation { - type?: JsonSchemaType; - title?: string; - description?: string; - default?: unknown; - readOnly?: boolean; - writeOnly?: boolean; - enum?: string[]; // TODO: Generalize enum values - enumNames?: string[]; + type?: JsonSchemaType; + title?: string; + description?: string; + default?: unknown; + readOnly?: boolean; + writeOnly?: boolean; + enum?: string[]; // TODO: Generalize enum values + enumNames?: string[]; } -export type JsonSchema = - SchemaAnnotation - & StringFieldType - & NumberFieldType - & BooleanFieldType - & ObjectFieldType - & ArrayFieldType - & IntegerFieldType +export type JsonSchema = SchemaAnnotation & + StringFieldType & + NumberFieldType & + BooleanFieldType & + ObjectFieldType & + ArrayFieldType & + IntegerFieldType; export type FieldConfig = { - id: string; - title: string; - description: string; - Class: JsonSchemaField; -} - - -// Visualization + id: string; + title: string; + description: string; + Class: Partial; +}; export type DataVisualizationType = { - data?: object; - schema: RJSFSchema; - name?: string - path?: string -} + schema: RJSFSchema; + data: unknown; + name?: string; + path?: string; +}; -export type NestedObject = { [key: string]: any }; +export type NestedObject = { [key: string]: unknown }; diff --git a/src/utils.ts b/src/utils.ts index f3d8ea4..c0bdad3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,109 +1,107 @@ -import {RJSFSchema} from "@rjsf/utils"; -import {DataVisualizationType, NestedObject} from "./types"; +import { RJSFSchema } from '@rjsf/utils'; +import { DataVisualizationType, NestedObject } from './types'; +import { SCHEMA_TYPE } from './constants'; +import React from 'react'; export const getSchemaFormatFromSchema = ( - schema: RJSFSchema, - SchemaFormat: { - ({schema, data}: DataVisualizationType): JSX.Element; - String({schema, data}: DataVisualizationType): JSX.Element; - Boolean({schema, data}: DataVisualizationType): JSX.Element; - Image({schema, data}: DataVisualizationType): JSX.Element; - Video({schema, data}: DataVisualizationType): JSX.Element; - Object({schema, data}: DataVisualizationType): JSX.Element; - Array({schema, data}: DataVisualizationType): JSX.Element; - Url({schema, data}: DataVisualizationType): JSX.Element; - RichText({schema, data}: DataVisualizationType): JSX.Element; - Map({schema, data}: DataVisualizationType): JSX.Element; - Date({schema, data}: DataVisualizationType): JSX.Element; - DateTime({schema, data}: DataVisualizationType): JSX.Element; - Enum({schema, data}: DataVisualizationType): JSX.Element; - Number({schema, data}: DataVisualizationType): JSX.Element; - Color({schema, data}: DataVisualizationType): JSX.Element; - Unknown({schema, data}: DataVisualizationType): JSX.Element; - }, + schema: RJSFSchema, + SchemaFormat: { + ({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + String({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Boolean({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Object({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Array({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Enum({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Number({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Integer({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + Unknown({ schema, data, name, path }: DataVisualizationType): React.JSX.Element; + }, ) => { - if (schema?.enum?.length > 0) return SchemaFormat.Enum; - if (schema?.type === 'boolean') return SchemaFormat.Boolean; - // if (schema?.type === 'string' && schema?.format === 'image-url') return SchemaFormat.Image; - // if (schema?.type === 'string' && schema?.format === 'video-url') return SchemaFormat.Video; - // if (schema?.type === 'string' && schema?.format === 'uri') return SchemaFormat.Url; - // if (schema?.type === 'string' && schema?.format === 'advance') return SchemaFormat.RichText; - // if (schema?.type === 'string' && schema?.ui?.widget === 'color') return SchemaFormat.Color; - // if (schema?.format === 'date') return SchemaFormat.Date; - // if (schema?.format === 'date-time') return SchemaFormat.DateTime; - if (schema?.type === 'string') return SchemaFormat.String; - if (schema?.type === 'number' || schema?.type === 'integer') return SchemaFormat.Number; - if (schema?.type === 'object' && schema?.format === 'map') return SchemaFormat.Map; - if (schema?.type === 'object') return SchemaFormat.Object; - if (schema?.type === 'array') return SchemaFormat.Array; - return SchemaFormat.Unknown; + if (schema?.enum?.length > 0) return SchemaFormat.Enum; + if (schema?.type === SCHEMA_TYPE.BOOLEAN) return SchemaFormat.Boolean; + // if (schema?.type === 'string' && schema?.format === 'image-url') return SchemaFormat.Image; + // if (schema?.type === 'string' && schema?.format === 'video-url') return SchemaFormat.Video; + // if (schema?.type === 'string' && schema?.format === 'uri') return SchemaFormat.Url; + // if (schema?.type === 'string' && schema?.format === 'advance') return SchemaFormat.RichText; + // if (schema?.type === 'string' && schema?.ui?.widget === 'color') return SchemaFormat.Color; + // if (schema?.format === 'date') return SchemaFormat.Date; + // if (schema?.format === 'date-time') return SchemaFormat.DateTime; + if (schema?.type === SCHEMA_TYPE.STRING) return SchemaFormat.String; + if (schema?.type === SCHEMA_TYPE.NUMBER) return SchemaFormat.Number; + if (schema?.type === SCHEMA_TYPE.INTEGER) return SchemaFormat.Integer; + // if (schema?.type === 'object' && schema?.format === 'map') + // return SchemaFormat.Map; + if (schema?.type === SCHEMA_TYPE.OBJECT) return SchemaFormat.Object; + if (schema?.type === SCHEMA_TYPE.ARRAY) return SchemaFormat.Array; + return SchemaFormat.Unknown; }; export const getFieldId = (schema: RJSFSchema) => { - if (schema?.type === 'boolean') return 'BOOLEAN'; - if (schema?.format === 'date') return 'DATE'; - if (schema?.format === 'date-time') return 'DATE_TIME'; - if (schema?.format === 'time') return 'TIME'; - if (schema?.type === 'string') return 'STRING'; - if (schema?.type === 'number' || schema?.type === 'integer') return 'NUMBER'; - if (schema?.type === 'object') return 'OBJECT'; - if (schema?.type === 'array') return 'ARRAY'; -} + if (schema?.type === 'boolean') return 'BOOLEAN'; + if (schema?.format === 'date') return 'DATE'; + if (schema?.format === 'date-time') return 'DATE_TIME'; + if (schema?.format === 'time') return 'TIME'; + if (schema?.type === 'string') return 'STRING'; + if (schema?.type === 'integer') return 'INTEGER'; + if (schema?.type === 'number') return 'NUMBER'; + if (schema?.type === 'object') return 'OBJECT'; + if (schema?.type === 'array') return 'ARRAY'; +}; export const generatePath = (parentPath: string = '', fieldName: string): string => { - let path = parentPath; - if (path?.length > 0) path += '.'; - path += fieldName; - return path; -} + let path = parentPath; + if (path?.length > 0) path += '.'; + path += fieldName; + return path; +}; export const accessToObjectFieldByPath = (object: object, path: string) => { - return path.split('.').reduce((o, i) => o[i], object) -} + return path.split('.').reduce((o, i) => o[i], object); +}; -export const updateNestedObjectByPath = (obj: NestedObject, path: string, value: any): NestedObject => { - const keys = path.split('.'); - const newObject = {...obj}; +export const updateNestedObjectByPath = (obj: NestedObject, path: string, value: unknown): NestedObject => { + const keys = path.split('.'); + const newObject = { ...obj }; - let current = newObject; - keys.forEach((key, index) => { - if (index === keys.length - 1) { - current[key] = value; - } else { - current[key] = current[key] ? {...current[key]} : {}; - current = current[key]; - } - }); + let current = newObject; + keys.forEach((key, index) => { + if (index === keys.length - 1) { + current[key] = value; + } else { + current[key] = current[key] ? { ...current[key] } : {}; + current = current[key]; + } + }); - return newObject; -} + return newObject; +}; export const deleteNestedPropertyByPath = (obj: NestedObject, path: string): NestedObject => { - const keys = path.split('.'); - const newObject = {...obj}; + const keys = path.split('.'); + const newObject = { ...obj }; - if (keys.length === 0) { - return newObject; - } + if (keys.length === 0) { + return newObject; + } - let current = newObject; - const stack = []; + let current = newObject; + const stack = []; - for (let i = 0; i < keys.length - 1; i++) { - stack.push(current); - current[keys[i]] = {...current[keys[i]]}; - current = current[keys[i]]; - } + for (let i = 0; i < keys.length - 1; i++) { + stack.push(current); + current[keys[i]] = { ...current[keys[i]] }; + current = current[keys[i]]; + } - delete current[keys[keys.length - 1]]; + delete current[keys[keys.length - 1]]; - for (let i = keys.length - 2; i >= 0; i--) { - const key = keys[i]; - current = stack.pop(); - if (Object.keys(current[key]).length === 0) { - delete current[key]; - } + for (let i = keys.length - 2; i >= 0; i--) { + const key = keys[i]; + current = stack.pop(); + if (Object.keys(current[key]).length === 0) { + delete current[key]; } + } - return newObject; -} + return newObject; +};