From 1352d1e9286ce199b81368d1881692af39a83abe Mon Sep 17 00:00:00 2001 From: NJ veneracion Date: Fri, 29 Aug 2025 17:35:21 +0800 Subject: [PATCH 01/14] landing page done --- language/.vscode/settings.json | 5 +- package.json | 1 + packages/www | 1 + yarn.lock | 2315 +++++++++++++++++++++++++++++++- 4 files changed, 2310 insertions(+), 12 deletions(-) create mode 160000 packages/www diff --git a/language/.vscode/settings.json b/language/.vscode/settings.json index eb71540..cdd1b07 100644 --- a/language/.vscode/settings.json +++ b/language/.vscode/settings.json @@ -1,8 +1,9 @@ { - "editor.insertSpaces": false, + "editor.insertSpaces": true, "typescript.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single", "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" - } + }, + "editor.tabSize": 2, } \ No newline at end of file diff --git a/package.json b/package.json index 3965ace..2db9a68 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:transformer": "yarn --cwd packages/idea-transformer build", "build:idea": "yarn --cwd packages/idea build", "build:example": "yarn --cwd example build", + "dev": "yarn --cwd packages/www dev", "report": "yarn report:env nyc yarn test && nyc report -r lcov", "report:env": "NODE_OPTIONS=\"--disable-warning=ExperimentalWarning --experimental-loader @istanbuljs/esm-loader-hook\"", "transform": "yarn --cwd example transform", diff --git a/packages/www b/packages/www new file mode 160000 index 0000000..a85d864 --- /dev/null +++ b/packages/www @@ -0,0 +1 @@ +Subproject commit a85d8647636727f9ea38276e95a76b6640176338 diff --git a/yarn.lock b/yarn.lock index 6778e18..3e30ddb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@ampproject/remapping@^2.2.0": +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -10,6 +10,19 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@antfu/install-pkg@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26" + integrity sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ== + dependencies: + package-manager-detector "^1.3.0" + tinyexec "^1.0.1" + +"@antfu/utils@^8.1.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-8.1.1.tgz#95b1947d292a9a2efffba2081796dcaa05ecedfb" + integrity sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ== + "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" @@ -80,6 +93,27 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/core@^7.26.10": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.3.tgz#aceddde69c5d1def69b839d09efa3e3ff59c97cb" + integrity sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.3" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.3" + "@babel/parser" "^7.28.3" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.3" + "@babel/types" "^7.28.2" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@^7.26.5": version "7.26.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" @@ -102,6 +136,17 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" +"@babel/generator@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.3.tgz#9626c1741c650cbac39121694a0f2d7451b8ef3e" + integrity sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw== + dependencies: + "@babel/parser" "^7.28.3" + "@babel/types" "^7.28.2" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz#4345d81a9a46a6486e24d069469f13e60445c05d" @@ -120,7 +165,7 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-compilation-targets@^7.27.1": +"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2": version "7.27.2" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== @@ -144,6 +189,11 @@ "@babel/traverse" "^7.27.1" semver "^6.3.1" +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + "@babel/helper-member-expression-to-functions@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" @@ -186,6 +236,15 @@ "@babel/helper-validator-identifier" "^7.27.1" "@babel/traverse" "^7.27.1" +"@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + "@babel/helper-optimise-call-expression@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" @@ -261,6 +320,21 @@ "@babel/template" "^7.27.1" "@babel/types" "^7.27.1" +"@babel/helpers@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.3.tgz#b83156c0a2232c133d1b535dd5d3452119c7e441" + integrity sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.2" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.3.tgz#d2d25b814621bca5fe9d172bc93792547e7a2a71" + integrity sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA== + dependencies: + "@babel/types" "^7.28.2" + "@babel/parser@^7.14.7", "@babel/parser@^7.27.1", "@babel/parser@^7.27.2": version "7.27.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127" @@ -304,6 +378,20 @@ "@babel/helper-module-transforms" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-transform-react-jsx-self@^7.25.9": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92" + integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-source@^7.25.9": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0" + integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-typescript@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz#d3bb65598bece03f773111e88cc4e8e5070f1140" @@ -326,6 +414,11 @@ "@babel/plugin-transform-modules-commonjs" "^7.27.1" "@babel/plugin-transform-typescript" "^7.27.1" +"@babel/runtime@^7.3.1": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.3.tgz#75c5034b55ba868121668be5d5bb31cc64e6e61a" + integrity sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA== + "@babel/template@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" @@ -335,7 +428,7 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/template@^7.27.1": +"@babel/template@^7.27.1", "@babel/template@^7.27.2": version "7.27.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== @@ -370,6 +463,27 @@ debug "^4.3.1" globals "^11.1.0" +"@babel/traverse@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.3.tgz#6911a10795d2cce43ec6a28cffc440cca2593434" + integrity sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.3" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.3" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.2" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" + integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/types@^7.25.9", "@babel/types@^7.26.5", "@babel/types@^7.26.7": version "7.26.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.7.tgz#5e2b89c0768e874d4d061961f3a5a153d71dc17a" @@ -386,6 +500,73 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.27.1" +"@codemirror/autocomplete@^6.0.0": + version "6.18.6" + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz#de26e864a1ec8192a1b241eb86addbb612964ddb" + integrity sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + +"@codemirror/commands@^6.0.0": + version "6.8.1" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.1.tgz#639f5559d2f33f2582a2429c58cb0c1b925c7a30" + integrity sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.4.0" + "@codemirror/view" "^6.27.0" + "@lezer/common" "^1.1.0" + +"@codemirror/language@^6.0.0": + version "6.11.3" + resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.11.3.tgz#8e6632df566a7ed13a1bd307f9837765bb1abfdd" + integrity sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.23.0" + "@lezer/common" "^1.1.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + style-mod "^4.0.0" + +"@codemirror/lint@^6.0.0": + version "6.8.5" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.5.tgz#9edaa808e764e28e07665b015951934c8ec3a418" + integrity sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.35.0" + crelt "^1.0.5" + +"@codemirror/search@^6.0.0": + version "6.5.11" + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.11.tgz#a324ffee36e032b7f67aa31c4fb9f3e6f9f3ed63" + integrity sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + +"@codemirror/state@^6.0.0", "@codemirror/state@^6.4.0", "@codemirror/state@^6.5.0": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.5.2.tgz#8eca3a64212a83367dc85475b7d78d5c9b7076c6" + integrity sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA== + dependencies: + "@marijn/find-cluster-break" "^1.0.0" + +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0": + version "6.38.1" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.38.1.tgz#74214434351719ec0710431363a85f7a01e80a73" + integrity sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ== + dependencies: + "@codemirror/state" "^6.5.0" + crelt "^1.0.6" + style-mod "^4.1.0" + w3c-keyname "^2.2.4" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -393,131 +574,309 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@emnapi/core@^1.4.3", "@emnapi/core@^1.4.5": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" + integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== + dependencies: + "@emnapi/wasi-threads" "1.0.4" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.4.5": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" + integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" + integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@^1.0.4": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + "@esbuild/aix-ppc64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz#b87036f644f572efb2b3c75746c97d1d2d87ace8" integrity sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag== +"@esbuild/aix-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9" + integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA== + "@esbuild/android-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz#5ca7dc20a18f18960ad8d5e6ef5cf7b0a256e196" integrity sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w== +"@esbuild/android-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz#d2e70be7d51a529425422091e0dcb90374c1546c" + integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg== + "@esbuild/android-arm@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.2.tgz#3c49f607b7082cde70c6ce0c011c362c57a194ee" integrity sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA== +"@esbuild/android-arm@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.9.tgz#d2a753fe2a4c73b79437d0ba1480e2d760097419" + integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ== + "@esbuild/android-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.2.tgz#8a00147780016aff59e04f1036e7cb1b683859e2" integrity sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg== +"@esbuild/android-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.9.tgz#5278836e3c7ae75761626962f902a0d55352e683" + integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw== + "@esbuild/darwin-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz#486efe7599a8d90a27780f2bb0318d9a85c6c423" integrity sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA== +"@esbuild/darwin-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz#f1513eaf9ec8fa15dcaf4c341b0f005d3e8b47ae" + integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg== + "@esbuild/darwin-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz#95ee222aacf668c7a4f3d7ee87b3240a51baf374" integrity sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA== +"@esbuild/darwin-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz#e27dbc3b507b3a1cea3b9280a04b8b6b725f82be" + integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ== + "@esbuild/freebsd-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz#67efceda8554b6fc6a43476feba068fb37fa2ef6" integrity sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w== +"@esbuild/freebsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz#364e3e5b7a1fd45d92be08c6cc5d890ca75908ca" + integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q== + "@esbuild/freebsd-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz#88a9d7ecdd3adadbfe5227c2122d24816959b809" integrity sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ== +"@esbuild/freebsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz#7c869b45faeb3df668e19ace07335a0711ec56ab" + integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg== + "@esbuild/linux-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz#87be1099b2bbe61282333b084737d46bc8308058" integrity sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g== +"@esbuild/linux-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz#48d42861758c940b61abea43ba9a29b186d6cb8b" + integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw== + "@esbuild/linux-arm@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz#72a285b0fe64496e191fcad222185d7bf9f816f6" integrity sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g== +"@esbuild/linux-arm@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz#6ce4b9cabf148274101701d112b89dc67cc52f37" + integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw== + "@esbuild/linux-ia32@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz#337a87a4c4dd48a832baed5cbb022be20809d737" integrity sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ== +"@esbuild/linux-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz#207e54899b79cac9c26c323fc1caa32e3143f1c4" + integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A== + "@esbuild/linux-loong64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz#1b81aa77103d6b8a8cfa7c094ed3d25c7579ba2a" integrity sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w== +"@esbuild/linux-loong64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz#0ba48a127159a8f6abb5827f21198b999ffd1fc0" + integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ== + "@esbuild/linux-mips64el@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz#afbe380b6992e7459bf7c2c3b9556633b2e47f30" integrity sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q== +"@esbuild/linux-mips64el@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz#a4d4cc693d185f66a6afde94f772b38ce5d64eb5" + integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA== + "@esbuild/linux-ppc64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz#6bf8695cab8a2b135cca1aa555226dc932d52067" integrity sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g== +"@esbuild/linux-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz#0f5805c1c6d6435a1dafdc043cb07a19050357db" + integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w== + "@esbuild/linux-riscv64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz#43c2d67a1a39199fb06ba978aebb44992d7becc3" integrity sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw== +"@esbuild/linux-riscv64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz#6776edece0f8fca79f3386398b5183ff2a827547" + integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg== + "@esbuild/linux-s390x@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz#419e25737ec815c6dce2cd20d026e347cbb7a602" integrity sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q== +"@esbuild/linux-s390x@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz#3f6f29ef036938447c2218d309dc875225861830" + integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA== + "@esbuild/linux-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz#22451f6edbba84abe754a8cbd8528ff6e28d9bcb" integrity sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg== +"@esbuild/linux-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz#831fe0b0e1a80a8b8391224ea2377d5520e1527f" + integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg== + "@esbuild/netbsd-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz#744affd3b8d8236b08c5210d828b0698a62c58ac" integrity sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw== +"@esbuild/netbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz#06f99d7eebe035fbbe43de01c9d7e98d2a0aa548" + integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q== + "@esbuild/netbsd-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz#dbbe7521fd6d7352f34328d676af923fc0f8a78f" integrity sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg== +"@esbuild/netbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz#db99858e6bed6e73911f92a88e4edd3a8c429a52" + integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g== + "@esbuild/openbsd-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz#f9caf987e3e0570500832b487ce3039ca648ce9f" integrity sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg== +"@esbuild/openbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz#afb886c867e36f9d86bb21e878e1185f5d5a0935" + integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ== + "@esbuild/openbsd-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz#d2bb6a0f8ffea7b394bb43dfccbb07cabd89f768" integrity sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw== +"@esbuild/openbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz#30855c9f8381fac6a0ef5b5f31ac6e7108a66ecf" + integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA== + +"@esbuild/openharmony-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz#2f2144af31e67adc2a8e3705c20c2bd97bd88314" + integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg== + "@esbuild/sunos-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz#49b437ed63fe333b92137b7a0c65a65852031afb" integrity sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA== +"@esbuild/sunos-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz#69b99a9b5bd226c9eb9c6a73f990fddd497d732e" + integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw== + "@esbuild/win32-arm64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz#081424168463c7d6c7fb78f631aede0c104373cf" integrity sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q== +"@esbuild/win32-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz#d789330a712af916c88325f4ffe465f885719c6b" + integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ== + "@esbuild/win32-ia32@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz#3f9e87143ddd003133d21384944a6c6cadf9693f" integrity sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg== +"@esbuild/win32-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz#52fc735406bd49688253e74e4e837ac2ba0789e3" + integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww== + "@esbuild/win32-x64@0.25.2": version "0.25.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz#839f72c2decd378f86b8f525e1979a97b920c67d" integrity sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA== +"@esbuild/win32-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f" + integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ== + +"@iconify/types@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@iconify/types/-/types-2.0.0.tgz#ab0e9ea681d6c8a1214f30cd741fe3a20cc57f57" + integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg== + +"@iconify/utils@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@iconify/utils/-/utils-2.3.0.tgz#1bbbf8c477ebe9a7cacaea78b1b7e8937f9cbfba" + integrity sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA== + dependencies: + "@antfu/install-pkg" "^1.0.0" + "@antfu/utils" "^8.1.0" + "@iconify/types" "^2.0.0" + debug "^4.4.0" + globals "^15.14.0" + kolorist "^1.8.0" + local-pkg "^1.0.0" + mlly "^1.7.4" + "@inquirer/checkbox@^4.0.2": version "4.1.1" resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-4.1.1.tgz#5f2c0ce74a75e3872f8e170fd209655972ce7802" @@ -650,6 +1009,25 @@ resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.4.tgz#fa5f9e91a0abf3c9e93d3e1990ecb891d8195cf2" integrity sha512-2MNFrDY8jkFYc9Il9DgLsHhMzuHnOYM1+CUYVWbzu9oT0hC7V7EcYvdCKeoll/Fcci04A+ERZ9wcc7cQ8lTkIA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + "@istanbuljs/esm-loader-hook@0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@istanbuljs/esm-loader-hook/-/esm-loader-hook-0.3.0.tgz#f63094877f7f74f3e6ccab375d95922728eb01d1" @@ -679,6 +1057,14 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== +"@jridgewell/gen-mapping@^0.3.12": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.8" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" @@ -688,6 +1074,14 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" +"@jridgewell/remapping@^2.3.4": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" @@ -703,6 +1097,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== +"@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" @@ -719,6 +1118,232 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@^0.3.28": + version "0.3.30" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz#4a76c4daeee5df09f5d3940e087442fb36ce2b99" + integrity sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@lezer/common@^1.0.0", "@lezer/common@^1.1.0": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.3.tgz#138fcddab157d83da557554851017c6c1e5667fd" + integrity sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA== + +"@lezer/highlight@^1.0.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.1.tgz#596fa8f9aeb58a608be0a563e960c373cbf23f8b" + integrity sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/lr@^1.0.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.2.tgz#931ea3dea8e9de84e90781001dae30dea9ff1727" + integrity sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA== + dependencies: + "@lezer/common" "^1.0.0" + +"@marijn/find-cluster-break@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8" + integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g== + +"@napi-rs/wasm-runtime@^0.2.12": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@noble/hashes@^1.1.5": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@paralleldrive/cuid2@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz#7f91364d53b89e2c9cb9e02e8dd0f129e834455f" + integrity sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA== + dependencies: + "@noble/hashes" "^1.1.5" + +"@peculiar/asn1-schema@^2.3.13", "@peculiar/asn1-schema@^2.3.8": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.4.0.tgz#e3aa7917d433b4c3fcfa1fcb57eac233b1c38787" + integrity sha512-umbembjIWOrPSOzEGG5vxFLkeM8kzIhLkgigtsOrfLKnuzxWxejAcUX+q/SoZCdemlODOcr5WiYa7+dIEzBXZQ== + dependencies: + asn1js "^3.0.6" + pvtsutils "^1.3.6" + tslib "^2.8.1" + +"@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + +"@peculiar/webcrypto@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz#9e57174c02c1291051c553600347e12b81469e10" + integrity sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg== + dependencies: + "@peculiar/asn1-schema" "^2.3.8" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.3.5" + tslib "^2.6.2" + webcrypto-core "^1.8.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.29" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.29.tgz#5a40109a1ab5f84d6fd8fc928b19f367cbe7e7b1" + integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww== + +"@rollup/rollup-android-arm-eabi@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz#ba432433f5e7b419dba2be407d1d59fea6b8de48" + integrity sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA== + +"@rollup/rollup-android-arm64@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz#4e05c86e0fb9af6eaf52fc298dcdec577477e35c" + integrity sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w== + +"@rollup/rollup-darwin-arm64@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz#788fad425b4129875639e0c14b6441c5f3b69d46" + integrity sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw== + +"@rollup/rollup-darwin-x64@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz#d44e05bee55b781d7c2cf535d9f9169787c3599d" + integrity sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg== + +"@rollup/rollup-freebsd-arm64@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz#107786b4d604495224c3543bfd2cae33ddf76500" + integrity sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA== + +"@rollup/rollup-freebsd-x64@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz#54e105c3da27f31084ca6913fed603627755abde" + integrity sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w== + +"@rollup/rollup-linux-arm-gnueabihf@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz#725c23e0766b5d9368180bc2c427a51e31d0e147" + integrity sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w== + +"@rollup/rollup-linux-arm-musleabihf@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz#6946b0d2f132f2baf5657945b81565d8abd51cc0" + integrity sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA== + +"@rollup/rollup-linux-arm64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz#83510a6d03e748619241a17f5a879418a963c5ed" + integrity sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg== + +"@rollup/rollup-linux-arm64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz#085b98d44c10908626dd40f26bf924433bbd8471" + integrity sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg== + +"@rollup/rollup-linux-loongarch64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz#13e0a4808e9f7924f2cc8c133603f627c7a00543" + integrity sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ== + +"@rollup/rollup-linux-ppc64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz#aeee4e47fc9ca5d6687e686fea4696202af6b2f4" + integrity sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g== + +"@rollup/rollup-linux-riscv64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz#603e4591643f1d7851a96d096cf7fcd273f7b0e1" + integrity sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw== + +"@rollup/rollup-linux-riscv64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz#f8fd9b01f1888e1816d5a398789d430511286c00" + integrity sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw== + +"@rollup/rollup-linux-s390x-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz#37a1fd372d9b93d2b75b2f37c482ecf52f52849b" + integrity sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A== + +"@rollup/rollup-linux-x64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz#131e66dbf7e71cb2a389acc45319bd4c990e093a" + integrity sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA== + +"@rollup/rollup-linux-x64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz#b7245a5ea57db9679e8bf3032c25a5d2c5f54056" + integrity sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg== + +"@rollup/rollup-win32-arm64-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz#768a128bb5da3c5472c3c56aec77507d28bc7209" + integrity sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA== + +"@rollup/rollup-win32-ia32-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz#ce3f3b2eebe585340631498666718f00983a6a62" + integrity sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA== + +"@rollup/rollup-win32-x64-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz#c2a0e3b81262a7e9dd12ce18b350a97558dd50bc" + integrity sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg== + +"@stackpress/ingest@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/ingest/-/ingest-0.6.1.tgz#20ba2a33a1d4a1573ed49774f887db2b0086fb35" + integrity sha512-i69p2fDHhEDQkWNfBiNp5pf74Gp0MQz6PkgrH0Nzf2I6L2d/5e25gQNeAAt9Qet9FPk0K0MlSgg46iMpXtQ4mQ== + dependencies: + "@stackpress/lib" "0.6.1" + "@whatwg-node/server" "0.6.7" + +"@stackpress/inquire@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/inquire/-/inquire-0.6.1.tgz#ab8c5842fdcbdce6cd7c5d8bdefc207511f36312" + integrity sha512-SjbNrRuVVwNboMO5Bv6swZpK49z41sB1U2iYKKO2RrsLZPMdvpEZtjL7JxIDW37fm1Gh4PXkVTuYgvZ5qma2zQ== + dependencies: + "@stackpress/lib" "0.6.1" + "@stackpress/lib@0.6.1": version "0.6.1" resolved "https://registry.yarnpkg.com/@stackpress/lib/-/lib-0.6.1.tgz#56b65e66daaeb1e4a2a67cb8d743cd784bc8ed14" @@ -726,6 +1351,116 @@ dependencies: "@inquirer/prompts" "7.1.0" +"@tailwindcss/node@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.12.tgz#9099c7c9a6b719b2cae265fecbb37e08ed3fd2a2" + integrity sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ== + dependencies: + "@jridgewell/remapping" "^2.3.4" + enhanced-resolve "^5.18.3" + jiti "^2.5.1" + lightningcss "1.30.1" + magic-string "^0.30.17" + source-map-js "^1.2.1" + tailwindcss "4.1.12" + +"@tailwindcss/oxide-android-arm64@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz#27920fe61fa2743afe8a8ca296fa640b609d17d5" + integrity sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ== + +"@tailwindcss/oxide-darwin-arm64@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz#e8bd4798f26ec1d012bf0683aeb77449f71505cd" + integrity sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw== + +"@tailwindcss/oxide-darwin-x64@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz#8ddb7e5ddfd9b049ec84a2bda99f2b04a86859f5" + integrity sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg== + +"@tailwindcss/oxide-freebsd-x64@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz#da1c0b16b7a5f95a1e400f299a3ec94fb6fd40ac" + integrity sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz#34e558aa6e869c6fe9867cb78ed7ba651b9fcaa4" + integrity sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz#0a00a8146ab6215f81b2d385056c991441bf390e" + integrity sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz#b138f494068884ae0d8c343dc1904b22f5e98dc6" + integrity sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz#5b9d5f23b15cdb714639f5b9741c0df5d610f794" + integrity sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q== + +"@tailwindcss/oxide-linux-x64-musl@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz#f68ec530d3ca6875ea9015bcd5dd0762ee5e2f5d" + integrity sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A== + +"@tailwindcss/oxide-wasm32-wasi@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz#9fd15a1ebde6076c42c445c5e305c31673ead965" + integrity sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg== + dependencies: + "@emnapi/core" "^1.4.5" + "@emnapi/runtime" "^1.4.5" + "@emnapi/wasi-threads" "^1.0.4" + "@napi-rs/wasm-runtime" "^0.2.12" + "@tybys/wasm-util" "^0.10.0" + tslib "^2.8.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz#938bcc6a82e1120ea4fe2ce94be0a8cdf3ae92c7" + integrity sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz#b1ee2ed0ef2c4095ddec3684a1987e2b3613af36" + integrity sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA== + +"@tailwindcss/oxide@4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.12.tgz#13a6f806aafa9c83629c9a04acd92031aef83f1c" + integrity sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw== + dependencies: + detect-libc "^2.0.4" + tar "^7.4.3" + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.12" + "@tailwindcss/oxide-darwin-arm64" "4.1.12" + "@tailwindcss/oxide-darwin-x64" "4.1.12" + "@tailwindcss/oxide-freebsd-x64" "4.1.12" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.12" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.12" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.12" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.12" + "@tailwindcss/oxide-linux-x64-musl" "4.1.12" + "@tailwindcss/oxide-wasm32-wasi" "4.1.12" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.12" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.12" + +"@tailwindcss/vite@^4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@tailwindcss/vite/-/vite-4.1.12.tgz#f2839180aa7ba938a5247114e32ee9d57215e7f8" + integrity sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ== + dependencies: + "@tailwindcss/node" "4.1.12" + "@tailwindcss/oxide" "4.1.12" + tailwindcss "4.1.12" + "@ts-morph/common@~0.25.0": version "0.25.0" resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.25.0.tgz#b76cbd517118acc8eadaf12b2fc2d47f42923452" @@ -735,6 +1470,15 @@ path-browserify "^1.0.1" tinyglobby "^0.2.9" +"@ts-morph/common@~0.26.0": + version "0.26.1" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.26.1.tgz#a346188e59d2befe4c71f66a7d626d81b1abe2a8" + integrity sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA== + dependencies: + fast-glob "^3.3.2" + minimatch "^9.0.4" + path-browserify "^1.0.1" + "@tsconfig/node10@^1.0.7": version "1.0.11" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" @@ -755,16 +1499,80 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@tybys/wasm-util@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" + integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== + dependencies: + tslib "^2.4.0" + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + "@types/chai@4.3.20": version "4.3.20" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== +"@types/chai@5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.1.tgz#85687a58b27eac736ec0e87e5cb98f21e57a0bb1" + integrity sha512-iu1JLYmGmITRzUgNiLMZD3WCoFzpYtueuyAgHTXqgwSRAMIlFTnZqG6/xenkpUGRJEzSfklUTI4GNSzks/dc0w== + dependencies: + "@types/deep-eql" "*" + +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + "@types/deep-equal-in-any-order@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/deep-equal-in-any-order/-/deep-equal-in-any-order-1.0.3.tgz#55baf558924d52adaec886f7f1930c05e69c4ca6" integrity sha512-jT0O3hAILDKeKbdWJ9FZLD0Xdfhz7hMvfyFlRWpirjiEVr8G+GZ4kVIzPIqM6x6Rpp93TNPgOAed4XmvcuV6Qg== +"@types/estree@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/hast@^2.0.0": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -775,6 +1583,13 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== +"@types/node@22.14.1": + version "22.14.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.1.tgz#53b54585cec81c21eee3697521e31312d6ca1e6f" + integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw== + dependencies: + undici-types "~6.21.0" + "@types/node@22.9.3": version "22.9.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.3.tgz#08f3d64b3bc6d74b162d36f60213e8a6704ef2b4" @@ -782,6 +1597,291 @@ dependencies: undici-types "~6.19.8" +"@types/react-dom@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.2.tgz#bd1fe3b8c28a3a2e942f85314dcfb71f531a242f" + integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw== + +"@types/react-syntax-highlighter@15.5.13": + version "15.5.13" + resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz#c5baf62a3219b3bf28d39cfea55d0a49a263d1f2" + integrity sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "19.1.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b" + integrity sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w== + dependencies: + csstype "^3.0.2" + +"@types/react@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.2.tgz#11df86f66f188f212c90ecb537327ec68bfd593f" + integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw== + dependencies: + csstype "^3.0.2" + +"@types/unist@^2": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + +"@unocss/astro@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/astro/-/astro-66.0.0.tgz#6564ef14c9d7c1346769c222c6e525d7d8995c98" + integrity sha512-GBhXT6JPqXjDXoJZTXhySk83NgOt0UigChqrUUdG4x7Z+DVYkDBION8vZUJjw0OdIaxNQ4euGWu4GDsMF6gQQg== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/reset" "66.0.0" + "@unocss/vite" "66.0.0" + +"@unocss/cli@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/cli/-/cli-66.0.0.tgz#4cd4b6e14a6743354fe532f6dc390bab30e04e35" + integrity sha512-KVQiskoOjVkLVpNaG6WpLa4grPplrZROYZJVIUYSTqZyZRFNSvjttHcsCwpoWUEUdEombPtVZl8FrXePjY5IiQ== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/preset-uno" "66.0.0" + cac "^6.7.14" + chokidar "^3.6.0" + colorette "^2.0.20" + consola "^3.4.0" + magic-string "^0.30.17" + pathe "^2.0.3" + perfect-debounce "^1.0.0" + tinyglobby "^0.2.10" + unplugin-utils "^0.2.4" + +"@unocss/config@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/config/-/config-66.0.0.tgz#16ff6da705cd7b97813d62a887adbf354ee423c8" + integrity sha512-nFRGop/guBa4jLkrgXjaRDm5JPz4x3YpP10m5IQkHpHwlnHUVn1L9smyPl04ohYWhYn9ZcAHgR28Ih2jwta8hw== + dependencies: + "@unocss/core" "66.0.0" + unconfig "~7.0.0" + +"@unocss/core@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/core/-/core-66.0.0.tgz#2a316f4e0e17bd3f77788479401ca84eaf52e847" + integrity sha512-PdVbSMHNDDkr++9nkqzsZRAkaU84gxMTEgYbqI7dt2p1DXp/5tomVtmMsr2/whXGYKRiUc0xZ3p4Pzraz8TcXA== + +"@unocss/core@^66.0.0": + version "66.4.2" + resolved "https://registry.yarnpkg.com/@unocss/core/-/core-66.4.2.tgz#4c4dac438a3b0e59025933ee36bf7728c6447fbb" + integrity sha512-cYgMQrLhB9nRekv5c+yPDDa+5dzlMkA2UMQRil0s5D9Lb5n7NsCMcr6+nfxkcSYVLy92SbwDV45c6T7vIxFTOA== + +"@unocss/extractor-arbitrary-variants@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/extractor-arbitrary-variants/-/extractor-arbitrary-variants-66.0.0.tgz#8bd37b36cc4e568db809d7d460f65ff3f4830b30" + integrity sha512-vlkOIOuwBfaFBJcN6o7+obXjigjOlzVFN/jT6pG1WXbQDTRZ021jeF3i9INdb9D/0cQHSeDvNgi1TJ5oUxfiow== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/inspector@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/inspector/-/inspector-66.0.0.tgz#98d9e4bf83abb4a4b119eea89c464aef066439ec" + integrity sha512-mkIxieVm0kMOKw+E4ABpIerihYMdjgq9A92RD5h2+W/ebpxTEw5lTTK1xcMLiAlmOrVYMQKjpgPeu3vQmDyGZQ== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + colorette "^2.0.20" + gzip-size "^6.0.0" + sirv "^3.0.0" + vue-flow-layout "^0.1.1" + +"@unocss/postcss@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/postcss/-/postcss-66.0.0.tgz#686a74de9de91809d02ae715b60b1470d2705826" + integrity sha512-6bi+ujzh8I1PJwtmHX71LH8z/H9+vPxeYD4XgFihyU1k4Y6MVhjr7giGjLX4yP27IP+NsVyotD22V7by/dBVEA== + dependencies: + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + css-tree "^3.1.0" + postcss "^8.5.2" + tinyglobby "^0.2.10" + +"@unocss/preset-attributify@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-attributify/-/preset-attributify-66.0.0.tgz#e319503c7ffb5a482cafb09744d33424db97167e" + integrity sha512-eYsOgmcDoiIgGAepIwRX+DKGYxc/wm0r4JnDuZdz29AB+A6oY/FGHS1BVt4rq9ny4B5PofP4p6Rty+vwD9rigw== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/preset-icons@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-icons/-/preset-icons-66.0.0.tgz#97d9e9e110a343e2c5b6de37070019ac05de1221" + integrity sha512-6ObwTvEGuPBbKWRoMMiDioHtwwQTFI5oojFLJ32Y8tW6TdXvBLkO88d7qpgQxEjgVt4nJrqF1WEfR4niRgBm0Q== + dependencies: + "@iconify/utils" "^2.3.0" + "@unocss/core" "66.0.0" + ofetch "^1.4.1" + +"@unocss/preset-mini@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-mini/-/preset-mini-66.0.0.tgz#8b1b5ee36aaa8d1226ff34179622d4433a872130" + integrity sha512-d62eACnuKtR0dwCFOQXgvw5VLh5YSyK56xCzpHkh0j0GstgfDLfKTys0T/XVAAvdSvAy/8A8vhSNJ4PlIc9V2A== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/extractor-arbitrary-variants" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-tagify@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-tagify/-/preset-tagify-66.0.0.tgz#8629c466ffdcdf771e79d19cca92f8a4b13bfb3f" + integrity sha512-GGYGyWxaevh0jN0NoATVO1Qe7DFXM3ykLxchlXmG6/zy963pZxItg/njrKnxE9la4seCdxpFH7wQBa68imwwdA== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/preset-typography@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-typography/-/preset-typography-66.0.0.tgz#85c62a0fa57e538f23ab9f56e68a8ac3bc4ed116" + integrity sha512-apjckP5nPU5mtaHTCzz5u/dK9KJWwJ2kOFCVk0+a/KhUWmnqnzmjRYZlEuWxxr5QxTdCW+9cIoRDSA0lYZS5tg== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-uno@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-uno/-/preset-uno-66.0.0.tgz#37633290c6594de40a40fc158504fa22c02c6ab7" + integrity sha512-qgoZ/hzTI32bQvcyjcwvv1X/dbPlmQNehzgjUaL7QFT0q0/CN/SRpysfzoQ8DLl2se9T+YCOS9POx3KrpIiYSQ== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + +"@unocss/preset-web-fonts@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-web-fonts/-/preset-web-fonts-66.0.0.tgz#39c936ad69f6777df1077ffff40d6694cf9368e9" + integrity sha512-9MzfDc6AJILN4Kq7Z91FfFbizBOYgw3lJd2UwqIs3PDYWG5iH5Zv5zhx6jelZVqEW5uWcIARYEEg2m4stZO1ZA== + dependencies: + "@unocss/core" "66.0.0" + ofetch "^1.4.1" + +"@unocss/preset-wind3@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-wind3/-/preset-wind3-66.0.0.tgz#3f17da21cea683d75d4adefbd4f9c95172eeb1bb" + integrity sha512-WAGRmpi1sb2skvYn9DBQUvhfqrJ+VmQmn5ZGsT2ewvsk7HFCvVLAMzZeKrrTQepeNBRhg6HzFDDi8yg6yB5c9g== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-wind@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-wind/-/preset-wind-66.0.0.tgz#eeb22cd66a32dc896c6263dc0eeb8be0c6c9b090" + integrity sha512-FtvGpHnGC7FiyKJavPnn5y9lsaoWRhXlujCqlT5Bw63kKhMNr0ogKySBpenUhJOhWhVM0OQXn2nZ3GZRxW2qpw== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + +"@unocss/reset@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/reset/-/reset-66.0.0.tgz#8e3301206ab315d3287fb133be6f03e60a3ebdd4" + integrity sha512-YLFz/5yT7mFJC8JSmIUA5+bS3CBCJbtztOw+8rWzjQr/BEVSGuihWUUpI2Df6VVxXIXxKanZR6mIl59yvf+GEA== + +"@unocss/rule-utils@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/rule-utils/-/rule-utils-66.0.0.tgz#5fd1c7bd2372e9f3724ed6858263a703a9ae064a" + integrity sha512-UJ51YHbwxYTGyj35ugsPlOT4gaa7tCbXdywZ3m5Nn0JgywwIqGmBFyiN9ZjHBHfJuDxmmPd6lxojoBscih/WMQ== + dependencies: + "@unocss/core" "^66.0.0" + magic-string "^0.30.17" + +"@unocss/transformer-attributify-jsx@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-attributify-jsx/-/transformer-attributify-jsx-66.0.0.tgz#f93168db7fd7efbccfa75cd3ea5f3457d1aee8eb" + integrity sha512-jS7szFXXC6RjTv9wo0NACskf618w981bkbyQ5izRO7Ha47sNpHhHDpaltnG7SR9qV4cCtGalOw4onVMHsRKwRg== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/transformer-compile-class@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-compile-class/-/transformer-compile-class-66.0.0.tgz#baa303da481e6df25d963436c4536479b620025b" + integrity sha512-ytUIE0nAcHRMACuTXkHp8auZ483DXrOZw99jk3FJ+aFjpD/pVSFmX14AWJ7bqPFObxb4SLFs6KhQma30ESC22A== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/transformer-directives@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-directives/-/transformer-directives-66.0.0.tgz#7cfff36c2b196937a54f107a76803aeb7236d0d8" + integrity sha512-utcg7m2Foi7uHrU5WHadNuJ0a3qWG8tZNkQMi+m0DQpX6KWfuDtDn0zDZ1X+z5lmiB3WGSJERRrsvZbj1q50Mw== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + css-tree "^3.1.0" + +"@unocss/transformer-variant-group@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-variant-group/-/transformer-variant-group-66.0.0.tgz#255ae998dd75c379df6af09f0b9f10a5dc0a5ad1" + integrity sha512-1BLjNWtAnR1JAcQGw0TS+nGrVoB9aznzvVZRoTx23dtRr3btvgKPHb8LrD48eD/p8Dtw9j3WfuxMDKXKegKDLg== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/vite@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/vite/-/vite-66.0.0.tgz#e0e4e50288d8b5ef6e53af85ae35149ce2a60b73" + integrity sha512-IVcPX8xL+2edyXKt4tp9yu5A6gcbPVCsspfcL0XgziCr01kS+4qSoZ90F3IUs3hXc/AyO5eCpRtGFMPLpOjXQg== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/inspector" "66.0.0" + chokidar "^3.6.0" + magic-string "^0.30.17" + tinyglobby "^0.2.10" + unplugin-utils "^0.2.4" + +"@vitejs/plugin-react@4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz#d7d1e9c9616d7536b0953637edfee7c6cbe2fe0f" + integrity sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w== + dependencies: + "@babel/core" "^7.26.10" + "@babel/plugin-transform-react-jsx-self" "^7.25.9" + "@babel/plugin-transform-react-jsx-source" "^7.25.9" + "@types/babel__core" "^7.20.5" + react-refresh "^0.17.0" + +"@whatwg-node/events@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.0.3.tgz#13a65dd4f5893f55280f766e29ae48074927acad" + integrity sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA== + +"@whatwg-node/fetch@^0.8.1": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.8.8.tgz#48c6ad0c6b7951a73e812f09dd22d75e9fa18cae" + integrity sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg== + dependencies: + "@peculiar/webcrypto" "^1.4.0" + "@whatwg-node/node-fetch" "^0.3.6" + busboy "^1.6.0" + urlpattern-polyfill "^8.0.0" + web-streams-polyfill "^3.2.1" + +"@whatwg-node/node-fetch@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz#e28816955f359916e2d830b68a64493124faa6d0" + integrity sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA== + dependencies: + "@whatwg-node/events" "^0.0.3" + busboy "^1.6.0" + fast-querystring "^1.1.1" + fast-url-parser "^1.1.3" + tslib "^2.3.1" + +"@whatwg-node/server@0.6.7": + version "0.6.7" + resolved "https://registry.yarnpkg.com/@whatwg-node/server/-/server-0.6.7.tgz#14f5d0aca49308759d64fc7faa3cbfc20162a1ee" + integrity sha512-M4zHWdJ6M1IdcxnZBdDmiUh1bHQ4gPYRxzkH0gh8Qf6MpWJmX6I/MNftqem3GNn+qn1y47qqlGSed7T7nzsRFw== + dependencies: + "@whatwg-node/fetch" "^0.8.1" + tslib "^2.3.1" + acorn-walk@^8.1.1: version "8.3.4" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" @@ -794,6 +1894,11 @@ acorn@^8.11.0, acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -819,6 +1924,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.0.tgz#2f302e7550431b1b7762705fffb52cf1ffa20447" + integrity sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg== + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -826,6 +1936,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -868,11 +1983,25 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +asn1js@^3.0.5, asn1js@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.6.tgz#53e002ebe00c5f7fd77c1c047c3557d7c04dce25" + integrity sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.3" + tslib "^2.8.1" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + babel-plugin-istanbul@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -909,7 +2038,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -936,6 +2065,18 @@ buffer-from@^1.0.0, buffer-from@^1.1.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + caching-transform@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" @@ -974,6 +2115,17 @@ chai@4.5.0: pathval "^1.1.1" type-detect "^4.1.0" +chai@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.2.0.tgz#1358ee106763624114addf84ab02697e411c9c05" + integrity sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -982,6 +2134,21 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -994,7 +2161,12 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -chokidar@^3.5.3: +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== + +chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -1009,6 +2181,18 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1037,11 +2221,38 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + code-block-writer@^13.0.3: version "13.0.3" resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-13.0.3.tgz#90f8a84763a5012da7af61319dd638655ae90b5b" integrity sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg== +codemirror@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29" + integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1054,6 +2265,16 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -1064,6 +2285,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +consola@^3.4.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.2.tgz#5af110145397bb67afdab77013fdc34cae590ea7" + integrity sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA== + convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" @@ -1074,12 +2310,22 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.0, cross-spawn@^7.0.3: +crelt@^1.0.5, crelt@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + +cross-spawn@^7.0.0, cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -1088,6 +2334,19 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css-tree@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd" + integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w== + dependencies: + mdn-data "2.12.2" + source-map-js "^1.0.1" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.5: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -1095,6 +2354,13 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.5: dependencies: ms "^2.1.3" +debug@^4.4.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1112,6 +2378,11 @@ deep-eql@^4.1.3: dependencies: type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + deep-equal-in-any-order@1.1.20: version "1.1.20" resolved "https://registry.yarnpkg.com/deep-equal-in-any-order/-/deep-equal-in-any-order-1.1.20.tgz#04328876a10864cc2af1325186a970aa5a845486" @@ -1127,6 +2398,21 @@ default-require-extensions@^3.0.0: dependencies: strip-bom "^4.0.0" +defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + +destr@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb" + integrity sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA== + +detect-libc@^2.0.3, detect-libc@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" + integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== + diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -1142,6 +2428,36 @@ diff@^5.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== +dotenv-cli@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-8.0.0.tgz#cea1519f5a06c7372a1428fca4605fcf3d50e1cf" + integrity sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw== + dependencies: + cross-spawn "^7.0.6" + dotenv "^16.3.0" + dotenv-expand "^10.0.0" + minimist "^1.2.6" + +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + +dotenv@^16.3.0: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + electron-to-chromium@^1.5.73: version "1.5.92" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.92.tgz#81e8ebe06f8e2a49fdba84bd10e9ad5b63efffe0" @@ -1152,11 +2468,56 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enhanced-resolve@^5.18.3: + version "5.18.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz#9b5f4c5c076b8787c78fe540392ce76a88855b44" + integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +esbuild@^0.25.0: + version "0.25.9" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.9.tgz#15ab8e39ae6cdc64c24ff8a2c0aef5b3fd9fa976" + integrity sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.9" + "@esbuild/android-arm" "0.25.9" + "@esbuild/android-arm64" "0.25.9" + "@esbuild/android-x64" "0.25.9" + "@esbuild/darwin-arm64" "0.25.9" + "@esbuild/darwin-x64" "0.25.9" + "@esbuild/freebsd-arm64" "0.25.9" + "@esbuild/freebsd-x64" "0.25.9" + "@esbuild/linux-arm" "0.25.9" + "@esbuild/linux-arm64" "0.25.9" + "@esbuild/linux-ia32" "0.25.9" + "@esbuild/linux-loong64" "0.25.9" + "@esbuild/linux-mips64el" "0.25.9" + "@esbuild/linux-ppc64" "0.25.9" + "@esbuild/linux-riscv64" "0.25.9" + "@esbuild/linux-s390x" "0.25.9" + "@esbuild/linux-x64" "0.25.9" + "@esbuild/netbsd-arm64" "0.25.9" + "@esbuild/netbsd-x64" "0.25.9" + "@esbuild/openbsd-arm64" "0.25.9" + "@esbuild/openbsd-x64" "0.25.9" + "@esbuild/openharmony-arm64" "0.25.9" + "@esbuild/sunos-x64" "0.25.9" + "@esbuild/win32-arm64" "0.25.9" + "@esbuild/win32-ia32" "0.25.9" + "@esbuild/win32-x64" "0.25.9" + esbuild@~0.25.0: version "0.25.2" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.2.tgz#55a1d9ebcb3aa2f95e8bba9e900c1a5061bc168b" @@ -1203,6 +2564,11 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +exsolve@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.7.tgz#3b74e4c7ca5c5f9a19c3626ca857309fa99f9e9e" + integrity sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw== + external-editor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -1212,11 +2578,60 @@ external-editor@^3.1.0: iconv-lite "^0.4.24" tmp "^0.0.33" +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-glob@3.3.3, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fast-querystring@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.2.tgz#a6d24937b4fc6f791b4ee31dcb6f53aeafb89f53" + integrity sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== + dependencies: + fast-decode-uri-component "^1.0.1" + +fast-url-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== + dependencies: + punycode "^1.3.2" + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + fdir@^6.4.2: version "6.4.3" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== +fdir@^6.4.3, fdir@^6.4.4: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -1262,6 +2677,14 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + foreground-child@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" @@ -1270,11 +2693,27 @@ foreground-child@^3.3.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== + fromentries@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== +frui@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/frui/-/frui-0.1.8.tgz#b04f534f0b6b0f942054388031b8fc3b8418f144" + integrity sha512-gz09LCW8xTeN4eMHI+zYOm3yByWq+NNVZ9naL1G0mSaEj2po3pnQFK5EZzNq+gJDzDcBnf0/BNrRAJMG9xBKIA== + dependencies: + codemirror "6.0.1" + inputmask "5.0.9" + markdown-to-jsx "7.7.4" + moment "2.30.1" + react-syntax-highlighter "15.6.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1312,13 +2751,25 @@ get-tsconfig@^4.7.5: dependencies: resolve-pkg-maps "^1.0.0" -glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob@^10.4.5: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -1347,11 +2798,23 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -graceful-fs@^4.1.15: +globals@^15.14.0: + version "15.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== + +graceful-fs@^4.1.15, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -1365,11 +2828,37 @@ hasha@^5.0.0: is-stream "^2.0.0" type-fest "^0.8.0" +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +highlightjs-vue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz#fdfe97fbea6354e70ee44e3a955875e114db086d" + integrity sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA== + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -1405,6 +2894,24 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inputmask@5.0.9: + version "5.0.9" + resolved "https://registry.yarnpkg.com/inputmask/-/inputmask-5.0.9.tgz#7bf4e83f5e199c88c0edf28545dc23fa208ef4be" + integrity sha512-s0lUfqcEbel+EQXtehXqwCJGShutgieOaIImFKC/r4reYNvX3foyrChl6LOEvaEgxEbesePIrw1Zi2jhZaDZbQ== + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -1412,6 +2919,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1429,6 +2941,11 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -1536,6 +3053,25 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^2.4.2, jiti@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.5.1.tgz#bd099c1c2be1c59bbea4e5adcd127363446759d0" + integrity sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w== + +jose@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/jose/-/jose-6.0.10.tgz#52d96e1a671b4c02e13b71e0d35abea2e774712b" + integrity sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1573,6 +3109,88 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +lightningcss-darwin-arm64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" + integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== + +lightningcss-darwin-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" + integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== + +lightningcss-freebsd-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" + integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== + +lightningcss-linux-arm-gnueabihf@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" + integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== + +lightningcss-linux-arm64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" + integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== + +lightningcss-linux-arm64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" + integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== + +lightningcss-linux-x64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" + integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== + +lightningcss-linux-x64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" + integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== + +lightningcss-win32-arm64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" + integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== + +lightningcss-win32-x64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" + integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== + +lightningcss@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" + integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-darwin-arm64 "1.30.1" + lightningcss-darwin-x64 "1.30.1" + lightningcss-freebsd-x64 "1.30.1" + lightningcss-linux-arm-gnueabihf "1.30.1" + lightningcss-linux-arm64-gnu "1.30.1" + lightningcss-linux-arm64-musl "1.30.1" + lightningcss-linux-x64-gnu "1.30.1" + lightningcss-linux-x64-musl "1.30.1" + lightningcss-win32-arm64-msvc "1.30.1" + lightningcss-win32-x64-msvc "1.30.1" + +local-pkg@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.2.tgz#c03d208787126445303f8161619dc701afa4abb5" + integrity sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A== + dependencies: + mlly "^1.7.4" + pkg-types "^2.3.0" + quansync "^0.2.11" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -1617,6 +3235,24 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +loupe@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -1624,6 +3260,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +magic-string@^0.30.17: + version "0.30.18" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.18.tgz#905bfbbc6aa5692703a93db26a9edcaa0007d2bb" + integrity sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -1643,6 +3286,29 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +markdown-to-jsx@7.7.4: + version "7.7.4" + resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.7.4.tgz#507d17c15af72ddf970fca84a95f0243244fcfa9" + integrity sha512-1bSfXyBKi+EYS3YY+e0Csuxf8oZ3decdfhOav/Z7Wrk89tjudyL5FOmwZQUoy0/qVXGUl+6Q3s2SWtpDEWITfQ== + +mdn-data@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.2.tgz#9ae6c41a9e65adf61318b32bff7b64fbfb13f8cf" + integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1669,6 +3335,18 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" + integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== + dependencies: + minipass "^7.1.2" + mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -1676,6 +3354,21 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +mlly@^1.7.4: + version "1.8.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.8.0.tgz#e074612b938af8eba1eaf43299cbc89cb72d824e" + integrity sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g== + dependencies: + acorn "^8.15.0" + pathe "^2.0.3" + pkg-types "^1.3.1" + ufo "^1.6.1" + mocha@10.8.2: version "10.8.2" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.8.2.tgz#8d8342d016ed411b12a429eb731b825f961afb96" @@ -1702,16 +3395,72 @@ mocha@10.8.2: yargs-parser "^20.2.9" yargs-unparser "^2.0.0" +mocha@11.2.2: + version "11.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.2.2.tgz#2dfefc9652de746389f5286888034239b6486231" + integrity sha512-VlSBxrPYHK4YNOEbFdkCxHQbZMoNzBkoPprqtZRW6311EUF/DlSxoycE2e/2NtRk4WKkIXzyrXDTrlikJMWgbw== + dependencies: + browser-stdout "^1.3.1" + chokidar "^4.0.1" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^10.4.5" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + picocolors "^1.1.1" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^17.7.2" + yargs-parser "^21.1.1" + yargs-unparser "^2.0.0" + +moment@2.30.1: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + +mrmime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc" + integrity sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ== + ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mustache@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" + integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== + mute-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== +nanoid@3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +node-fetch-native@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz#9d09ca63066cc48423211ed4caf5d70075d76a71" + integrity sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q== + node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -1724,6 +3473,11 @@ node-releases@^2.0.19: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== +nodemailer@6.9.16: + version "6.9.16" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.16.tgz#3ebdf6c6f477c571c0facb0727b33892635e0b8b" + integrity sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ== + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -1762,6 +3516,15 @@ nyc@17.1.0: test-exclude "^6.0.0" yargs "^15.0.2" +ofetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.4.1.tgz#b6bf6b0d75ba616cef6519dd8b6385a8bae480ec" + integrity sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw== + dependencies: + destr "^2.0.3" + node-fetch-native "^1.6.4" + ufo "^1.5.4" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1824,6 +3587,33 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +package-manager-detector@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/package-manager-detector/-/package-manager-detector-1.3.0.tgz#b42d641c448826e03c2b354272456a771ce453c0" + integrity sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ== + +papaparse@5.5.1: + version "5.5.1" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.5.1.tgz#4322da01e85d8e9e282c1e4387793a5978b5a0a1" + integrity sha512-EuEKUhyxrHVozD7g3/ztsJn6qaKse8RPfR6buNB2dMJvdtXNhcw8jccVi/LxNEY3HVrV6GO6Z4OoeCG9Iy9wpA== + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + path-browserify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" @@ -1844,17 +3634,40 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + +perfect-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a" + integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== + picocolors@^1.0.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -1864,6 +3677,11 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + pkg-dir@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -1871,6 +3689,48 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" +pkg-types@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.3.0.tgz#037f2c19bd5402966ff6810e32706558cb5b5726" + integrity sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig== + dependencies: + confbox "^0.2.2" + exsolve "^1.0.7" + pathe "^2.0.3" + +postcss@^8.5.2, postcss@^8.5.3: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prettier@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +prismjs@^1.27.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" + integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== + +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + process-on-spawn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.1.0.tgz#9d5999ba87b3bf0a8acb05322d69f2f5aa4fb763" @@ -1878,6 +3738,45 @@ process-on-spawn@^1.0.0: dependencies: fromentries "^1.2.0" +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +pvtsutils@^1.3.5, pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + +quansync@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.11.tgz#f9c3adda2e1272e4f8cf3f1457b04cbdb4ee692a" + integrity sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +r22n@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/r22n/-/r22n-1.0.10.tgz#bab4b5888bcdb3f44d93ac076acfe6cec5ab102d" + integrity sha512-2jFDC6oCe5UhzL4s8iAMN+7FbAtaxK9SjzZ6HxYm8O7+zmxZsiSSqjZD7iFfsjJtJkPx760p7Nc6jTXjc+Yd2w== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -1885,6 +3784,54 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +react-dom@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" + integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== + dependencies: + scheduler "^0.26.0" + +react-refresh@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53" + integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== + +react-syntax-highlighter@15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz#fa567cb0a9f96be7bbccf2c13a3c4b5657d9543e" + integrity sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + highlightjs-vue "^1.0.0" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-toastify@11.0.5, react-toastify@^11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.0.5.tgz#ce4c42d10eeb433988ab2264d3e445c4e9d13313" + integrity sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA== + dependencies: + clsx "^2.1.1" + +react@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" + integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== + +reactus@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/reactus/-/reactus-0.6.1.tgz#fea94424481052ba298e511ad8f7e6e53dbff084" + integrity sha512-+NP6BJYMYrk79NkIvgd094ghxHQ4zTDCVFvuSBZJRePYpXEHNkoqjIGl+2IUGGbO+gVGGqNTfALZEnJ13pvh7A== + dependencies: + "@stackpress/lib" "0.6.1" + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1892,6 +3839,15 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + release-zalgo@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" @@ -1919,6 +3875,11 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -1926,6 +3887,42 @@ rimraf@^3.0.0: dependencies: glob "^7.1.3" +rollup@^4.34.9: + version "4.49.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.49.0.tgz#9751ad9d06a47a4496c3c5c238b27b1422c8b0eb" + integrity sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.49.0" + "@rollup/rollup-android-arm64" "4.49.0" + "@rollup/rollup-darwin-arm64" "4.49.0" + "@rollup/rollup-darwin-x64" "4.49.0" + "@rollup/rollup-freebsd-arm64" "4.49.0" + "@rollup/rollup-freebsd-x64" "4.49.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.49.0" + "@rollup/rollup-linux-arm-musleabihf" "4.49.0" + "@rollup/rollup-linux-arm64-gnu" "4.49.0" + "@rollup/rollup-linux-arm64-musl" "4.49.0" + "@rollup/rollup-linux-loongarch64-gnu" "4.49.0" + "@rollup/rollup-linux-ppc64-gnu" "4.49.0" + "@rollup/rollup-linux-riscv64-gnu" "4.49.0" + "@rollup/rollup-linux-riscv64-musl" "4.49.0" + "@rollup/rollup-linux-s390x-gnu" "4.49.0" + "@rollup/rollup-linux-x64-gnu" "4.49.0" + "@rollup/rollup-linux-x64-musl" "4.49.0" + "@rollup/rollup-win32-arm64-msvc" "4.49.0" + "@rollup/rollup-win32-ia32-msvc" "4.49.0" + "@rollup/rollup-win32-x64-msvc" "4.49.0" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -1936,6 +3933,11 @@ safe-buffer@^5.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== + semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -1980,6 +3982,15 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +sirv@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.1.tgz#32a844794655b727f9e2867b777e0060fbe07bf3" + integrity sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + sort-any@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-any/-/sort-any-2.0.0.tgz#62a5409c9905c9483f03e41e17f46cc451aa7c55" @@ -1987,6 +3998,11 @@ sort-any@^2.0.0: dependencies: lodash "^4.17.21" +source-map-js@^1.0.1, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -2000,6 +4016,11 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + spawn-wrap@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" @@ -2017,7 +4038,41 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -string-width@^4.1.0, string-width@^4.2.0: +stackpress@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/stackpress/-/stackpress-0.6.1.tgz#2609acfc3d063b20ca614b5bbaa9afd379dde79d" + integrity sha512-y0xUvvlXR2Tfkq4ZHy7R5KsNL3e7PjpEy563YGWVTm294AxwAO7jjNa0/tbfpuxFhKp+kxougz78nrSIVjJpeA== + dependencies: + "@paralleldrive/cuid2" "2.2.2" + "@stackpress/idea-transformer" "0.6.1" + "@stackpress/ingest" "0.6.1" + "@stackpress/inquire" "0.6.1" + "@stackpress/lib" "0.6.1" + jose "6.0.10" + mustache "4.2.0" + nanoid "3.3.8" + nodemailer "6.9.16" + papaparse "5.5.1" + r22n "1.0.10" + react-toastify "11.0.5" + reactus "0.6.1" + universal-cookie "8.0.1" + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2026,6 +4081,22 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -2033,6 +4104,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -2048,6 +4126,11 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-mod@^4.0.0, style-mod@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67" + integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw== + supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -2062,6 +4145,28 @@ supports-color@^8.1.1: dependencies: has-flag "^4.0.0" +tailwindcss@4.1.12, tailwindcss@^4.1.12: + version "4.1.12" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.12.tgz#7baeed5b5ac77370571c2baa72ee06e0050fc0a8" + integrity sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA== + +tapable@^2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.3.tgz#4b67b635b2d97578a06a2713d2f04800c237e99b" + integrity sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg== + +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -2071,6 +4176,19 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +tinyexec@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" + integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== + +tinyglobby@^0.2.10, tinyglobby@^0.2.12: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + tinyglobby@^0.2.9: version "0.2.10" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" @@ -2093,6 +4211,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + ts-mocha@10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9" @@ -2102,6 +4225,11 @@ ts-mocha@10.0.0: optionalDependencies: tsconfig-paths "^3.5.0" +ts-mocha@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-11.1.0.tgz#d8336ec0146bd6f36cca2555f4cfc7df85bd1586" + integrity sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ== + ts-morph@24.0.0: version "24.0.0" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-24.0.0.tgz#6249b526ade40cf99c8803e7abdae6c65882e58e" @@ -2110,6 +4238,14 @@ ts-morph@24.0.0: "@ts-morph/common" "~0.25.0" code-block-writer "^13.0.3" +ts-morph@25.0.1: + version "25.0.1" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-25.0.1.tgz#7de0b60fcc6e86955c8766831bcd2c5d87ffbd4f" + integrity sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ== + dependencies: + "@ts-morph/common" "~0.26.0" + code-block-writer "^13.0.3" + ts-node@10.9.2: version "10.9.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" @@ -2153,6 +4289,11 @@ tsconfig-paths@^3.5.0: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@^2.0.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsx@4.19.3: version "4.19.3" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.3.tgz#2bdbcb87089374d933596f8645615142ed727666" @@ -2190,11 +4331,74 @@ typescript@5.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== +typescript@5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +ufo@^1.5.4, ufo@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +unconfig@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/unconfig/-/unconfig-7.0.0.tgz#0c917fbbeb9ac49341b4bc56b155351646dd6ff2" + integrity sha512-G5CJSoG6ZTxgzCJblEfgpdRK2tos9+UdD2WtecDUVfImzQ0hFjwpH5RVvGMhP4pRpC9ML7NrC4qBsBl0Ttj35A== + dependencies: + "@antfu/utils" "^8.1.0" + defu "^6.1.4" + jiti "^2.4.2" + undici-types@~6.19.8: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +universal-cookie@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-8.0.1.tgz#19263fcda6889978a081c610a90fc395eeaeec64" + integrity sha512-B6ks9FLLnP1UbPPcveOidfvB9pHjP+wekP2uRYB9YDfKVpvcjKgy1W5Zj+cEXJ9KTPnqOKGfVDQBmn8/YCQfRg== + dependencies: + cookie "^1.0.2" + +unocss@66.0.0: + version "66.0.0" + resolved "https://registry.yarnpkg.com/unocss/-/unocss-66.0.0.tgz#4f6842b54fc1a1a1c7d86d925b972ba035e03c4f" + integrity sha512-SHstiv1s7zGPSjzOsADzlwRhQM+6817+OqQE3Fv+N/nn2QLNx1bi3WXybFfz5tWkzBtyTZlwdPmeecsIs1yOCA== + dependencies: + "@unocss/astro" "66.0.0" + "@unocss/cli" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/postcss" "66.0.0" + "@unocss/preset-attributify" "66.0.0" + "@unocss/preset-icons" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/preset-tagify" "66.0.0" + "@unocss/preset-typography" "66.0.0" + "@unocss/preset-uno" "66.0.0" + "@unocss/preset-web-fonts" "66.0.0" + "@unocss/preset-wind" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + "@unocss/transformer-attributify-jsx" "66.0.0" + "@unocss/transformer-compile-class" "66.0.0" + "@unocss/transformer-directives" "66.0.0" + "@unocss/transformer-variant-group" "66.0.0" + "@unocss/vite" "66.0.0" + +unplugin-utils@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.2.5.tgz#d2fe44566ffffd7f216579bbb01184f6702e379b" + integrity sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg== + dependencies: + pathe "^2.0.3" + picomatch "^4.0.3" + update-browserslist-db@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" @@ -2203,6 +4407,11 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.1" +urlpattern-polyfill@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5" + integrity sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ== + uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" @@ -2213,6 +4422,46 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +vite@6.3.2: + version "6.3.2" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.2.tgz#4c1bb01b1cea853686a191657bbc14272a038f0a" + integrity sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.3" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.12" + optionalDependencies: + fsevents "~2.3.3" + +vue-flow-layout@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/vue-flow-layout/-/vue-flow-layout-0.1.1.tgz#4095d9e79b80e845f110d4d015de6faf2c71f735" + integrity sha512-JdgRRUVrN0Y2GosA0M68DEbKlXMqJ7FQgsK8CjQD2vxvNSqAU6PZEpi4cfcTVtfM2GVOMjHo7GKKLbXxOBqDqA== + +w3c-keyname@^2.2.4: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + +web-streams-polyfill@^3.2.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + +webcrypto-core@^1.8.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.8.1.tgz#09d5bd8a9c48e9fbcaf412e06b1ff1a57514ce86" + integrity sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A== + dependencies: + "@peculiar/asn1-schema" "^2.3.13" + "@peculiar/json-schema" "^1.1.12" + asn1js "^3.0.5" + pvtsutils "^1.3.5" + tslib "^2.7.0" + which-module@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" @@ -2230,6 +4479,15 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -2248,6 +4506,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -2263,6 +4530,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" @@ -2278,6 +4550,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -2291,6 +4568,11 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.9: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-unparser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -2331,6 +4613,19 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From 4172f2aa59f2f0665a5680b00d916f5aa377eec4 Mon Sep 17 00:00:00 2001 From: NJ veneracion Date: Mon, 8 Sep 2025 11:33:29 +0800 Subject: [PATCH 02/14] created idea website 4d --- packages/www | 1 - packages/www/.gitignore | 137 + packages/www/README.md | 2 + packages/www/build.ts | 93 + packages/www/config/build.ts | 60 + packages/www/config/common.ts | 83 + packages/www/config/develop.ts | 57 + packages/www/config/preview.ts | 59 + packages/www/package.json | 52 + packages/www/plugins/app/Layout.tsx | 113 + packages/www/plugins/app/pages/error.ts | 58 + packages/www/plugins/app/plugin.ts | 20 + packages/www/plugins/app/styles/page.css | 1 + packages/www/plugins/app/views/error.tsx | 108 + packages/www/plugins/app/views/home.tsx | 52 + .../AIDevelopmentWorkflowSection.tsx | 77 + .../app/views/landingpage/AboutSection.tsx | 15 + .../app/views/landingpage/AudienceSection.tsx | 57 + .../app/views/landingpage/BenefitsSection.tsx | 79 + .../app/views/landingpage/FutureSection.tsx | 72 + .../app/views/landingpage/HeroSection.tsx | 185 + .../landingpage/PluginEcosystemSection.tsx | 67 + .../landingpage/RealWorldExampleSection.tsx | 102 + packages/www/plugins/assets/plugin.ts | 39 + packages/www/plugins/docs/components/Code.tsx | 79 + .../www/plugins/docs/components/Editor.tsx | 139 + .../www/plugins/docs/components/Layout.tsx | 482 +++ .../www/plugins/docs/components/index.tsx | 218 + packages/www/plugins/docs/plugin.ts | 102 + .../plugins/docs/views/getting-started.tsx | 126 + packages/www/plugins/docs/views/index.tsx | 226 ++ .../docs/views/parser/api-reference.tsx | 178 + .../docs/views/parser/best-practices.tsx | 191 + .../docs/views/parser/core-concepts.tsx | 97 + .../plugins/docs/views/parser/examples.tsx | 130 + .../docs/views/parser/installation.tsx | 116 + .../plugins/docs/views/parser/pages/ast.tsx | 856 ++++ .../docs/views/parser/pages/compiler.tsx | 754 ++++ .../views/parser/pages/exception-handling.tsx | 306 ++ .../plugins/docs/views/parser/pages/lexer.tsx | 755 ++++ .../docs/views/parser/pages/tokens.tsx | 995 +++++ .../plugin-development/advanced-tutorials.tsx | 218 + .../available-tutorials.tsx | 167 + .../plugin-development/best-practices.tsx | 192 + .../plugin-development/error-handling.tsx | 151 + .../plugin-development/getting-started.tsx | 424 ++ .../plugin-configuration.tsx | 125 + .../plugin-development-guide.tsx | 279 ++ .../plugin-development/plugin-examples.tsx | 266 ++ .../views/specifications/best-practices.tsx | 260 ++ .../specifications/complete-examples.tsx | 375 ++ .../components/data-types/Enums.tsx | 84 + .../components/data-types/Models.tsx | 117 + .../components/data-types/Props.tsx | 87 + .../components/data-types/Type.tsx | 75 + .../components/schema-directives/Plugin.tsx | 216 + .../components/schema-directives/Use.tsx | 143 + .../docs/views/specifications/data-types.tsx | 108 + .../views/specifications/error-handling.tsx | 254 ++ .../views/specifications/plugin-system.tsx | 142 + .../views/specifications/processing-flow.tsx | 105 + .../specifications/schema-directives.tsx | 95 + .../views/specifications/schema-elements.tsx | 235 ++ .../views/specifications/schema-structure.tsx | 120 + .../views/specifications/syntax-overview.tsx | 175 + .../docs/views/transformers/api-reference.tsx | 151 + .../docs/views/transformers/architecture.tsx | 86 + .../views/transformers/best-practices.tsx | 105 + .../views/transformers/common-use-cases.tsx | 116 + .../views/transformers/error-handling.tsx | 96 + .../docs/views/transformers/examples.tsx | 133 + .../docs/views/transformers/introduction.tsx | 111 + .../views/transformers/pages/terminal.tsx | 883 +++++ .../views/transformers/pages/transformer.tsx | 687 ++++ .../views/transformers/usage-patterns.tsx | 125 + .../views/tutorials/api-client-plugin.tsx | 1042 +++++ .../ts-morph/advance-tsmorph-pluginn.tsx | 142 + .../components/ts-morph/best-practices.tsx | 203 + .../ts-morph/create-first-plugin.tsx | 521 +++ .../components/ts-morph/installation.tsx | 40 + .../components/ts-morph/introduction.tsx | 40 + .../components/ts-morph/references.tsx | 69 + .../ts-morph/setting-up-project.tsx | 63 + .../ts-morph/testing-your-plugin.tsx | 147 + .../components/ts-morph/troubleshooting.tsx | 183 + .../ts-morph/understanding-tsmorph-basics.tsx | 344 ++ .../views/tutorials/graphql-schema-plugin.tsx | 892 +++++ .../docs/views/tutorials/html-form-plugin.tsx | 1358 +++++++ .../markdown-documentation-plugin.tsx | 1447 +++++++ .../views/tutorials/mysql-table-plugin.tsx | 914 +++++ .../openapi-specification-plugin.tsx | 1436 +++++++ .../docs/views/tutorials/test-data-plugin.tsx | 806 ++++ .../views/tutorials/tsmorph-plugin-guide.tsx | 134 + .../tutorials/typescript-interface-plugin.tsx | 1097 +++++ .../views/tutorials/validation-plugin.tsx | 974 +++++ packages/www/public/favicon.ico | Bin 0 -> 15086 bytes packages/www/public/icon.png | Bin 0 -> 31828 bytes packages/www/public/styles/global.css | 452 +++ packages/www/public/v1.html | 461 +++ packages/www/tsconfig.json | 15 + packages/www/uno.config.ts | 19 + packages/www/yarn.lock | 3511 +++++++++++++++++ 102 files changed, 30554 insertions(+), 1 deletion(-) delete mode 160000 packages/www create mode 100644 packages/www/.gitignore create mode 100644 packages/www/README.md create mode 100644 packages/www/build.ts create mode 100644 packages/www/config/build.ts create mode 100644 packages/www/config/common.ts create mode 100644 packages/www/config/develop.ts create mode 100644 packages/www/config/preview.ts create mode 100644 packages/www/package.json create mode 100644 packages/www/plugins/app/Layout.tsx create mode 100644 packages/www/plugins/app/pages/error.ts create mode 100644 packages/www/plugins/app/plugin.ts create mode 100644 packages/www/plugins/app/styles/page.css create mode 100644 packages/www/plugins/app/views/error.tsx create mode 100644 packages/www/plugins/app/views/home.tsx create mode 100644 packages/www/plugins/app/views/landingpage/AIDevelopmentWorkflowSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/AboutSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/AudienceSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/BenefitsSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/FutureSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/HeroSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/PluginEcosystemSection.tsx create mode 100644 packages/www/plugins/app/views/landingpage/RealWorldExampleSection.tsx create mode 100644 packages/www/plugins/assets/plugin.ts create mode 100644 packages/www/plugins/docs/components/Code.tsx create mode 100644 packages/www/plugins/docs/components/Editor.tsx create mode 100644 packages/www/plugins/docs/components/Layout.tsx create mode 100644 packages/www/plugins/docs/components/index.tsx create mode 100644 packages/www/plugins/docs/plugin.ts create mode 100644 packages/www/plugins/docs/views/getting-started.tsx create mode 100644 packages/www/plugins/docs/views/index.tsx create mode 100644 packages/www/plugins/docs/views/parser/api-reference.tsx create mode 100644 packages/www/plugins/docs/views/parser/best-practices.tsx create mode 100644 packages/www/plugins/docs/views/parser/core-concepts.tsx create mode 100644 packages/www/plugins/docs/views/parser/examples.tsx create mode 100644 packages/www/plugins/docs/views/parser/installation.tsx create mode 100644 packages/www/plugins/docs/views/parser/pages/ast.tsx create mode 100644 packages/www/plugins/docs/views/parser/pages/compiler.tsx create mode 100644 packages/www/plugins/docs/views/parser/pages/exception-handling.tsx create mode 100644 packages/www/plugins/docs/views/parser/pages/lexer.tsx create mode 100644 packages/www/plugins/docs/views/parser/pages/tokens.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/best-practices.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/error-handling.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/getting-started.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx create mode 100644 packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx create mode 100644 packages/www/plugins/docs/views/specifications/best-practices.tsx create mode 100644 packages/www/plugins/docs/views/specifications/complete-examples.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx create mode 100644 packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx create mode 100644 packages/www/plugins/docs/views/specifications/data-types.tsx create mode 100644 packages/www/plugins/docs/views/specifications/error-handling.tsx create mode 100644 packages/www/plugins/docs/views/specifications/plugin-system.tsx create mode 100644 packages/www/plugins/docs/views/specifications/processing-flow.tsx create mode 100644 packages/www/plugins/docs/views/specifications/schema-directives.tsx create mode 100644 packages/www/plugins/docs/views/specifications/schema-elements.tsx create mode 100644 packages/www/plugins/docs/views/specifications/schema-structure.tsx create mode 100644 packages/www/plugins/docs/views/specifications/syntax-overview.tsx create mode 100644 packages/www/plugins/docs/views/transformers/api-reference.tsx create mode 100644 packages/www/plugins/docs/views/transformers/architecture.tsx create mode 100644 packages/www/plugins/docs/views/transformers/best-practices.tsx create mode 100644 packages/www/plugins/docs/views/transformers/common-use-cases.tsx create mode 100644 packages/www/plugins/docs/views/transformers/error-handling.tsx create mode 100644 packages/www/plugins/docs/views/transformers/examples.tsx create mode 100644 packages/www/plugins/docs/views/transformers/introduction.tsx create mode 100644 packages/www/plugins/docs/views/transformers/pages/terminal.tsx create mode 100644 packages/www/plugins/docs/views/transformers/pages/transformer.tsx create mode 100644 packages/www/plugins/docs/views/transformers/usage-patterns.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/api-client-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/advance-tsmorph-pluginn.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/installation.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/introduction.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/references.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/setting-up-project.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/troubleshooting.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/components/ts-morph/understanding-tsmorph-basics.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/graphql-schema-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/html-form-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/markdown-documentation-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/openapi-specification-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/test-data-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/tsmorph-plugin-guide.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/typescript-interface-plugin.tsx create mode 100644 packages/www/plugins/docs/views/tutorials/validation-plugin.tsx create mode 100644 packages/www/public/favicon.ico create mode 100644 packages/www/public/icon.png create mode 100644 packages/www/public/styles/global.css create mode 100644 packages/www/public/v1.html create mode 100644 packages/www/tsconfig.json create mode 100644 packages/www/uno.config.ts create mode 100644 packages/www/yarn.lock diff --git a/packages/www b/packages/www deleted file mode 160000 index a85d864..0000000 --- a/packages/www +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a85d8647636727f9ea38276e95a76b6640176338 diff --git a/packages/www/.gitignore b/packages/www/.gitignore new file mode 100644 index 0000000..185824a --- /dev/null +++ b/packages/www/.gitignore @@ -0,0 +1,137 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +archives +.ink +.DS_Store +.build + +archives \ No newline at end of file diff --git a/packages/www/README.md b/packages/www/README.md new file mode 100644 index 0000000..8a35447 --- /dev/null +++ b/packages/www/README.md @@ -0,0 +1,2 @@ +# stackpress.github.io +Official Website diff --git a/packages/www/build.ts b/packages/www/build.ts new file mode 100644 index 0000000..9ec1611 --- /dev/null +++ b/packages/www/build.ts @@ -0,0 +1,93 @@ +//node +import fs from 'node:fs/promises'; +import path from 'node:path'; +//stackpress +import { Terminal } from 'stackpress/terminal'; +import * as scripts from 'stackpress/scripts'; +//plugins +import { docs } from './config/common.js'; +import bootstrap from './config/build.js'; + +async function build() { + const server = await bootstrap(); + const cli = new Terminal(['build'], server); + + cli.control.system('Copying public to docs...'); + await fsCopyFolder(path.join(cli.cwd, 'public'), docs); + + cli.control.system('Building pages, client and styles...'); + await scripts.build(server); + + cli.control.system('Generating markup in docs...'); + const ignore = Array.from(server.action.expressions.keys()); + const routes = Array.from(server.routes.entries()).filter( + ([event]) => !ignore.includes(event) + ); + + for (const [event, route] of routes) { + const request = server.request({ + url: new URL(`https://www.stackpress.io${route.path}`), + }); + const response = await server.resolve(event, request); + cli.control.system(`Generating ${request.url.href} ...`); + if (response.results) { + const routepath = route.path.replace(/^\//, ''); + const filepath = routepath === '' ? 'index.html' : `${routepath}.html`; + await fsWriteFile( + path.join(docs, filepath), + response.results as string + ) + } + } +}; + +async function fsWriteFile(file: string, data: string) { + const dirname = path.dirname(file); + if (!await fsExists(dirname)) { + await fs.mkdir(dirname, { recursive: true }); + } + await fs.writeFile(file, data, 'utf-8'); +} + +async function fsCopyFile(source: string, destination: string) { + if (await fsExists(source)) { + const dirname = path.dirname(destination); + if (!await fsExists(dirname)) { + await fs.mkdir(dirname, { recursive: true }); + } + await fs.copyFile(source, destination); + } +}; + +async function fsCopyFolder(source: string, destination: string) { + //find all the files from source + const files = await fs.readdir(source); + for (const file of files) { + //ignore . and .. + if (file === '.' || file === '..') continue; + //make an absolute source path + const absolute = path.join(source, file); + const stat = await fs.stat(absolute); + //if file is a directory, recurse + if (stat.isDirectory()) { + fsCopyFolder( + path.join(source, file), + path.join(destination, file) + ); + continue; + } + await fsCopyFile(absolute, path.join(destination, file)); + } +}; + +async function fsExists(path: string) { + return await fs.access(path).then(() => true).catch(() => false); +} + +build().then(() => { + console.log('Build completed successfully.'); + process.exit(0); +}).catch((error) => { + console.error('Build failed:', error); + process.exit(1); +}); \ No newline at end of file diff --git a/packages/www/config/build.ts b/packages/www/config/build.ts new file mode 100644 index 0000000..b894c8c --- /dev/null +++ b/packages/www/config/build.ts @@ -0,0 +1,60 @@ +//node +import path from 'node:path'; +//modules +import unocss from 'unocss/vite'; +//stackpress +import { server as http } from 'stackpress/http'; +//config +import type { Config } from './common.js'; +import * as common from './common.js'; + +export const config: Config = { + server: { + ...common.server, + mode: 'production' + }, + view: { + ...common.view, + //reactus specific settings + engine: { + //path where to save assets (css, images, etc) + assetPath: path.join(common.docs, 'assets'), + //path where to save the client scripts (js) + clientPath: path.join(common.docs, 'client'), + //path where to save the server scripts (js) + pagePath: path.join(common.build, 'pages'), + //filepath to a global css file + cssFiles: [ + 'frui/frui.css', + 'stackpress/stackpress.css', + 'virtual:uno.css' + ], + //vite plugins + plugins: [ unocss() ], + //original vite options (overrides other settings related to vite) + vite: undefined + } + }, + brand: common.brand, + cli: common.cli, + cookie: common.cookie, + language: common.language, + session: common.session +}; + +export default async function bootstrap() { + //make a server + const server = http(); + //set config + server.config.set(config); + //load the plugins + await server.bootstrap(); + //initialize the plugins + await server.resolve('config'); + //add events + await server.resolve('listen'); + //add routes + await server.resolve('route'); + //return the server + return server; +}; \ No newline at end of file diff --git a/packages/www/config/common.ts b/packages/www/config/common.ts new file mode 100644 index 0000000..33f5bd7 --- /dev/null +++ b/packages/www/config/common.ts @@ -0,0 +1,83 @@ +//node +import path from 'node:path'; + +export type { Config } from 'stackpress/types'; + +export const cwd = process.cwd(); +export const docs = path.join(cwd, 'docs'); +export const build = path.join(cwd, '.build'); +export const assets = path.join(cwd, 'public'); + +export const brand = { + name: 'Stackpress', + logo: '/logo.png', + icon: '/icon.png', + favicon: '/favicon.ico' +}; + +export const server = { + port: 3000, + cwd: cwd +}; + +export const view = { + //url flag (ie. ?json) used to disable template + //rendering and show the raw json data instead + noview: 'json', + //used by vite and in development mode + //to determine the root of the project + base: '/', + //frontend notification display settings + notify: { + position: 'bottom-center', + autoClose: 1000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + theme: 'dark', + } +}; + +export const session = { + //name of the session cookie + key: 'session', + //used to generate the session id + seed: 'abc123', + access: { GUEST: [ { method: 'ALL', route: '/**' } ] } +}; + +export const cookie = { + //see: https://github.com/jshttp/cookie?tab=readme-ov-file#options-1 + path: '/' +}; + +export const language = { + //url flag (ie. ?json) used to change the user's locale + //this is also the name of the cookie used to store the locale + key: 'locale', + //default locale + locale: 'en_US', + //languages and translations + languages: { + en_US: { + label: 'EN', + translations: { + 'Sign In': 'Signin', + 'Home Page': 'Home Page' + } + }, + th_TH: { + label: 'TH', + translations: { + 'Sign In': 'Signin', + 'Home Page': 'Home Pagesss' + } + } + } +}; + +export const cli = { + label: '[WWW]', + idea: path.join(cwd, 'schema.idea') +}; \ No newline at end of file diff --git a/packages/www/config/develop.ts b/packages/www/config/develop.ts new file mode 100644 index 0000000..ab1a1ac --- /dev/null +++ b/packages/www/config/develop.ts @@ -0,0 +1,57 @@ +//modules +import unocss from 'unocss/vite'; +//stackpress +import { server as http } from 'stackpress/http'; +//config +import type { Config } from './common.js'; +import * as common from './common.js'; + +export const config: Config = { + server: { + ...common.server, + mode: 'development' + }, + view: { + ...common.view, + //reactus specific settings + engine: { + //base path (used in vite) + basePath: '/', + //client script route prefix used in the document markup + //ie. /client/[id][extname] + // + // + clientRoute: '/client', + //filepath to a global css file + cssFiles: [ + 'frui/frui.css', + 'stackpress/stackpress.css', + 'virtual:uno.css' + ], + //vite plugins + plugins: [ unocss() ] + } + }, + brand: common.brand, + cli: common.cli, + cookie: common.cookie, + language: common.language, + session: common.session +}; + +export default async function bootstrap() { + //make a server + const server = http(); + //set config + server.config.set(config); + //load the plugins + await server.bootstrap(); + //initialize the plugins + await server.resolve('config'); + //add events + await server.resolve('listen'); + //add routes + await server.resolve('route'); + //return the server + return server; +}; \ No newline at end of file diff --git a/packages/www/config/preview.ts b/packages/www/config/preview.ts new file mode 100644 index 0000000..32769f7 --- /dev/null +++ b/packages/www/config/preview.ts @@ -0,0 +1,59 @@ +//node +import path from 'node:path'; +//stackpress +import type { Server } from 'stackpress/server'; +import { server as http } from 'stackpress/http'; +//plugin +import assets from '../plugins/assets/plugin.js'; +//config +import type { Config } from './common.js'; +import * as common from './common.js'; + +export const config: Config = { + assets: common.assets, + server: { + ...common.server, + mode: 'production' + }, + view: { + ...common.view, + //reactus specific settings + engine: { + //client script route prefix used in the document markup + //ie. /client/[id][extname] + // + // + clientRoute: '/client', + //style route prefix used in the document markup + //ie. /assets/[id][extname] + // + // + cssRoute: '/assets', + //path where to save and load (live) the server script (js) + pagePath: path.join(common.cwd, '.build/views') + } + }, + brand: common.brand, + cli: common.cli, + cookie: common.cookie, + language: common.language +}; + +export default async function bootstrap() { + //make a server + const server = http(); + //set config + server.config.set(config); + //load the plugins + await server.bootstrap(); + //add the assets plugin + assets(server as Server); + //initialize the plugins + await server.resolve('config'); + //add events + await server.resolve('listen'); + //add routes + await server.resolve('route'); + //return the server + return server; +}; \ No newline at end of file diff --git a/packages/www/package.json b/packages/www/package.json new file mode 100644 index 0000000..c741b11 --- /dev/null +++ b/packages/www/package.json @@ -0,0 +1,52 @@ +{ + "type": "module", + "name": "stackpress-with-unocss", + "version": "1.0.0", + "private": true, + "plugins": [ + "./plugins/app/plugin", + "./plugins/docs/plugin", + "stackpress" + ], + "scripts": { + "build": "yarn build:purge && yarn build:tsx", + "build:purge": "rm -rf docs", + "build:tsx": "npx tsx build.ts", + "dev": "stackpress serve -v --b config/develop", + "emit": "stackpress emit -v --b config/develop", + "preview": "stackpress serve -v --b config/preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.12", + "frui": "0.1.8", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-syntax-highlighter": "15.6.1", + "react-toastify": "^11.0.5", + "stackpress": "0.6.1", + "tailwindcss": "^4.1.12" + }, + "devDependencies": { + "@stackpress/idea-transformer": "0.6.1", + "@types/chai": "5.2.1", + "@types/mocha": "10.0.10", + "@types/node": "22.14.1", + "@types/react": "19.1.2", + "@types/react-dom": "19.1.2", + "@types/react-syntax-highlighter": "15.5.13", + "@vitejs/plugin-react": "4.4.1", + "chai": "5.2.0", + "dotenv-cli": "8.0.0", + "fast-glob": "3.3.3", + "mocha": "11.2.2", + "nyc": "17.1.0", + "prettier": "3.5.3", + "ts-mocha": "11.1.0", + "ts-morph": "25.0.1", + "ts-node": "10.9.2", + "tsx": "4.19.3", + "typescript": "5.8.3", + "unocss": "66.0.0", + "vite": "6.3.2" + } +} diff --git a/packages/www/plugins/app/Layout.tsx b/packages/www/plugins/app/Layout.tsx new file mode 100644 index 0000000..bf76f82 --- /dev/null +++ b/packages/www/plugins/app/Layout.tsx @@ -0,0 +1,113 @@ +//modules +import { useState, useEffect } from 'react'; +//views +import type { + PanelAppProps, + LayoutHeadProps, + LayoutPanelProps +} from 'stackpress/view/client'; +import { + unload, + useTheme, + useLanguage, + NotifyContainer, + LayoutMain, + LayoutProvider +} from 'stackpress/view/client'; + +export function Head(props: LayoutHeadProps) { + const { theme, toggleTheme } = props; + const { _ } = useLanguage(); + const themeColor = theme === 'dark' ? 'bg-gray-600' : 'bg-orange-600'; + const themeIcon = theme === 'dark' ? 'fa-moon' : 'fa-sun'; + return ( + +
+
+ + idea-logo + idea + + + +
+
+ ); +} + +export function App(props: PanelAppProps) { + const { children } = props; + const { theme, toggle: toggleTheme } = useTheme(); + return ( +
+ + {children} +
+ ); +} + +export default function Layout(props: LayoutPanelProps) { + const { + data, + session, + response, + children + } = props; + const [request, setRequest] = useState>({ + ...(props.request || {}), + session: { + ...(props.request?.session || {}), + theme: props.request?.session?.theme || 'dark' + } + }); + //unload flash message + useEffect(() => { + const light = document.cookie.includes('theme=light'); + if (!request.session?.theme) { + setRequest({ + ...request, + session: { theme: light ? 'light' : 'dark' } + }); + } + unload(); + }, []); + if (!request?.session?.theme) { + return null; + } + return ( + + {children} + + + ); +} \ No newline at end of file diff --git a/packages/www/plugins/app/pages/error.ts b/packages/www/plugins/app/pages/error.ts new file mode 100644 index 0000000..2b68665 --- /dev/null +++ b/packages/www/plugins/app/pages/error.ts @@ -0,0 +1,58 @@ +//node +import fs from 'node:fs'; +import path from 'node:path'; +//stackpress +import { action } from 'stackpress/server'; + +export default action(async function ErrorPage(req, res, ctx) { + //if there is already a body + if (res.body) return; + //set data for template layer + res.data.set('server', { + mode: ctx.config.path('server.mode', 'production'), + }); + //general settings + const response = res.toStatusResponse(); + const { stack = [] } = response; + //add snippets to stack + stack.forEach((trace, i) => { + //skip the first trace + if (i === 0 + || !trace.file.startsWith(path.sep) + || !fs.existsSync(trace.file) + ) return; + const { file, line, char } = trace; + const source = fs.readFileSync(file, 'utf8') + const lines = source.split('\n'); + const snippet: Record = { + before: lines[line - 2] || undefined, + main: lines[line - 1] || undefined, + after: lines[line] || undefined, + }; + //if location doesnt match main line + if (snippet.main && snippet.main.length >= char) { + snippet.location = ' '.repeat(Math.max(char - 1, 0)) + '^'; + } + //@ts-ignore - snippet does not exist in type Trace + stack[i] = { ...trace, snippet }; + }); + if (req.url.pathname.endsWith('.js')) { + delete response.stack; + res.setBody( + 'application/javascript', + `console.log(${JSON.stringify(response)});`, + res.code, + res.status + ); + return; + } else if (req.url.pathname.endsWith('.css')) { + delete response.stack; + res.setBody( + 'text/css', + `/* ${JSON.stringify(response)} */`, + res.code, + res.status + ); + return; + } +}); \ No newline at end of file diff --git a/packages/www/plugins/app/plugin.ts b/packages/www/plugins/app/plugin.ts new file mode 100644 index 0000000..96c410e --- /dev/null +++ b/packages/www/plugins/app/plugin.ts @@ -0,0 +1,20 @@ +//stackpress +import type { Server } from 'stackpress/server'; + +export default function plugin(server: Server) { + server.on('listen', async _ => { + //on error, show error page + server.on('error', () => import('./pages/error.js')); + server.on('error', '@/plugins/app/views/error', -100); + //on response, check for errors + server.on('response', async (req, res, ctx) => { + if (res.error) { + await ctx.emit('error', req, res); + } + }); + }); + server.on('route', async _ => { + server.get('/', '@/plugins/app/views/home', -100); + server.get('/future', '@/plugins/app/views/future', -100); + }); +}; \ No newline at end of file diff --git a/packages/www/plugins/app/styles/page.css b/packages/www/plugins/app/styles/page.css new file mode 100644 index 0000000..28a0b3b --- /dev/null +++ b/packages/www/plugins/app/styles/page.css @@ -0,0 +1 @@ +:root { display: initial; } \ No newline at end of file diff --git a/packages/www/plugins/app/views/error.tsx b/packages/www/plugins/app/views/error.tsx new file mode 100644 index 0000000..4a73cf5 --- /dev/null +++ b/packages/www/plugins/app/views/error.tsx @@ -0,0 +1,108 @@ +import '../styles/page.css'; +import type { Trace, ServerPageProps } from 'stackpress/view/client'; +import Layout from '../Layout.js'; + +//placeholder for translation +const _ = (text: string) => text; + +export type Config = { + server: { mode: string } +} + +export default function ErrorPage(props: ServerPageProps) { + const { + data = { server: { mode: 'production' } }, + request, + response + } = props; + + const theme = request.session.theme as string | undefined; + const mode = data.server?.mode || 'production'; + const production = mode === 'production'; + const notfound = response.code === 404; + const title = notfound ? _('Not Found') : _('Oops...'); + const description = notfound + ? _('The requested resource was not found.') + : _(response.error || 'There was an error.'); + const stack = (response.stack || []) as (Trace & { + snippet: Record + })[]; + const red = theme === 'dark' ? 'bg-red-900' : 'bg-red-100'; + return ( + +
+

+ {title} +

+

+ + {description} +

+ {!production && !notfound && stack.length > 0 && ( +
+ {stack.map((trace, index) => ( +
+

+ #{stack.length - Number(index)} {trace.method} +

+
+ {trace.file}:{trace.line}:{trace.char} +
+ {trace.snippet && ( +
+ {trace.snippet.before && ( +
{trace.line - 1} | {trace.snippet.before}
+ )} + {trace.snippet.main && ( +
{trace.line} | {trace.snippet.main}
+ )} + {trace.snippet.location && ( +
{' '.repeat(String(trace.line).length + 3)}{trace.snippet.location}
+ )} + {trace.snippet.after && ( +
{trace.line + 1} | {trace.snippet.after}
+ )} +
+ )} +
+ ))} +
+ )} +
+
+ ) +} + +export function Head(props: ServerPageProps) { + const { + request, + response, + styles = [] + } = props; + + const notfound = response.code === 404; + const url = request.url?.pathname || '/'; + const title = notfound ? _('Not Found') : _('Oops...'); + const description = notfound + ? _('The requested resource was not found.') + : _('There was an error.'); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/home.tsx b/packages/www/plugins/app/views/home.tsx new file mode 100644 index 0000000..caa4647 --- /dev/null +++ b/packages/www/plugins/app/views/home.tsx @@ -0,0 +1,52 @@ +//styles +import '../styles/page.css'; +import { ToastContainer } from 'react-toastify'; +//stackpress +import type { ServerPageProps } from 'stackpress/view/client'; +import Layout from '../Layout.js'; +import HeroSection from './landingpage/HeroSection.js'; +import AboutSection from './landingpage/AboutSection.js'; +import BenefitsSection from './landingpage/BenefitsSection.js'; +import AudienceSection from './landingpage/AudienceSection.js'; +import PluginEcosystemSection from './landingpage/PluginEcosystemSection.js'; +import RealWorldExampleSection from './landingpage/RealWorldExampleSection.js'; +import AIDevelopmentWorkflowSection from './landingpage/AIDevelopmentWorkflowSection.js'; +import FutureSection from './landingpage/FutureSection.js'; + +export function Head(props: ServerPageProps) { + const { styles = [] } = props; + return ( + <> + Idea + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export default function HomePage(props: ServerPageProps) { + const { session, request, response } = props; + + return ( + + + +
+ + + + + + + + + +
+ +
+ ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/landingpage/AIDevelopmentWorkflowSection.tsx b/packages/www/plugins/app/views/landingpage/AIDevelopmentWorkflowSection.tsx new file mode 100644 index 0000000..def5634 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/AIDevelopmentWorkflowSection.tsx @@ -0,0 +1,77 @@ +export default function AIDevelopmentWorkflowSection() { + const steps = [ + { + title: 'Describe your application to an AI assistant', + icon: 'fa-comments', + accent: 'from-pink-500/25 to-fuchsia-500/25', + ring: 'ring-pink-400/40' + }, + { + title: 'Generate a .idea schema from the description', + icon: 'fa-lightbulb', + accent: 'from-violet-500/25 to-indigo-500/25', + ring: 'ring-violet-400/40' + }, + { + title: 'Configure plugins for your target technologies', + icon: 'fa-plug', + accent: 'from-amber-500/25 to-orange-500/25', + ring: 'ring-amber-400/40' + }, + { + title: 'Execute the transformation to generate full‑stack code', + icon: 'fa-bolt', + accent: 'from-emerald-500/25 to-teal-500/25', + ring: 'ring-emerald-400/40' + }, + { + title: 'Iterate by updating the schema and regenerating', + icon: 'fa-rotate', + accent: 'from-sky-500/25 to-cyan-500/25', + ring: 'ring-sky-400/40' + } + ]; + + return ( +
+
+ + + AI‑Powered Development Workflow + +

Build faster with AI + .idea

+

The .idea format is perfect for AI‑driven development.

+
+ +
+
+
+ {steps.map((step, index) => ( +
+
+ + + +
+
+
+
Step {index + 1}
+
{step.title}
+
+
+ ))} +
+
+ +
+
+

+ This workflow enables rapid prototyping and development — go from idea to working application in minutes rather than days. +

+
+
+
+ ) +} + + diff --git a/packages/www/plugins/app/views/landingpage/AboutSection.tsx b/packages/www/plugins/app/views/landingpage/AboutSection.tsx new file mode 100644 index 0000000..01e5a76 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/AboutSection.tsx @@ -0,0 +1,15 @@ +export default function AboutSection() { + return ( +
+
+

+ .idea +

+
+

+ The .idea file format is a declarative schema definition language designed to simplify application development by providing a single source of truth for data structures, relationships, and code generation. +

+
+
+ ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/landingpage/AudienceSection.tsx b/packages/www/plugins/app/views/landingpage/AudienceSection.tsx new file mode 100644 index 0000000..78267b7 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/AudienceSection.tsx @@ -0,0 +1,57 @@ +export default function AudienceSection() { + const items = [ + { + title: 'Junior Developers', + icon: 'fa-user-graduate text-yellow-300', + points: [ + 'Easy-to-understand syntax with examples', + 'Rapid prototyping without deep framework knowledge' + ] + }, + { + title: 'Senior Developers', + icon: 'fa-user-gear text-sky-300', + points: [ + 'Powerful features for complex apps', + 'Extensible plugin system', + 'Cross-platform code generation' + ] + }, + { + title: 'CTOs & Leaders', + icon: 'fa-briefcase text-emerald-300', + points: [ + 'Reduce dev time by 60–80%', + 'Improve code consistency across teams', + 'Lower maintenance costs', + 'Accelerate time-to-market' + ] + } + ]; + + return ( +
+

👥 Who Should Use This?

+
+
+
+ {items.map((item, idx) => ( +
+
+ +
+
+
{item.title}
+
    + {item.points.map((p, i) => ( +
  • {p}
  • + ))} +
+
+
+ ))} +
+
+
+ ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/landingpage/BenefitsSection.tsx b/packages/www/plugins/app/views/landingpage/BenefitsSection.tsx new file mode 100644 index 0000000..01f797c --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/BenefitsSection.tsx @@ -0,0 +1,79 @@ +export default function BenefitsSection() { + const cards = [ + { + title: 'Single Source of Truth', + desc: 'One schema powers DB, types, APIs, docs, and forms.', + icon: 'fa-bullseye', + accent: 'from-emerald-500/20 to-teal-500/20', + ring: 'ring-emerald-400/30', + span: 'md:col-span-2', + color: 'text-emerald-400' + }, + { + title: 'Type Safety Everywhere', + desc: 'Consistent, type‑safe code across languages and frameworks.', + icon: 'fa-shield-halved', + accent: 'from-sky-500/20 to-indigo-500/20', + ring: 'ring-sky-400/30', + span: '', + color: 'text-sky-400' + }, + { + title: 'Rapid Development', + desc: 'Generate boilerplate, forms, and docs in seconds.', + icon: 'fa-bolt', + accent: 'from-violet-500/20 to-fuchsia-500/20', + ring: 'ring-violet-400/30', + span: '', + color: 'text-violet-400' + }, + { + title: 'Perfect Consistency', + desc: 'Update the schema once—everything stays in sync.', + icon: 'fa-arrows-rotate', + accent: 'from-amber-500/20 to-orange-500/20', + ring: 'ring-amber-400/30', + span: 'md:row-span-2', + color: 'text-amber-400' + }, + { + title: 'Extensible by Plugins', + desc: 'Target any framework or language with custom generators.', + icon: 'fa-plug', + accent: 'from-pink-500/20 to-rose-500/20', + ring: 'ring-pink-400/30', + span: '', + color: 'text-pink-400' + }, + { + title: 'AI‑to‑Code Bridge', + desc: 'Describe your model, generate production‑ready code.', + icon: 'fa-robot', + accent: 'from-teal-500/20 to-emerald-500/20', + ring: 'ring-teal-400/30', + span: '', + color: 'text-teal-400' + } + ]; + + return ( +
+

Key Benefits

+
+ {cards.map((c, idx) => ( +
+
+ + + +
+
{c.title}
+

{c.desc}

+
+
+
+ ))} +
+
+ ) +} diff --git a/packages/www/plugins/app/views/landingpage/FutureSection.tsx b/packages/www/plugins/app/views/landingpage/FutureSection.tsx new file mode 100644 index 0000000..bb25273 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/FutureSection.tsx @@ -0,0 +1,72 @@ +import Button from 'frui/form/Button'; + +export default function FutureSection() { + return ( +
+
+
+ + + The Future + +

+ Declarative. Type‑Safe. Automated. +

+

+ Define intent once. Generate apps, APIs, and docs in seconds. +

+ +
+
+
+
Automated
+

Less boilerplate. More building.

+
+
+
Unified
+

One spec, many outputs.

+
+
+
Proactive
+

Types catch issues early.

+
+
+
Instant
+

Generate full layers fast.

+
+
+
+
+
Endless Possibilities
+

Mobile, desktop, microservices, infra, docs, tests, monitoring.

+
+
+
Start Today
+ +
+
+
+ The fastest, safest line of code is the one you never write. +
+
— Steve Jobs
+
+
+
+ ) +} + + diff --git a/packages/www/plugins/app/views/landingpage/HeroSection.tsx b/packages/www/plugins/app/views/landingpage/HeroSection.tsx new file mode 100644 index 0000000..547e1f5 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/HeroSection.tsx @@ -0,0 +1,185 @@ +import Button from 'frui/form/Button'; +import Code from 'frui/format/Code'; +import { Bounce, toast } from 'react-toastify'; +import { useEffect, useState } from 'react'; + +export default function HeroSection() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + setIsVisible(true); + }, []); + + const code = [ + `$ npm i -D @stackpress/idea`, + `model User { + id String @id @default("nanoid()") + name String @required + email String @unique @required + created Date @default("now()") +} + +plugin "./plugins/typescript-generator.js" { + output "./generated/types.ts" +}`, + `npx idea transform --input schema.idea` + ]; + + const notify = () => toast.success('Copied to clipboard!', { + position: "bottom-center", + autoClose: 1000, + hideProgressBar: false, + closeOnClick: false, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "dark", + transition: Bounce, + }); + + return ( + <> + {/* Hero Content */} +
+
+ + {/* Light Bulb Icon */} +
+
+ 💡 +
+ {/* Static yellow glow effect behind bulb */} +
+
+ + {/* Title */} +

+ From Idea to Code +

+ + {/* Subtitle */} +

+ A meta language to express and transform your ideas to reality. +

+ + {/* Tagline */} +

+ 💫 Generate TypeScript, GraphQL, REST APIs, and more from a single schema +

+ + {/* Simple Buttons */} +
+ +
+ + {/* Simple Feature Icons */} +
+
+
+
Fast
+
+
+
🛡️
+
Safe
+
+
+
🔧
+
Flexible
+
+
+
+
+ + {/* Simple Demo Section */} +
+
+

+ 💡 Turn Your Ideas Into Reality +

+

+ Simple steps to transform your schema into production-ready code +

+
+ +
+ {/* Step 1 - Install */} +
+
+
📦
+

1. Install the Package

+
+ + {code[0]} + +
+ + {/* Step 2 - Schema */} +
+
+
✏️
+

2. Create Your Schema

+
+

Define your data models in a simple .idea file:

+ + {code[1]} + +
+ + {/* Step 3 - Transform */} +
+
+
+

3. Generate Code

+
+

Run the transformer to generate your code:

+ + {code[2]} + +
+ + {/* Step 4 - Results */} +
+
+
+ 💡 +
+

4. Your Idea is Now Code!

+
+
+

✨ Generated files include:

+
    +
  • • TypeScript interfaces & types
  • +
  • • GraphQL schema definitions
  • +
  • • REST API client libraries
  • +
  • • Validation schemas (Zod)
  • +
  • • Database migrations
  • +
  • • API documentation
  • +
+
+
+
+
+ + ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/landingpage/PluginEcosystemSection.tsx b/packages/www/plugins/app/views/landingpage/PluginEcosystemSection.tsx new file mode 100644 index 0000000..9f87655 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/PluginEcosystemSection.tsx @@ -0,0 +1,67 @@ +export default function PluginEcosystemSection() { + return ( +
+ +

🔌 The Plugin Ecosystem

+

+ The true power of .idea lies in its plugin system — a bridge from simple schema definitions to full‑stack applications. +

+
+
+
+ +
Multi‑Language Support
+
+
    +
  • TypeScript/JavaScript: Interfaces, types, validation
  • +
  • Python: Dataclasses, Pydantic, SQLAlchemy
  • +
  • Rust: Structs, enums, serde
  • +
  • Go: Structs, JSON tags, validation
  • +
  • Java: POJOs, JPA, annotations
  • +
  • C#: Classes, EF models
  • +
  • PHP: Classes, Eloquent, validation
  • +
  • …and more
  • +
+
+
+
+ +
Framework Integration
+
+
    +
  • React, Vue, Angular, Svelte
  • +
  • Next.js, Express, FastAPI, Django
  • +
  • Components, routes, models, middleware
  • +
+
+
+
+ +
Database Support
+
+
    +
  • SQL: Postgres, MySQL, SQLite, SQL Server
  • +
  • NoSQL: MongoDB, DynamoDB, Firestore
  • +
  • Graph: Neo4j, ArangoDB
  • +
  • Time‑series: InfluxDB, TimescaleDB
  • +
  • Search: Elasticsearch, Solr
  • +
+
+
+
+ +
Documentation & Tools
+
+
    +
  • OpenAPI/Swagger specs
  • +
  • Schema diagrams & table docs
  • +
  • Form generators with validation
  • +
  • Mock data & fixtures
  • +
  • Migration scripts
  • +
  • Environment & CI/CD configs
  • +
+
+
+
+ ) +} \ No newline at end of file diff --git a/packages/www/plugins/app/views/landingpage/RealWorldExampleSection.tsx b/packages/www/plugins/app/views/landingpage/RealWorldExampleSection.tsx new file mode 100644 index 0000000..25c4f07 --- /dev/null +++ b/packages/www/plugins/app/views/landingpage/RealWorldExampleSection.tsx @@ -0,0 +1,102 @@ +import Code from 'frui/format/Code'; + +export default function RealWorldExampleSection() { + const schema = `enum UserRole { + ADMIN "Administrator" + CUSTOMER "Customer" + VENDOR "Vendor" +} + +type Address { + street String @required + city String @required + country String @default("US") +} + +model User { + id String @id @default("nanoid()") + email String @unique @required @field.input(Email) + name String @required @field.input(Text) + role UserRole @default("CUSTOMER") + address Address? + orders Order[] @relation(Order.userId) + created Date @default("now()") +} + +model Product { + id String @id @default("nanoid()") + name String @required @field.input(Text) + price Number @required @field.input(Currency) + description String @field.textarea + category String @field.select + inStock Boolean @default(true) +} + +model Order { + id String @id @default("nanoid()") + userId String @relation(User.id) + user User @relation(User, userId) + items OrderItem[] @relation(OrderItem.orderId) + total Number @required + status OrderStatus @default("PENDING") + created Date @default("now()") +} + +plugin "./plugins/typescript-generator.js" { + output "./src/types/schema.ts" +} + +plugin "./plugins/database-generator.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +plugin "./plugins/react-forms.js" { + output "./src/components/forms/" + framework "react" + styling "tailwind" +} + +plugin "./plugins/api-generator.js" { + output "./src/api/" + framework "express" + includeValidation true +}`; + + const outputs = [ + 'TypeScript interfaces and types', + 'PostgreSQL database schema', + 'React form components with Tailwind CSS', + 'Express.js API routes with validation', + 'OpenAPI documentation', + 'Test data and fixtures', + 'Database migration files', + 'Validation schemas (Zod, Joi, etc.)' + ]; + + return ( +
+
+
+

Real‑World Example

+

See how a simple e‑commerce schema can generate a full-stack application:

+
+ + {schema} + +
+
+
+
+
From this single schema, generate:
+
    + {outputs.map((item, idx) => ( +
  • {item}
  • + ))} +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/packages/www/plugins/assets/plugin.ts b/packages/www/plugins/assets/plugin.ts new file mode 100644 index 0000000..d73cdfb --- /dev/null +++ b/packages/www/plugins/assets/plugin.ts @@ -0,0 +1,39 @@ +//node +import fs from 'node:fs'; +import path from 'node:path'; +//stackpress +import type { Server } from 'stackpress/server'; + +const mime: Record = { + '.html': 'text/html', + '.css': 'text/css', + '.js': 'text/javascript', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon' +}; + +export default function plugin(server: Server) { + server.on('route', async _ => { + //static assets + server.on('request', async (req, res) => { + //if there is a body or a code that is not 404, skip + if (res.body || (res.code && res.code !== 404)) return; + //get the resource pathname + const resource = req.url.pathname.substring(1).replace(/\/\//, '/'); + //if no pathname, skip + if (resource.length === 0) return; + const assets = server.config.get('assets'); + const file = path.resolve(assets, resource); + if (fs.existsSync(file)) { + const ext = path.extname(file); + const type = mime[ext] || 'application/octet-stream'; + res.setBody(type, fs.createReadStream(file)); + } + }); + }); +}; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/Code.tsx b/packages/www/plugins/docs/components/Code.tsx new file mode 100644 index 0000000..40efca7 --- /dev/null +++ b/packages/www/plugins/docs/components/Code.tsx @@ -0,0 +1,79 @@ +import type { CSSProperties } from 'react'; +import { useEffect, useState } from 'react'; +import SyntaxHighlighter from 'react-syntax-highlighter'; +import { atomOneDark } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; + +// copy should reveal the copy button, but onCopy should be defined to modify its behavior +// meanwhile, the presence of onCopy should be enough to show the copy button + +export default function Code(props: { + copy?: boolean; + className?: string; + value?: string; + language?: string; + numbers?: boolean; + onCopy?: () => void; + children: string; + style?: CSSProperties; +}) { + const [ mounted, setMounted ] = useState(false); + const { + children, + className, + copy, + onCopy, + language = 'javascript', + numbers, + style = { + background: 'transparent', + color: 'inherit', + padding: '0 10px 10px', + width: '100%' + } + } = props; + + const body = children + .split('\n') + .map((line) => (language === 'bash' ? `$ ${line}` : line)) + .join('\n'); + + //extends the default copy function if an extension is provided + const handleCopy = () => { + if (onCopy) { + onCopy(); + } + navigator.clipboard.writeText(children.toString()); + }; + + //only add highlighting when mounted + //necessary because of problems with SSR + useEffect(() => { + setMounted(true); + }, []); + + return ( +
+ {copy && ( +
+ Copy +
+ )} + {mounted && ( + + {body} + + )} +
+ ); +} diff --git a/packages/www/plugins/docs/components/Editor.tsx b/packages/www/plugins/docs/components/Editor.tsx new file mode 100644 index 0000000..d99cbce --- /dev/null +++ b/packages/www/plugins/docs/components/Editor.tsx @@ -0,0 +1,139 @@ +import { useState } from 'react'; +import { notify } from 'stackpress/view/client'; +import Code from './Code.js'; + +export type File = { + type: 'file', + id: string, + name: string, + level: number, + content: string +}; +export type Folder = { + type: 'folder', + name: string, + level: number +}; +export type EditorTabsProps = { + active: string, + files: (File|Folder)[], + open: (file: string) => void +}; +export type EditorFilesProps = { + active: string, + files: (File|Folder)[], + className?: string +}; +export type EditorExplorerProps = { + active: string, + files: (File|Folder)[], + open: (file: string) => void +}; +export type EditorProps = { + files: (File|Folder)[], + value: string, + className?: string, + leftClassName?: string, + topClassName?: string, + mainClassName?: string, + title?: string +}; + +export function EditorExplorer(props: EditorExplorerProps) { + const { active, files, open } = props; + return ( +
+ {files.map((item, index) => { + const left = 5 + (item.level * 15); + if (item.type === 'folder') { + return ( +
+ + {item.name} +
+ ); + } + const icon = item.name.endsWith('.tsx') ? 'fab fa-react' : 'fas fa-file'; + return ( +
open(item.id)} + > + + {item.name} +
+ ); + })} +
+ ); +}; + +export function EditorTabs(props: EditorTabsProps) { + const { active, files, open } = props; + return ( +
+ {files.filter(item => item.type === 'file').map((item, index) => { + const icon = item.name.endsWith('.tsx') ? 'fab fa-react' : 'fas fa-file'; + return ( +
open(item.id)} + > + + {item.name} +
+ ); + })} +
+ ); +}; + +export function EditorFiles(props: EditorFilesProps) { + const { active, className = '', files } = props; + return ( + <> + {files.filter(item => item.type === 'file').map((item, index) => { + return ( + notify('success', 'Copied to clipboard')} + className={`${active !== item.id ? 'hidden': ''} rsm-px-l-0 bg-black text-white overflow-auto !absolute px-r-0 px-b-0 px-t-34 ${className}`} + >{item.content} + ); + })} + + ); +}; + +export default function Editor(props: EditorProps) { + const { + title = 'PROJECT', + files = [], + value, + className = '', + leftClassName = '', + topClassName = '', + mainClassName = '' + } = props; + const [ file, open ] = useState(value); + return ( +
+
+
{title}
+ +
+
+ +
+ +
+ ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/Layout.tsx b/packages/www/plugins/docs/components/Layout.tsx new file mode 100644 index 0000000..dc40ad1 --- /dev/null +++ b/packages/www/plugins/docs/components/Layout.tsx @@ -0,0 +1,482 @@ +//modules +import type { ReactNode } from 'react'; +import { useState, useEffect } from 'react'; +import { useLanguage } from 'r22n'; +//stackpress +import type { + LayoutProviderProps, + PanelAppProps, +} from 'stackpress/view/client'; +import { + LayoutProvider, + NotifyContainer, + unload, + useTheme, + useRequest, + useToggle +} from 'stackpress/view/client'; + +export function LayoutHead(props: { + open?: boolean, + theme: string, + base?: string, + logo?: string, + brand?: string, + toggleLeft?: () => void, + toggleTheme?: () => void +}) { + const { + open, + theme, + base, + logo, + brand, + toggleLeft, + toggleTheme + } = props; + const left = open ? 'rmd-px-l-220' : 'rmd-px-l-0'; + const full = typeof open === 'undefined' ? 'px-l-0' : 'px-l-220'; + const themeColor = theme === 'dark' ? 'bg-gray-600' : 'bg-orange-600'; + const themeIcon = theme === 'dark' ? 'fa-moon' : 'fa-sun'; + return ( +
+
+ {toggleLeft && ( + + )} +
+ {base ? ( + + {logo && {brand}} + {brand && {brand}} + + ) : brand || logo ? ( + + {logo && {brand}} + {brand && {brand}} + + ) : undefined} +
+ {toggleTheme && ( + + )} +
+
+ ); +} + +export function LayoutLeft(props: { + pathname?: string, + open: boolean, + toggle: () => void +}) { + const { pathname = '/', open, toggle } = props; + const left = open ? 'rmd-px-l-0' : 'rmd-px-l--220'; + const { _ } = useLanguage(); + const menu = [ + { + label: '', + search: '', + children: [ + { + label: 'Introduction', + search: '/docs/introduction', + href: '/docs/introduction' + }, + { + label: 'Getting Started', + search: '/docs/getting-started', + href: '/docs/getting-started' + } + ] + }, + { + label: 'Specifications', + search: '/docs/specifications', + children: [ + { + label: 'Syntax Overview', + search: '/docs/specifications/syntax-overview', + href: '/docs/specifications/syntax-overview' + }, + { + label: 'Data Types', + search: '/docs/specifications/data-types', + href: '/docs/specifications/data-types' + }, + { + label: 'Schema Elements', + search: '/docs/specifications/schema-elements', + href: '/docs/specifications/schema-elements' + }, + { + label: 'Schema Structure', + search: '/docs/specifications/schema-structure', + href: '/docs/specifications/schema-structure' + }, + { + label: 'Schema Directives', + search: '/docs/specifications/schema-directives', + href: '/docs/specifications/schema-directives' + }, + { + label: 'Processing Flow', + search: '/docs/specifications/processing-flow', + href: '/docs/specifications/processing-flow' + }, + { + label: 'Plugin System', + search: '/docs/specifications/plugin-system', + href: '/docs/specifications/plugin-system' + }, + { + label: 'Complete Example', + search: '/docs/specifications/complete-examples', + href: '/docs/specifications/complete-examples' + }, + { + label: 'Best Practices', + search: '/docs/specifications/best-practices', + href: '/docs/specifications/best-practices' + }, + { + label: 'Error Handling', + search: '/docs/specifications/error-handling', + href: '/docs/specifications/error-handling' + } + ] + }, + { + label: 'Parser', + search: '/docs/parser', + children: [ + { + label: 'Installation', + search: '/docs/parser/installation', + href: '/docs/parser/installation' + }, + { + label: 'Core Concepts', + search: '/docs/parser/core-concepts', + href: '/docs/parser/core-concepts' + }, + { + label: 'API Reference', + search: '/docs/parser/api-reference', + href: '/docs/parser/api-reference' + }, + { + label: 'Examples', + search: '/docs/parser/examples', + href: '/docs/parser/examples' + }, + { + label: 'Best Practices', + search: '/docs/parser/best-practices', + href: '/docs/parser/best-practices' + } + ] + }, + { + label: 'Transformers', + search: '/docs/transformers', + children: [ + { + label: 'Introduction', + search: '/docs/transformers/introduction', + href: '/docs/transformers/introduction' + }, + { + label: 'API Reference', + search: '/docs/transformers/api-reference', + href: '/docs/transformers/api-reference' + }, + { + label: 'Architecture', + search: '/docs/transformers/architecture', + href: '/docs/transformers/architecture' + }, + { + label: 'Usage Patterns', + search: '/docs/transformers/usage-patterns', + href: '/docs/transformers/usage-patterns' + }, + { + label: 'Common Use Cases', + search: '/docs/transformers/common-use-cases', + href: '/docs/transformers/common-use-cases' + }, + { + label: 'Examples', + search: '/docs/transformers/examples', + href: '/docs/transformers/examples' + }, + { + label: 'Error Handling', + search: '/docs/transformers/error-handling', + href: '/docs/transformers/error-handling' + }, + { + label: 'Best Practices', + search: '/docs/transformers/best-practices', + href: '/docs/transformers/best-practices' + } + + ] + }, + { + label: 'Plugin', + search: '/docs/plugin-development', + children: [ + { + label: 'Plugin Development Guide', + search: '/docs/plugin-development/plugin-development-guide', + href: '/docs/plugin-development/plugin-development-guide' + }, + { + label: 'Plugin Examples', + search: '/docs/plugin-development/plugin-examples', + href: '/docs/plugin-development/plugin-examples' + }, + { + label: 'Plugin Configuration', + search: '/docs/plugin-development/plugin-configuration', + href: '/docs/plugin-development/plugin-configuration' + }, + { + label: 'Error Handling', + search: '/docs/plugin-development/error-handling', + href: '/docs/plugin-development/error-handling' + }, + { + label: 'Best Practices', + search: '/docs/plugin-development/best-practices', + href: '/docs/plugin-development/best-practices' + }, + { + label: 'Available Tutorials', + search: '/docs/plugin-development/available-tutorials', + href: '/docs/plugin-development/available-tutorials' + }, + { + label: 'Advanced Tutorials', + search: '/docs/plugin-development/advanced-tutorials', + href: '/docs/plugin-development/advanced-tutorials' + }, + { + label: 'Getting Started', + search: '/docs/plugin-development/getting-started', + href: '/docs/plugin-development/getting-started' + } + ] + }, + { + label: 'Tutorials', + search: '/docs/tutorials', + children: [ + { + label: 'TSMorph Plugin Guide', + search: '/docs/tutorials/tsmorph-plugin-guide', + href: '/docs/tutorials/tsmorph-plugin-guide' + }, + { + label: 'MySQL Tables Plugin', + search: '/docs/tutorials/mysql-table-plugin', + href: '/docs/tutorials/mysql-table-plugin' + }, + { + label: 'HTML Form Plugin', + search: '/docs/tutorials/html-form-plugin', + href: '/docs/tutorials/html-form-plugin' + }, + { + label: 'Markdown Documentation Plugin', + search: '/docs/tutorials/markdown-documentation-plugin', + href: '/docs/tutorials/markdown-documentation-plugin' + }, + { + label: 'GraphQL Schema Plugin', + search: '/docs/tutorials/graphql-schema-plugin', + href: '/docs/tutorials/graphql-schema-plugin' + }, + { + label: 'TypeScript Interface Plugin', + search: '/docs/tutorials/typescript-interface-plugin', + href: '/docs/tutorials/typescript-interface-plugin' + }, + { + label: 'API Client Plugin', + search: '/docs/tutorials/api-client-plugin', + href: '/docs/tutorials/api-client-plugin' + }, + { + label: 'Validation Plugin', + search: '/docs/tutorials/validation-plugin', + href: '/docs/tutorials/validation-plugin' + }, + { + label: 'Test Data Plugin', + search: '/docs/tutorials/test-data-plugin', + href: '/docs/tutorials/test-data-plugin' + }, + { + label: 'OpenAPI Specification Plugin', + search: '/docs/tutorials/openapi-specification-plugin', + href: '/docs/tutorials/openapi-specification-plugin' + } + + ] + } + + ]; + return ( + + ); +} + +export function LayoutMain(props: { + open?: boolean, + right?: boolean, + children: ReactNode +}) { + const { open, children } = props; + const left = open ? 'rmd-px-l-220' : 'rmd-px-l-0'; + const right = props.right ? 'px-r-220 rlg-px-r-0' : 'px-r-0'; + const full = typeof open === 'undefined' ? 'px-l-0' : 'px-l-220'; + return ( +
+ {children} +
+ ); +} + +export function LayoutRight({ children }: { + children: ReactNode +}) { + return ( + + ); +} + +export function LayoutApp(props: { + right?: ReactNode, + children: ReactNode +}) { + const { children } = props; + const request = useRequest(); + const [left, toggleLeft] = useToggle(); + const { theme, toggle: toggleTheme } = useTheme(); + const pathname = request?.url?.pathname || '/'; + return ( +
+ + + {props.right ? ({props.right}) : null} + {children} +
+ ); +} + +export default function Layout(props: LayoutProviderProps & PanelAppProps) { + const { + data, + session, + response, + right, + children + } = props; + const [request, setRequest] = useState>({ + ...(props.request || {}), + session: { + ...(props.request?.session || {}), + theme: props.request?.session?.theme || 'dark' + } + }); + //unload flash message + useEffect(() => { + const light = document.cookie.includes('theme=light'); + if (!request.session?.theme) { + setRequest({ + ...request, + session: { theme: light ? 'light' : 'dark' } + }); + } + unload(); + }, []); + return ( + + + {children} + + + + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/index.tsx b/packages/www/plugins/docs/components/index.tsx new file mode 100644 index 0000000..2f43ad5 --- /dev/null +++ b/packages/www/plugins/docs/components/index.tsx @@ -0,0 +1,218 @@ +import type { ReactNode } from 'react'; +import { useEffect, useState } from 'react'; +import SyntaxHighlighter from 'react-syntax-highlighter'; +import { atomOneDark } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; +import { notify, useLanguage, Translate } from 'stackpress/view/client'; +import Alert from 'frui/element/Alert'; +import CodeView from './Code.js'; +import Editor from './Editor.js'; +import Layout from './Layout.js'; + +export type { File, Folder } from './Editor.js'; + +export { Editor, Layout }; + +export function Header1({ children }: { children: string }) { + const { _ } = useLanguage(); + return ( +

+ {_(children)} +

+ ); +} + +export function Header2({ children }: { children: string }) { + const { _ } = useLanguage(); + return ( +

+ {_(children)} +

+ ); +} + +export function Header3({ children }: { children: string }) { + const { _ } = useLanguage(); + return ( +

+ {_(children)} +

+ ); +} + +export function Header4({ children }: { children: string }) { + const { _ } = useLanguage(); + return ( +

+ {_(children)} +

+ ); +} + +export function Paragraph({ children }: { children: ReactNode }) { + return ( +
+ {children} +
+ ); +} + +export function Highlight({ children }: { children: ReactNode }) { + return ( + + + {children} + + + ); +} + +export function InlineCode({ lang = 'typescript', children }: { + lang?: string, + children: string +}) { + const [ mounted, setMounted ] = useState(false); + //only add highlighting when mounted + //necessary because of problems with SSR + useEffect(() => { + setMounted(true); + }, []); + if (mounted) { + return ( + + + {children} + + + ); + } + return null; +} + +export function Bash({ children }: { children: string }) { + return ( + {children} + ); +} + +export function Code(props: { lang?: string, children: string }) { + const { lang = 'typescript', children } = props; + return ( + notify('success', 'Copied to clipboard')} + >{children} + ); +} + +export function Link(props: { + className?: string, + blank?: boolean, + href?: string, + children: ReactNode +}) { + const { className = '', blank, children, ...attributes } = props; + return ( + {children} + ); +} + +export function Strong({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} + +export function Semibold({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} + +export function Emphasis({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} + +export function Note({ children }: { children: ReactNode }) { + return ( + + + NOTE: {children} + + ); +} + +export function Congrats({ children }: { children: ReactNode }) { + return ( + + + CONGRATS: {children} + + ); +} + +export function Warn({ children }: { children: ReactNode }) { + return ( + + + WARNING: {children} + + ); +} + +export function Nav({ next, prev }: { + next?: { text: string, href: string }, + prev?: { text: string, href: string } +}) { + const { _ } = useLanguage(); + return ( + + ); +} + +export const H1 = Header1; +export const H2 = Header2; +export const H3 = Header3; +export const H4 = Header4; +export const A = Link; +export const H = Highlight; +export const S = Semibold; +export const SS = Strong; +export const E = Emphasis; +export const P = Paragraph; +export const C = InlineCode; +export const B = Bash; diff --git a/packages/www/plugins/docs/plugin.ts b/packages/www/plugins/docs/plugin.ts new file mode 100644 index 0000000..06d1ba8 --- /dev/null +++ b/packages/www/plugins/docs/plugin.ts @@ -0,0 +1,102 @@ +//stackpress +import type { Server, Response } from 'stackpress/server'; +//view +import type { ViewConfig, BrandConfig, LanguageConfig } from 'stackpress'; + +export function setServerProps(server: Server, res: Response) { + //get the view, brand and auth config + const view = server.config.path('view', {}); + const brand = server.config.path('brand', {}); + const language = server.config.path('language', { + key: 'locale', + locale: 'en_US', + languages: {} + }); + //set data for template layer + res.data.set('view', { + base: view.base || '/', + props: view.props || {} + }); + res.data.set('brand', { + name: brand.name || 'Stackpress', + logo: brand.logo || '/logo.png', + icon: brand.icon || '/icon.png', + favicon: brand.favicon || '/favicon.ico', + }); + res.data.set('language', { + key: language.key || 'locale', + locale: language.locale || 'en_US', + languages: language.languages || {} + }); +} + +export default function plugin(server: Server) { + //on route, add docs routes + server.on('route', _ => { + server.get('/docs', (_req, res, ctx) => setServerProps(ctx, res)); + server.get('/docs/**', (_req, res, ctx) => setServerProps(ctx, res)); + server.get('/docs', '@/plugins/docs/views/index', -100); + server.get('/docs/introduction', '@/plugins/docs/views/index', -100); + + //other routes + [ + 'getting-started', + //specifications + 'specifications/introduction', + 'specifications/syntax-overview', + 'specifications/data-types', + 'specifications/schema-elements', + 'specifications/schema-structure', + 'specifications/schema-directives', + 'specifications/processing-flow', + 'specifications/plugin-system', + 'specifications/complete-examples', + 'specifications/best-practices', + 'specifications/error-handling', + //parser + 'parser/installation', + 'parser/core-concepts', + 'parser/api-reference', + 'parser/examples', + 'parser/best-practices', + 'parser/pages/compiler', + 'parser/pages/lexer', + 'parser/pages/ast', + 'parser/pages/tokens', + 'parser/pages/exception-handling', + //transformers + 'transformers/introduction', + 'transformers/api-reference', + 'transformers/architecture', + 'transformers/usage-patterns', + 'transformers/common-use-cases', + 'transformers/examples', + 'transformers/error-handling', + 'transformers/best-practices', + 'transformers/pages/transformer', + 'transformers/pages/terminal', + //plugins + 'plugin-development/plugin-development-guide', + 'plugin-development/plugin-examples', + 'plugin-development/plugin-configuration', + 'plugin-development/error-handling', + 'plugin-development/best-practices', + 'plugin-development/available-tutorials', + 'plugin-development/advanced-tutorials', + 'plugin-development/getting-started', + //tutorials + 'tutorials/tsmorph-plugin-guide', + 'tutorials/mysql-table-plugin', + 'tutorials/html-form-plugin', + 'tutorials/markdown-documentation-plugin', + 'tutorials/graphql-schema-plugin', + 'tutorials/typescript-interface-plugin', + 'tutorials/api-client-plugin', + 'tutorials/validation-plugin', + 'tutorials/test-data-plugin', + 'tutorials/openapi-specification-plugin', + ].map(route => { + server.get(`/docs/${route}`, `@/plugins/docs/views/${route}`, -100); + }); + }); +}; \ No newline at end of file diff --git a/packages/www/plugins/docs/views/getting-started.tsx b/packages/www/plugins/docs/views/getting-started.tsx new file mode 100644 index 0000000..c94243a --- /dev/null +++ b/packages/www/plugins/docs/views/getting-started.tsx @@ -0,0 +1,126 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav } from '../components/index.js'; +import Code from '../components/Code.js'; +import Layout from '../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Getting Started'); + const description = _( + 'describe' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const [install, setInstall] = useState('npm'); + return ( +
+

Getting Started

+

+ The following is a guide to get you started with Idea. +

+ +

Installation

+ +
+
+
setInstall('npm')} + > + +
+
setInstall('yarn')} + > + +
+
+ { + ' npm i -D @stackpress/idea' + } + { + 'yarn add --dev @stackpress/idea' + } +
+ +

Create your first schema

+

Create a new file called schema.idea

+ + + {`model User { + id String @id @default("nanoid()") + name String @required + email String @unique @required + created Date @default("now()") +} + +plugin "./plugins/typescript-generator.js" { + output "./generated/types.ts" +} + +`} + + +

Generate Code

+ + {`npx idea transform --input schema.idea + `} + + +

Explore the Results

+

Check the generated files in your output directories!

+ +
+ ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/index.tsx b/packages/www/plugins/docs/views/index.tsx new file mode 100644 index 0000000..a336236 --- /dev/null +++ b/packages/www/plugins/docs/views/index.tsx @@ -0,0 +1,226 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'r22n'; +//docs +import { H1, H2, P, Nav, SS } from '../components/index.js'; +import Layout from '../components/Layout.js'; +import Code from '../components/Code.js'; + +export function DocumentationHead(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const url = request.url?.pathname || '/docs'; + const title = _('What is .idea?'); + const description = _( + 'The .idea file format is a declarative schema definition language designed to simplify application development by providing a single source of truth for data structures, relationships, and code generation.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function DocumentationBody() { + return ( +
+

What is .idea?

+ +

+ The .idea file format is a declarative schema definition language designed to simplify application development by providing a single source of truth for data structures, relationships, and code generation. It enables developers to define their application's data model once and generate multiple outputs including database schemas, TypeScript interfaces, API documentation, forms, and more. +

+ +

+ Think of it as the bridge between AI prompting and full-stack code generation - where a simple schema definition can automatically generate everything from database tables to React components, API endpoints to documentation sites. +

+ +

Why Use .idea?

+
    +
  • Single Source of Truth
  • +
  • Type Safety Everywhere
  • +
  • Rapid Development
  • +
  • Perfect Consistency
  • +
  • Infinite Extensibility
  • +
  • AI-to-Code Bridge
  • +
+

+ Single Source of Truth
+ Define your data model once, use it everywhere. No more maintaining separate schemas for database, frontend, and API. +

+ +

+ Type Safety Everywhere
+ Generate type-safe code across languages - TypeScript, Python, Rust, Go, and more. Catch errors at compile time. +

+ +

+ Rapid Development
+ Generate boilerplate code, forms, and documentation in seconds. What used to take hours now happens instantly. +

+ +

Who Should Use This?

+ +

+ Junior Developers
+ Easy syntax, rapid prototyping, learn best practices through generated code. +

+ +

+ Senior Developers
+ Powerful features, extensible plugins, maintain consistency across large codebases. +

+ +

+ CTOs & Technical Leaders
+ Reduce development time by 60-80%, improve consistency, accelerate time-to-market. +

+ +

The Plugin Ecosystem

+

+ The power of .idea comes from its plugin system. Generate code for any technology: +

+ +

+ Languages
+ TypeScript, Python, Rust, Go, Java, C#, PHP, and more. +

+ +

+ Frameworks
+ React, Vue, Angular, Next.js, Express, FastAPI, Django, and more. +

+ +

+ Databases
+ PostgreSQL, MySQL, MongoDB, Neo4j, and more. +

+ +

Real-World Example

+ +

+ Here's how a simple e-commerce schema becomes a full application: +

+ + + {`// schema.idea +enum UserRole { + ADMIN "Administrator" + CUSTOMER "Customer" +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("CUSTOMER") + orders Order[] @relation(Order.userId) +} + +model Product { + id String @id @default("nanoid()") + name String @required + price Number @required + inStock Boolean @default(true) +} + +model Order { + id String @id @default("nanoid()") + userId String @relation(User.id) + total Number @required + status String @default("PENDING") +} + +// Generate everything with plugins +plugin "./plugins/typescript-generator.js" { + output "./src/types/schema.ts" +} + +plugin "./plugins/database-generator.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +plugin "./plugins/react-forms.js" { + output "./src/components/forms/" + framework "react" + styling "tailwind" +} + +plugin "./plugins/api-generator.js" { + output "./src/api/" + framework "express" + includeValidation true +}`} + + +

+ From this single schema, generate: +

+
    +
  • ✅ TypeScript interfaces
  • +
  • ✅ PostgreSQL schema
  • +
  • ✅ React components
  • +
  • ✅ API documentation
  • +
  • ✅ Validation schemas
  • +
  • ✅ Test data
  • +
+ +

AI-Powered Workflow

+ +

+ The perfect workflow for AI-driven development: +

+
    +
  1. 1. Describe your app to an AI
  2. +
  3. 2. Get a .idea schema
  4. +
  5. 3. Configure plugins
  6. +
  7. 4. Generate full-stack code
  8. +
  9. 5. Iterate and improve
  10. +
+ +

+ Go from idea to working application in minutes, not days. +

+ +
+ ); +} + +export function DocumentationPage(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} + +export const Head = DocumentationHead; +export default DocumentationPage; \ No newline at end of file diff --git a/packages/www/plugins/docs/views/parser/api-reference.tsx b/packages/www/plugins/docs/views/parser/api-reference.tsx new file mode 100644 index 0000000..80d1c01 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/api-reference.tsx @@ -0,0 +1,178 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav, SS, A } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('API Reference'); + const description = _( + 'API Reference for the parser library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
+ {_('API Reference')} +
+ +
+ ); +} + +const exampleCode = [ + `import { parse } from '@stackpress/idea-parser'; + +const result = parse(\` +prop Text { type "text" } +model User { + name String @field.input(Text) +} +\`); + +console.log(result); +// Output includes prop references: { prop: { Text: { type: "text" } }, ... }`, + `import { final } from '@stackpress/idea-parser'; + +const result = final(\` +prop Text { type "text" } +model User { + name String @field.input(Text) +} +\`); + +console.log(result); +// Output has resolved references: { model: { User: { ... } } } +// No 'prop' section in output`, +`import { Exception } from '@stackpress/idea-parser'; + +try { + const result = parse(invalidCode); +} catch (error) { + if (error instanceof Exception) { + console.log('Parsing error:', error.message); + } +}` +] + +export function Body() { + return ( +
+

API Reference

+

Main Functions

+

parse(code: string)

+

Converts schema code into a JSON representation with references preserved.

+ Parameters: +
  • code (string): The schema code to parse
  • + + Returns: +
  • SchemaConfig: JSON object representing the parse schema
  • + +

    Example:

    + + {exampleCode[0]} + + +

    final(code: string)

    +

    + Converts schema code into a clean JSON representation with references resolved and removed. +

    + + Parameters +
  • code (string): The schema code to parse
  • + + Returns: +
  • FinalSchemaConfig: Clean JSON object without prop/use references
  • + + Example: + + {exampleCode[1]} + + +

    Core Classes

    +
      +
    • Compiler: Static methods for converting AST tokens to JSON
    • +
    • Lexer: Tokenization and parsing utilities
    • +
    • SchemaTree: Main parser for complete schema files
    • +
    • Syntax Trees: Individual parsers for different schema elements
    • +
    • Tokens: AST token structures and type definitions
    • +
    + +

    Exception Handling

    +

    The library uses a custom Exception class that extends the standard Exception class for better error reporting.

    + + {exampleCode[2]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/best-practices.tsx b/packages/www/plugins/docs/views/parser/best-practices.tsx new file mode 100644 index 0000000..d6c4b71 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/best-practices.tsx @@ -0,0 +1,191 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Best practices for using the parser library effectively' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const typeSafetyExamples = [ + `import type { SchemaConfig, ModelConfig } from '@stackpress/idea-parser'; + +const schema: SchemaConfig = parse(code); +` +]; + +const errorHandlingExamples = [ + `import { parse, Exception } from '@stackpress/idea-parser'; + +try { + const result = parse(schemaCode); + // Process result +} catch (error) { + if (error instanceof Exception) { + console.error('Schema parsing failed:', error.message); + // Handle parsing error + } else { + console.error('Unexpected error:', error); + // Handle other errors + } +}` +]; + +const schemaStructureExamples = [ + `// Good: Proper model structure +model User { + id String @id + name String +} + +// Bad: Missing required properties +model User { + // Missing columns - will throw error +}` +]; + +const namingExamples = [ + `// Good +enum UserStatus { ACTIVE "Active" SUSPENDED "Suspended" } +prop EmailInput { type "email" format "email" } + +// Less clear +enum Status { A "Active" S "Suspended" } +prop Input { type "email" }` +]; + +const errorSolutionsExamples = [ + `Error: "Invalid Schema"`, + `Error: "Expecting a columns property"`, + `Error: "Duplicate [name]"`, + `Error: "Unknown reference [name]"` +]; + +export function Body() { + return ( +
    +

    Best Practices

    +

    + Follow these best practices to use the parser library effectively and avoid common pitfalls. +

    + +

    1. Use Type Safety

    +

    + The library is built with TypeScript and provides comprehensive type definitions: +

    + + {typeSafetyExamples[0]} + + +

    2. Handle Errors Gracefully

    +

    + Always wrap parsing operations in try-catch blocks: +

    + + {errorHandlingExamples[0]} + + +

    3. Choose the Right Function

    +
  • Use parse() when you need to preserve references for further processing
  • +
  • Use final() when you want a clean output for final consumption
  • + +

    4. Validate Schema Structure

    +

    + Ensure your schema follows the expected structure: +

    + + {schemaStructureExamples[0]} + + +

    5. Use Meaningful Names

    +

    + Choose descriptive names for your schema elements: +

    + + {namingExamples[0]} + + +

    Error Handling

    +

    + Common errors and their solutions: +

    + +

    Invalid Schema Structure

    + + {errorSolutionsExamples[0]} + +
  • Solution: Ensure your schema follows the correct syntax and structure.
  • + +

    Missing Required Properties

    + + {errorSolutionsExamples[1]} + +
  • Solution: Models and types must have a columns definition.
  • + +

    Duplicate Declarations

    + + {errorSolutionsExamples[2]} + +
  • Solution: Each declaration name must be unique within the schema.
  • + +

    Unknown References

    + + {errorSolutionsExamples[3]} + +
  • Solution: Ensure all referenced props and types are defined before use.
  • + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/core-concepts.tsx b/packages/www/plugins/docs/views/parser/core-concepts.tsx new file mode 100644 index 0000000..2d60112 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/core-concepts.tsx @@ -0,0 +1,97 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Getting Started'); + const description = _( + 'describe' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + return ( +
    +

    Core Concepts

    +

    Schema Structure

    +

    An .idea schema file can contain several types of declarations:

    + +
      +
    1. Plugins: External integrations and configurations +
    2. +
    3. Use statements: Import other schema files
    4. +
    5. Props: Reusable property configurations
    6. +
    7. Enums: Enumerated value definitions
    8. +
    9. Types: Custom type definitions with columns
    10. +
    11. Models: Database model definitions
    12. +
    + +

    Processing FLow

    +

    The library follows this processing flow:

    + + + {`Raw Schema Code → SchemaTree → Compiler → JSON Output + `} + + +
      +
    1. Raw Code: Your .idea schema file content
    2. +
    3. SchemaTree: Parses the entire file into an Abstract Syntax Tree
    4. +
    5. Compiler: Converts AST tokens into structured JSON
    6. +
    7. JSON Output: Final configuration object
    8. +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/examples.tsx b/packages/www/plugins/docs/views/parser/examples.tsx new file mode 100644 index 0000000..023865d --- /dev/null +++ b/packages/www/plugins/docs/views/parser/examples.tsx @@ -0,0 +1,130 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Examples'); + const description = _( + 'Examples of how to use the parser library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const completeSchemaExample = [ + `import { final } from '@stackpress/idea-parser'; + +const schemaCode = \` +plugin "./database-plugin" { + provider "postgresql" + url env("DATABASE_URL") +} + +prop Text { type "text" } +prop Email { type "email" format "email" } + +enum UserRole { + ADMIN "Administrator" + USER "Regular User" + GUEST "Guest User" +} + +type Address { + street String @field.input(Text) @is.required + city String @field.input(Text) @is.required + country String @field.select + postal String @field.input(Text) +} + +model User! { + id String @id @default("nanoid()") + email String @field.input(Email) @is.required @is.unique + name String @field.input(Text) @is.required + role UserRole @default("USER") + address Address? + active Boolean @default(true) + created Date @default("now()") + updated Date @default("updated()") +} +\`; + +const result = final(schemaCode); +console.log(JSON.stringify(result, null, 2));`, +`import { Compiler, EnumTree, ModelTree } from '@stackpress/idea-parser'; + +// Parse individual enum +const enumCode = \`enum Status { ACTIVE "Active" INACTIVE "Inactive" }\`; +const enumAST = EnumTree.parse(enumCode); +const [enumName, enumConfig] = Compiler.enum(enumAST); + +// Parse individual model +const modelCode = \`model User { id String @id name String }\`; +const modelAST = ModelTree.parse(modelCode); +const [modelName, modelConfig] = Compiler.model(modelAST);` +] + +export function Body() { + return ( +
    +

    Examples

    +

    Complete Schema Example

    + + {completeSchemaExample[0]} + + +

    Working with Individual Components

    + + {completeSchemaExample[1]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/installation.tsx b/packages/www/plugins/docs/views/parser/installation.tsx new file mode 100644 index 0000000..3c884e9 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/installation.tsx @@ -0,0 +1,116 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Installation'); + const description = _( + 'A TypeScript library for parsing .idea schema files into Abstract Syntax Trees (AST) and converting them to readable JSON configurations. This library is designed to help developers work with schema definitions in a structured and type-safe manner.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const examples = [ + `npm install @stackpress/idea-parser + `, + `import { parse, final } from '@stackpress/idea-parser'; + +// Parse a schema file into JSON (includes references) +const schemaCode = \` +prop Text { type "text" } +enum Roles { + ADMIN "Admin" + USER "User" +} +model User { + id String @id + name String @field.input(Text) + role Roles +} +\`; + +// Parse with references intact +const parsedSchema = parse(schemaCode); + +// Parse and clean up references (final version) +const finalSchema = final(schemaCode);` +] + +export function Body() { + return ( +
    +

    Idea Parser

    +

    + A TypeScript library for parsing .idea schema files into Abstract Syntax Trees (AST) and converting them to readable JSON configurations. This library is designed to help developers work with schema definitions in a structured and type-safe manner. +

    + +

    Installation

    +

    Install the package using npm:

    + + {examples[0]} + + +

    Quick Start

    +

    The library provides two main functions for parsing schema files:

    + +

    Basic Usage

    + + {examples[1]} + + +
  • Difference between parse and final
  • +
  • parse(code: string): Converts schema code to JSON while preserving prop and use references
  • +
  • final(code: string): Like parse but removes prop and use references for a clean final output
  • + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/pages/ast.tsx b/packages/www/plugins/docs/views/parser/pages/ast.tsx new file mode 100644 index 0000000..02f6d18 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/pages/ast.tsx @@ -0,0 +1,856 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; + import Code from '../../../components/Code.js'; + import Layout from '../../../components/Layout.js'; + import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Syntax Trees'); + const description = _( + 'The AST classes are responsible for parsing specific parts of schema code into Abstract Syntax Trees (ASTs). Each AST class handles a different type of declaration or construct in the schema language.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + +const examples = [ + `import { + SchemaTree, + EnumTree, + ModelTree, + TypeTree, + PropTree, + PluginTree, + UseTree +} from '@stackpress/idea-parser';`, + `import { SchemaTree, Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +SchemaTree.definitions(lexer); + +// Lexer now has definitions for all schema constructs: +// enum, prop, type, model, plugin, use keywords and structures`, + `import { SchemaTree } from '@stackpress/idea-parser'; + +const schemaCode = \` +plugin "./database" { + provider "postgresql" +} + +enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +} + +prop Text { type "text" } + +model User { + id String @id + name String @field.input(Text) + status Status +} +\`; + +const ast = SchemaTree.parse(schemaCode); +console.log(ast.type); // 'Program' +console.log(ast.kind); // 'schema' +console.log(ast.body.length); // 4 (plugin, enum, prop, model)`, + `import { SchemaTree } from '@stackpress/idea-parser'; + +const tree = new SchemaTree(); +const schemaCode = 'enum Status { ACTIVE "Active" }'; + +const result = tree.parse(schemaCode, 0); +console.log(result.body[0].kind); // 'enum'`, + `import { EnumTree, Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +EnumTree.definitions(lexer); + +// Adds 'EnumWord' token definition for 'enum' keyword`, + `import { EnumTree } from '@stackpress/idea-parser'; + +const enumCode = \`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`; + +const ast = EnumTree.parse(enumCode); +console.log(ast.kind); // 'enum' +console.log(ast.declarations[0].id.name); // 'Roles' +console.log(ast.declarations[0].init.properties.length); // 3 +console.log(ast.declarations[0].init.properties[0].key.name); // 'ADMIN' +console.log(ast.declarations[0].init.properties[0].value.value); // 'Admin'`, + `const tree = new EnumTree(); +tree._lexer.load('enum Status { ACTIVE "Active" INACTIVE "Inactive" }'); + +const enumToken = tree.enum(); +console.log(enumToken.declarations[0].id.name); // 'Status' +console.log(enumToken.declarations[0].init.properties[0].key.name); // 'ACTIVE' +console.log(enumToken.declarations[0].init.properties[0].value.value); // 'Active'`, + `// Inside enum parsing, after opening brace +const property = tree.property(); +console.log(property.key.name); // e.g., 'ADMIN' +console.log(property.value.value); // e.g., 'Admin'`, + `import { ModelTree } from '@stackpress/idea-parser'; + +const modelCode = \`model User @label("User" "Users") { + id String @label("ID") @id @default("nanoid(20)") + username String @label("Username") @searchable @field.input(Text) @is.required + password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide + role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) + address Address? @label("Address") @list.hide + age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) + active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno + created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) +}\`; + +const ast = ModelTree.parse(modelCode); +console.log(ast.kind); // 'model' +console.log(ast.mutable); // false (because of '!' modifier) +console.log(ast.declarations[0].id.name); // 'User'`, + `const tree = new ModelTree(); +tree._lexer.load('model User { id String @id }'); + +const modelToken = tree.model(); +console.log(modelToken.kind); // 'model' +console.log(modelToken.mutable); // false (immutable due to '!')`, + `import { TypeTree } from '@stackpress/idea-parser'; + +const typeCode = \`type Address @label("Address" "Addresses") { + street String @field.input @is.required + city String @field.input @is.required + country String @field.select + postal String @field.input +}\`; + +const ast = TypeTree.parse(typeCode); +console.log(ast.kind); // 'type' +console.log(ast.mutable); // true (mutable by default) +console.log(ast.declarations[0].id.name); // 'Address'`, + `const tree = new TypeTree(); +tree._lexer.load('type Address { street String city String }'); + +const typeToken = tree.type(); +console.log(typeToken.kind); // 'type' +console.log(typeToken.mutable); // true (default for types)`, + `// Inside type parsing +const property = tree.property(); +console.log(property.key.name); // e.g., 'street' +console.log(property.value); // Object containing type and attributes`, + `// For parsing generic type parameters +const parameter = tree.parameter(); +console.log(parameter.key.name); // Parameter name +console.log(parameter.value); // Parameter type/constraint`, + `import { PropTree } from '@stackpress/idea-parser'; + +const propCode = \`prop EmailInput { + type "email" + format "email" + placeholder "Enter your email" + required true +}\`; + +const ast = PropTree.parse(propCode); +console.log(ast.kind); // 'prop' +console.log(ast.declarations[0].id.name); // 'EmailInput'`, + `const tree = new PropTree(); +tree._lexer.load('prop Text { type "text" format "lowercase" }'); + +const propToken = tree.prop(); +console.log(propToken.kind); // 'prop' +console.log(propToken.declarations[0].id.name); // 'Text'`, + `import { PluginTree } from '@stackpress/idea-parser'; + +const pluginCode = \`plugin "./database-plugin" { + provider "postgresql" + url env("DATABASE_URL") + previewFeatures ["fullTextSearch"] +}\`; + +const ast = PluginTree.parse(pluginCode); +console.log(ast.kind); // 'plugin' +console.log(ast.declarations[0].id.name); // './database-plugin'`, + `const tree = new PluginTree(); +tree._lexer.load('plugin "./custom" { provider "custom-provider" }'); + +const pluginToken = tree.plugin(); +console.log(pluginToken.kind); // 'plugin' +console.log(pluginToken.declarations[0].id.name); // './custom'`, + `import { UseTree } from '@stackpress/idea-parser'; + +const useCode = 'use "./shared/types.idea"'; + +const ast = UseTree.parse(useCode); +console.log(ast.type); // 'ImportDeclaration' +console.log(ast.source.value); // './shared/types.idea'`, + `const tree = new UseTree(); +tree._lexer.load('use "./another.idea"'); + +const useToken = tree.use(); +console.log(useToken.type); // 'ImportDeclaration' +console.log(useToken.source.value); // './another.idea'`, + `import { EnumTree, ModelTree, TypeTree } from '@stackpress/idea-parser'; + +// Parse individual enum +const enumAST = EnumTree.parse(\`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`); + +// Parse individual model +const modelAST = ModelTree.parse(\`model User { + id String @id + username String @is.required +}\`); + +// Parse individual type +const typeAST = TypeTree.parse(\`type Address { + street String + city String +}\`);`, + `import { EnumTree, Compiler } from '@stackpress/idea-parser'; + +// Parse and compile in one step +const enumAST = EnumTree.parse(\`enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +}\`); +const [enumName, enumConfig] = Compiler.enum(enumAST); + +console.log(enumName); // 'Status' +console.log(enumConfig); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`, + `import { AbstractTree, Lexer } from '@stackpress/idea-parser'; +import type { DeclarationToken } from '@stackpress/idea-parser'; + +class CustomTree extends AbstractTree { + static definitions(lexer: Lexer) { + super.definitions(lexer); + // Add custom token definitions + lexer.define('CustomKeyword', (code, index) => { + // Custom token reader implementation + }); + return lexer; + } + + static parse(code: string, start = 0) { + return new this().parse(code, start); + } + + parse(code: string, start = 0): DeclarationToken { + this._lexer.load(code, start); + return this.customDeclaration(); + } + + customDeclaration(): DeclarationToken { + // Custom parsing logic + const keyword = this._lexer.expect('CustomKeyword'); + // ... more parsing logic + + return { + type: 'VariableDeclaration', + kind: 'custom', + start: keyword.start, + end: this._lexer.index, + declarations: [/* ... */] + }; + } +}`, + `import { SchemaTree, Exception } from '@stackpress/idea-parser'; + +try { + // Invalid syntax - missing closing brace + SchemaTree.parse('enum Status { ACTIVE "Active"'); +} catch (error) { + if (error instanceof Exception) { + console.log('Parse error:', error.message); + console.log('Position:', error.start, '-', error.end); + } +}`, + `try { + // Invalid - 'enum' keyword expected but found 'model' + EnumTree.parse('model User { id String }'); +} catch (error) { + console.log('Expected enum but found model'); +}`, + `import { EnumTree } from '@stackpress/idea-parser'; + +try { + // Empty string will throw an error + EnumTree.parse(''); +} catch (error) { + console.log('Error:', error.message); // 'Unexpected end of input' +}`, + `import { ModelTree } from '@stackpress/idea-parser'; + +try { + // Invalid - model names must be capitalized + ModelTree.parse('model user { id String }'); +} catch (error) { + console.log('Expected CapitalIdentifier but got something else'); +}`, + `// This is what happens internally: +import { SchemaTree, Compiler } from '@stackpress/idea-parser'; + +export function parse(code: string) { + const ast = SchemaTree.parse(code); // Parse to AST + return Compiler.schema(ast); // Compile to JSON +} + +export function final(code: string) { + const ast = SchemaTree.parse(code); // Parse to AST + return Compiler.final(ast); // Compile and clean up +}`, + `import { Lexer, SchemaTree } from '@stackpress/idea-parser'; + +// Create and configure lexer once +const lexer = new Lexer(); +SchemaTree.definitions(lexer); + +// Reuse for multiple parses +const tree = new SchemaTree(lexer); + +const result1 = tree.parse(code1); +const result2 = tree.parse(code2); +const result3 = tree.parse(code3);`, + `// Inside tree parsing methods +const checkpoint = this._lexer.clone(); + +try { + // Try to parse optional structure + return this.parseOptionalStructure(); +} catch (error) { + // Restore lexer state and continue + this._lexer = checkpoint; + return this.parseAlternativeStructure(); +}`, + `const enumCode = \`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`; + +const ast = EnumTree.parse(enumCode); +// Produces a complete AST with all three enum values`, + `const modelCode = \`model User @label("User" "Users") { + id String @label("ID") @id @default("nanoid(20)") + username String @label("Username") @searchable @field.input(Text) @is.required + password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide + role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) + address Address? @label("Address") @list.hide + age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) + balance Number[] @label("Balance") @filterable @sortable @field.number() @list.number() @view.number + active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno + created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) + updated Date @label("Updated") @default("updated()") @filterable @sortable @list.date(Pretty) + company Company? @label("My Company") +}\`; + +const ast = ModelTree.parse(modelCode); +// Produces a complete model AST with all columns and attributes` +] + + export function Body() { + return ( +
    +

    Syntax Trees

    +

    The AST classes are responsible for parsing specific parts of schema code into Abstract Syntax Trees (ASTs). Each AST class handles a different type of declaration or construct in the schema language.

    + + {examples[0]} + + +

    SchemaTree

    +

    Parses complete schema files containing multiple declarations.

    + +

    Static Methods

    + +

    Setting Up Schema Definitions

    +

    The following example shows how to configure a lexer for schema parsing.

    + + {examples[1]} + + +

    Parameters

    + + Parameter + Type + Description + + lexer + Lexer + The lexer instance to configure + +
    + + Returns +
  • The configured lexer instance.
  • + +

    Parsing Complete Schemas

    +

    The following example shows how to parse a complete schema file.

    + + {examples[2]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The complete schema code to parse + +
    + + Returns +
  • A SchemaToken representing the entire parsed schema.
  • + +

    Methods

    + +

    Parsing Schema Content

    +

    The following example shows how to parse schema content with custom starting position.

    + + {examples[3]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The schema code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A SchemaToken containing all parsed declarations.
  • + +

    EnumTree

    +

    Parses enum declarations into AST tokens.

    + +

    Static Methods

    + +

    Setting Up Enum Definitions

    +

    The following example shows how to configure a lexer for enum parsing.

    + + {examples[4]} + + +

    Parsing Enum Declarations

    +

    The following example shows how to parse enum declarations based on the test fixtures.

    + + {examples[5]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The enum declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A DeclarationToken representing the parsed enum.
  • + +

    Methods

    + +

    Parsing Enum Structure

    +

    The following example shows how to parse the enum structure.

    + + {examples[6]} + + + Returns +
  • A DeclarationToken representing the enum structure.
  • + +

    Parsing Enum Properties

    +

    The following example shows how individual enum properties are parsed.

    + + {examples[7]} + + + Returns +
  • A PropertyToken representing a single enum key-value pair.
  • + +

    ModelTree

    +

    Parses model declarations (extends TypeTree for shared functionality).

    + +

    Static Methods

    + +

    Parsing Model Declarations

    +

    The following example shows how to parse model declarations based on the test fixtures.

    + + {examples[8]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The model declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A DeclarationToken representing the parsed model.
  • + +

    Methods

    + +

    Parsing Model Structure

    +

    The following example shows how to parse the model structure.

    + + {examples[9]} + + + Returns +
  • A DeclarationToken representing the model structure.
  • + +

    TypeTree

    +

    Parses type declarations.

    + +

    Static Methods

    + +

    Parsing Type Declarations

    +

    The following example shows how to parse type declarations.

    + + {examples[10]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The type declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A DeclarationToken representing the parsed type.
  • + +

    Methods

    + +

    Parsing Type Structure

    +

    The following example shows how to parse the type structure.

    + + {examples[11]} + + + Returns +
  • A DeclarationToken representing the type structure.
  • + +

    Parsing Type Properties

    +

    The following example shows how type properties (columns) are parsed.

    + + {examples[12]} + + + Returns +
  • A PropertyToken representing a type column definition.
  • + +

    Parsing Type Parameters

    +

    The following example shows how type parameters are parsed.

    + + {examples[13]} + + + Returns +
  • A PropertyToken representing a type parameter.
  • + +

    PropTree

    +

    Parses prop (property configuration) declarations.

    + +

    Static Methods

    + +

    Parsing Prop Declarations

    +

    The following example shows how to parse prop declarations.

    + + {examples[14]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The prop declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A DeclarationToken representing the parsed prop.
  • + +

    Methods

    + +

    Parsing Prop Structure

    +

    The following example shows how to parse the prop structure.

    + + {examples[15]} + + + Returns +
  • A DeclarationToken representing the prop configuration.
  • + +

    PluginTree

    +

    Parses plugin declarations.

    + +

    Static Methods

    + +

    Parsing Plugin Declarations

    +

    The following example shows how to parse plugin declarations.

    + + {examples[16]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The plugin declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • A DeclarationToken representing the parsed plugin.
  • + +

    Methods

    + +

    Parsing Plugin Structure

    +

    The following example shows how to parse the plugin structure.

    + + {examples[17]} + + + Returns +
  • A DeclarationToken representing the plugin configuration.
  • + +

    UseTree

    +

    Parses use (import) declarations.

    + +

    Static Methods

    + +

    Parsing Use Declarations

    +

    The following example shows how to parse use declarations.

    + + {examples[18]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The use declaration code to parse + + + start + number + Starting position in the code (default: 0) + +
    + + Returns +
  • An ImportToken representing the parsed use statement.
  • + +

    Methods

    + +

    Parsing Use Structure

    +

    The following example shows how to parse the use structure.

    + + {examples[19]} + + + Returns +
  • An ImportToken representing the import statement.
  • + +

    Usage Patterns

    + +

    Parsing Individual Components

    + + {examples[20]} + + +

    Using with Compiler

    + + {examples[21]} + + +

    Custom AST Classes

    +

    You can extend AbstractTree to create custom parsers:

    + + {examples[22]} + + +

    Error Handling

    +

    AST classes provide detailed error information when parsing fails:

    + +

    Syntax Errors

    + + {examples[23]} + + +

    Unexpected Tokens

    + + {examples[24]} + + +

    Empty Input Handling

    + + {examples[25]} + + +

    Invalid Identifiers

    + + {examples[26]} + + +

    Integration with Main Functions

    +

    AST classes are used internally by the main parse and final functions:

    + + {examples[27]} + + +

    Performance Considerations

    + +

    Lexer Reuse

    +

    AST classes can share lexer instances for better performance:

    + + {examples[28]} + + +

    Cloning for Backtracking

    +

    AST classes use lexer cloning for safe parsing attempts:

    + + {examples[29]} + + +

    Test-Driven Examples

    +

    Based on the test fixtures, here are real-world examples:

    + +

    Enum with Multiple Values

    + + {examples[30]} + + +

    Complex Model with Attributes

    + + {examples[31]} + + +

    This demonstrates the parser's ability to handle:

    +
      +
    • Model mutability (! modifier)
    • +
    • Attributes (@label, @id, @default, etc.)
    • +
    • Optional types (Address?, Company?)
    • +
    • Array types (Number[])
    • +
    • Complex attribute parameters (@field.input(Text), @is.clt(80))
    • +
    + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } \ No newline at end of file diff --git a/packages/www/plugins/docs/views/parser/pages/compiler.tsx b/packages/www/plugins/docs/views/parser/pages/compiler.tsx new file mode 100644 index 0000000..0d75bbe --- /dev/null +++ b/packages/www/plugins/docs/views/parser/pages/compiler.tsx @@ -0,0 +1,754 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../../components/index.js'; +import Code from '../../../components/Code.js'; +import Layout from '../../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Compiler'); + const description = _( + 'Compiler class for the parser library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const compilerParams = [ + `import { Compiler } from '@stackpress/idea-parser';`, + `import { Compiler } from '@stackpress/idea-parser'; + +// Example array token from parsing ["value1", "value2", "value3"] +const arrayToken = { + type: 'ArrayExpression', + elements: [ + { type: 'Literal', value: 'value1' }, + { type: 'Literal', value: 'value2' }, + { type: 'Literal', value: 'value3' } + ] +}; + +const result = Compiler.array(arrayToken); +console.log(result); // ['value1', 'value2', 'value3']`, +`import { Compiler } from '@stackpress/idea-parser'; + +// Compile different types of data tokens +const literalResult = Compiler.data({ type: 'Literal', value: 'hello' }); +console.log(literalResult); // 'hello' + +const objectResult = Compiler.data({ + type: 'ObjectExpression', + properties: [ + { + key: { name: 'name' }, + value: { type: 'Literal', value: 'John' } + } + ] +}); +console.log(objectResult); // { name: 'John' }`, +`import { Compiler } from '@stackpress/idea-parser'; + +// Example enum token from parsing: enum Status { ACTIVE "Active" INACTIVE "Inactive" } +const enumToken = { + kind: 'enum', + declarations: [{ + id: { name: 'Status' }, + init: { + properties: [ + { key: { name: 'ACTIVE' }, value: { type: 'Literal', value: 'Active' } }, + { key: { name: 'INACTIVE' }, value: { type: 'Literal', value: 'Inactive' } } + ] + } + }] +}; + +const [name, config] = Compiler.enum(enumToken); +console.log(name); // 'Status' +console.log(config); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`, +`import { Compiler } from '@stackpress/idea-parser'; + +// This method removes prop and use references for a clean final output +const finalSchema = Compiler.final(schemaToken); +console.log(finalSchema); +// Output will not contain 'prop' or 'use' sections`, + +] + +export function Body() { + return ( +
    +

    Compiler

    +

    + The Compiler class provides static methods for converting Abstract Syntax Tree (AST) tokens into structured JSON configurations. It serves as the bridge between parsed tokens and the final JSON output. +

    + + {compilerParams[0]} + + +

    Static Methods

    +

    + The following methods can be accessed directly from the Compiler class. +

    + +

    Converting Array Tokens

    +

    + The following example shows how to compile array tokens into actual arrays. +

    + + {compilerParams[1]} + + +

    Parameters

    + + Parameter + Type + Description + + token + ArrayToken + The array token to compile + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    An array containing the compiled elements.

    + +

    Converting Data Tokens

    +

    + The following example shows how to compile various data tokens into their actual values. +

    + + {compilerParams[2]} + + +

    Parameters

    + + Parameter + Type + Description + + token + DataToken + The data token to compile (can be object, array, literal, or identifier) + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    The compiled data value based on the token type.

    + +

    Converting Enum Declarations

    +

    + The following example shows how to compile enum declarations into JSON configurations. +

    + + {compilerParams[3]} + + +

    Parameters

    + + Parameter + Type + Description + + token + DeclarationToken + The enum declaration token to compile + +
    + +

    Returns

    +

    A tuple containing the enum name and its configuration object.

    + +

    Converting Schema to Final JSON

    +

    + The following example shows how to compile a schema token into a final JSON configuration. +

    + + {compilerParams[4]} + + +

    Parameters

    + + Parameter + Type + Description + + token + SchemaToken + The schema token to compile into final form + +
    + +

    Returns

    +

    A FinalSchemaConfig object with references resolved and removed.

    + +

    Converting Identifier Tokens

    +

    + The following example shows how to resolve identifier tokens to their actual values. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// With references provided +const references = { MyProp: { type: 'text' } }; +const result1 = Compiler.identifier({ name: 'MyProp' }, references); +console.log(result1); // { type: 'text' } + +// Without references (returns template string) +const result2 = Compiler.identifier({ name: 'MyProp' }, false); +console.log(result2); // '\${MyProp}' + +// With empty references (throws error) +try { + Compiler.identifier({ name: 'UnknownProp' }, {}); +} catch (error) { + console.log(error.message); // 'Unknown reference UnknownProp' +}`} + + +

    Parameters

    + + Parameter + Type + Description + + token + IdentifierToken + The identifier token to resolve + + + references + UseReferences + Reference map for resolving the identifier + +
    + +

    Returns

    +

    The resolved value from references, a template string, or throws an error.

    + +

    Converting Literal Tokens

    +

    + The following example shows how to extract values from literal tokens. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +const stringLiteral = Compiler.literal({ type: 'Literal', value: 'hello' }); +console.log(stringLiteral); // 'hello' + +const numberLiteral = Compiler.literal({ type: 'Literal', value: 42 }); +console.log(numberLiteral); // 42 + +const booleanLiteral = Compiler.literal({ type: 'Literal', value: true }); +console.log(booleanLiteral); // true`} + + +

    Parameters

    + + Parameter + Type + Description + + token + LiteralToken + The literal token to extract value from + +
    + +

    Returns

    +

    The literal value (string, number, boolean, etc.).

    + +

    Converting Model Declarations

    +

    + The following example shows how to compile model declarations into JSON configurations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example model token from parsing: model User { id String @id name String } +const modelToken = { + kind: 'model', + mutable: false, // model User! would be true + declarations: [{ + id: { name: 'User' }, + init: { + properties: [ + { + key: { name: 'columns' }, + value: { + type: 'ObjectExpression', + properties: [ + { + key: { name: 'id' }, + value: { + type: 'ObjectExpression', + properties: [ + { key: { name: 'type' }, value: { type: 'Literal', value: 'String' } }, + { key: { name: 'attributes' }, value: { /* attributes */ } } + ] + } + } + ] + } + } + ] + } + }] +}; + +const [name, config] = Compiler.model(modelToken); +console.log(name); // 'User' +console.log(config.mutable); // false +console.log(config.columns); // Array of column configurations`} + + +

    Parameters

    + + Parameter + Type + Description + + token + DeclarationToken + The model declaration token to compile + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    A tuple containing the model name and its configuration object.

    + +

    Converting Object Tokens

    +

    + The following example shows how to compile object tokens into actual objects. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example object token from parsing { name "John" age 30 } +const objectToken = { + type: 'ObjectExpression', + properties: [ + { key: { name: 'name' }, value: { type: 'Literal', value: 'John' } }, + { key: { name: 'age' }, value: { type: 'Literal', value: 30 } } + ] +}; + +const result = Compiler.object(objectToken); +console.log(result); // { name: 'John', age: 30 }`} + + +

    Parameters

    + + Parameter + Type + Description + + token + ObjectToken + The object token to compile + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    An object with compiled key-value pairs.

    + +

    Converting Plugin Declarations

    +

    + The following example shows how to compile plugin declarations into JSON configurations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example plugin token from parsing: plugin "./database" { provider "postgresql" } +const pluginToken = { + kind: 'plugin', + declarations: [{ + id: { name: './database' }, + init: { + properties: [ + { key: { name: 'provider' }, value: { type: 'Literal', value: 'postgresql' } } + ] + } + }] +}; + +const [name, config] = Compiler.plugin(pluginToken); +console.log(name); // './database' +console.log(config); // { provider: 'postgresql' }`} + + +

    Parameters

    + + Parameter + Type + Description + + token + DeclarationToken + The plugin declaration token to compile + +
    + +

    Returns

    +

    A tuple containing the plugin name and its configuration object.

    + +

    Converting Prop Declarations

    +

    + The following example shows how to compile prop declarations into JSON configurations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example prop token from parsing: prop Text { type "text" format "lowercase" } +const propToken = { + kind: 'prop', + declarations: [{ + id: { name: 'Text' }, + init: { + properties: [ + { key: { name: 'type' }, value: { type: 'Literal', value: 'text' } }, + { key: { name: 'format' }, value: { type: 'Literal', value: 'lowercase' } } + ] + } + }] +}; + +const [name, config] = Compiler.prop(propToken); +console.log(name); // 'Text' +console.log(config); // { type: 'text', format: 'lowercase' }`} + + +

    Parameters

    + + Parameter + Type + Description + + token + DeclarationToken + The prop declaration token to compile + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    A tuple containing the prop name and its configuration object.

    + +

    Converting Schema Declarations

    +

    + The following example shows how to compile complete schema tokens into JSON configurations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Compile a complete schema with all declaration types +const schemaConfig = Compiler.schema(schemaToken); +console.log(schemaConfig); +// Output contains: { enum: {...}, prop: {...}, type: {...}, model: {...}, plugin: {...}, use: [...] } + +// Compile with finalization (resolves references) +const finalizedConfig = Compiler.schema(schemaToken, true); +console.log(finalizedConfig); +// References are resolved in the output`} + + +

    Parameters

    + + Parameter + Type + Description + + token + SchemaToken + The schema token to compile + + + finalize + boolean + Whether to resolve references (default: false) + +
    + +

    Returns

    +

    A SchemaConfig object containing all compiled declarations.

    + +

    Converting Type Declarations

    +

    + The following example shows how to compile type declarations into JSON configurations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example type token from parsing: type Address { street String city String } +const typeToken = { + kind: 'type', + mutable: true, // type Address (mutable) vs type Address! (immutable) + declarations: [{ + id: { name: 'Address' }, + init: { + properties: [ + { + key: { name: 'columns' }, + value: { + type: 'ObjectExpression', + properties: [ + { + key: { name: 'street' }, + value: { + type: 'ObjectExpression', + properties: [ + { key: { name: 'type' }, value: { type: 'Literal', value: 'String' } } + ] + } + } + ] + } + } + ] + } + }] +}; + +const [name, config] = Compiler.type(typeToken); +console.log(name); // 'Address' +console.log(config.mutable); // true +console.log(config.columns); // Array of column configurations`} + + +

    Parameters

    + + Parameter + Type + Description + + token + DeclarationToken + The type declaration token to compile + + + references + UseReferences + Reference map for resolving identifiers (default: false) + +
    + +

    Returns

    +

    A tuple containing the type name and its configuration object.

    + +

    Converting Use Declarations

    +

    + The following example shows how to compile use (import) declarations. +

    + +{`import { Compiler } from '@stackpress/idea-parser'; + +// Example use token from parsing: use "./another.idea" +const useToken = { + type: 'ImportDeclaration', + source: { type: 'Literal', value: './another.idea' } +}; + +const importPath = Compiler.use(useToken); +console.log(importPath); // './another.idea'`} + + +

    Parameters

    + + Parameter + Type + Description + + token + ImportToken + The import declaration token to compile + +
    + +

    Returns

    +

    The import path as a string.

    + +

    Error Handling

    +

    + The Compiler class throws Exception errors for various invalid conditions: +

    + +

    Invalid Token Types

    + +{`// Throws: "Invalid data token type" +Compiler.data({ type: 'UnknownType' }); + +// Throws: "Invalid Enum" +Compiler.enum({ kind: 'notAnEnum' }); + +// Throws: "Invalid Plugin" +Compiler.plugin({ kind: 'notAPlugin' }); + +// Throws: "Invalid Prop" +Compiler.prop({ kind: 'notAProp' }); + +// Throws: "Invalid Schema" +Compiler.schema({ kind: 'notASchema' }); + +// Throws: "Invalid Type" +Compiler.type({ kind: 'notAType' }); + +// Throws: "Invalid Import" +Compiler.use({ type: 'NotAnImportDeclaration' });`} + + +

    Missing Required Properties

    + +{`// Throws: "Expecting a columns property" +Compiler.model({ + kind: 'model', + declarations: [{ + id: { name: 'User' }, + init: { properties: [] } // Missing columns + }] +});`} + + +

    Unknown References

    + +{`// Throws: "Unknown reference MyProp" +Compiler.identifier({ name: 'MyProp' }, {});`} + + +

    Duplicate Declarations

    + +{`// Throws: "Duplicate MyEnum" when compiling schema with duplicate names +Compiler.schema(schemaWithDuplicates);`} + + +

    Type Processing

    +

    + The Compiler automatically processes type information for models and types: +

    + +

    Type Modifiers

    + +{`Optional types: String? → { type: 'String', required: false } +Array types: String[] → { type: 'String', multiple: true } +Combined: String[]? → { type: 'String', required: false, multiple: true }`} + + +

    Column Configuration

    +

    + Models and types are converted from object format to array format to preserve column order: +

    + +{`// Input object format +{ + columns: { + id: { type: 'String', attributes: { id: true } }, + name: { type: 'String', attributes: { required: true } } + } +} + +// Output array format +{ + columns: [ + { name: 'id', type: 'String', required: true, multiple: false, attributes: { id: true } }, + { name: 'name', type: 'String', required: true, multiple: false, attributes: { required: true } } + ] +}`} + + +

    Usage with AST

    +

    + The Compiler is typically used in conjunction with AST classes: +

    + +{`import { Compiler, EnumTree, ModelTree, SchemaTree } from '@stackpress/idea-parser'; + +// Parse and compile individual components +const enumAST = EnumTree.parse('enum Status { ACTIVE "Active" }'); +const [enumName, enumConfig] = Compiler.enum(enumAST); + +const modelAST = ModelTree.parse('model User { id String @id }'); +const [modelName, modelConfig] = Compiler.model(modelAST); + +// Parse and compile complete schema +const schemaAST = SchemaTree.parse(schemaCode); +const schemaConfig = Compiler.schema(schemaAST);`} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} + + + + diff --git a/packages/www/plugins/docs/views/parser/pages/exception-handling.tsx b/packages/www/plugins/docs/views/parser/pages/exception-handling.tsx new file mode 100644 index 0000000..f5b24be --- /dev/null +++ b/packages/www/plugins/docs/views/parser/pages/exception-handling.tsx @@ -0,0 +1,306 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; + import Code from '../../../components/Code.js'; + import Layout from '../../../components/Layout.js'; + import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Exception'); + const description = _( + 'The Exception class extends the Exception class from @stackpress/lib to provide enhanced error handling specific to the idea parser library. It includes position information and better error reporting for parsing failures.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + +const examples = [ + `import { Exception } from '@stackpress/idea-parser';`, + `import { parse, Exception } from '@stackpress/idea-parser'; + +try { + const result = parse('invalid schema syntax'); +} catch (error) { + if (error instanceof Exception) { + console.log('Parser error:', error.message); + console.log('Error position:', error.start, '-', error.end); + console.log('Stack trace:', error.stack); + } +}`, + `import { EnumTree, Exception } from '@stackpress/idea-parser'; + +try { + // Missing closing brace + EnumTree.parse('enum Status { ACTIVE "Active"'); +} catch (error) { + if (error instanceof Exception) { + console.log('Error message:', error.message); + console.log('Error starts at character:', error.start); + console.log('Error ends at character:', error.end); + + // Can be used for syntax highlighting in editors + const errorRange = { start: error.start, end: error.end }; + } +}`, + `try { + parse('enum Status { ACTIVE "Active"'); // Missing closing brace +} catch (error) { + console.log(error.message); // "Unexpected end of input expecting }" +}`, + `try { + parse('model user { id String }'); // Invalid - should be capitalized +} catch (error) { + console.log(error.message); // "Expected CapitalIdentifier but got something else" +}`, + `try { + parse('model User { name String @field.input(UnknownProp) }'); +} catch (error) { + console.log(error.message); // "Unknown reference UnknownProp" +}`, + `try { + parse(\` + enum Status { ACTIVE "Active" } + enum Status { INACTIVE "Inactive" } + \`); +} catch (error) { + console.log(error.message); // "Duplicate Status" +}`, + `import { SchemaTree, EnumTree, ModelTree, Exception } from '@stackpress/idea-parser'; + +// Any parsing operation can throw Exception +try { + const schema = SchemaTree.parse(schemaCode); + const enumAST = EnumTree.parse(enumCode); + const modelAST = ModelTree.parse(modelCode); +} catch (error) { + if (error instanceof Exception) { + // Handle parser-specific errors + console.error('Parsing failed:', error.message); + } else { + // Handle other types of errors + console.error('Unexpected error:', error); + } +}`, + `import { parse, Exception } from '@stackpress/idea-parser'; + +function parseWithFallback(code: string, fallbackCode?: string) { + try { + return parse(code); + } catch (error) { + if (error instanceof Exception && fallbackCode) { + console.warn('Primary parsing failed, trying fallback:', error.message); + return parse(fallbackCode); + } + throw error; // Re-throw if no fallback or different error type + } +}`, + `import { parse, Exception } from '@stackpress/idea-parser'; + +function validateSchema(code: string) { + try { + parse(code); + return { valid: true, errors: [] }; + } catch (error) { + if (error instanceof Exception) { + return { + valid: false, + errors: [{ + message: error.message, + range: { + start: error.start, + end: error.end + }, + severity: 'error' + }] + }; + } + throw error; + } +}`, + `try { + parse(schemaCode); +} catch (error) { + if (error instanceof Exception) { + // Handle parser errors specifically + handleParserError(error); + } else { + // Handle other errors (network, file system, etc.) + handleGenericError(error); + } +}`, + `function highlightError(code: string, error: Exception) { + const lines = code.split('\\n'); + let currentPos = 0; + + for (let i = 0; i < lines.length; i++) { + const lineEnd = currentPos + lines[i].length; + + if (error.start >= currentPos && error.start <= lineEnd) { + const lineStart = error.start - currentPos; + const lineEnd = Math.min(error.end - currentPos, lines[i].length); + + console.log(\`Line \${i + 1}: \${lines[i]}\`); + console.log(' '.repeat(lineStart + 8) + '^'.repeat(lineEnd - lineStart)); + break; + } + + currentPos = lineEnd + 1; // +1 for newline + } +}`, + `function parseWithContext(code: string, filename?: string) { + try { + return parse(code); + } catch (error) { + if (error instanceof Exception) { + const context = filename ? \` in \${filename}\` : ''; + throw new Exception( + \`Parse error\${context}: \${error.message}\`, + error.code + ).withPosition(error.start, error.end); + } + throw error; + } +}` +] + + export function Body() { + return ( +
    +

    Exception

    +

    The Exception class extends the Exception class from @stackpress/lib to provide enhanced error handling specific to the idea parser library. It includes position information and better error reporting for parsing failures.

    + + {examples[0]} + + +

    Overview

    +

    Exception is a specialized error class that extends the base Exception class with additional functionality for parser-specific error handling. It automatically includes position information when parsing fails, making it easier to identify and fix syntax errors in schema files.

    + +

    Usage Examples

    + +

    Basic Error Handling

    + + {examples[1]} + + +

    Position Information

    +

    Exception includes position information to help locate errors in the source code:

    + + {examples[2]} + + +

    Common Error Scenarios

    + + Syntax Errors + + {examples[3]} + + + Invalid Token Types + + {examples[4]} + + + Unknown References + + {examples[5]} + + + Duplicate Declarations + + {examples[6]} + + +

    Integration with AST

    +

    All AST classes throw Exception when parsing fails:

    + + {examples[7]} + + +

    Error Recovery

    +

    While Exception indicates parsing failure, you can implement error recovery strategies:

    + + {examples[8]} + + +

    Language Server Integration

    +

    Exception's position information makes it ideal for language server implementations:

    + + {examples[9]} + + +

    Inherited Features

    +

    Since Exception extends the base Exception class from @stackpress/lib, it inherits all the enhanced error handling features:

    +
      +
    • Template-based error messages
    • +
    • Enhanced stack trace parsing
    • +
    • Position information support
    • +
    • HTTP status code integration
    • +
    • Validation error aggregation
    • +
    +

    For more details on the base Exception functionality, refer to the @stackpress/lib Exception documentation.

    + +

    Best Practices

    + +

    Always Check Error Type

    + + {examples[10]} + + +

    Use Position Information

    + + {examples[11]} + + +

    Provide Helpful Error Messages

    + + {examples[12]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } diff --git a/packages/www/plugins/docs/views/parser/pages/lexer.tsx b/packages/www/plugins/docs/views/parser/pages/lexer.tsx new file mode 100644 index 0000000..db761e0 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/pages/lexer.tsx @@ -0,0 +1,755 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../../components/index.js'; +import Code from '../../../components/Code.js'; +import Layout from '../../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Lexer'); + const description = _( + 'The Lexer class implements the Parser interface and provides tokenization and parsing utilities for schema code. It manages a dictionary of token definitions and handles the parsing process by matching patterns against the input code.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const examples = [ + `import { Lexer } from '@stackpress/idea-parser'; + `, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.load('enum Status { ACTIVE "Active" }'); +lexer.define('enum', enumReader); + +// Clone preserves code, index position, and all definitions +const clonedLexer = lexer.clone(); +console.log(clonedLexer.index); // Same index as original +console.log(clonedLexer.dictionary); // Same definitions as original`, + `import { Lexer } from '@stackpress/idea-parser'; +import definitions from '@stackpress/idea-parser/definitions'; + +const lexer = new Lexer(); + +// Load all predefined token definitions +Object.keys(definitions).forEach((key) => { + lexer.define(key, definitions[key]); +}); + +// Define a custom token +lexer.define('customKeyword', (code, start, lexer) => { + if (code.substring(start, start + 6) === 'custom') { + return { + type: 'Keyword', + value: 'custom', + start: start, + end: start + 6 + }; + } + return undefined; +});`, + `import { Lexer } from '@stackpress/idea-parser'; +import definitions, { data } from '@stackpress/idea-parser/definitions'; + +const lexer = new Lexer(); +Object.keys(definitions).forEach((key) => { + lexer.define(key, definitions[key]); +}); + +// Parse a float literal +lexer.load('4.4'); +const floatToken = lexer.expect('Float'); +console.log(floatToken.value); // 4.4 +console.log(floatToken.start); // 0 +console.log(floatToken.end); // 3 + +// Parse any data type (scalar, object, or array) +lexer.load('"hello world"'); +const stringToken = lexer.expect(data); +console.log(stringToken.value); // 'hello world' + +// Expect one of multiple token types +lexer.load('true'); +const booleanToken = lexer.expect(['Boolean', 'String', 'Integer']); +console.log(booleanToken.value); // true`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.define('String', definitions['String']); + +const definition = lexer.get('String'); +if (definition) { + console.log('Definition key:', definition.key); // 'String' + console.log('Reader function:', typeof definition.reader); // 'function' +} else { + console.log('Definition not found'); +}`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); + +// Load code from the beginning +lexer.load('enum Status { ACTIVE "Active" }'); +console.log(lexer.index); // 0 + +// Load code starting from a specific position +lexer.load('enum Status { ACTIVE "Active" }', 5); +console.log(lexer.index); // 5 +console.log(lexer.substring(5, 11)); // 'Status'`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.define('literal', (code, start) => { + if (code.startsWith('42', start)) { + return { type: 'Literal', value: 42, start, end: start + 2 }; + } + return undefined; +}); + +const code = '42'; + +// Match against specific token types +const match = lexer.match(code, 0, ['literal']); +if (match) { + console.log('Matched:', match.type); // 'Literal' + console.log('Value:', match.value); // 42 +} + +// Match against all available definitions (pass undefined for keys) +const match2 = lexer.match('42', 0, undefined); +if (match2) { + console.log('Matched:', match2.type); // 'Literal' +}`, + `import { Lexer } from '@stackpress/idea-parser'; +import definitions from '@stackpress/idea-parser/definitions'; + +const lexer = new Lexer(); +Object.keys(definitions).forEach((key) => { + lexer.define(key, definitions[key]); +}); + +lexer.load('enum Status { ACTIVE "Active" }'); + +// Test if next token matches (doesn't advance index) +if (lexer.next('AnyIdentifier')) { + console.log('Next token is an identifier'); + console.log(lexer.index); // Still 0 +} + +// Test for multiple possible tokens +if (lexer.next(['String', 'Integer', 'Boolean'])) { + console.log('Next token is a literal value'); +}`, + `import { Lexer } from '@stackpress/idea-parser'; +import definitions from '@stackpress/idea-parser/definitions'; + +const lexer = new Lexer(); +Object.keys(definitions).forEach((key) => { + lexer.define(key, definitions[key]); +}); + +lexer.load('/* some comment */ enum Status'); + +// Try to parse optional whitespace/comments +const comment = lexer.optional('note'); +if (comment) { + console.log('Found comment:', comment.value); // '/* some comment */' +} + +// Skip optional whitespace +lexer.optional('whitespace'); + +// Now parse the enum keyword +const enumToken = lexer.expect('AnyIdentifier'); +console.log(enumToken.name); // 'enum'`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.load(''); // Empty string + +// Read the next token (tries all definitions) +const nextToken = lexer.read(); +console.log(nextToken); // undefined (no tokens in empty string) + +lexer.load('42'); +lexer.define('Integer', definitions['Integer']); + +const token = lexer.read(); +if (token) { + console.log('Token type:', token.type); // 'Literal' + console.log('Token value:', token.value); // 42 +}`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.load('some code'); + +// Extract specific portions of code +const substring = lexer.substring(5, 9); +console.log(substring); // 'code' + +// Return empty string when start and end are the same +const empty = lexer.substring(5, 5); +console.log(empty); // ''`, + `import { Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.load('enum Status { ACTIVE "Active" }'); + +// Find next space from current position +const spaceIndex = lexer.nextSpace(); +console.log(spaceIndex); // 4 (position of space after 'enum') + +// If no space found, returns code length +lexer.load('enumStatus'); +const endIndex = lexer.nextSpace(); +console.log(endIndex); // 10 (length of code)`, + `import { Lexer } from '@stackpress/idea-parser'; +import { Compiler } from '@stackpress/idea-parser'; +import definitions, { data } from '@stackpress/idea-parser/definitions'; + +const lexer = new Lexer(); +Object.keys(definitions).forEach((key) => { + lexer.define(key, definitions[key]); +}); + +// Parse a simple object +lexer.load('{ foo "bar" bar 4.4 }'); +const objectToken = lexer.expect('Object'); +const compiled = Compiler.object(objectToken); +console.log(compiled); // { foo: 'bar', bar: 4.4 } + +// Parse nested objects +lexer.load('{ foo "bar" zoo { foo false bar null } }'); +const nestedToken = lexer.expect('Object'); +const nestedCompiled = Compiler.object(nestedToken); +console.log(nestedCompiled.zoo.foo); // false +console.log(nestedCompiled.zoo.bar); // null`, + `// Parse a simple array +lexer.load('[ 4.4 "bar" false null ]'); +const arrayToken = lexer.expect('Array'); +const compiledArray = Compiler.array(arrayToken); +console.log(compiledArray); // [4.4, 'bar', false, null] + +// Parse nested arrays +lexer.load('[ 4.4 "bar" [ 4 true ] ]'); +const nestedArrayToken = lexer.expect('Array'); +const nestedArray = Compiler.array(nestedArrayToken); +console.log(nestedArray[2]); // [4, true] + +// Parse array of objects +lexer.load('[ { label "US" value "United States" } { label "CA" value "Canada" } ]'); +const objectArrayToken = lexer.expect('Array'); +const objectArray = Compiler.array(objectArrayToken); +console.log(objectArray[0].label); // 'US' +console.log(objectArray[1].value); // 'Canada'`, + `// Parse block comments +lexer.load('/* some comment */'); +const noteToken = lexer.expect('note'); +console.log(noteToken.type); // '_Note' +console.log(noteToken.value); // '/* some comment */' + +// Parse line comments +lexer.load('//some comment'); +const commentToken = lexer.expect('comment'); +console.log(commentToken.type); // '_Comment' +console.log(commentToken.value); // '//some comment' + +// Parse multiline block comments +lexer.load("/* + some + // comment +*/"); +const multilineToken = lexer.expect('note'); +console.log(multilineToken.value); // Contains newlines and nested //`, + `const lexer = new Lexer(); + +// Throws: "Unknown definition unknownKey" +try { + lexer.expect('unknownKey'); +} catch (error) { + console.log(error.message); // "Unknown definition unknownKey" +} + +// Throws: "Unknown definition missingKey" +try { + lexer.match('some code', 0, ['missingKey']); +} catch (error) { + console.log(error.message); // "Unknown definition missingKey" +}`, + `import { Exception } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +lexer.define('String', definitions['String']); +lexer.load('42'); // Number, not string + +try { + lexer.expect('String'); // Expecting string but found number +} catch (error) { + if (error instanceof Exception) { + console.log(error.message); // "Unexpected 42 expecting String" + console.log(error.start); // Position where error occurred + console.log(error.end); // End position for error highlighting + } +}`, + `import { Lexer, EnumTree } from '@stackpress/idea-parser'; + +// AST classes configure lexers with appropriate definitions +const lexer = new Lexer(); +EnumTree.definitions(lexer); // Adds enum-specific token definitions + +lexer.load('enum Status { ACTIVE "Active" INACTIVE "Inactive" }'); + +const enumTree = new EnumTree(lexer); +const result = enumTree.enum(); // Parse enum using configured lexer`, + `// Save current state for potential backtracking +const checkpoint = lexer.clone(); + +try { + // Try to parse complex structure + const result = parseComplexStructure(lexer); + return result; +} catch (error) { + // Restore state and try alternative parsing + const restoredLexer = checkpoint; + return parseAlternativeStructure(restoredLexer); +}`, + `// Parse different types based on lookahead +if (lexer.next('AnyIdentifier')) { + const identifier = lexer.expect('AnyIdentifier'); + if (identifier.name === 'enum') { + // Parse enum declaration + } else if (identifier.name === 'model') { + // Parse model declaration + } +}`, + `import type { Reader } from '@stackpress/idea-parser'; + +const customReader: Reader = (code, start, lexer) => { + // Check if pattern matches at current position + if (!code.startsWith('custom', start)) { + return undefined; // No match + } + + // Calculate end position + const end = start + 6; + + // Return token object + return { + type: 'CustomToken', + value: 'custom', + start: start, + end: end + }; +}; + +// Register the custom reader +lexer.define('custom', customReader);` +] + +export function Body() { + return ( +
    +

    Lexer

    +

    The Lexer class implements the Parser interface and provides tokenization and parsing utilities for schema code. It manages a dictionary of token definitions and handles the parsing process by matching patterns against the input code.

    + + {examples[0]} + + +

    Properties

    +

    The following properties are available when instantiating a Lexer.

    + + + Property + Type + Description + + dictionary + Record‹string, Definition› Shallow copy of all token definitions + The current index position in the code + + + index + number + Current parsing position in the code + +
    + +

    Methods

    +

    The following methods are available when instantiating a Lexer.

    + +

    Cloning the Lexer

    +

    The following example shows how to create an exact copy of the lexer's current state.

    + + {examples[1]} + + + Returns +
  • A new Lexer instance with identical state to original
  • + +

    Defining Token Patterns

    +

    The following example shows how to register token definitions for parsing.

    + + {examples[2]} + + +

    Parameters

    + + Parameter + Type + Description + + key + string + Unique identifier for the token definition + + + reader + Reader + Function that attempts to match and parse the token + +
    + + Returns +
  • Void (modifies the lexer's internal dictionary).
  • + +

    Expecting Specific Tokens

    +

    The following example shows how to require specific tokens at the current position.

    + + {examples[3]} + + +

    Parameters

    + + Parameter + Type + Description + + keys + string | string[] + Token definition key(s) to expect + +
    + + Returns +
  • The matched token object, or throws an exception if no match is found.
  • + +

    Getting Token Definitions

    +

    The following example shows how to retrieve registered token definitions.

    + + {examples[4]} + + +

    Parameters

    + + Parameter + Type + Description + + key + string + The token definition key to retrieve + +
    + + Returns +
  • The Definition object if found, undefined otherwise.
  • + +

    Loading Code

    +

    The following example shows how to load code for parsing.

    + + {examples[5]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The source code to parse + + + index + number + Starting position in the code (default: 0) + +
    + + Returns +
  • The Lexer instance to allow method chaining.
  • + +

    Matching Tokens

    +

    The following example shows how to find the first matching token from available definitions.

    + + {examples[6]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + The code to match against + + + start + number + Starting position for matching + + + keys + string[] + Optional array of definition keys to try (default: all definitions) + +
    + + Returns +
  • The first matching token object, or null if no match is found.
  • + +

    Testing for Next Tokens

    +

    The following example shows how to check if the next tokens match without consuming them.

    + + {examples[7]} + + +

    Parameters

    + + Parameter + Type + Description + + names + string | string[] + Token definition key(s) to test for + +
    + + Returns +
  • true if the next token(s) match, false otherwise. Does not advance the index.
  • + +

    Optional Token Parsing

    +

    The following example shows how to optionally parse tokens without throwing errors.

    + + {examples[8]} + + +

    Parameters

    + + Parameter + Type + Description + + names + string | string[] + Token definition key(s) to try parsing + +
    + + Returns +
  • The matched token object if found, undefined otherwise.
  • + +

    Reading Ahead

    +

    The following example shows how to read the next available token.

    + + {examples[9]} + + + Returns +
  • The next available token object, or undefined if no token can be parsed.
  • + +

    Getting Substrings

    +

    The following example shows how to extract portions of the source code.

    + + {examples[10]} + + +

    Parameters

    + + Parameter + Type + Description + + start + number + Starting position in the code + + + end + number + Ending position in the code + +
    + + Returns +
  • The substring of code between start and end positions.
  • + +

    Finding Next Space

    +

    The following example shows how to find the next whitespace character (useful for error reporting).

    + + {examples[11]} + + + Returns +
  • The index of the next space character, or the code length if no space is found.
  • + +

    Parsing Complex Data Structures

    +

    The Lexer can parse complex nested data structures using the predefined token definitions:

    + +

    Parsing Objects

    + + {examples[12]} + + +

    Parsing Arrays

    + + {examples[13]} + + +

    Parsing Comments

    + + {examples[14]} + + +

    Error Handling

    +

    The Lexer provides detailed error information when parsing fails:

    + +

    Unknown Definitions

    + + {examples[15]} + + +

    Unexpected Tokens

    + + {examples[16]} + + +

    Predefined Token Definitions

    +

    The library comes with comprehensive predefined token definitions:

    + +

    Literals

    +
      +
    • Null: Matches null keyword
    • +
    • Boolean: Matches true and false
    • +
    • String: Matches quoted strings "hello"
    • +
    • Float: Matches decimal numbers 4.4, -3.14
    • +
    • Integer: Matches whole numbers 42, -10
    • +
    • Environment: Matches environment variables env("VAR_NAME")
    • +
    + +

    Identifiers

    +
      +
    • AnyIdentifier: Matches any valid identifier [a-z_][a-z0-9_]*
    • +
    • UpperIdentifier: Matches uppercase identifiers [A-Z_][A-Z0-9_]*
    • +
    • CapitalIdentifier: Matches capitalized identifiers [A-Z_][a-zA-Z0-9_]*
    • +
    • CamelIdentifier: Matches camelCase identifiers [a-z_][a-zA-Z0-9_]*
    • +
    • LowerIdentifier: Matches lowercase identifiers [a-z_][a-z0-9_]*
    • +
    • AttributeIdentifier: Matches attribute identifiers @field.input
    • +
    + +

    Structural

    +
      +
    • Array: Matches array expressions [ ... ]
    • +
    • Object: Matches object expressions { ... }
    • +
    • {, }, [, ], (, ): Bracket and brace tokens
    • +
    • !: Final modifier token
    • +
    + +

    Whitespace and Comments

    +
      +
    • whitespace: Matches any whitespace \s+
    • +
    • space: Matches spaces only
    • +
    • line: Matches line breaks
    • +
    • note: Matches block comments /* ... */
    • +
    • comment: Matches line comments // ...
    • +
    + +

    Data Groups

    +
      +
    • scalar: Array of scalar types ['Null', 'Boolean', 'String', 'Float', 'Integer', 'Environment']
    • +
    • data: Array of all data types [...scalar, 'Object', 'Array']
    • +
    + +

    Usage with AST

    +

    The Lexer is typically used by AST classes for parsing specific language constructs:

    + + {examples[17]} + + +

    Advanced Usage Patterns

    + +

    Backtracking with Clone

    + + {examples[18]} + + +

    Conditional Parsing

    + + {examples[19]} + + +

    Custom Reader Functions

    +

    Reader functions should follow this pattern:

    + + {examples[20]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} + + + + diff --git a/packages/www/plugins/docs/views/parser/pages/tokens.tsx b/packages/www/plugins/docs/views/parser/pages/tokens.tsx new file mode 100644 index 0000000..f6b1544 --- /dev/null +++ b/packages/www/plugins/docs/views/parser/pages/tokens.tsx @@ -0,0 +1,995 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; + import Code from '../../../components/Code.js'; + import Layout from '../../../components/Layout.js'; + import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Tokens'); + const description = _( + 'Token types define the Abstract Syntax Tree (AST) structures used by the idea parser to represent parsed schema code. These types form the foundation of the parsing system, providing type-safe representations of schema elements.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + +const examples = [ + `import type { + SchemaToken, + DeclarationToken, + IdentifierToken, + LiteralToken, + ObjectToken, + ArrayToken, + PropertyToken, + ImportToken +} from '@stackpress/idea-parser';`, + `const unknownToken: UnknownToken = { + type: 'CustomType', + start: 0, + end: 10, + value: 'some value', + raw: 'raw text' +};`, + `const identifierToken: IdentifierToken = { + type: 'Identifier', + name: 'UserRole', + start: 5, + end: 13 +};`, + `// From enum.json fixture +{ + "type": "Identifier", + "start": 5, + "end": 10, + "name": "Roles" +} + +// Property key identifier +{ + "type": "Identifier", + "start": 15, + "end": 20, + "name": "ADMIN" +}`, + `const stringLiteral: LiteralToken = { + type: 'Literal', + start: 21, + end: 28, + value: 'Admin', + raw: '"Admin"' +}; + +const numberLiteral: LiteralToken = { + type: 'Literal', + start: 10, + end: 12, + value: 42, + raw: '42' +};`, + `// From enum.json fixture +{ + "type": "Literal", + "start": 21, + "end": 28, + "value": "Admin", + "raw": "'Admin'" +}`, + `const objectToken: ObjectToken = { + type: 'ObjectExpression', + start: 0, + end: 64, + properties: [ + { + type: 'Property', + kind: 'init', + start: 15, + end: 28, + method: false, + shorthand: false, + computed: false, + key: { type: 'Identifier', name: 'ADMIN', start: 15, end: 20 }, + value: { type: 'Literal', value: 'Admin', start: 21, end: 28, raw: '"Admin"' } + } + ] +};`, + `const arrayToken: ArrayToken = { + type: 'ArrayExpression', + start: 0, + end: 25, + elements: [ + { type: 'Literal', value: 'item1', start: 2, end: 9, raw: '"item1"' }, + { type: 'Literal', value: 'item2', start: 11, end: 18, raw: '"item2"' } + ] +};`, + `const propertyToken: PropertyToken = { + type: 'Property', + kind: 'init', + start: 15, + end: 28, + method: false, + shorthand: false, + computed: false, + key: { + type: 'Identifier', + name: 'ADMIN', + start: 15, + end: 20 + }, + value: { + type: 'Literal', + value: 'Admin', + start: 21, + end: 28, + raw: '"Admin"' + } +};`, + `const enumDeclaration: DeclarationToken = { + type: 'VariableDeclaration', + kind: 'enum', + start: 0, + end: 64, + declarations: [{ + type: 'VariableDeclarator', + start: 5, + end: 64, + id: { + type: 'Identifier', + name: 'Roles', + start: 5, + end: 10 + }, + init: { + type: 'ObjectExpression', + start: 0, + end: 64, + properties: [/* property tokens */] + } + }] +};`, + `const declaratorToken: DeclaratorToken = { + type: 'VariableDeclarator', + start: 5, + end: 64, + id: { + type: 'Identifier', + name: 'Roles', + start: 5, + end: 10 + }, + init: { + type: 'ObjectExpression', + start: 0, + end: 64, + properties: [/* property tokens */] + } +};`, + `const importToken: ImportToken = { + type: 'ImportDeclaration', + start: 0, + end: 25, + specifiers: [], + source: { + type: 'Literal', + value: './shared/types.idea', + start: 4, + end: 25, + raw: '"./shared/types.idea"' + } +};`, + `const schemaToken: SchemaToken = { + type: 'Program', + kind: 'schema', + start: 0, + end: 150, + body: [ + // ImportTokens for use statements + { + type: 'ImportDeclaration', + start: 0, + end: 25, + specifiers: [], + source: { type: 'Literal', value: './types.idea', start: 4, end: 25, raw: '"./types.idea"' } + }, + // DeclarationTokens for enums, props, types, models, plugins + { + type: 'VariableDeclaration', + kind: 'enum', + start: 27, + end: 91, + declarations: [/* declarator */] + } + ] +};`, + `type Token = DataToken | UnknownToken;`, + `type DataToken = IdentifierToken | LiteralToken | ObjectToken | ArrayToken;`, + `type Reader = ( + code: string, + start: number, + lexer: Parser +) => Token | undefined;`, + `type Definition = { + key: string, + reader: Reader +};`, + `interface Parser { + get dictionary(): Record; + get index(): number; + clone(): Parser; + define(key: string, reader: Reader, type?: string): void; + expect(keys: string | string[]): T; + get(key: string): Definition | undefined; + load(code: string, index: number): this; + match(code: string, start: number, keys?: string[]): Token | null; + next(keys: string | string[]): boolean; + optional(keys: string | string[]): T | undefined; + read(): Token | undefined; +}`, + `type UseReferences = Record | false;`, + `type Scalar = string | number | null | boolean;`, + `type Data = Scalar | Data[] | { [key: string]: Data };`, + `import { EnumTree } from '@stackpress/idea-parser'; + +const enumCode = \`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`; + +// Parse generates a DeclarationToken +const enumToken = EnumTree.parse(enumCode); +console.log(enumToken.kind); // 'enum' +console.log(enumToken.declarations[0].id.name); // 'Roles'`, + `import { Compiler } from '@stackpress/idea-parser'; + +// Convert DeclarationToken to configuration +const [enumName, enumConfig] = Compiler.enum(enumToken); +console.log(enumName); // 'Roles' +console.log(enumConfig); // { ADMIN: 'Admin', MANAGER: 'Manager', USER: 'User' }`, + `// ObjectToken processing +const objectToken: ObjectToken = { + type: 'ObjectExpression', + start: 0, + end: 30, + properties: [ + { + type: 'Property', + kind: 'init', + start: 2, + end: 15, + method: false, + shorthand: false, + computed: false, + key: { type: 'Identifier', name: 'type', start: 2, end: 6 }, + value: { type: 'Literal', value: 'text', start: 7, end: 13, raw: '"text"' } + } + ] +}; + +const compiled = Compiler.object(objectToken); +console.log(compiled); // { type: 'text' }`, + `import { Exception } from '@stackpress/idea-parser'; + +try { + const invalidToken = { kind: 'invalid' } as DeclarationToken; + Compiler.enum(invalidToken); +} catch (error) { + if (error instanceof Exception) { + console.log('Token error:', error.message); // 'Invalid Enum' + } +}`, + `// Position information for error highlighting +const token: IdentifierToken = { + type: 'Identifier', + name: 'InvalidName', + start: 10, + end: 21 +}; + +// Can be used to highlight errors in editors +const errorRange = { start: token.start, end: token.end };` +] + + export function Body() { + return ( +
    +

    Tokens

    +

    Token types define the Abstract Syntax Tree (AST) structures used by the idea parser to represent parsed schema code. These types form the foundation of the parsing system, providing type-safe representations of schema elements.

    + + {examples[0]} + + +

    Core Token Types

    +

    The following types define the fundamental token structures used throughout the parsing system.

    + +

    UnknownToken

    +

    Base token structure for unrecognized or generic tokens during parsing.

    + + {examples[1]} + + +

    Properties

    + + Property + Type + Description + + type + string + Token type identifier + + + start + number + Starting character position in source code + + + end + number + Ending character position in source code + + + value + any + Parsed value of the token + + + raw + string + Raw text from source code + +
    + + Usage +

    Used as a fallback for tokens that don't match specific patterns and as a base structure for other token types.

    + +

    IdentifierToken

    +

    Represents identifiers such as variable names, type names, and property keys.

    + + {examples[2]} + + +

    Properties

    + + Property + Type + Description + + type + 'Identifier' + Always 'Identifier' for identifier tokens + + + name + string + The identifier name + + + start + number + Starting character position + + + end + number + Ending character position + +
    + + Usage +

    Used throughout the parser for:

    +
      +
    • Enum names: enum UserRole
    • +
    • Model names: model User
    • +
    • Property names: name String
    • +
    • Type references: role UserRole
    • +
    + + Examples from Tests + + {examples[3]} + + +

    LiteralToken

    +

    Represents literal values such as strings, numbers, booleans, and null.

    + + {examples[4]} + + +

    Properties

    + + Property + Type + Description + + type + 'Literal' + Always 'Literal' for literal tokens + + + start + number + Starting character position + + + end + number + Ending character position + + + value + any + The parsed literal value + + + raw + string + Raw text representation from source + +
    + + Usage +

    Used for all scalar values in schema definitions:

    +
      +
    • String literals: "Admin", "localhost"
    • +
    • Number literals: 5432, 3.14
    • +
    • Boolean literals: true, false
    • +
    • Null literals: null
    • +
    + + Examples from Tests + + {examples[5]} + + +

    ObjectToken

    +

    Represents object expressions containing key-value pairs.

    + + {examples[6]} + + +

    Properties

    + + Property + Type + Description + + type + 'ObjectExpression' + Always 'ObjectExpression' for object tokens + + + start + number + Starting character position + + + end + number + Ending character position + + + properties + PropertyToken[] + Array of property tokens + +
    + + Usage +

    Used for:

    +
      +
    • Enum definitions: { ADMIN "Admin", USER "User" }
    • +
    • Model column definitions: { id String @id, name String }
    • +
    • Plugin configurations: { provider "postgresql", url env("DATABASE_URL") }
    • +
    • Attribute parameters: @field.input({ type "text" })
    • +
    + + Examples from Tests +

    The enum fixture shows an ObjectToken containing three PropertyTokens for ADMIN, MANAGER, and USER enum values.

    + +

    ArrayToken

    +

    Represents array expressions containing ordered elements.

    + + {examples[7]} + + +

    Properties

    + + Property + Type + Description + + type + 'ArrayExpression' + Always 'ArrayExpression' for array tokens + + + start + number + Starting character position + + + end + number + Ending character position + + + elements + DataToken[] + Array of data tokens + +
    + + Usage +

    Used for:

    +
      +
    • Array type definitions: String[]
    • +
    • Plugin feature lists: previewFeatures ["fullTextSearch", "metrics"]
    • +
    • Attribute arrays: @is.oneOf(["admin", "user", "guest"])
    • +
    + +

    PropertyToken

    +

    Represents key-value pairs within object expressions.

    + + {examples[8]} + + +

    Properties

    + + Property + Type + Description + + type + 'Property' + Always 'Property' for property tokens + + + kind + 'init' + Always 'init' for initialization properties + + + start + number + Starting character position + + + end + number + Ending character position + + + method + boolean + Always false (not used for method properties) + + + shorthand + boolean + Always false (not used for shorthand properties) + + + computed + boolean + Always false (not used for computed properties) + + + key + IdentifierToken + Property key identifier + + + value + DataToken + Property value (literal, object, array, or identifier) + +
    + + Usage +

    Used within ObjectTokens for:

    +
      +
    • Enum key-value pairs: ADMIN "Admin"
    • +
    • Model column definitions: id String
    • +
    • Plugin configuration options: provider "postgresql"
    • +
    • Attribute parameters: type "text"
    • +
    + + Examples from Tests +

    From the enum fixture, each enum value is represented as a PropertyToken with an IdentifierToken key and LiteralToken value.

    + +

    Declaration Tokens

    +

    The following types represent top-level declarations in schema files.

    + +

    DeclarationToken

    +

    Represents variable declarations for enums, props, types, models, and plugins.

    + + {examples[9]} + + +

    Properties

    + + Property + Type + Description + + type + 'VariableDeclaration' + Always 'VariableDeclaration' for declarations + + + kind + string + Declaration type: 'enum', 'prop', 'type', 'model', 'plugin' + + + mutable + boolean + Optional mutability flag (for types and models) + + + start + number + Starting character position + + + end + number + Ending character position + + + declarations + [DeclaratorToken] + Array with single declarator token + +
    + + Usage +

    Used by all tree parsers (EnumTree, PropTree, TypeTree, ModelTree, PluginTree) to represent their respective declarations. The kind property determines how the Compiler processes the declaration.

    + + Examples from Tests +

    The enum fixture shows a complete DeclarationToken with kind 'enum' containing the Roles enum definition.

    + +

    DeclaratorToken

    +

    Represents the declarator part of a variable declaration, containing the identifier and initialization.

    + + {examples[10]} + + +

    Properties

    + + Property + Type + Description + + type + 'VariableDeclarator' + Always 'VariableDeclarator' for declarators + + + start + number + Starting character position + + + end + number + Ending character position + + + id + IdentifierToken + Declaration identifier (name) + + + init + ObjectToken + Initialization object containing the declaration body + +
    + + Usage +

    Used within DeclarationTokens to separate the declaration name from its body. The id contains the name (e.g., "Roles", "User") and init contains the definition object.

    + +

    ImportToken

    +

    Represents use statements for importing other schema files.

    + + {examples[11]} + + +

    Properties

    + + Property + Type + Description + + type + 'ImportDeclaration' + Always 'ImportDeclaration' for imports + + + start + number + Starting character position + + + end + number + Ending character position + + + specifiers + [] + Always empty array (not used for named imports) + + + source + LiteralToken + Source file path as literal token + +
    + + Usage +

    Used by UseTree to represent use "./path/to/file.idea" statements. The Compiler extracts the source path for dependency resolution.

    + +

    SchemaToken

    +

    Represents the complete parsed schema file containing all declarations and imports.

    + + {examples[12]} + + +

    Properties

    + + Property + Type + Description + + type + 'Program' + Always 'Program' for complete schemas + + + kind + 'schema' + Always 'schema' for schema files + + + start + number + Starting character position (usually 0) + + + end + number + Ending character position + + + body + (DeclarationToken|ImportToken)[] + Array of all declarations and imports + +
    + + Usage +

    Used by SchemaTree as the root token representing the entire parsed schema file. The Compiler processes the body array to generate the final schema configuration.

    + +

    U Types

    +

    The following types provide flexible token handling for different contexts.

    + +

    Token

    +

    Union type for all possible token types that can be returned by readers.

    + + {examples[13]} + + + Usage +

    Used as the return type for lexer operations and reader functions. Allows handling both recognized data tokens and unknown tokens.

    + +

    DataToken

    +

    Union type for tokens representing data values.

    + + {examples[14]} + + + Usage +

    Used throughout the Compiler for processing data values. These tokens can be converted to actual JavaScript values using Compiler.data().

    + +

    Parser Interface

    +

    The following types define the parser interface and reader functions.

    + +

    Reader

    +

    Function type for token readers that attempt to parse specific patterns.

    + + {examples[15]} + + +

    Parameters

    + + Parameter + Type + Description + + code + string + Source code being parsed + + + start + number + Starting position to attempt parsing + + + lexer + Parser + Parser instance for recursive parsing + +
    + + Returns +

    Token object if pattern matches, undefined otherwise.

    + + Usage +

    Used to define token recognition patterns in the definitions system. Each token type has a corresponding reader function.

    + +

    Definition

    +

    Pairs a token key with its reader function for lexer registration.

    + + {examples[16]} + + +

    Properties

    + + Property + Type + Description + + key + string + Unique identifier for the token type + + + reader + Reader + Function that attempts to parse the token + +
    + + Usage +

    Used by the Lexer to register and manage token definitions. The key identifies the token type, and the reader attempts to parse it.

    + +

    Parser

    +

    Interface defining the contract for parser implementations.

    + + {examples[17]} + + + Usage +

    Implemented by the Lexer class to provide consistent parsing operations across all tree parsers.

    + +

    Reference Types

    +

    The following types handle reference resolution and data processing.

    + +

    UseReferences

    +

    Type for managing prop and type references during compilation.

    + + {examples[18]} + + + Usage +

    Used by the Compiler to resolve identifier references:

    +
      +
    • false: Return template strings like ${PropName}
    • +
    • Record<string, any>: Resolve identifiers to actual values
    • +
    • Empty object {}: Throw error for unknown references
    • +
    + +

    Scalar

    +

    Union type for primitive values that can be stored in schema configurations.

    + + {examples[19]} + + + Usage +

    Used in enum configurations and other places where only primitive values are allowed.

    + +

    Data

    +

    Recursive type for nested data structures in schema configurations.

    + + {examples[20]} + + + Usage +

    Used throughout the system for representing complex nested data structures in plugin configurations, attributes, and other schema elements.

    + +

    Usage Examples

    + +

    Parsing and Token Generation

    + + {examples[21]} + + +

    Token Processing with Compiler

    + + {examples[22]} + + +

    Working with Complex Tokens

    + + {examples[23]} + + +

    Error Handling with Tokens

    + + {examples[24]} + + +

    Token Validation

    +

    Tokens include position information for error reporting and validation:

    + + {examples[25]} + + +

    Integration with AST

    +

    AST classes generate specific token types:

    +
      +
    • EnumTree: Generates DeclarationToken with kind: 'enum'
    • +
    • PropTree: Generates DeclarationToken with kind: 'prop'
    • +
    • TypeTree: Generates DeclarationToken with kind: 'type'
    • +
    • ModelTree: Generates DeclarationToken with kind: 'model'
    • +
    • PluginTree: Generates DeclarationToken with kind: 'plugin'
    • +
    • UseTree: Generates ImportToken
    • +
    • SchemaTree: Generates SchemaToken containing all other tokens
    • +
    + +

    Each AST class uses the Lexer to generate appropriate tokens, which are then processed by the Compiler to produce the final JSON configuration.

    + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } diff --git a/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx b/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx new file mode 100644 index 0000000..0b1a0d8 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx @@ -0,0 +1,218 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Advanced Tutorials'); + const description = _( + 'Advanced plugin development topics for developers who need to create sophisticated code generation tools' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Advanced Tutorials')} +
    + +
    + ); +} + +export function Body() { + return ( +
    +

    Advanced Tutorials

    +

    + This section covers advanced plugin development topics for developers who need to create sophisticated code generation tools. These tutorials demonstrate complex patterns and integration techniques for building enterprise-grade plugins. +

    + +

    7.1. API Development Plugins

    + +

    7.1.1. GraphQL Schema Plugin

    +

    + The GraphQL Schema Plugin tutorial teaches you how to create a plugin that generates GraphQL type definitions and schemas from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate GraphQL type definitions from models and types
    • +
    • Create queries, mutations, and subscriptions
    • +
    • Support for custom scalars and directives
    • +
    • Handle relationships and nested types
    • +
    • Generate complete GraphQL schema files
    • +
    + +

    + Generated Output: GraphQL schema files with type definitions, queries, and mutations +

    + +

    7.1.2. TypeScript Interface Plugin

    +

    + The TypeScript Interface Plugin tutorial demonstrates how to create a plugin that generates TypeScript interfaces and types from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate TypeScript interfaces from models and types
    • +
    • Create enums and utility types
    • +
    • Support for namespaces and modules
    • +
    • Handle optional and array types
    • +
    • Generate comprehensive type definitions
    • +
    + +

    + Generated Output: TypeScript definition files with interfaces, types, and enums +

    + +

    7.1.3. API Client Plugin

    +

    + The API Client Plugin tutorial shows how to create a plugin that generates API client libraries from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate REST and GraphQL API clients
    • +
    • Support multiple authentication strategies
    • +
    • Create type-safe client methods
    • +
    • Handle request/response transformations
    • +
    • Generate both JavaScript and TypeScript clients
    • +
    + +

    + Generated Output: Complete API client libraries with methods and types +

    + +

    7.2. Validation and Testing Plugins

    +

    + Validation and testing plugins help ensure data quality and application reliability by generating validation schemas and test data. These plugins are essential for building robust applications that can handle edge cases and maintain data integrity across different environments. +

    + +

    7.2.1. Validation Plugin

    +

    + The Validation Plugin tutorial teaches you how to create a plugin that generates Zod validation schemas from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate Zod schemas from models and types
    • +
    • Create custom validators and transformations
    • +
    • Handle complex validation rules
    • +
    • Support for nested object validation
    • +
    • Generate comprehensive validation suites
    • +
    + +

    + Generated Output: Zod validation schemas with custom validators +

    + +

    7.2.2. Test Data Plugin

    +

    + The Test Data Plugin tutorial demonstrates how to create a plugin that generates realistic test data and fixtures from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate realistic mock data using Faker.js
    • +
    • Create factory functions for dynamic data generation
    • +
    • Support for relationships and constraints
    • +
    • Generate test fixtures and seed data
    • +
    • Handle localization and custom generators
    • +
    + +

    + Generated Output: Test data files, factories, and fixtures in multiple formats +

    + +

    7.3. Documentation and Specification Plugins

    +

    + The OpenAPI Specification Plugin tutorial shows how to create a plugin that generates OpenAPI 3.0 specifications from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate OpenAPI 3.0 compliant specifications
    • +
    • Create schemas and CRUD endpoints automatically
    • +
    • Support multiple authentication schemes
    • +
    • Generate multiple output formats (JSON, YAML, HTML)
    • +
    • Include validation rules and examples
    • +
    + +

    + Generated Output: Complete OpenAPI specifications with interactive documentation +

    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx b/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx new file mode 100644 index 0000000..f742f10 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx @@ -0,0 +1,167 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Available Tutorials'); + const description = _( + 'Comprehensive tutorials for creating specific types of plugins with step-by-step instructions and complete code examples' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Available Tutorials')} +
    + +
    + ); + } + +export function Body() { + return ( +
    +

    Available Tutorials

    +

    + This section provides links to comprehensive tutorials for creating specific types of plugins. Each tutorial includes step-by-step instructions, complete code examples, and explanations of key concepts for building production-ready plugins. +

    + +

    6.1. Meta Coding With TSMorph

    +

    + The TSMorph Plugin Guide demonstrates how to create powerful code generation plugins using ts-morph, a TypeScript library that provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code. This guide is essential for developers who need to generate complex TypeScript code with proper syntax and formatting. +

    + +

    6.2. Database Integration Plugins

    +

    + The MySQL Tables Plugin tutorial teaches you how to create a plugin that generates MySQL CREATE TABLE statements from your schema. +

    + +

    + Learn how to create a plugin that generates MySQL CREATE TABLE statements from your schema. +

    + +

    What you'll learn:

    +
      +
    • Parse schema models and their columns
    • +
    • Map schema types to MySQL data types
    • +
    • Generate SQL DDL statements with constraints
    • +
    • Handle primary keys, foreign keys, and indexes
    • +
    • Implement proper error handling and validation
    • +
    + +

    + Generated Output: SQL files that can be executed to create database tables +

    + +

    6.3. Frontend Development Plugins

    +

    + The HTML Form Plugin tutorial demonstrates how to create a plugin that generates responsive HTML forms from your schema. +

    + +

    + Learn how to create a plugin that generates responsive HTML forms from your schema. +

    + +

    What you'll learn:

    +
      +
    • Generate HTML form elements based on field types
    • +
    • Support multiple CSS frameworks (Bootstrap, Tailwind, Custom)
    • +
    • Include client-side validation and constraints
    • +
    • Handle different form layouts and themes
    • +
    • Create accessible, responsive forms
    • +
    + +

    + Generated Output: Complete HTML files with forms, styling, and JavaScript validation +

    + +

    6.4. Documentation Generation Plugins

    +

    + The Markdown Documentation Plugin tutorial shows how to create a plugin that generates comprehensive markdown documentation from your schema. +

    + +

    + Learn how to create a plugin that generates comprehensive markdown documentation from your schema. +

    + +

    What you'll learn:

    +
      +
    • Parse all schema elements (models, types, enums, props)
    • +
    • Generate structured documentation with navigation
    • +
    • Include examples and cross-references
    • +
    • Support multiple documentation formats and templates
    • +
    • Create both single-file and multi-file documentation
    • +
    + +

    + Generated Output: Markdown documentation files with complete schema reference +

    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/best-practices.tsx b/packages/www/plugins/docs/views/plugin-development/best-practices.tsx new file mode 100644 index 0000000..7fa7cee --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/best-practices.tsx @@ -0,0 +1,192 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Essential best practices for plugin development covering type safety, configuration validation, file operations, and CLI integration' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const typeSafetyExample = [ + `// Always use proper typing for plugin props +import type { PluginProps, PluginWithCLIProps } from '@stackpress/idea-transformer/types'; + +// Define custom config types +interface MyPluginConfig { + output: string; + format: 'typescript' | 'javascript'; + strict?: boolean; +} + +// Use typed props +export default async function typedPlugin( + props: PluginProps<{ config: MyPluginConfig }> +) { + const { config } = props; + + // TypeScript will enforce config structure + const output: string = config.output; // ✅ Type-safe + const format: 'typescript' | 'javascript' = config.format; // ✅ Type-safe + const strict: boolean = config.strict ?? false; // ✅ Type-safe with default +}` +]; + +const configurationValidationExample = [ + `function validateConfig(config: any): asserts config is MyPluginConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('Plugin requires "output" configuration as string'); + } + + if (!config.format || !['typescript', 'javascript'].includes(config.format)) { + throw new Error('Plugin requires "format" to be "typescript" or "javascript"'); + } +} + +export default async function validatedPlugin(props: PluginProps<{}>) { + validateConfig(props.config); + + // Now config is properly typed + const { output, format } = props.config; +}` +]; + +const fileOperationsExample = [ + `// Use transformer's file loader for consistent path resolution +export default async function filePlugin(props: PluginProps<{}>) { + const { config, transformer } = props; + + // ✅ Use transformer.loader for path resolution + const outputPath = await transformer.loader.absolute(config.output); + + // ✅ Create directories if needed + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + + // ✅ Write file with proper error handling + try { + await fs.writeFile(outputPath, content, 'utf8'); + } catch (error) { + throw new Error(\`Failed to write output file: \${error.message}\`); + } +}` +]; + +const cliIntegrationExample = [ + `// Use CLI props when available +export default async function adaptivePlugin(props: PluginWithCLIProps) { + const { cli, config } = props; + + // Adapt behavior based on CLI context + const outputDir = config.outputDir || path.join(cli.cwd, 'generated'); + const verbose = config.verbose || false; + + if (verbose) { + console.log(\`Generating files in: \${outputDir}\`); + console.log(\`Working directory: \${cli.cwd}\`); + console.log(\`File extension: \${cli.extname}\`); + } + + // Use CLI working directory for relative paths + const absoluteOutputDir = path.resolve(cli.cwd, outputDir); + + // Generate files... +}` +]; + +export function Body() { + return ( +
    +

    Best Practices

    +

    + This section outlines essential best practices for plugin development, covering type safety, configuration validation, file operations, and CLI integration. Following these practices ensures that plugins are reliable, maintainable, and provide excellent developer experiences. +

    + +

    5.1. Type Safety

    +

    + Type safety is crucial for creating reliable plugins that catch errors at compile time rather than runtime. This section demonstrates how to use TypeScript effectively in plugin development, including proper typing for configuration objects and plugin properties. +

    + + + {typeSafetyExample[0]} + + +

    5.2. Configuration Validation

    +

    + Configuration validation ensures that plugins receive valid configuration options and fail early with clear error messages when configuration is invalid. This approach prevents runtime errors and provides better debugging experiences for plugin users. +

    + + + {configurationValidationExample[0]} + + +

    5.3. File Operations

    +

    + File operations in plugins should follow consistent patterns for path resolution, directory creation, and error handling. This section demonstrates best practices for working with files and directories in a way that's compatible with the idea transformer system. +

    + + + {fileOperationsExample[0]} + + +

    5.4. CLI Integration

    +

    + CLI integration enables plugins to provide rich command-line experiences by adapting behavior based on the execution context. This section shows how to use CLI properties effectively and create plugins that work well in both programmatic and interactive environments. +

    + + + {cliIntegrationExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/error-handling.tsx b/packages/www/plugins/docs/views/plugin-development/error-handling.tsx new file mode 100644 index 0000000..3f13558 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/error-handling.tsx @@ -0,0 +1,151 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Error Handling'); + const description = _( + 'Proper error handling is essential for creating robust plugins that provide clear feedback when issues occur' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const pluginErrorHandlingExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; + +export default async function safePlugin(props: PluginProps<{}>) { + const { config, schema, transformer } = props; + + try { + // Validate required configuration + if (!config.output) { + throw new Error('Missing required "output" configuration'); + } + + // Validate schema has required elements + if (!schema.model || Object.keys(schema.model).length === 0) { + throw new Error('Schema must contain at least one model'); + } + + // Process schema + const content = await processSchema(schema); + + // Write output + const outputPath = await transformer.loader.absolute(config.output); + await writeOutput(outputPath, content); + + console.log(\`✅ Plugin completed successfully: \${outputPath}\`); + + } catch (error) { + console.error(\`❌ Plugin failed:\`, error.message); + throw error; // Re-throw to stop transformation + } +}` +]; + +const gracefulErrorRecoveryExample = [ + `export default async function resilientPlugin(props: PluginProps<{}>) { + const { config, schema, transformer } = props; + + const warnings: string[] = []; + + try { + // Attempt primary functionality + await primaryGeneration(schema, config); + } catch (error) { + warnings.push(\`Primary generation failed: \${error.message}\`); + + // Fallback to basic generation + try { + await fallbackGeneration(schema, config); + warnings.push('Used fallback generation'); + } catch (fallbackError) { + throw new Error(\`Both primary and fallback generation failed: \${fallbackError.message}\`); + } + } + + // Report warnings + if (warnings.length > 0) { + console.warn('Plugin completed with warnings:'); + warnings.forEach(warning => console.warn(\` ⚠️ \${warning}\`)); + } +}` +]; + +export function Body() { + return ( +
    +

    Error Handling

    +

    + Proper error handling is essential for creating robust plugins that provide clear feedback when issues occur. This section covers error handling strategies, validation patterns, and techniques for graceful failure recovery in plugin development. +

    + +

    4.1. Plugin Error Handling

    +

    + Plugin error handling demonstrates how to implement comprehensive error checking and reporting in plugins. This approach ensures that plugins fail gracefully with meaningful error messages, helping users quickly identify and resolve configuration or schema issues. +

    + + + {pluginErrorHandlingExample[0]} + + +

    4.2. Graceful Error Recovery

    +

    + Graceful error recovery shows how plugins can implement fallback mechanisms and continue operation even when primary functionality fails. This approach improves plugin reliability and provides better user experiences by attempting alternative approaches when errors occur. +

    + + + {gracefulErrorRecoveryExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/getting-started.tsx b/packages/www/plugins/docs/views/plugin-development/getting-started.tsx new file mode 100644 index 0000000..6ff4898 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/getting-started.tsx @@ -0,0 +1,424 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Getting Started'); + const description = _( + 'Essential information for developers who are new to plugin development with prerequisites, basic concepts, and step-by-step guidance' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + + +const commonPluginStructureExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface MyPluginConfig { + output: string; + // ... other configuration options +} + +export default async function myPlugin( + props: PluginProps<{ config: MyPluginConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // 1. Validate configuration + if (!config.output) { + throw new Error('Plugin requires "output" configuration'); + } + + // 2. Process schema + const content = processSchema(schema); + + // 3. Write output + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ Generated: \${outputPath}\`); +}` +]; + +const schemaStructureExample = [ + `{ + model: { + [modelName]: { + mutable: boolean, + columns: [ + { + name: string, + type: string, + required: boolean, + multiple: boolean, + attributes: object + } + ] + } + }, + enum: { + [enumName]: { + [key]: value + } + }, + type: { + [typeName]: { + mutable: boolean, + columns: [...] + } + }, + prop: { + [propName]: { + // Property configuration + } + } +}` +]; + +const typeSafetyExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; + +interface MyPluginConfig { + output: string; + format?: 'json' | 'yaml'; +} + +export default async function myPlugin( + props: PluginProps<{ config: MyPluginConfig }> +) { + // TypeScript will enforce the config structure +}` +]; + +const configurationValidationExample = [ + `function validateConfig(config: any): void { + if (!config.output) { + throw new Error('Plugin requires "output" configuration'); + } + + if (config.format && !['json', 'yaml'].includes(config.format)) { + throw new Error(\`Unsupported format: \${config.format}\`); + } +}` +]; + +const fileOperationsExample = [ + `// ✅ Good - uses transformer's file loader +const outputPath = await transformer.loader.absolute(config.output); + +// ✅ Good - creates directories if needed +await fs.mkdir(path.dirname(outputPath), { recursive: true }); + +// ✅ Good - proper error handling +try { + await fs.writeFile(outputPath, content, 'utf8'); +} catch (error) { + throw new Error(\`Failed to write file: \${error.message}\`); +}` +]; + +const errorHandlingExample = [ + `export default async function myPlugin(props: PluginProps<{}>) { + try { + // Validate configuration + validateConfig(props.config); + + // Check for required schema elements + if (!props.schema.model || Object.keys(props.schema.model).length === 0) { + console.warn('⚠️ No models found in schema. Skipping generation.'); + return; + } + + // Process and generate + // ... + + console.log('✅ Plugin completed successfully'); + + } catch (error) { + console.error(\`❌ Plugin failed: \${error.message}\`); + throw error; + } +}` +]; + +const schemaProcessingExample = [ + `// ✅ Good - checks for existence before processing +if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + // Process model + } +} + +// ✅ Good - provides defaults for optional attributes +const attributes = column.attributes || {}; +const label = attributes.label || column.name; +const description = attributes.description || '';` +]; + +const usageInSchemaFilesExample = [ + `// schema.idea +plugin "./plugins/mysql-tables-plugin.js" { + output "./database/tables.sql" + database "my_app" + engine "InnoDB" +} + +plugin "./plugins/html-form-plugin.js" { + output "./forms/user-form.html" + title "User Registration" + theme "bootstrap" +} + +plugin "./plugins/markdown-docs-plugin.js" { + output "./docs/schema.md" + title "API Documentation" + format "single" + includeExamples true +} + +model User { + id String @id @default("nanoid()") + email String @unique @field.input(Email) + name String @field.input(Text) + role UserRole @default("USER") + active Boolean @default(true) + created Date @default("now()") +} + +enum UserRole { + ADMIN "Administrator" + USER "Regular User" +}` +]; + +export function Body() { + return ( +
    +

    Getting Started

    +

    + This section provides essential information for developers who are new to plugin development. It covers prerequisites, basic concepts, and step-by-step guidance for creating your first plugin. +

    + +

    8.1. Prerequisites

    +

    + Before starting plugin development, ensure you have the necessary knowledge and tools. These prerequisites will help you understand the examples and successfully implement your own plugins. +

    + +

    + Before starting these tutorials, make sure you have: +

    + +
      +
    • Basic understanding of TypeScript/JavaScript
    • +
    • Familiarity with the idea-transformer plugin system
    • +
    • Understanding of the target technology (MySQL, HTML/CSS, Markdown)
    • +
    + +

    8.2. Plugin Development Basics

    +

    + Plugin development follows consistent patterns that make it easy to create new plugins once you understand the core concepts. This section outlines the fundamental steps and patterns used across all plugin types. +

    + +

    + All plugins in the idea-transformer system follow a similar pattern: +

    + +
      +
    1. Import Types: Use the provided TypeScript types for type safety
    2. +
    3. Define Configuration: Specify what configuration options your plugin accepts
    4. +
    5. Validate Input: Check that required configuration is provided
    6. +
    7. Process Schema: Parse the schema and extract relevant information
    8. +
    9. Generate Output: Create the target files or content
    10. +
    11. Handle Errors: Provide meaningful error messages and graceful failure
    12. +
    + +

    8.3. Common Plugin Structure

    +

    + The common plugin structure provides a template that can be adapted for any type of code generation. This structure ensures consistency across plugins and includes all essential components for robust plugin development. +

    + + + {commonPluginStructureExample[0]} + + +

    8.4. Schema Structure

    +

    + Understanding the schema structure is crucial for plugin development. The processed schema provides a standardized format that plugins can rely on, regardless of the original .idea file structure. +

    + +

    + All plugins receive a processed schema with this structure: +

    + + + {schemaStructureExample[0]} + + +

    8.5. Implementation Guidelines

    +

    + These implementation guidelines help ensure that your plugins are reliable, maintainable, and follow established patterns. Following these guidelines will make your plugins easier to debug and extend. +

    + +

    8.5.1. Type Safety

    +

    + Type safety prevents runtime errors and provides better development experiences through IDE support and compile-time error checking. +

    + +

    + Always use the provided TypeScript types: +

    + + + {typeSafetyExample[0]} + + +

    8.5.2. Configuration Validation

    +

    + Configuration validation ensures that plugins receive valid input and fail early with clear error messages when configuration is incorrect. +

    + +

    + Validate all required configuration upfront: +

    + + + {configurationValidationExample[0]} + + +

    8.5.3. File Operations

    +

    + File operations should follow consistent patterns for path resolution, directory creation, and error handling to ensure compatibility with the idea transformer system. +

    + +

    + Use the transformer's file loader for consistent path resolution: +

    + + + {fileOperationsExample[0]} + + +

    8.5.4. Error Handling

    +

    + Comprehensive error handling provides better user experiences and makes plugins more reliable in production environments. +

    + +

    + Provide meaningful error messages and handle edge cases: +

    + + + {errorHandlingExample[0]} + + +

    8.5.5. Schema Processing

    +

    + Schema processing should handle optional elements gracefully and provide meaningful defaults to ensure plugins work with various schema configurations. +

    + +

    + Handle optional schema elements gracefully: +

    + + + {schemaProcessingExample[0]} + + +

    8.6. Usage in Schema Files

    +

    + This section demonstrates how to use plugins within .idea schema files, showing the declarative syntax for plugin configuration and how multiple plugins can work together to generate comprehensive outputs. +

    + +

    + To use any of these plugins in your schema file: +

    + + + {usageInSchemaFilesExample[0]} + + +

    8.7. Next Steps

    +

    + After completing the getting started section, you'll be ready to dive into specific tutorials and start building your own plugins. These next steps will guide you toward becoming proficient in plugin development. +

    + +
      +
    1. Choose a Tutorial: Start with the tutorial that matches your immediate needs
    2. +
    3. Follow Along: Each tutorial provides step-by-step instructions with complete code examples
    4. +
    5. Customize: Adapt the examples to your specific requirements
    6. +
    7. Extend: Use the patterns learned to create your own custom plugins
    8. +
    + +

    8.8. Additional Plugin Ideas

    +

    + Beyond the provided tutorials, there are many other types of plugins you can create using the patterns and techniques covered in this documentation: +

    + +
      +
    • Database Migration Generator: Create migration files for various databases
    • +
    • Form Validation Generator: Generate client-side validation rules
    • +
    • Mock Server Generator: Create mock API servers for testing
    • +
    • Documentation Site Generator: Build complete documentation websites
    • +
    • Configuration File Generator: Generate app configuration files
    • +
    • Seed Data Generator: Create database seed scripts
    • +
    • API Test Generator: Generate automated API test suites
    • +
    + +

    + Happy coding! 🚀 +

    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx new file mode 100644 index 0000000..c9717c5 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx @@ -0,0 +1,125 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Configuration'); + const description = _( + 'Plugin configuration enables developers to customize plugin behavior through schema declarations' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const schemaPluginDefinitionExample = [ + `// schema.idea +plugin "./plugins/my-plugin.js" { + output "./generated/output.ts" + format "typescript" + options { + strict true + comments true + } +}` +]; + +const pluginConfigurationAccessExample = [ + `export default async function myPlugin(props: PluginProps<{}>) { + const { config } = props; + + // Access top-level config + const output = config.output; + const format = config.format; + + // Access nested options + const options = config.options || {}; + const strict = options.strict || false; + const comments = options.comments || false; + + // Use configuration in plugin logic + if (strict) { + // Enable strict mode + } + + if (comments) { + // Add comments to generated code + } +}` +]; + +export function Body() { + return ( +
    +

    Plugin Configuration

    +

    + Plugin configuration enables developers to customize plugin behavior through schema declarations. This section covers how to define configuration options in schema files, access configuration within plugins, and implement flexible plugin behavior based on user preferences. +

    + +

    3.1. Schema Plugin Definition

    +

    + Schema plugin definitions specify how plugins are declared and configured within .idea schema files. This declarative approach allows users to configure multiple plugins with different settings while maintaining clean, readable schema files. +

    + + + {schemaPluginDefinitionExample[0]} + + +

    3.2. Plugin Configuration Access

    +

    + Plugin configuration access demonstrates how plugins can read and utilize configuration options provided in schema files. This section shows how to access both simple and nested configuration values, provide defaults, and implement conditional behavior based on configuration settings. +

    + + + {pluginConfigurationAccessExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx new file mode 100644 index 0000000..390a315 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx @@ -0,0 +1,279 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Development Guide'); + const description = _( + 'Comprehensive guide covering everything from basic plugin structure to advanced development patterns for the idea ecosystem' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const basicPluginExample = [ + `import type { PluginWithCLIProps } from '@stackpress/idea'; + +export default function generate(props: PluginWithCLIProps) {}` +]; + +const basicPluginStructureExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +export default async function myPlugin(props: PluginProps<{}>) { + const { config, schema, transformer, cwd } = props; + + // 1. Validate configuration + if (!config.output) { + throw new Error('Plugin requires "output" configuration'); + } + + // 2. Process schema + const content = processSchema(schema); + + // 3. Resolve output path + const outputPath = await transformer.loader.absolute(config.output); + + // 4. Write output + await fs.writeFile(outputPath, content, 'utf8'); +} + +function processSchema(schema: SchemaConfig): string { + // Implementation for processing schema + return '// Generated content'; +}` +]; + +const cliPluginExample = [ + `import type { PluginWithCLIProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; + +export default async function cliPlugin(props: PluginWithCLIProps) { + const { config, schema, transformer, cwd, cli } = props; + + // Access CLI properties + const workingDir = cli.cwd; + const fileExtension = cli.extname; + + // Use CLI for logging or user interaction + console.log(\`Processing schema in: \${workingDir}\`); + + // Process based on CLI context + if (config.interactive) { + // Interactive mode logic + console.log('Running in interactive mode...'); + } + + // Generate output + const content = generateContent(schema, { workingDir, fileExtension }); + + // Write to file + const outputPath = path.resolve(workingDir, config.output); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`Generated: \${outputPath}\`); +}` +]; + +const customPluginPropsExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; + +// Define custom props +interface CustomProps { + timestamp: string; + version: string; + debug: boolean; +} + +// Use custom props in plugin +export default async function customPlugin(props: PluginProps) { + const { config, schema, transformer, cwd, timestamp, version, debug } = props; + + if (debug) { + console.log(\`Plugin executed at \${timestamp} for version \${version}\`); + } + + // Plugin implementation +} + +// Usage with transformer +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform({ + timestamp: new Date().toISOString(), + version: '1.0.0', + debug: true +});` +]; + +export function Body() { + return ( +
    +

    Idea Plugins

    +

    + The following documentation explains how to develop plugins for .idea files. This comprehensive guide covers everything from basic plugin structure to advanced development patterns, providing developers with the knowledge needed to create powerful code generation plugins for the idea ecosystem. +

    + +

    1. Plugin Development Guide

    +

    + This section covers the fundamental concepts and structures needed to create effective plugins for the idea ecosystem. Plugins are JavaScript or TypeScript modules that process schema definitions and generate various outputs like code, documentation, or configuration files. +

    + +

    + Creating a plugin involves just exporting a function like the example below: +

    + + + {basicPluginExample[0]} + + +

    1.1. Basic Plugin Structure

    +

    + The basic plugin structure provides the foundation for all idea plugins. This structure ensures consistency across plugins and provides access to essential functionality like schema processing, file operations, and configuration management. +

    + + + {basicPluginStructureExample[0]} + + +

    Properties

    +

    + The PluginProps contains the following properties. +

    + + + Property + Type + Description + + config + PluginConfig + Plugin-specific configuration from the schema + + + schema + SchemaConfig + Complete processed schema configuration + + + transformer + Transformer<{}> + The transformer instance executing the plugin + + + cwd + string + Current working directory for file operations + +
    + +

    1.2. CLI-Aware Plugin Structure

    +

    + CLI-aware plugins extend the basic plugin structure to include command-line interface capabilities. These plugins can interact with the terminal, access CLI-specific properties, and provide enhanced user experiences through interactive features and detailed logging. +

    + + + {cliPluginExample[0]} + + +

    Properties

    +

    + The PluginWithCLIProps contains the following properties. +

    + + + Property + Type + Description + + config + PluginConfig + Plugin-specific configuration from the schema + + + schema + SchemaConfig + Complete processed schema configuration + + + transformer + Transformer<{}> + The transformer instance executing the plugin + + + cwd + string + Current working directory for file operations + + + cli + Terminal + Terminal instance for CLI interactions + +
    + +

    1.3. Custom Plugin Props

    +

    + Custom plugin props allow developers to extend the base plugin functionality with additional properties and configuration options. This feature enables plugins to receive custom data, maintain state, and implement specialized behaviors beyond the standard plugin interface. +

    + +

    + You can extend the base plugin props with custom properties: +

    + + + {customPluginPropsExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx new file mode 100644 index 0000000..4604410 --- /dev/null +++ b/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx @@ -0,0 +1,266 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Examples'); + const description = _( + 'Practical examples of common plugin implementations demonstrating real-world patterns and best practices' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const typescriptInterfaceGeneratorExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface TypeGenConfig { + output: string; + namespace?: string; + exportType?: 'named' | 'default'; +} + +export default async function generateInterfaces( + props: PluginProps<{ config: TypeGenConfig }> +) { + const { config, schema, transformer, cwd } = props; + + let content = ''; + + // Add namespace if specified + if (config.namespace) { + content += \`export namespace \${config.namespace} {\\n\`; + } + + // Generate interfaces from models + if (schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + content += generateInterface(name, model); + } + } + + // Generate types from type definitions + if (schema.type) { + for (const [name, type] of Object.entries(schema.type)) { + content += generateType(name, type); + } + } + + // Close namespace + if (config.namespace) { + content += '}\\n'; + } + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.writeFile(outputPath, content, 'utf8'); +} + +function generateInterface(name: string, model: any): string { + let content = \`export interface \${name} {\\n\`; + + for (const column of model.columns || []) { + const optional = column.required ? '' : '?'; + const type = mapToTypeScript(column.type); + content += \` \${column.name}\${optional}: \${type};\\n\`; + } + + content += '}\\n\\n'; + return content; +} + +function generateType(name: string, type: any): string { + // Implementation for generating TypeScript types + return \`export type \${name} = any; // TODO: Implement\\n\\n\`; +} + +function mapToTypeScript(schemaType: string): string { + const typeMap: Record = { + 'String': 'string', + 'Number': 'number', + 'Boolean': 'boolean', + 'Date': 'Date', + 'JSON': 'any' + }; + + return typeMap[schemaType] || 'any'; +}` +]; + +const enumGeneratorExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; + +export default async function generateEnums(props: PluginProps<{}>) { + const { config, schema, transformer } = props; + + if (!schema.enum) { + console.log('No enums found in schema'); + return; + } + + let content = '// Generated Enums\\n\\n'; + + for (const [name, enumDef] of Object.entries(schema.enum)) { + content += \`export enum \${name} {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key} = "\${value}",\\n\`; + } + + content += '}\\n\\n'; + } + + const outputPath = await transformer.loader.absolute(config.output); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`Generated enums: \${outputPath}\`); +}` +]; + +const cliInteractivePluginExample = [ + `import type { PluginWithCLIProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +export default async function interactiveGenerator(props: PluginWithCLIProps) { + const { config, schema, transformer, cli } = props; + + // Use CLI for interactive prompts + console.log(\`\\n🚀 Interactive Generator\`); + console.log(\`Working Directory: \${cli.cwd}\`); + console.log(\`Schema Extension: \${cli.extname}\`); + + // Process based on available schema elements + const hasModels = schema.model && Object.keys(schema.model).length > 0; + const hasEnums = schema.enum && Object.keys(schema.enum).length > 0; + const hasTypes = schema.type && Object.keys(schema.type).length > 0; + + console.log(\`\\n📊 Schema Summary:\`); + console.log(\` Models: \${hasModels ? Object.keys(schema.model!).length : 0}\`); + console.log(\` Enums: \${hasEnums ? Object.keys(schema.enum!).length : 0}\`); + console.log(\` Types: \${hasTypes ? Object.keys(schema.type!).length : 0}\`); + + // Generate based on configuration + const outputs: string[] = []; + + if (config.generateModels && hasModels) { + const modelContent = generateModels(schema.model!); + const modelPath = path.resolve(cli.cwd, 'generated/models.ts'); + await fs.mkdir(path.dirname(modelPath), { recursive: true }); + await fs.writeFile(modelPath, modelContent, 'utf8'); + outputs.push(modelPath); + } + + if (config.generateEnums && hasEnums) { + const enumContent = generateEnums(schema.enum!); + const enumPath = path.resolve(cli.cwd, 'generated/enums.ts'); + await fs.mkdir(path.dirname(enumPath), { recursive: true }); + await fs.writeFile(enumPath, enumContent, 'utf8'); + outputs.push(enumPath); + } + + // Report results + console.log(\`\\n✅ Generated \${outputs.length} files:\`); + outputs.forEach(file => console.log(\` 📄 \${file}\`)); +} + +function generateModels(models: Record): string { + // Implementation for generating models + return '// Generated models\\n'; +} + +function generateEnums(enums: Record): string { + // Implementation for generating enums + return '// Generated enums\\n'; +}` +]; + +export function Body() { + return ( +
    +

    Plugin Examples

    +

    + This section provides practical examples of common plugin implementations. These examples demonstrate real-world patterns and best practices for creating plugins that generate TypeScript interfaces, enums, and interactive CLI tools. +

    + +

    2.1. TypeScript Interface Generator

    +

    + The TypeScript interface generator demonstrates how to create a plugin that processes schema models and types to generate TypeScript interface definitions. This example shows how to handle type mapping, optional properties, and namespace organization. +

    + + + {typescriptInterfaceGeneratorExample[0]} + + +

    2.2. Enum Generator

    +

    + The enum generator plugin shows how to process schema enum definitions and convert them into TypeScript enum declarations. This example demonstrates simple schema processing and file generation patterns that can be adapted for other output formats. +

    + + + {enumGeneratorExample[0]} + + +

    2.3. CLI-Interactive Plugin

    +

    + The CLI-interactive plugin demonstrates how to create plugins that provide rich command-line experiences. This example shows how to use the CLI properties for user interaction, progress reporting, and adaptive behavior based on the execution context. +

    + + + {cliInteractivePluginExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/specifications/best-practices.tsx b/packages/www/plugins/docs/views/specifications/best-practices.tsx new file mode 100644 index 0000000..db9bd54 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/best-practices.tsx @@ -0,0 +1,260 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Best practices for using the .idea file format to generate various outputs like TypeScript interfaces, database schemas, API documentation, and more.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const bestPractices = [ + `// ✅ Good +enum UserAccountStatus { + ACTIVE "Active Account" + SUSPENDED "Temporarily Suspended" + DEACTIVATED "Permanently Deactivated" +} + +// ❌ Avoid +enum Status { + A "Active" + S "Suspended" + D "Deactivated" +}`, + `// User-related enums +enum UserRole { /* ... */ } +enum UserStatus { /* ... */ } + +// User-related types +type UserProfile { /* ... */ } +type UserPreferences { /* ... */ } + +// User-related models +model User { /* ... */ } +model UserSession { /* ... */ }`, + `// Models: PascalCase +model UserAccount { /* ... */ } + +// Enums: PascalCase +enum OrderStatus { /* ... */ } + +// Props: PascalCase +prop EmailInput { /* ... */ } + +// Columns: camelCase +model User { + firstName String + lastName String + emailAddress String +}`, + `type Money { + amount Number @required @min(0) + currency String @default("USD") +} + +type Coordinates { + latitude Number @required @min(-90) @max(90) + longitude Number @required @min(-180) @max(180) +} + +model Product { + price Money @required + location Coordinates? +}`, + `// ✅ Good - type-safe and self-documenting +enum Priority { + LOW "Low Priority" + MEDIUM "Medium Priority" + HIGH "High Priority" + URGENT "Urgent" +} + +model Task { + priority Priority @default("MEDIUM") +} + +// ❌ Avoid - error-prone and unclear +model Task { + priority String @default("medium") +}`, + `model User { + email String @required @unique @pattern("^[^\s@]+@[^\s@]+\.[^\s@]+$") + age Number @min(13) @max(120) + username String @required @minLength(3) @maxLength(30) @pattern("^[a-zA-Z0-9_]+$") + bio String @maxLength(500) + tags String[] @maxItems(10) +}`, + `model User { + role UserRole @default("USER") + active Boolean @default(true) + emailVerified Boolean @default(false) + created Date @default("now()") + updated Date @default("updated()") + preferences { + theme String @default("light") + language String @default("en") + notifications Boolean @default(true) + } +}`, + `// One-to-many relationship +model User { + id String @id + posts Post[] @relation(Post.authorId) +} + +model Post { + id String @id + authorId String @relation(User.id) + author User @relation(User, authorId) +} + +// Many-to-many relationship +model Post { + id String @id + tags Tag[] @relation(PostTag.postId) +} + +model Tag { + id String @id + posts Post[] @relation(PostTag.tagId) +} + +model PostTag { + postId String @relation(Post.id) + tagId String @relation(Tag.id) +}`, + `// Type generation +plugin "./plugins/typescript-generator.js" { + output "./src/types/schema.ts" + namespace "Schema" +} + +// Database schema +plugin "./plugins/database-generator.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +// API documentation +plugin "./plugins/openapi-generator.js" { + output "./docs/api.yaml" + version "1.0.0" +} + +// Form generation +plugin "./plugins/form-generator.js" { + output "./src/components/forms/" + framework "react" + styling "tailwind" +}` +] + +export function Body() { + return ( +
    +

    Best Practices

    +

    1. Schema Organization

    +

    Use Descriptive Names

    + + {bestPractices[0]} + + +

    Group Related Elements

    + + {bestPractices[1]} + + +

    Use Consistent Naming Conventions

    + + {bestPractices[2]} + + +

    2. Type Safety

    +

    Define Custom Types for Complex Data

    + + {bestPractices[3]} + + +

    Use Enums for Fixed Sets of Values

    + + {bestPractices[4]} + + +

    3. Validation and Constraints

    +

    Use Appropriate Validation Attributes

    + + {bestPractices[5]} + + +

    Provide Meaningful Defaults

    + + {bestPractices[6]} + + +

    4. Relationships

    +

    Use Clear Relationship Patterns

    + + {bestPractices[7]} + + +

    5. Plugin Configuration

    +

    Organize Plugins by Purpose

    + + {bestPractices[8]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/complete-examples.tsx b/packages/www/plugins/docs/views/specifications/complete-examples.tsx new file mode 100644 index 0000000..2cc69f3 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/complete-examples.tsx @@ -0,0 +1,375 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useState } from 'react'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Complete Examples'); + const description = _( + 'Complete examples of how to use the .idea file format to generate various outputs like TypeScript interfaces, database schemas, API documentation, and more.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + const ecommerceSchema = `// E-commerce application schema +plugin "./plugins/generate-types.js" { + output "./src/types/schema.ts" +} + +plugin "./plugins/generate-database.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +plugin "./plugins/generate-api-docs.js" { + output "./docs/api.yaml" + format "openapi" +} + +// Reusable props +prop Email { + type "email" + validation { + required true + format "email" + } + ui { + placeholder "Enter email address" + icon "envelope" + } +} + +prop Currency { + type "number" + format "currency" + validation { + min 0 + precision 2 + } + ui { + symbol "$" + locale "en-US" + } +} + +prop Text { + type "text" + validation { + maxLength 255 + } +} + +// Enums +enum UserRole { + ADMIN "Administrator" + CUSTOMER "Customer" + VENDOR "Vendor" +} + +enum OrderStatus { + PENDING "Pending" + CONFIRMED "Confirmed" + SHIPPED "Shipped" + DELIVERED "Delivered" + CANCELLED "Cancelled" +} + +enum PaymentStatus { + PENDING "Pending" + COMPLETED "Completed" + FAILED "Failed" + REFUNDED "Refunded" +} + +// Types +type Address { + street String @required @field.input(Text) + city String @required @field.input(Text) + state String @required @field.select + postalCode String @required @field.input(Text) + country String @default("US") @field.select +} + +type Money { + amount Number @required @field.input(Currency) + currency String @default("USD") +} + +// Models +model User! { + id String @id @default("nanoid()") + email String @unique @required @field.input(Email) + username String @unique @required @field.input(Text) + firstName String @required @field.input(Text) + lastName String @required @field.input(Text) + role UserRole @default("CUSTOMER") + addresses Address[] @relation(UserAddress.userId) + orders Order[] @relation(Order.userId) + active Boolean @default(true) + emailVerified Boolean @default(false) + created Date @default("now()") + updated Date @default("updated()") +} + +model Category { + id String @id @default("nanoid()") + name String @unique @required @field.input(Text) + slug String @unique @generated + description String @field.textarea + parentId String? @relation(Category.id) + parent Category? @relation(Category, parentId) + children Category[] @relation(Category.parentId) + products Product[] @relation(Product.categoryId) + active Boolean @default(true) + created Date @default("now()") +} + +model Product! { + id String @id @default("nanoid()") + name String @required @field.input(Text) + slug String @unique @generated + description String @field.richtext + shortDescription String @field.textarea + sku String @unique @required @field.input(Text) + price Money @required + comparePrice Money? + cost Money? + categoryId String @relation(Category.id) + category Category @relation(Category, categoryId) + images String[] @field.upload + inventory { + quantity Number @default(0) + trackQuantity Boolean @default(true) + allowBackorder Boolean @default(false) + } + seo { + title String @field.input(Text) + description String @field.textarea + keywords String[] @field.tags + } + active Boolean @default(true) + featured Boolean @default(false) + created Date @default("now()") + updated Date @default("updated()") +} + +model Order { + id String @id @default("nanoid()") + orderNumber String @unique @generated + userId String @relation(User.id) + user User @relation(User, userId) + items OrderItem[] @relation(OrderItem.orderId) + status OrderStatus @default("PENDING") + paymentStatus PaymentStatus @default("PENDING") + shippingAddress Address @required + billingAddress Address @required + subtotal Money @required + tax Money @required + shipping Money @required + total Money @required + notes String? @field.textarea + created Date @default("now()") + updated Date @default("updated()") +} + +model OrderItem { + id String @id @default("nanoid()") + orderId String @relation(Order.id) + order Order @relation(Order, orderId) + productId String @relation(Product.id) + product Product @relation(Product, productId) + quantity Number @required @min(1) + price Money @required + total Money @required +}` + +const blogSchema = `// Blog application schema +plugin "./plugins/generate-types.js" { + output "./src/types/blog.ts" +} + +plugin "./plugins/generate-forms.js" { + output "./src/components/forms/" + framework "react" +} + +// Props +prop RichText { + type "richtext" + validation { + required true + minLength 100 + } + ui { + toolbar ["bold", "italic", "link", "image"] + placeholder "Write your content here..." + } +} + +prop Slug { + type "text" + validation { + pattern "^[a-z0-9-]+$" + maxLength 100 + } + ui { + placeholder "url-friendly-slug" + } +} + +// Enums +enum PostStatus { + DRAFT "Draft" + PUBLISHED "Published" + ARCHIVED "Archived" +} + +enum CommentStatus { + PENDING "Pending Moderation" + APPROVED "Approved" + REJECTED "Rejected" +} + +// Models +model Author! { + id String @id @default("nanoid()") + email String @unique @required @field.input(Email) + name String @required @field.input(Text) + bio String @field.textarea + avatar String @field.upload + social { + twitter String? @field.input(Text) + github String? @field.input(Text) + website String? @field.input(URL) + } + posts Post[] @relation(Post.authorId) + active Boolean @default(true) + created Date @default("now()") +} + +model Category { + id String @id @default("nanoid()") + name String @unique @required @field.input(Text) + slug String @unique @field.input(Slug) + description String @field.textarea + color String @field.color + posts Post[] @relation(PostCategory.categoryId) + created Date @default("now()") +} + +model Tag { + id String @id @default("nanoid()") + name String @unique @required @field.input(Text) + slug String @unique @field.input(Slug) + posts Post[] @relation(PostTag.tagId) + created Date @default("now()") +} + +model Post! { + id String @id @default("nanoid()") + title String @required @field.input(Text) + slug String @unique @field.input(Slug) + excerpt String @field.textarea + content String @required @field.input(RichText) + featuredImage String @field.upload + authorId String @relation(Author.id) + author Author @relation(Author, authorId) + categories Category[] @relation(PostCategory.postId) + tags Tag[] @relation(PostTag.postId) + status PostStatus @default("DRAFT") + publishedAt Date? @field.datetime + seo { + title String @field.input(Text) + description String @field.textarea + keywords String[] @field.tags + } + stats { + views Number @default(0) + likes Number @default(0) + shares Number @default(0) + } + comments Comment[] @relation(Comment.postId) + created Date @default("now()") + updated Date @default("updated()") +} + +model Comment { + id String @id @default("nanoid()") + postId String @relation(Post.id) + post Post @relation(Post, postId) + authorName String @required @field.input(Text) + authorEmail String @required @field.input(Email) + content String @required @field.textarea + status CommentStatus @default("PENDING") + parentId String? @relation(Comment.id) + parent Comment? @relation(Comment, parentId) + replies Comment[] @relation(Comment.parentId) + created Date @default("now()") +}` + + export function Body() { + return ( +
    +

    Complete Examples

    +

    E-commerce Application Schema

    + + {ecommerceSchema} + + +

    Blog Application Schema

    + + {blogSchema} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx new file mode 100644 index 0000000..aede100 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx @@ -0,0 +1,84 @@ +import { H1, H2, P, SS } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const enumsExamples = [ + `enum EnumName { + KEY1 "Display Value 1" + KEY2 "Display Value 2" + KEY3 "Display Value 3" +}`, + `enum UserRole { + ADMIN "Administrator" + MODERATOR "Moderator" + USER "Regular User" + GUEST "Guest User" +} + +enum OrderStatus { + PENDING "Pending Payment" + PAID "Payment Confirmed" + SHIPPED "Order Shipped" + DELIVERED "Order Delivered" + CANCELLED "Order Cancelled" +} + +enum Priority { + LOW "Low Priority" + MEDIUM "Medium Priority" + HIGH "High Priority" + URGENT "Urgent" +}`, + `export enum UserRole { + ADMIN = "Administrator", + MODERATOR = "Moderator", + USER = "Regular User", + GUEST = "Guest User" +}`, + `{ + "enum": { + "UserRole": { + "ADMIN": "Administrator", + "MODERATOR": "Moderator", + "USER": "Regular User", + "GUEST": "Guest User" + } + } +}` +] + +export default function Enums() { + return ( +
    +

    Enums

    +

    Enums define a set of named constants with associated values, perfect for representing fixed sets of options like user roles, status values, or categories.

    +

    Syntax

    + + {enumsExamples[0]} + + +

    Structure

    +
      +
    • EnumName: The identifier used to reference this enum
    • +
    • KEY: The constant name (typically uppercase)
    • +
    • "Display Value": Human-readable label for the constant
    • +
    + +

    Example

    + + {enumsExamples[1]} + + +

    Generate Output

    +

    When processed, enums generate language-specific constants:

    + TypeScript: + + {enumsExamples[2]} + + + JSON: + + {enumsExamples[3]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx new file mode 100644 index 0000000..f4ad4e0 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx @@ -0,0 +1,117 @@ +import { H1, H2, P, SS, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const modelsExamples = [ + `model ModelName { + columnName DataType @attribute1 @attribute2 + relationColumn RelatedModel @relation +} + +model ModelName! { // Mutable model + // columns... +}`, +`// base-schema.idea +model User { + id String @id + name String @required +} + +// extended-schema.idea +use "./base-schema.idea" + +// This will merge with the imported User model +model User { + email String @required + created Date @default("now()") +} + +// This will NOT merge - it completely replaces the imported User +model User! { + id String @id + username String @required + password String @required +}`, +`model User! { + id String @id @default("nanoid()") + email String @unique @required @field.input(Email) + username String @unique @required @field.input(Text) + password String @required @field.input(Password) + profile UserProfile? + role UserRole @default("USER") + active Boolean @default(true) + lastLogin Date? + created Date @default("now()") + updated Date @default("updated()") +} + +model UserProfile { + id String @id @default("nanoid()") + userId String @relation(User.id) + firstName String @required @field.input(Text) + lastName String @required @field.input(Text) + bio String @field.textarea + avatar String @field.upload + address Address + contact ContactInfo + preferences { + theme String @default("light") + language String @default("en") + notifications Boolean @default(true) + } +} + +model Post { + id String @id @default("nanoid()") + title String @required @field.input(Text) + slug String @unique @generated + content String @required @field.richtext + excerpt String @field.textarea + authorId String @relation(User.id) + author User @relation(User, authorId) + status PostStatus @default("DRAFT") + tags String[] @field.tags + publishedAt Date? + created Date @default("now()") + updated Date @default("updated()") +} + +enum PostStatus { + DRAFT "Draft" + PUBLISHED "Published" + ARCHIVED "Archived" +}` + +] + +export default function Models() { + return ( +
    +

    Models

    +

    Models represent the core entities in your application, typically corresponding to database tables or API resources. They define the structure, relationships, and behavior of your data.

    +

    Syntax

    + + {modelsExamples[0]} + + +

    Structure

    +
      +
    • ModelName: The identifier for this model
    • +
    • !: Optional non-mergeable indicator (prevents automatic merging when using use directives)
    • +
    • columnName: The field name within the model
    • +
    • DataType: Built-in types (String, Number, Boolean, Date) or custom types/enums
    • +
    • @attribute: Attributes for validation, relationships, UI, etc.
    • +
    + +

    Merging Behavior

    +

    By default, when importing schemas with use directives, models with the same name are automatically merged. The ! suffix prevents this behavior:

    + + {modelsExamples[1]} + + +

    Example

    + + {modelsExamples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx new file mode 100644 index 0000000..05fd4f7 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx @@ -0,0 +1,87 @@ +import { H1, H2, P, SS, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const propsExamples = [ + `prop PropName { + property "value" + nested { + property "value" + } +}`, +`prop Email { + type "email" + format "email" + validation { + required true + pattern "^[^\s@]+@[^\s@]+\.[^\s@]+$" + } + ui { + component "EmailInput" + placeholder "Enter your email address" + icon "envelope" + } +} + +prop Password { + type "password" + validation { + required true + minLength 8 + pattern "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]" + } + ui { + component "PasswordInput" + placeholder "Enter a secure password" + showStrength true + } +} + +prop Currency { + type "number" + format "currency" + validation { + min 0 + precision 2 + } + ui { + component "CurrencyInput" + symbol "$" + locale "en-US" + } +}`, +`model User { + email String @field.input(Email) + password String @field.input(Password) +}` +] + +export default function Props() { + return ( +
    +

    Props

    +

    Props are reusable property configurations that define common field behaviors, validation rules, and UI components. They promote consistency and reduce duplication across your schema.

    +

    Syntax

    + + {propsExamples[0]} + + +

    Structure

    +
      +
    • PropName: The identifier used to reference this prop
    • +
    • property: Configuration key-value pairs
    • +
    • nested: A nested prop
    • +
    + +

    Example

    + + {propsExamples[1]} + + + Usage in Models +

    Props are referenced using the @field attribute:

    + + {propsExamples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx new file mode 100644 index 0000000..41579ed --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx @@ -0,0 +1,75 @@ +import { H1, H2, P, SS} from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const typeExamples = [ + `type TypeName { + columnName DataType @attribute1 @attribute2 + anotherColumn DataType @attribute +}`, +`type Address { + street String @required @field.input(Text) + city String @required @field.input(Text) + state String @field.select + postalCode String @field.input(Text) + country String @default("US") @field.select + coordinates { + latitude Number @field.input(Number) + longitude Number @field.input(Number) + } +} + +type ContactInfo { + email String @required @field.input(Email) + phone String @field.input(Phone) + website String @field.input(URL) + socialMedia { + twitter String @field.input(Text) + linkedin String @field.input(Text) + github String @field.input(Text) + } +} + +type Money { + amount Number @required @field.input(Currency) + currency String @default("USD") @field.select + exchangeRate Number @field.input(Number) +}`, +`model Company { + name String @required + address Address @required + contact ContactInfo + revenue Money +}` +] + +export default function Type() { + return ( +
    +

    Type

    +

    Types define custom data structures with multiple columns, similar to objects or structs in programming languages. They're perfect for representing complex data that doesn't warrant a full model.

    +

    Syntax

    + + {typeExamples[0]} + + +

    Structure

    +
      +
    • TypeName: The identifier used to reference this type
    • +
    • columnName: The field name within the type
    • +
    • DataType: The data type (String, Number, Boolean, Date, etc.)
    • +
    • attribute1: Optional attributes for validation, UI, or behavior
    • +
    + +

    Example

    + + {typeExamples[1]} + + + Usage in Models +

    Types are used as column data types:

    + + {typeExamples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx b/packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx new file mode 100644 index 0000000..0458494 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx @@ -0,0 +1,216 @@ +import { H1, H2, P, SS, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const pluginExamples = [ + `plugin "path/to/plugin.js" { + configKey "configValue" + nestedConfig { + option "value" + flag true + } +}`, + `// TypeScript interface generation +plugin "./plugins/typescript-generator.js" { + output "./src/types/schema.ts" + namespace "Schema" + exportType "named" + includeComments true + formatting { + indent 2 + semicolons true + trailingCommas true + } +} + +// Database schema generation +plugin "./plugins/database-generator.js" { + output "./database/schema.sql" + dialect "postgresql" + includeIndexes true + includeForeignKeys true + tablePrefix "app_" + options { + dropExisting false + addTimestamps true + charset "utf8mb4" + } +} + +// API documentation generation +plugin "./plugins/openapi-generator.js" { + output "./docs/api.yaml" + version "1.0.0" + title "My API Documentation" + description "Comprehensive API documentation generated from schema" + servers [ + { + url "https://api.example.com/v1" + description "Production server" + } + { + url "https://staging-api.example.com/v1" + description "Staging server" + } + ] + security { + type "bearer" + scheme "JWT" + } +} + +// Form generation +plugin "./plugins/form-generator.js" { + output "./src/components/forms/" + framework "react" + styling "tailwind" + validation "zod" + features { + typescript true + storybook true + tests true + } + components { + inputWrapper "FormField" + submitButton "SubmitButton" + errorMessage "ErrorText" + } +}`, + `plugin "./plugins/my-plugin.js" { + // Output configuration + output "./generated/output.ts" + outputDir "./generated/" + + // Format and style options + format "typescript" // or "javascript", "json", "yaml" + style "camelCase" // or "snake_case", "kebab-case" + + // Feature flags + includeComments true + generateTests false + addValidation true + + // Framework-specific options + framework "react" // or "vue", "angular", "svelte" + styling "tailwind" // or "bootstrap", "material", "custom" + + // Advanced configuration + templates { + model "./templates/model.hbs" + enum "./templates/enum.hbs" + } + + // Custom options (plugin-specific) + customOptions { + apiVersion "v1" + includeMetadata true + compressionLevel 9 + } +}`, + `// Generate TypeScript types +plugin "./plugins/typescript.js" { + output "./src/types/index.ts" +} + +// Generate database schema +plugin "./plugins/database.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +// Generate API documentation +plugin "./plugins/docs.js" { + output "./docs/api.md" + format "markdown" +} + +// Generate form components +plugin "./plugins/forms.js" { + output "./src/forms/" + framework "react" +} + +// Generate validation schemas +plugin "./plugins/validation.js" { + output "./src/validation/index.ts" + library "zod" +}`, +`// Example plugin structure +import type { PluginProps } from '@stackpress/idea-transformer/types'; + +interface MyPluginConfig { + output: string; + format?: 'typescript' | 'javascript'; + includeComments?: boolean; +} + +export default async function myPlugin( + props: PluginProps<{ config: MyPluginConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // Validate configuration + if (!config.output) { + throw new Error('Output path is required'); + } + + // Process schema + const content = generateContent(schema, config); + + // Write output + const outputPath = await transformer.loader.absolute(config.output); + await writeFile(outputPath, content); + + console.log(\`✅ Generated: \${outputPath}\`); +}` +] + +export default function Plugin() { + return ( +
    +

    Plugin

    +

    + The plugin directive configures code generation plugins that process your schema and generate various outputs like TypeScript interfaces, database schemas, API documentation, and more. +

    +

    Syntax

    + + {pluginExamples[0]} + + +

    Structure

    +
      +
    • Path: Relative or absolute path to the plugin file
    • +
    • Configuration Block: Key-value pairs that configure the plugin behavior
    • +
    • Nested Configuration: Support for complex configuration structures
    • +
    + +

    Example

    + + {pluginExamples[1]} + + +

    Plugin Configuration Options

    +

    + Common configuration patterns across different plugin types: +

    + + {pluginExamples[2]} + + +

    Multiple Plugins Execution

    +

    + You can configure multiple plugins to generate different outputs from the same schema: +

    + + {pluginExamples[3]} + + +

    Plugin Development

    +

    + Plugins are JavaScript/TypeScript modules that export a default function: +

    + + {pluginExamples[4]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx b/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx new file mode 100644 index 0000000..f2f2805 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx @@ -0,0 +1,143 @@ +import { H1, H2, P, SS, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const useExamples = [ + `use "package/to/schema.idea" +use "./relative/path/schema.idea" +use "../parent/directory/schema.idea"`, + `// Common types used across multiple schemas +type Address { + street String @required + city String @required + country String @default("US") +} + +enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +} + +prop Email { + type "email" + validation { + required true + format "email" + } +}`, + `// Import common definitions +use "../shared/common.idea" + +// Extend the Status enum (will merge with imported one) +enum Status { + PENDING "Pending Approval" + SUSPENDED "Temporarily Suspended" +} + +// Use imported types and props +model User { + id String @id @default("nanoid()") + email String @field.input(Email) + address Address + status Status @default("PENDING") +}`, + `// The Status enum now contains all values +enum Status { + ACTIVE "Active" // From common.idea + INACTIVE "Inactive" // From common.idea + PENDING "Pending Approval" // From user-schema.idea + SUSPENDED "Temporarily Suspended" // From user-schema.idea +}`, +`enum UserRole { + USER "Regular User" + ADMIN "Administrator" +}`, +`use "./base-schema.idea" + +// This will NOT merge with the imported UserRole +// Instead, it will override it completely +enum UserRole! { + GUEST "Guest User" + MEMBER "Member" + MODERATOR "Moderator" + ADMIN "Administrator" +}`, +`// ✅ Good - organize by domain +use "./shared/common-types.idea" +use "./auth/user-types.idea" +use "./commerce/product-types.idea" + +// ✅ Good - clear file naming +use "./enums/status-enums.idea" +use "./types/address-types.idea" +use "./props/form-props.idea" + +// ❌ Avoid - unclear imports +use "./stuff.idea" +use "./misc.idea"` +] + +export default function Use() { + return ( +
    +

    Use

    +

    + The use directive imports definitions from other .idea files, enabling modular schema organization and reusability. When importing, data types with the same name are automatically merged unless the ! (non-mergeable) indicator is used. +

    +

    Syntax

    + + {useExamples[0]} + + +

    Structure

    +
      +
    • Path: Relative or absolute path to the .idea file to import
    • +
    • Automatic Merging: Data types with matching names are merged by default
    • +
    • Merge Prevention: Use ! suffix to prevent merging
    • +
    + +

    Example

    +

    shared/common.idea

    + + {useExamples[1]} + + +

    user/user-schema.idea:

    + + {useExamples[2]} + + +

    Result after merging:

    + + {useExamples[3]} + + + Prevent merging with ! +

    + When you want to prevent automatic merging and keep definitions separate, use the ! suffix: +

    + + base-schema.idea: + + {useExamples[4]} + + + extended-schema.idea: + + {useExamples[5]} + + +

    Use Cases

    +
      +
    • Shared Types: Define common types once and reuse across multiple schemas
    • +
    • Modular Organization: Split large schemas into manageable, focused files
    • +
    • Team Collaboration: Different teams can work on separate schema files
    • +
    • Environment-Specific: Override certain definitions for different environments
    • +
    + +

    Best Practices

    + + {useExamples[6]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/data-types.tsx b/packages/www/plugins/docs/views/specifications/data-types.tsx new file mode 100644 index 0000000..77aab05 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/data-types.tsx @@ -0,0 +1,108 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, P, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Models from './components/data-types/Models.js'; +import Type from './components/data-types/Type.js'; +import Props from './components/data-types/Props.js'; +import Enums from './components/data-types/Enums.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Data Types'); + const description = _( + 'The .idea format supports four primary data types that form the building blocks of your application schema.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + return ( +
    +

    Data Types

    +

    The .idea format supports four primary data types that form the building blocks of your application schema.

    + + +
    + +
    + +
    + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/error-handling.tsx b/packages/www/plugins/docs/views/specifications/error-handling.tsx new file mode 100644 index 0000000..d28088c --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/error-handling.tsx @@ -0,0 +1,254 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Error Handling'); + const description = _( + 'Error handling is a crucial aspect of any application. The .idea file format provides a way to handle errors in a structured way.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const errors = [ + `// ❌ Invalid - missing quotes around enum values +enum Status { + ACTIVE Active + INACTIVE Inactive +} + +// ✅ Valid - proper enum syntax +enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +}`, + `// ❌ Invalid - empty model +model User { +} + +// ✅ Valid - model with columns +model User { + id String @id + name String @required +}`, + `// ❌ Invalid - duplicate model names +model User { + id String @id +} + +model User { // Duplicate! + name String +} + +// ✅ Valid - unique names +model User { + id String @id +} + +model UserProfile { + name String +}`, + `// ❌ Invalid - EmailInput prop not defined +model User { + email String @field.input(EmailInput) +} + +// ✅ Valid - define prop first +prop EmailInput { + type "email" + validation { required true } +} + +model User { + email String @field.input(EmailInput) +}`, + `// ❌ Invalid - Boolean can't have @minLength +model User { + active Boolean @minLength(5) +} + +// ✅ Valid - appropriate attributes for type +model User { + active Boolean @default(true) + name String @minLength(2) @maxLength(50) +}` + +] + +const errorPrevention = [ + `import type { PluginProps, SchemaConfig } from '@stackpress/idea-transformer/types'; + +export default async function myPlugin(props: PluginProps<{}>) { + // TypeScript will catch type errors at compile time + const { config, schema } = props; + + // Validate configuration + if (!config.output) { + throw new Error('Output path is required'); + } + + // Process schema safely + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + // Process each model + } + } +}`, +`// Always validate required fields +model User { + id String @id @required + email String @required @unique + name String @required +} + +// Use appropriate data types +model Product { + price Number @min(0) // Not String + active Boolean // Not Number + created Date @default("now()") // Not String +}`, +`// Consistent ID patterns +model User { + id String @id @default("nanoid()") +} + +model Post { + id String @id @default("nanoid()") +} + +// Consistent timestamp patterns +model User { + created Date @default("now()") + updated Date @default("updated()") +}`, +`# Parse schema to check for errors +npm run idea:parse schema.idea + +# Transform schema to validate plugins +npm run idea:transform schema.idea + +# Generate output to verify results +npm run idea:generate` +] + +export function Body() { + return ( +
    +

    Error Handling

    +

    Common Errors and Solutions

    +

    1. Invalid Schema Structure

    +

    Error: Invalid Schema

    +

    Cause: Syntax errors or malformed declarations

    +

    Solution:

    + + {errors[0]} + + +

    2. Missing Required Properties

    +

    Error: Expecting a columns property

    +

    Cause: Models and types must have column definitions

    +

    Solution:

    + + {errors[1]} + + +

    3. Duplicate Declarations

    +

    Error: Duplicate [name]

    +

    Cause: Models and types must have column definitions

    +

    Solution: Multiple declarations with the same name

    + + {errors[2]} + + + +

    4. Unknown References

    +

    Error: Unknown reference [name]

    +

    Cause: Referencing undefined props, types, or enums

    +

    Solution:

    + + {errors[3]} + + +

    5. Type Mismatches

    +

    Error: Type mismatch

    +

    Cause: Using incompatible types or attributes

    +

    Solution:

    + + {errors[4]} + + +

    Error Prevention

    +

    1. Use TypeScript for Plugin Development

    + + {errorPrevention[0]} + + +

    2. Validate Schema Before Processing

    + + {errorPrevention[1]} + + +

    3. Use Consistent Patterns

    + + {errorPrevention[2]} + + +

    4. Test Schema Changes

    + + {errorPrevention[3]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/plugin-system.tsx b/packages/www/plugins/docs/views/specifications/plugin-system.tsx new file mode 100644 index 0000000..beb0d2d --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/plugin-system.tsx @@ -0,0 +1,142 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin System'); + const description = _( + 'The plugin system enables extensible code generation from your schema definitions.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + const pluginDeclaration = [ + `plugin "./path/to/plugin.js" { + output "./generated/output.ts" + format "typescript" + options { + strict true + comments true + } +}`, +`import type { PluginProps } from '@stackpress/idea-transformer/types'; + +export default async function myPlugin(props: PluginProps<{}>) { + const { config, schema, transformer } = props; + + // Process schema and generate output + const content = generateFromSchema(schema); + + // Write to configured output path + const outputPath = await transformer.loader.absolute(config.output); + await writeFile(outputPath, content); +}` + ] + + export function Body() { + return ( +
    +

    Plugin System

    +

    The plugin system enables extensible code generation from your schema definitions.

    + +

    Plugin Declaration

    + + {pluginDeclaration[0]} + + +

    Common Plugin Types

    + + Plugin Type + Purpose + Output + + TypeScript Generator + Generate interfaces and types + .ts files + + + Database Schema + Generate SQL DDL + .sql files + + + API Documentation + Generate OpenAPI Specs + .json/.yaml files + + + Form Generator + Generate HTML Forms + .html files + + + Validation Schema + Generate Zod/Joi schemas + .ts files + + + Mock Data + Generate test fixtures + .json files + +
    + +

    Plugin Development

    + + + {pluginDeclaration[1]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/specifications/processing-flow.tsx b/packages/www/plugins/docs/views/specifications/processing-flow.tsx new file mode 100644 index 0000000..32b2a76 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/processing-flow.tsx @@ -0,0 +1,105 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useState } from 'react'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, P, C, H, Nav, SS } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Processing Flow'); + const description = _( + 'The .idea file format follows a structured processing flow:' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + export function Body() { + return ( +
    +

    Processing Flow

    +

    The .idea file format follows a structured processing flow:

    + + {`┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ .idea File │───▶│ Parser │───▶│ AST (JSON) │ +│ │ │ │ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Validation │ │ Transformer │ + │ │ │ │ + └─────────────────┘ └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Plugins │ + │ │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Generated Code │ + │ │ + └─────────────────┘`} + + +

    Processing Steps

    +
      +
    1. Parsing: Convert .idea syntax into Abstract Syntax Tree (AST)
    2. +
    3. Validation: Check for syntax errors, type consistency, and constraint violations
    4. +
    5. Transformation: Convert AST into structured JSON configuration
    6. +
    7. Plugin Execution: Run configured plugins to generate output files
    8. +
    9. Code Generation: Create TypeScript, SQL, documentation, forms, etc.
    10. +
    + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/specifications/schema-directives.tsx b/packages/www/plugins/docs/views/specifications/schema-directives.tsx new file mode 100644 index 0000000..c6978e8 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/schema-directives.tsx @@ -0,0 +1,95 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Use from './components/schema-directives/Use.js'; +import Plugin from './components/schema-directives/Plugin.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Schema Directives'); + const description = _( + 'Schema directives are special declarations that control how the schema is processed and what outputs are generated.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + return ( +
    +

    Schema Directives

    +

    + Schema directives are special declarations that control how the schema is processed and what outputs are generated. +

    + + + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/schema-elements.tsx b/packages/www/plugins/docs/views/specifications/schema-elements.tsx new file mode 100644 index 0000000..6f5b4d9 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/schema-elements.tsx @@ -0,0 +1,235 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Schema Elements'); + const description = _( + 'Schema elements are the building blocks of your application schema.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const examples = [ + `// Simple boolean attribute (sets value to true) +@filterable + +// Function with single argument +@label("Name") + +// Function with multiple arguments +@is.cgt(3 "Name should be more than 3 characters") + +// Function with object argument +@view.image({ width 100 height 100 }) + +// Nested attribute names using periods +@field.input(Email) +@validation.required +@ui.component("CustomInput")`, + `// Boolean (implicit true) +@required +@unique +@filterable + +// String values +@label("User Name") +@placeholder("Enter your name") +@description("This field is required") + +// Number values +@min(0) +@max(100) +@precision(2) + +// Object values +@validation({ required true minLength 3 }) +@ui({ component "Input" placeholder "Enter text" }) +@options({ multiple true searchable false }) + +// Array values +@tags(["admin" "user" "guest"]) +@options(["small" "medium" "large"]) +@toolbar(["bold" "italic" "underline"]) + +// Mixed arguments +@between(1 100 "Value must be between 1 and 100") +@pattern("^[a-zA-Z]+$" "Only letters allowed")`, + `// Model-level attributes +model User @table("users") @index(["email" "created"]) { + // Column-level attributes + id String @id @default("nanoid()") + name String @required @minLength(2) +} + +// Type-level attributes +type Address @serializable @cacheable(3600) { + street String @required + city String @required +}`, + `model User { + name String // Required string + bio String? // Optional string + tags String[] // Array of strings + addresses Address[] // Array of custom types + metadata JSON? // Optional JSON +}`, + `model User { + profile { + firstName String + lastName String + social { + twitter String? + github String? + } + } + settings { + theme String @default("light") + notifications Boolean @default(true) + } +}` +] + +export function Body() { + return ( +
    +

    Schema Elements

    +

    Attributes (@)

    +

    + Attributes provide metadata and configuration for columns, types, and models. They define validation rules, UI components, relationships, and behavior. Attributes can be attached to any schema element and are processed by plugins according to their specific needs. +

    + + + Note: + There are no reserved or pre-defined attributes in idea. You can define any arbitrary attributes in your schema. It's up to the plugins to recognize and process them. + + +

    Attribute Syntax

    +

    + Attributes always start with the at symbol (@) followed by letters, numbers, and periods. They can be expressed in several forms: +

    + + {examples[0]} + + +

    Attribute Value Types

    +

    Attributes can hold different types of values:

    + + {examples[1]} + + +

    Attribute Scope

    +

    Attributes can be applied to different schema elements:

    + + {examples[2]} + + +

    Columns

    +

    + Columns define the individual fields within models and types, specifying their data type, constraints, and behavior. +

    + + + Types + Description + Example + + String + Text data + name String + + + Number + Numeric data + age Number + + + Boolean + True or false values + active Boolean + + + Date + Date/time values + created Date + + + JSON + JSON Objects + metadata JSON + + + CustomType + User-defined types + address Address + + + EnumType + Enum values + role UserRole + +
    + +

    Optional and Array Types

    + + {examples[3]} + + +

    Nested Types

    + + {examples[4]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/schema-structure.tsx b/packages/www/plugins/docs/views/specifications/schema-structure.tsx new file mode 100644 index 0000000..3e68258 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/schema-structure.tsx @@ -0,0 +1,120 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useState } from 'react'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Schema Structure'); + const description = _( + 'A complete .idea schema file can contain multiple elements organized in a specific structure.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + return ( +
    +

    Schema Structure

    +

    A complete .idea schema file can contain multiple elements organized in a specific structure:

    + + {`// 1. Plugin declarations +plugin "./plugins/generate-types.js" { + output "./generated/types.ts" +} + +plugin "./plugins/generate-database.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +// 2. Use statements (imports) +use "./shared/common-types.idea" +use "./auth/user-types.idea" + +// 3. Prop definitions +prop Email { + type "email" + validation { required true } +} + +prop Text { + type "text" + validation { maxLength 255 } +} + +// 4. Enum definitions +enum UserRole { + ADMIN "Administrator" + USER "Regular User" +} + +// 5. Type definitions +type Address { + street String @required + city String @required + country String @default("US") +} + +// 6. Model definitions +model User! { + id String @id @default("nanoid()") + email String @unique @field.input(Email) + name String @field.input(Text) + role UserRole @default("USER") + address Address? + active Boolean @default(true) + created Date @default("now()") +}`} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/syntax-overview.tsx b/packages/www/plugins/docs/views/specifications/syntax-overview.tsx new file mode 100644 index 0000000..21b6355 --- /dev/null +++ b/packages/www/plugins/docs/views/specifications/syntax-overview.tsx @@ -0,0 +1,175 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, C, H, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Syntax Overview'); + const description = _( + 'The .idea file format uses a simplified syntax that eliminates the need for traditional separators like commas (,) and colons (:) found in JSON or JavaScript. The parser can logically determine separations, making the syntax cleaner and more readable.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const examples = [ + `// JavaScript object +{ foo: "bar", bar: "foo" } + +// JavaScript array +[ "foo", "bar" ] + +// Nested structure +{ + user: { + name: "John", + age: 30, + active: true + }, + tags: ["admin", "user"] +}`, + `// Object structure +{ foo "bar" bar "foo" } + +// Array structure +[ "foo" "bar" ] + +// Nested structure +{ + user { + name "John" + age 30 + active true + } + tags ["admin" "user"] +}`, + `// Strings - always use double quotes +name "John Doe" +description "A comprehensive user management system" + +// Numbers - no quotes needed +age 30 +price 99.99 +count -5 + +// Booleans - no quotes needed +active true +verified false + +// Arrays - space-separated values +tags ["admin" "user" "moderator"] +numbers [1 2 3 4 5] +mixed ["text" 123 true] + +// Objects - nested key-value pairs +profile { + firstName "John" + lastName "Doe" + settings { + theme "dark" + notifications true + } +}`, + `// This is a single-line comment +model User { + id String @id // Inline comment + name String @required + // Another comment + email String @unique +} + +/* + Multi-line comments are also supported + for longer explanations +*/` +] + +export function Body() { + return ( +
    +

    Syntax Overview

    +

    + The .idea file format uses a simplified syntax that eliminates the need for traditional separators like commas (,) and colons (:) found in JSON or JavaScript. The parser can logically determine separations, making the syntax cleaner and more readable. +

    + +

    Key Syntax Rules

    +
      +
    • No Separators Required: The parser intelligently determines where values begin and end
    • +
    • Double Quotes Only: All strings must use double quotes (") - single quotes are not supported
    • +
    • Context Awareness: The parser understands context and can differentiate between keys, values, and nested structures
    • +
    + +

    Syntax Comparison

    +

    Traditional JavaScript/JSON:

    + + {examples[0]} + + +

    Equivalent .idea syntax:

    + + {examples[1]} + + +

    Data Types Representations

    + + {examples[2]} + + +

    Comments

    +

    Comments in .idea files use the standard // syntax:

    + + {examples[3]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/transformers/api-reference.tsx b/packages/www/plugins/docs/views/transformers/api-reference.tsx new file mode 100644 index 0000000..87abd98 --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/api-reference.tsx @@ -0,0 +1,151 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('API Reference'); + const description = _( + 'Detailed documentation for all components and interfaces in the idea-transformer library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('API Reference')} +
    + +
    + ); +} + +export function Body() { + return ( +
    +

    API Reference

    +

    + The API reference provides detailed documentation for all components and interfaces available in the idea-transformer library. This section covers the main classes and their methods for schema processing and plugin execution. +

    + +

    Core Components

    +

    + The core components form the foundation of the transformation system, providing the main classes and interfaces you'll use to process schemas and execute plugins. +

    + + + Component + Description + Documentation + + Transformer + Main class for loading and transforming schema files + View Docs + + + Terminal + Command-line interface for schema processing + View Docs + +
    + +

    Key Features

    +

    + The idea-transformer library offers several key features that make schema processing and code generation efficient and reliable. These features work together to provide a comprehensive transformation solution. +

    + +

    Schema Loading and Processing

    +

    + The transformer provides robust schema loading capabilities that handle complex schema structures and dependencies. This includes support for modular schemas and intelligent merging strategies. +

    +
      +
    • Support for both .idea and .json schema files
    • +
    • Automatic dependency resolution with use directives
    • +
    • Intelligent schema merging based on mutability rules
    • +
    • Comprehensive error handling and validation
    • +
    + +

    Plugin System

    +

    + The plugin system enables extensible code generation through a type-safe and flexible architecture. Plugins can access the complete schema context and generate any type of output. +

    +
      +
    • Type-safe plugin development with PluginProps and PluginWithCLIProps
    • +
    • Access to complete schema configuration and transformation context
    • +
    • CLI integration for interactive plugins
    • +
    • Flexible plugin configuration system
    • +
    + +

    Command-Line Interface

    +

    + The CLI provides convenient command-line access for integrating schema processing into build pipelines and development workflows. It supports various configuration options and batch processing capabilities. +

    +
      +
    • Simple CLI for processing schemas in build pipelines
    • +
    • Configurable working directories and file extensions
    • +
    • Integration with npm scripts and build tools
    • +
    • Support for batch processing multiple schemas
    • +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/transformers/architecture.tsx b/packages/www/plugins/docs/views/transformers/architecture.tsx new file mode 100644 index 0000000..875fd7e --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/architecture.tsx @@ -0,0 +1,86 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, P, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Architecture'); + const description = _( + 'The idea-transformer follows a clear architectural pattern that separates concerns between schema loading, processing, and output generation. This design enables flexible plugin development and maintainable code generation workflows.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + + + +export function Body() { + return ( +
    + +

    Architecture

    +

    + The idea-transformer follows a clear architectural pattern that separates concerns between schema loading, processing, and output generation. This design enables flexible plugin development and maintainable code generation workflows. +

    + + {`┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Schema File │───▶│ Transformer │───▶│ Plugins │ +│ (.idea/.json) │ │ │ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Schema Config │ │ Generated Files │ + │ │ │ │ + └─────────────────┘ └─────────────────┘`} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/transformers/best-practices.tsx b/packages/www/plugins/docs/views/transformers/best-practices.tsx new file mode 100644 index 0000000..498971c --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/best-practices.tsx @@ -0,0 +1,105 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Best practices for maintainable, scalable, and reliable schema processing workflows' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + export function Body() { + return ( +
    +

    Best Practices

    +

    + Following best practices ensures maintainable, scalable, and reliable schema processing workflows. These guidelines help you avoid common pitfalls and optimize your development experience. +

    + +

    Schema Organization

    +

    + Organize your schemas for maintainability and clarity to support team collaboration and long-term project success. Proper organization makes schemas easier to understand and modify. +

    +
      +
    • Use use directives to split large schemas into manageable files
    • +
    • Organize shared types and enums in separate files
    • +
    • Follow consistent naming conventions across schemas
    • +
    • Document complex relationships and business rules
    • +
    + +

    Plugin Development

    +

    + Follow these guidelines when developing plugins to ensure reliability, maintainability, and type safety. Good plugin development practices lead to more robust code generation. +

    +
      +
    • Always validate plugin configuration
    • +
    • Use TypeScript for type safety
    • +
    • Handle errors gracefully with meaningful messages
    • +
    • Use the transformer's file loader for consistent path resolution
    • +
    + +

    Build Integration

    +

    + Integrate schema processing effectively into your workflow to maximize productivity and maintain consistency across environments. Proper build integration ensures reliable code generation. +

    +
      +
    • Add schema generation to your build process
    • +
    • Use watch mode during development
    • +
    • Version control generated files when appropriate
    • +
    • Document the generation process for team members
    • +
    + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/transformers/common-use-cases.tsx b/packages/www/plugins/docs/views/transformers/common-use-cases.tsx new file mode 100644 index 0000000..27e5bae --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/common-use-cases.tsx @@ -0,0 +1,116 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Common Use Cases'); + const description = _( + 'Various use cases for code generation and schema processing with the idea-transformer library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + export function Body() { + return ( +
    +

    Common Use Cases

    +

    + The idea-transformer library supports a wide variety of use cases for code generation and schema processing. These use cases demonstrate the flexibility and power of the transformation system. +

    + +

    Code Generation

    +

    + Generate various code artifacts from your schema definitions to maintain consistency across your application. This use case covers the most common code generation scenarios. +

    +
      +
    • Generate TypeScript interfaces from schema models
    • +
    • Create enum definitions from schema enums
    • +
    • Build API client libraries from schema definitions
    • +
    • Generate database migration files
    • +
    + +

    Documentation

    +

    + Create comprehensive documentation from your schemas to improve developer experience and API usability. This use case focuses on generating human-readable documentation. +

    +
      +
    • Create API documentation from schema
    • +
    • Generate schema reference guides
    • +
    • Build interactive schema explorers
    • +
    • Create validation rule documentation
    • +
    + +

    Validation

    +

    + Build validation systems from your schema definitions to ensure data integrity across your application. This use case covers various validation library integrations. +

    +
      +
    • Generate validation schemas (Joi, Yup, Zod)
    • +
    • Create form validation rules
    • +
    • Build API request/response validators
    • +
    • Generate test fixtures and mock data
    • +
    + +

    Build Integration

    +

    + Integrate schema processing into your build pipeline for automated code generation and consistent development workflows. This use case covers various build system integrations. +

    +
      +
    • Integrate with webpack, rollup, or other bundlers
    • +
    • Add to npm scripts for automated generation
    • +
    • Use in CI/CD pipelines for consistent builds
    • +
    • Create watch mode for development workflows
    • +
    + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/transformers/error-handling.tsx b/packages/www/plugins/docs/views/transformers/error-handling.tsx new file mode 100644 index 0000000..4ea27c6 --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/error-handling.tsx @@ -0,0 +1,96 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Error Handling'); + const description = _( + 'Comprehensive error handling for the idea-transformer library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + const errorHandlingExample = [ + `import { Exception } from '@stackpress/idea-parser'; + +try { + const transformer = await Transformer.load('./schema.idea'); + await transformer.transform(); +} catch (error) { + if (error instanceof Exception) { + console.error('Schema error:', error.message); + console.error('Error code:', error.code); + } else { + console.error('Unexpected error:', error); + } +}` + ]; + + export function Body() { + return ( +
    +

    Error Handling

    +

    + The idea-transformer library provides comprehensive error handling to help you identify and resolve issues during schema processing. This section covers error types and handling strategies. +

    + +

    + The library provides comprehensive error handling with detailed error messages: +

    + + + {errorHandlingExample[0]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/transformers/examples.tsx b/packages/www/plugins/docs/views/transformers/examples.tsx new file mode 100644 index 0000000..90168ee --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/examples.tsx @@ -0,0 +1,133 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Examples'); + const description = _( + 'Practical examples of using the idea-transformer library for common code generation tasks' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const schemaExample = [ + `// schema.idea +model User { + id String @id + name String @required + email String @required @unique + role UserRole + profile Profile? +} + +enum UserRole { + ADMIN "admin" + USER "user" +} + +type Profile { + bio String + avatar String? +} + +plugin "./generate-types.js" { + output "./generated/types.ts" +}` +]; + +const pluginExample = [ + '// generate-types.js\nexport default async function generateTypes({ schema, config, transformer }) {\n let content = \'\';\n \n // Generate enums\n if (schema.enum) {\n for (const [name, enumDef] of Object.entries(schema.enum)) {\n content += `export enum ${name} {\\n`;\n for (const [key, value] of Object.entries(enumDef)) {\n content += ` ${key} = "${value}",\\n`;\n }\n content += \'}\\n\\n\';\n }\n }\n \n // Generate interfaces\n if (schema.model) {\n for (const [name, model] of Object.entries(schema.model)) {\n content += `export interface ${name} {\\n`;\n for (const column of model.columns) {\n const optional = column.required ? \'\' : \'?\';\n content += ` ${column.name}${optional}: ${mapType(column.type)};\\n`;\n }\n content += \'}\\n\\n\';\n }\n }\n \n const outputPath = await transformer.loader.absolute(config.output);\n await writeFile(outputPath, content);\n}' +]; + +const cliExample = [ + `{ + "scripts": { + "generate": "idea transform --input ./schema.idea", + "build": "npm run generate && tsc", + "dev": "npm run generate && npm run build -- --watch" + } +}` +]; + +export function Body() { + return ( +
    +

    Examples

    +

    + This section provides practical examples of using the idea-transformer library for common code generation tasks. These examples demonstrate real-world usage patterns and best practices. +

    + +

    TypeScript Interface Generation

    +

    + This example shows how to create a plugin that generates TypeScript interfaces from schema models. The example includes both the schema definition and the plugin implementation. +

    + +

    Schema Definition

    + + {schemaExample[0]} + + +

    Plugin Implementation

    + + {pluginExample[0]} + + +

    CLI Integration

    +

    + This example demonstrates how to integrate the idea-transformer CLI into your npm scripts for automated code generation during the build process. +

    + + {cliExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/transformers/introduction.tsx b/packages/www/plugins/docs/views/transformers/introduction.tsx new file mode 100644 index 0000000..a7e0524 --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/introduction.tsx @@ -0,0 +1,111 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Quick Start'); + const description = _( + 'Get started with the idea-transformer library' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + const installationExample = [ + `npm install @stackpress/idea-transformer` + ]; + + const basicUsageExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +// Load and process a schema +const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); +await transformer.transform();` + ]; + + export function Body() { + return ( +
    +

    Overview

    +

    + The idea-transformer library provides a complete solution for processing schema files and generating code through a flexible plugin system. This library serves as the core transformation engine that bridges schema definitions with code generation. +

    + +

    + The idea-transformer library provides a complete solution for: +

    + +
      +
    • Schema Processing: Load and parse .idea schema files with support for imports and merging
    • +
    • Plugin System: Execute transformation plugins that generate code, documentation, or other outputs
    • +
    • CLI Integration: Command-line interface for processing schemas in build pipelines
    • +
    • Type Safety: Full TypeScript support with comprehensive type definitions
    • +
    + +

    Quick Start

    +

    + Get started with the idea-transformer library in just a few steps. This section shows you how to install the library and perform basic schema transformation operations. +

    + +

    Installation

    + + {installationExample[0]} + + +

    Basic Usage

    + + {basicUsageExample[0]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/transformers/pages/terminal.tsx b/packages/www/plugins/docs/views/transformers/pages/terminal.tsx new file mode 100644 index 0000000..a1ee86c --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/pages/terminal.tsx @@ -0,0 +1,883 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, H4, P, C, Nav, SS } from '../../../components/index.js'; +import Code from '../../../components/Code.js'; +import Layout from '../../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Terminal'); + const description = _( + 'A command-line interface for processing schema files and executing transformations through terminal commands' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Terminal')} +
    + +
    + ); +} + +const basicExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +const terminal = await Terminal.load(['transform', '--input', './schema.idea']); +await terminal.run();` +]; + +const loadExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +// Load with command-line arguments +const args = ['transform', '--input', './schema.idea']; +const terminal = await Terminal.load(args); + +// Load with custom options +const terminal = await Terminal.load(args, { + cwd: '/custom/working/directory', + extname: '.schema', + brand: '[MY-TOOL]' +});` +]; + +const runExample = [ + `const terminal = await Terminal.load(['transform', '--input', './schema.idea']); +await terminal.run();` +]; + +const basicCommandExecutionExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +// Process a schema file +const args = ['transform', '--input', './schema.idea']; +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const shortFlagExample = [ + `// Using the short flag alias +const args = ['transform', '--i', './schema.idea']; +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const customWorkingDirectoryExample = [ + `// Set custom working directory +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: '/path/to/project' +}); +await terminal.run();` +]; + +const customFileExtensionExample = [ + `// Use custom file extension +const terminal = await Terminal.load(['transform', '--i', './schema.custom'], { + extname: '.custom' +}); +await terminal.run();` +]; + +const customBrandExample = [ + `// Use custom terminal brand +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + brand: '[MY-SCHEMA-TOOL]' +}); +await terminal.run();` +]; + +const directCommandLineExample = [ + `## Basic usage +node cli.js transform --input ./schema.idea + +## Using short flag +node cli.js transform --i ./schema.idea + +## With custom working directory +cd /path/to/project && node cli.js transform --i ./schema.idea` +]; + +const cliScriptExample = [ + `#!/usr/bin/env node +import Terminal from '@stackpress/idea-transformer/Terminal'; + +async function main() { + try { + const args = process.argv.slice(2); + const terminal = await Terminal.load(args, { + cwd: process.cwd(), + brand: '[SCHEMA-CLI]' + }); + await terminal.run(); + } catch (error) { + console.error('CLI Error:', error.message); + process.exit(1); + } +} + +main();` +]; + +const packageJsonIntegrationExample = [ + `{ + "name": "my-schema-tool", + "bin": { + "schema": "./cli.js" + }, + "scripts": { + "build": "schema transform --i ./schema.idea", + "dev": "schema transform --i ./dev-schema.idea" + } +}` +]; + +const defaultPathExample = [ + `// Default file path construction +const defaultPath = \`\${terminal.cwd}/schema\${terminal.extname}\`; +// Example: "/current/directory/schema.idea"` +]; + +const flagProcessingExample = [ + `// These are equivalent: +['transform', '--input', './schema.idea'] +['transform', '--i', './schema.idea'] + +// Uses default path: ./schema.idea +['transform']` +]; + +const missingSchemaFileExample = [ + `try { + const terminal = await Terminal.load(['transform', '--i', './nonexistent.idea']); + await terminal.run(); +} catch (error) { + console.error('File not found:', error.message); +}` +]; + +const invalidCommandExample = [ + `try { + const terminal = await Terminal.load(['invalid-command']); + await terminal.run(); +} catch (error) { + console.error('Unknown command:', error.message); +}` +]; + +const pluginErrorsExample = [ + `// If plugins fail during transformation +try { + const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + await terminal.run(); +} catch (error) { + console.error('Transformation failed:', error.message); +}` +]; + +const customEventHandlersExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + +// Add custom event handler +terminal.on('custom-command', async (event) => { + console.log('Custom command executed'); + // Custom logic here +}); + +await terminal.run();` +]; + +const programmaticCLIExample = [ + `// Build CLI arguments programmatically +function buildCLIArgs(schemaFile: string, options: any = {}) { + const args = ['transform']; + + if (schemaFile) { + args.push('--input', schemaFile); + } + + return args; +} + +const args = buildCLIArgs('./my-schema.idea'); +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const batchProcessingExample = [ + `import { glob } from 'glob'; + +async function processAllSchemas(pattern: string) { + const schemaFiles = await glob(pattern); + + for (const schemaFile of schemaFiles) { + console.log(\`Processing \${schemaFile}...\`); + + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + + console.log(\`Completed \${schemaFile}\`); + } +} + +// Process all .idea files in a directory +await processAllSchemas('./schemas/**/*.idea');` +]; + +const environmentBasedConfigExample = [ + `const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: process.env.SCHEMA_CWD || process.cwd(), + extname: process.env.SCHEMA_EXT || '.idea', + brand: process.env.CLI_BRAND || '[IDEA]' +}); + +await terminal.run();` +]; + +const webpackPluginExample = [ + `class SchemaTransformPlugin { + constructor(options = {}) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.beforeCompile.tapAsync('SchemaTransformPlugin', async (params, callback) => { + try { + const terminal = await Terminal.load(['transform', '--i', this.options.schemaFile]); + await terminal.run(); + callback(); + } catch (error) { + callback(error); + } + }); + } +}` +]; + +const gulpTaskExample = [ + `import gulp from 'gulp'; +import Terminal from '@stackpress/idea-transformer/Terminal'; + +gulp.task('transform-schema', async () => { + const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + await terminal.run(); +});` +]; + +const npmScriptsExample = [ + `{ + "scripts": { + "schema:build": "node -e \"import('./cli.js').then(m => m.default(['transform', '--i', './schema.idea']))\"", + "schema:dev": "node -e \"import('./cli.js').then(m => m.default(['transform', '--i', './dev-schema.idea']))\"", + "schema:watch": "nodemon --watch schema.idea --exec \"npm run schema:build\"" + } +}` +]; + +const unitTestingExample = [ + `import { expect } from 'chai'; +import Terminal from '@stackpress/idea-transformer/Terminal'; + +describe('Terminal Tests', () => { + it('should process schema file', async () => { + const terminal = await Terminal.load(['transform', '--i', './test-schema.idea'], { + cwd: './test-fixtures' + }); + + expect(terminal.cwd).to.include('test-fixtures'); + + // Run the terminal command + await terminal.run(); + + // Verify output files were created + // ... assertions here + }); + + it('should use default options', async () => { + const terminal = await Terminal.load(['transform']); + + expect(terminal.extname).to.equal('.idea'); + expect(terminal.cwd).to.be.a('string'); + }); +});` +]; + +const integrationTestingExample = [ + `import fs from 'fs'; +import path from 'path'; + +describe('Terminal Integration', () => { + it('should generate expected output files', async () => { + const outputDir = './test-output'; + const schemaFile = './test-schema.idea'; + + // Clean output directory + if (fs.existsSync(outputDir)) { + fs.rmSync(outputDir, { recursive: true }); + } + + // Run transformation + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + + // Verify expected files were created + const expectedFiles = ['types.ts', 'enums.ts', 'models.ts']; + for (const file of expectedFiles) { + const filePath = path.join(outputDir, file); + expect(fs.existsSync(filePath)).to.be.true; + } + }); +});` +]; + +const errorHandlingBestPracticeExample = [ + `// Always wrap terminal execution in try-catch +async function safeTransform(schemaFile: string) { + try { + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + console.log(\`✅ Successfully processed \${schemaFile}\`); + } catch (error) { + console.error(\`❌ Failed to process \${schemaFile}:\`, error.message); + throw error; + } +}` +]; + +const configurationManagementExample = [ + `// Use configuration objects for reusable settings +const defaultConfig = { + cwd: process.cwd(), + extname: '.idea', + brand: '[SCHEMA-TOOL]' +}; + +async function createTerminal(args: string[], config = defaultConfig) { + return await Terminal.load(args, config); +}` +]; + +const loggingAndDebuggingExample = [ + `// Add logging for better debugging +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: process.cwd() +}); + +console.log(\`Working directory: \${terminal.cwd}\`); +console.log(\`File extension: \${terminal.extname}\`); + +await terminal.run();` +]; + +export function Body() { + return ( +
    +

    Terminal

    +

    + A command-line interface for processing schema files and executing transformations through terminal commands. The Terminal class provides a comprehensive CLI interface for the idea-transformer library, enabling developers to process schema files and execute transformations from the command line. +

    + + + {basicExample[0]} + + + +
    +

    Overview

    +

    + The Terminal class provides a command-line interface for processing schema files and executing transformations. This section outlines the core capabilities and features of the Terminal class, which extends the base Terminal functionality to provide schema-specific command-line operations. +

    + +

    + The Terminal class (exported as IdeaTerminal) extends the base Terminal class from @stackpress/lib to provide command-line functionality for the idea-transformer library. It handles: +

    + +
      +
    • Command-line argument parsing
    • +
    • Schema file transformation via CLI commands
    • +
    • Integration with the Transformer class for processing
    • +
    • Configurable working directories and file extensions
    • +
    + +
    +

    Loading a Terminal Instance

    +

    + The load method creates a new Terminal instance from command-line arguments and optional configuration. This is the primary way to create a terminal instance for processing schema files from the command line. +

    + +

    + The following example shows how to create a new Terminal instance from command-line arguments. +

    + + + {loadExample[0]} + + +

    Parameters

    + + + Parameter + Type + Description + + args + string[] + Command-line arguments array + + + options + TerminalOptions + Optional configuration for terminal behavior + +
    + +

    Returns

    +

    + A promise that resolves to a new Terminal instance configured with the specified arguments and options. +

    + +
    +

    Properties

    +

    + The properties section describes the instance variables available on Terminal objects. These properties provide access to configuration details and runtime information needed for command-line operations. +

    + +

    Properties

    +

    + The following properties are available when instantiating a Terminal. +

    + + + Property + Type + Description + + cwd + string + Current working directory for file operations + + + extname + string + Default file extension for schema files (default: '.idea') + +
    + + +
    +

    Running Terminal Commands

    +

    + The run method executes the configured terminal command and processes the specified schema file. This method handles the complete workflow from command parsing to schema transformation execution. +

    + +

    + The Terminal automatically sets up event handlers for processing commands. The main command supported is transform. +

    + + + {runExample[0]} + + +

    Command Structure

    +

    + The terminal expects commands in the following format: +

    + + transform --input <schema-file> [--i <schema-file>] + + +

    Flags

    + + + Flag + Alias + Description + + --input + --i + Path to the schema file to process + +
    + +
    +

    Usage Examples

    +

    + This section provides practical examples of how to use the Terminal class in various scenarios. These examples demonstrate common patterns and use cases for command-line schema processing. +

    + +

    Basic Command Execution

    +

    + Basic command execution demonstrates the fundamental workflow for processing schema files through the Terminal interface. This example shows the simplest way to transform a schema file using command-line arguments. +

    + + + {basicCommandExecutionExample[0]} + + +

    Using Short Flag Syntax

    +

    + Short flag syntax provides convenient aliases for common command-line options. This example shows how to use abbreviated flags to make command-line usage more efficient. +

    + + + {shortFlagExample[0]} + + +

    Custom Working Directory

    +

    + Custom working directory configuration allows you to specify where the Terminal should operate. This is useful when processing schema files from different locations or when integrating with build systems. +

    + + + {customWorkingDirectoryExample[0]} + + +

    Custom File Extension

    +

    + Custom file extension support enables the Terminal to work with schema files that use non-standard extensions. This flexibility allows integration with different naming conventions and file organization strategies. +

    + + + {customFileExtensionExample[0]} + + +

    Custom Brand/Label

    +

    + Custom brand configuration allows you to customize the Terminal's display name and branding. This is useful when building custom CLI tools based on the idea-transformer library. +

    + + + {customBrandExample[0]} + + +
    +

    Command-Line Integration

    +

    + This section demonstrates how to integrate the Terminal class with actual command-line environments and build systems. These examples show practical applications for creating CLI tools and automating schema processing. +

    + +

    Direct Command-Line Usage

    +

    + Direct command-line usage shows how to invoke the Terminal functionality from shell commands. This section provides examples of the actual command syntax and available options. +

    + + + {directCommandLineExample[0]} + + +

    CLI Script Example

    +

    + CLI script examples demonstrate how to create executable scripts that use the Terminal class. This pattern is useful for creating standalone CLI tools and integrating with package managers. +

    + + + {cliScriptExample[0]} + + +

    Package.json Integration

    +

    + Package.json integration shows how to configure npm scripts and binary commands using the Terminal class. This enables seamless integration with Node.js project workflows and package distribution. +

    + + + {packageJsonIntegrationExample[0]} + + + +
    +

    Default Behavior

    +

    + This section explains the default behavior and conventions used by the Terminal class. Understanding these defaults helps developers predict how the Terminal will behave in different scenarios and configure it appropriately. +

    + +

    File Path Resolution

    +

    + File path resolution describes how the Terminal determines which schema file to process when no explicit path is provided. This automatic resolution simplifies common use cases while maintaining flexibility. +

    + +

    + When no input file is specified, the terminal uses a default path: +

    + + + {defaultPathExample[0]} + + +

    Flag Processing

    +

    + Flag processing explains how the Terminal parses and prioritizes command-line flags. Understanding this order of precedence helps developers use the most appropriate flag syntax for their needs. +

    + +

    + The terminal processes the following flags in order of preference: +

    + +
      +
    1. --input (full flag name)
    2. +
    3. --i (short alias)
    4. +
    5. Default file path if no flags provided
    6. +
    + + + {flagProcessingExample[0]} + + +
    +

    Error Handling

    +

    + This section covers common error conditions that can occur when using the Terminal class. Understanding these error scenarios helps developers implement proper error handling and provide better user experiences. +

    + +

    Missing Schema File

    +

    + Missing schema file errors occur when the specified schema file doesn't exist or isn't accessible. This section shows how these errors are reported and how to handle them appropriately in CLI applications. +

    + + + {missingSchemaFileExample[0]} + + +

    Invalid Command

    +

    + Invalid command errors occur when unsupported commands are passed to the Terminal. This section explains how the Terminal handles unknown commands and provides guidance for error recovery. +

    + + + {invalidCommandExample[0]} + + +

    Plugin Errors

    +

    + Plugin errors can occur during the transformation process when plugins fail to execute properly. This section covers how to handle and debug plugin-related issues in CLI environments. +

    + + + {pluginErrorsExample[0]} + + +
    +

    Advanced Usage

    +

    + This section covers advanced patterns and techniques for using the Terminal class in complex scenarios. These examples demonstrate sophisticated use cases and integration patterns for power users. +

    + +

    Custom Event Handlers

    +

    + Custom event handlers allow you to extend the Terminal's functionality with additional commands and behaviors. This pattern enables building specialized CLI tools with custom functionality. +

    + + + {customEventHandlersExample[0]} + + +

    Programmatic CLI Building

    +

    + Programmatic CLI building demonstrates how to construct command-line arguments dynamically in code. This approach is useful for building tools that generate CLI commands based on configuration or user input. +

    + + + {programmaticCLIExample[0]} + + +

    Batch Processing

    +

    + Batch processing shows how to use the Terminal class to process multiple schema files in sequence. This pattern is essential for build systems and automation tools that need to handle multiple schemas. +

    + + + {batchProcessingExample[0]} + + +

    Environment-Based Configuration

    +

    + Environment-based configuration demonstrates how to use environment variables to configure Terminal behavior. This approach enables flexible deployment and configuration management across different environments. +

    + + + {environmentBasedConfigExample[0]} + + +
    +

    Integration with Build Tools

    +

    + This section demonstrates how to integrate the Terminal class with popular build tools and development workflows. These examples show practical applications for automating schema processing in development and deployment pipelines. +

    + +

    Webpack Plugin

    +

    + Webpack plugin integration shows how to incorporate schema transformation into Webpack build processes. This enables automatic schema processing as part of the application build pipeline. +

    + + + {webpackPluginExample[0]} + + +

    Gulp Task

    +

    + Gulp task integration demonstrates how to create Gulp tasks that use the Terminal class for schema processing. This pattern is useful for projects that use Gulp as their primary build tool. +

    + + + {gulpTaskExample[0]} + + +

    NPM Scripts

    +

    + NPM scripts integration shows how to configure package.json scripts that use the Terminal class. This approach enables easy schema processing through standard npm commands and supports development workflows. +

    + + + {npmScriptsExample[0]} + + +
    +

    Testing

    +

    + This section covers testing strategies and patterns for applications that use the Terminal class. These examples demonstrate how to write effective tests for CLI functionality and ensure reliable schema processing. +

    + +

    Unit Testing

    +

    + Unit testing examples show how to test Terminal functionality in isolation. These tests verify that the Terminal class behaves correctly with different command-line arguments and configuration options. +

    + + + {unitTestingExample[0]} + + +

    Integration Testing

    +

    + Integration testing demonstrates how to test the complete workflow from command-line input to generated output files. These tests ensure that the entire transformation pipeline works correctly in realistic scenarios. +

    + + + {integrationTestingExample[0]} + + +
    +

    Best Practices

    +

    + This section outlines recommended approaches for using the Terminal class effectively. Following these practices helps ensure reliable, maintainable, and user-friendly CLI applications. +

    + +

    Error Handling

    +

    + Error handling best practices ensure that CLI applications provide clear feedback when issues occur. This section demonstrates patterns for implementing robust error handling and user-friendly error messages. +

    + + + {errorHandlingBestPracticeExample[0]} + + +

    Configuration Management

    +

    + Configuration management best practices help maintain clean, reusable configuration patterns. This section provides guidance on organizing configuration options and providing sensible defaults. +

    + + + {configurationManagementExample[0]} + + +

    Logging and Debugging

    +

    + Logging and debugging practices help developers troubleshoot issues and understand Terminal behavior. This section demonstrates effective logging strategies and debugging techniques for CLI applications. +

    + + + {loggingAndDebuggingExample[0]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/transformers/pages/transformer.tsx b/packages/www/plugins/docs/views/transformers/pages/transformer.tsx new file mode 100644 index 0000000..3530e8c --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/pages/transformer.tsx @@ -0,0 +1,687 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, H3, H4, P, C, Nav, SS } from '../../../components/index.js'; + import Code from '../../../components/Code.js'; + import Layout from '../../../components/Layout.js'; + import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Transformer'); + const description = _( + 'A class for loading, processing, and transforming schema files with plugin support and schema merging capabilities' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Transformer')} +
    + +
    + ); + } + + const basicExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); +await transformer.transform();` + ]; + + const loadExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +// Load with default options +const transformer = await Transformer.load('./schema.idea'); + +// Load with custom options +const transformer = await Transformer.load('./schema.idea', { + cwd: '/custom/working/directory', + fs: customFileSystem +});` + ]; + + const schemaExample = [ + `const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); + +console.log(schema.model); // Access model definitions +console.log(schema.enum); // Access enum definitions +console.log(schema.type); // Access type definitions +console.log(schema.prop); // Access prop definitions +console.log(schema.plugin); // Access plugin configurations` + ]; + + const transformExample = [ + `const transformer = await Transformer.load('./schema.idea'); + +// Transform with no additional context +await transformer.transform(); + +// Transform with additional context +await transformer.transform({ + outputDir: './generated', + debug: true +});` + ]; + + const pluginContextExample = [ + `{ + transformer: Transformer, // The transformer instance + config: PluginConfig, // Plugin-specific configuration + schema: SchemaConfig, // Complete processed schema + cwd: string, // Current working directory + ...extras // Any additional context passed to transform() +}` + ]; + + const basicSchemaLoadingExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); + +// Access different parts of the schema +console.log('Models:', Object.keys(schema.model || {})); +console.log('Enums:', Object.keys(schema.enum || {})); +console.log('Types:', Object.keys(schema.type || {}));` + ]; + + const multipleSchemaFilesExample = [ + `// main.idea +/* +use "./shared/types.idea" +use "./shared/enums.idea" + +model User { + id String @id + profile Profile // From shared/types.idea + role UserRole // From shared/enums.idea +} +*/ + +const transformer = await Transformer.load('./main.idea'); +const schema = await transformer.schema(); + +// The schema now includes definitions from all imported files +console.log(schema.type?.Profile); // Available from shared/types.idea +console.log(schema.enum?.UserRole); // Available from shared/enums.idea` + ]; + + const pluginDevelopmentExample = [ + `// schema.idea +/* +plugin "./plugins/generate-types.js" { + output "./generated/types.ts" + format "typescript" +} +*/ + +// plugins/generate-types.js +export default function generateTypes({ transformer, config, schema, cwd }) { + const outputPath = config.output; + const format = config.format; + + // Generate TypeScript types based on schema + let content = ''; + + if (schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + content += \`export interface \${name} {\n\`; + for (const column of model.columns) { + const optional = column.required ? '' : '?'; + content += \` \${column.name}\${optional}: \${column.type};\n\`; + } + content += '}\n\n'; + } + } + + // Write generated content to file + await writeFile(path.resolve(cwd, outputPath), content); +} + +// Execute the transformation +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform({ + timestamp: new Date().toISOString() +});` + ]; + + const errorHandlingExample = [ + `import { Exception } from '@stackpress/idea-parser'; + +try { + const transformer = await Transformer.load('./schema.idea'); + const schema = await transformer.schema(); + await transformer.transform(); +} catch (error) { + if (error instanceof Exception) { + console.error('Schema processing error:', error.message); + console.error('Error code:', error.code); + } else { + console.error('Unexpected error:', error); + } +}` + ]; + + const customFileSystemExample = [ + `import { NodeFS } from '@stackpress/lib'; + +// Using custom file system +const customFS = new NodeFS(); +const transformer = await Transformer.load('./schema.idea', { + fs: customFS, + cwd: '/custom/working/directory' +});` + ]; + + const fileNotFoundExample = [ + `// Throws: "Input file /path/to/nonexistent.idea does not exist" +const transformer = await Transformer.load('./nonexistent.idea'); +await transformer.schema(); // Error thrown here` + ]; + + const noPluginsExample = [ + `// If schema has no plugins defined +const transformer = await Transformer.load('./schema-without-plugins.idea'); +await transformer.transform(); // Throws: "No plugins defined in schema file"` + ]; + + const invalidPluginExample = [ + `// If plugin file doesn't export a function +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform(); // Plugin is silently skipped if not a function` + ]; + + const schemaOrganizationExample = [ + `// Organize schemas hierarchically +// shared/base.idea - Common types and enums +// modules/user.idea - User-specific models +// main.idea - Main schema that imports others + +use "./shared/base.idea" +use "./modules/user.idea" + +// Additional models specific to this schema +model Application { + id String @id + users User[] +}` + ]; + + const pluginDevelopmentBestPracticeExample = [ + `// Always validate plugin configuration +export default async function myPlugin({ config, schema, transformer, cwd }) { + // Validate required configuration + if (!config.output) { + throw new Error('Plugin requires output configuration'); + } + + // Use transformer's file loader for consistent path resolution + const outputPath = await transformer.loader.absolute(config.output); + + // Process schema safely + const models = schema.model || {}; + const enums = schema.enum || {}; + + // Generate output... +}` + ]; + + const errorRecoveryExample = [ + `// Implement graceful error handling +async function processSchema(schemaPath) { + try { + const transformer = await Transformer.load(schemaPath); + const schema = await transformer.schema(); + await transformer.transform(); + return { success: true, schema }; + } catch (error) { + console.error(\`Failed to process \${schemaPath}:\`, error.message); + return { success: false, error: error.message }; + } +}` + ]; + + const buildSystemIntegrationExample = [ + `// Integration with build tools +import Transformer from '@stackpress/idea-transformer'; + +export async function buildSchemas(inputDir, outputDir) { + const schemaFiles = await glob(\`\${inputDir}/**/*.idea\`); + + for (const schemaFile of schemaFiles) { + const transformer = await Transformer.load(schemaFile); + await transformer.transform({ outputDir }); + } +}` + ]; + + const testingExample = [ + `// Testing schema transformations +import { expect } from 'chai'; + +describe('Schema Transformation', () => { + it('should process schema correctly', async () => { + const transformer = await Transformer.load('./test-schema.idea'); + const schema = await transformer.schema(); + + expect(schema.model).to.have.property('User'); + expect(schema.model.User.columns).to.have.length.greaterThan(0); + }); +});` + ]; + + export function Body() { + return ( +
    +

    Transformer

    +

    + A class for loading, processing, and transforming schema files with plugin support and schema merging capabilities. The Transformer class serves as the core component of the idea-transformer library, providing comprehensive functionality for schema processing, plugin execution, and file management. +

    + + + {basicExample[0]} + + +
    +

    Overview

    +

    + The Transformer class provides a comprehensive solution for processing schema files and executing transformations. This section outlines the core capabilities and responsibilities of the Transformer class within the idea-transformer ecosystem. +

    + +

    + The Transformer class is the core component of the idea-transformer library. It handles: +

    + +
      +
    • Loading schema files (both .idea and .json formats)
    • +
    • Processing and merging schema configurations from multiple files
    • +
    • Executing plugins defined in the schema
    • +
    • Managing file dependencies and imports
    • +
    + +
    +

    Loading a Transformer

    +

    + The load method creates a new Transformer instance configured with the specified input file and options. This is the primary way to create a transformer and begin working with schema files. +

    + +

    + The following example shows how to create a new Transformer instance. +

    + + + {loadExample[0]} + + +

    Parameters

    + + + Parameter + Type + Description + + input + string + Path to the schema file to load + + + options + FileLoaderOptions + Optional configuration for file loading + +
    + +

    Returns

    +

    + A promise that resolves to a new Transformer instance configured with the specified input file and options. +

    + +
    +

    Properties

    +

    + The properties section describes the instance variables available on Transformer objects. These properties provide access to the underlying file system operations and configuration details needed for schema processing. +

    + +

    Properties

    +

    + The following properties are available when instantiating a Transformer. +

    + + + Property + Type + Description + + loader + FileLoader + File system loader for handling file operations + + + input + string + Absolute path to the input schema file + +
    + +
    +

    Methods

    +

    + The methods section covers the instance methods available on Transformer objects. These methods provide the core functionality for loading schema configurations, processing dependencies, and executing plugin transformations. +

    + +

    Loading Schema Configuration

    +

    + The schema method loads and processes the complete schema configuration, including all dependencies and imports. This method handles the complex process of merging multiple schema files and resolving all references. +

    + +

    + The following example shows how to load and process the schema configuration. +

    + + + {schemaExample[0]} + + +

    Returns

    +

    + A promise that resolves to a SchemaConfig object containing all processed schema definitions. +

    + +

    Features

    +
      +
    • File Format Support: Automatically detects and handles both .idea and .json schema files
    • +
    • Dependency Resolution: Processes use directives to import and merge external schema files
    • +
    • Schema Merging: Intelligently merges child schemas into parent schemas based on mutability rules
    • +
    • Caching: Caches the processed schema to avoid redundant processing
    • +
    + +

    Schema Merging Rules

    +

    + When processing use directives, the transformer applies these merging rules: +

    + +
      +
    1. Props and Enums: Simple merge where parent takes precedence
    2. +
    3. Types and Models: +
        +
      • If parent doesn't exist or is immutable: child is added
      • +
      • If parent is mutable: attributes and columns are merged
      • +
      • Child columns are prepended to parent columns
      • +
      • Parent attributes take precedence over child attributes
      • +
      +
    4. +
    + +

    Transforming with Plugins

    +

    + The transform method executes all plugins defined in the schema configuration. This method coordinates the plugin execution process, providing each plugin with the necessary context and handling any errors that occur during transformation. +

    + +

    + The following example shows how to execute all plugins defined in the schema. +

    + + + {transformExample[0]} + + +

    Parameters

    + + + Parameter + Type + Description + + extras + T + Optional additional context to pass to plugins + +
    + +

    Returns

    +

    + A promise that resolves when all plugins have been executed. +

    + +

    Plugin Execution Process

    +
      +
    1. Validation: Ensures plugins are defined in the schema
    2. +
    3. Module Resolution: Resolves plugin file paths relative to the schema file
    4. +
    5. Dynamic Import: Loads plugin modules dynamically
    6. +
    7. Context Injection: Passes context including transformer, schema, config, and extras
    8. +
    9. Execution: Calls each plugin function with the injected context
    10. +
    + +

    Plugin Context

    +

    + Each plugin receives a context object with the following properties: +

    + + + {pluginContextExample[0]} + + +
    +

    Usage Examples

    +

    + This section provides practical examples of how to use the Transformer class in various scenarios. These examples demonstrate common patterns and best practices for working with schema files, plugins, and transformations. +

    + +

    Basic Schema Loading

    +

    + Basic schema loading demonstrates the fundamental workflow for loading and accessing schema configurations. This example shows how to create a transformer instance and retrieve different parts of the processed schema. +

    + + + {basicSchemaLoadingExample[0]} + + +

    Working with Multiple Schema Files

    +

    + Working with multiple schema files shows how the Transformer handles complex schema hierarchies with imports and dependencies. This example demonstrates how the use directive enables modular schema organization. +

    + + + {multipleSchemaFilesExample[0]} + + +

    Plugin Development and Execution

    +

    + Plugin development and execution demonstrates how to create and use plugins with the Transformer. This example shows both the schema configuration and plugin implementation, illustrating the complete plugin workflow. +

    + + + {pluginDevelopmentExample[0]} + + +

    Error Handling

    +

    + Error handling examples show how to properly catch and handle different types of errors that can occur during schema processing and transformation. This includes both expected errors from the idea-parser and unexpected runtime errors. +

    + + + {errorHandlingExample[0]} + + +

    Custom File System

    +

    + Custom file system usage demonstrates how to configure the Transformer to work with different file system implementations. This is useful for testing, custom storage backends, or specialized deployment scenarios. +

    + + + {customFileSystemExample[0]} + + +
    +

    Error Scenarios

    +

    + This section covers common error conditions that can occur when using the Transformer class. Understanding these scenarios helps developers implement proper error handling and debugging strategies. +

    + +

    File Not Found

    +

    + File not found errors occur when the specified schema file doesn't exist or isn't accessible. This section shows how these errors are reported and how to handle them appropriately. +

    + + + {fileNotFoundExample[0]} + + +

    No Plugins Defined

    +

    + No plugins defined errors occur when attempting to execute transformations on schemas that don't have any plugin configurations. This section explains when this error occurs and how to handle it. +

    + + + {noPluginsExample[0]} + + +

    Invalid Plugin Module

    +

    + Invalid plugin module scenarios occur when plugin files exist but don't export the expected function interface. This section covers how the Transformer handles these situations and what developers should expect. +

    + + + {invalidPluginExample[0]} + + +
    +

    Best Practices

    +

    + This section outlines recommended approaches for using the Transformer class effectively. Following these practices helps ensure reliable, maintainable, and efficient schema processing workflows. +

    + +

    Schema Organization

    +

    + Schema organization best practices help maintain clean, modular, and reusable schema files. This section provides guidance on structuring schema hierarchies and managing dependencies effectively. +

    + + + {schemaOrganizationExample[0]} + + +

    Plugin Development

    +

    + Plugin development best practices ensure that plugins are robust, reliable, and integrate well with the Transformer ecosystem. This section covers validation, error handling, and proper use of the plugin context. +

    + + + {pluginDevelopmentBestPracticeExample[0]} + + +

    Error Recovery

    +

    + Error recovery strategies help build resilient applications that can handle schema processing failures gracefully. This section demonstrates patterns for implementing robust error handling and recovery mechanisms. +

    + + + {errorRecoveryExample[0]} + + +
    +

    Integration with Other Tools

    +

    + This section demonstrates how to integrate the Transformer class with other development tools and workflows. These examples show practical applications in build systems, testing frameworks, and development environments. +

    + +

    Build Systems

    +

    + Build system integration shows how to incorporate schema transformation into automated build processes. This enables continuous generation of code, documentation, and other artifacts from schema definitions. +

    + + + {buildSystemIntegrationExample[0]} + + +

    Testing

    +

    + Testing integration demonstrates how to write tests for schema transformations and validate that schemas are processed correctly. This is essential for maintaining schema quality and catching regressions. +

    + + + {testingExample[0]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/transformers/usage-patterns.tsx b/packages/www/plugins/docs/views/transformers/usage-patterns.tsx new file mode 100644 index 0000000..6e95067 --- /dev/null +++ b/packages/www/plugins/docs/views/transformers/usage-patterns.tsx @@ -0,0 +1,125 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps + } from 'stackpress/view/client'; + import { useLanguage } from 'stackpress/view/client'; + //docs + import { H1, H2, P, Nav } from '../../components/index.js'; + import Code from '../../components/Code.js'; + import Layout from '../../components/Layout.js'; + + export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Usage Patterns'); + const description = _( + 'Common usage patterns for integrating the idea-transformer library into different development workflows' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) + } + + const basicTransformationExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +// Load schema and execute plugins +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform();` + ]; + + const cliUsageExample = [ + `# Process schema file +node cli.js transform --input ./schema.idea + +# Using short flag +node cli.js transform --i ./schema.idea` + ]; + + const pluginDevelopmentExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; + +export default async function myPlugin(props: PluginProps<{}>) { + const { config, schema, transformer, cwd } = props; + + // Process schema and generate output + const content = generateFromSchema(schema); + const outputPath = await transformer.loader.absolute(config.output); + await writeFile(outputPath, content); +}` + ]; + + export function Body() { + return ( +
    +

    Usage Patterns

    +

    + This section demonstrates common usage patterns for the idea-transformer library. These patterns show how to integrate the transformer into different development workflows and use cases. +

    + +

    Basic Schema Transformation

    +

    + The most common usage pattern involves loading a schema file and executing all configured plugins. This pattern is suitable for most build processes and automated workflows. +

    + + {basicTransformationExample[0]} + + +

    CLI Usage

    +

    + The command-line interface provides a simple way to process schemas from build scripts or CI/CD pipelines. This pattern is ideal for integrating schema processing into existing build workflows. +

    + + {cliUsageExample[0]} + + +

    Plugin Development

    +

    + Creating custom plugins allows you to extend the transformer with domain-specific code generation. This pattern shows the basic structure for developing type-safe plugins. +

    + + {pluginDevelopmentExample[0]} + + +
    + ); + } + + export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); + } + \ No newline at end of file diff --git a/packages/www/plugins/docs/views/tutorials/api-client-plugin.tsx b/packages/www/plugins/docs/views/tutorials/api-client-plugin.tsx new file mode 100644 index 0000000..22f9fe1 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/api-client-plugin.tsx @@ -0,0 +1,1042 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface APIClientConfig { + output: string; + clientType: 'rest' | 'graphql' | 'both'; + httpLibrary?: 'fetch' | 'axios'; + baseUrl?: string; + authentication?: { + type: 'bearer' | 'apikey' | 'basic' | 'custom'; + headerName?: string; + }; + generateTypes?: boolean; + includeValidation?: boolean; + errorHandling?: 'throw' | 'return' | 'callback'; +} + +export default async function generateAPIClient( + props: PluginProps<{ config: APIClientConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`, + `export default async function generateAPIClient( + props: PluginProps<{ config: APIClientConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate client content + let content = ''; + + // Add file header and imports + content += generateFileHeader(config); + content += generateImports(config); + + // Generate types if requested + if (config.generateTypes) { + content += generateTypes(schema, config); + } + + // Generate base client class + content += generateBaseClient(config); + + // Generate model-specific clients + if (schema.model) { + if (config.clientType === 'rest' || config.clientType === 'both') { + content += generateRESTClients(schema.model, config); + } + + if (config.clientType === 'graphql' || config.clientType === 'both') { + content += generateGraphQLClients(schema.model, config); + } + } + + // Generate main client export + content += generateMainClient(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ API client generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ API client generation failed:', error.message); + throw error; + } +}`, + `function generateFileHeader(config: APIClientConfig): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated API Client + * Generated at: \${timestamp} + * Client Type: \${config.clientType} + * HTTP Library: \${config.httpLibrary || 'fetch'} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateImports(config: APIClientConfig): string { + let imports = ''; + + if (config.httpLibrary === 'axios') { + imports += \`import axios, { AxiosInstance, AxiosResponse, AxiosError } from 'axios';\\n\`; + } + + if (config.clientType === 'graphql' || config.clientType === 'both') { + imports += \`import { ApolloClient, InMemoryCache, gql, DocumentNode } from '@apollo/client';\\n\`; + } + + imports += \` +// Base types +interface APIResponse { + success: boolean; + data?: T; + error?: string; + errors?: Record; +} + +interface PaginatedResponse extends APIResponse { + total: number; + page: number; + limit: number; +} + +interface RequestOptions { + headers?: Record; + signal?: AbortSignal; +} + +\`; + + return imports; +}`, + `function generateTypes(schema: any, config: APIClientConfig): string { + let content = '// Generated Types\\n'; + + // Generate enums + if (schema.enum) { + for (const [enumName, enumDef] of Object.entries(schema.enum)) { + content += \`export enum \${enumName} {\\n\`; + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key} = "\${value}",\\n\`; + } + content += '}\\n\\n'; + } + } + + // Generate interfaces + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + content += \`export interface \${modelName} {\\n\`; + for (const column of model.columns || []) { + const optional = !column.required ? '?' : ''; + const type = mapTypeToTypeScript(column.type); + content += \` \${column.name}\${optional}: \${type};\\n\`; + } + content += '}\\n\\n'; + + // Generate input types + const autoFields = model.columns + ?.filter((col: any) => col.attributes?.id || col.attributes?.default) + .map((col: any) => \`'\${col.name}'\`) + .join(' | '); + + if (autoFields) { + content += \`export type Create\${modelName}Input = Omit<\${modelName}, \${autoFields}>;\\n\`; + } else { + content += \`export type Create\${modelName}Input = \${modelName};\\n\`; + } + + content += \`export type Update\${modelName}Input = Partial<\${modelName}>;\\n\\n\`; + } + } + + return content; +}`, + `function generateBaseClient(config: APIClientConfig): string { + const authType = config.authentication?.type || 'bearer'; + const headerName = config.authentication?.headerName || 'Authorization'; + + return \` +// Base Client Class +export class BaseAPIClient { + private baseUrl: string; + private authToken?: string; + \${config.httpLibrary === 'axios' ? 'private axiosInstance: AxiosInstance;' : ''} + + constructor(baseUrl: string = '\${config.baseUrl || '/api'}') { + this.baseUrl = baseUrl.replace(/\\/$/, ''); + \${config.httpLibrary === 'axios' ? generateAxiosSetup() : ''} + } + + setAuthToken(token: string): void { + this.authToken = token; + } + + private getAuthHeaders(): Record { + if (!this.authToken) return {}; + + \${generateAuthHeaders(authType, headerName)} + } + + \${config.httpLibrary === 'axios' ? generateAxiosMethods() : generateFetchMethods()} +} + +\`; +}`, + `function generateRESTClients(models: Record, config: APIClientConfig): string { + let content = '// REST API Clients\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + const pluralName = \`\${lowerName}s\`; + + content += \` +export class \${modelName}Client extends BaseAPIClient { + // Get all \${pluralName} + async getAll(params?: { + page?: number; + limit?: number; + search?: string; + sort?: string; + }, options?: RequestOptions): Promise> { + const queryParams = new URLSearchParams(); + if (params?.page) queryParams.set('page', params.page.toString()); + if (params?.limit) queryParams.set('limit', params.limit.toString()); + if (params?.search) queryParams.set('search', params.search); + if (params?.sort) queryParams.set('sort', params.sort); + + const query = queryParams.toString(); + const url = \\\`/\${pluralName}\\\${query ? \\\`?\\\${query}\\\` : ''}\\\`; + + return this.get<\${modelName}[]>(url, options) as Promise>; + } + + // Get single \${lowerName} by ID + async getById(id: string, options?: RequestOptions): Promise> { + return this.get<\${modelName}>(\\\`/\${pluralName}/\\\${id}\\\`, options); + } + + // Create new \${lowerName} + async create(data: Create\${modelName}Input, options?: RequestOptions): Promise> { + return this.post<\${modelName}>(\\\`/\${pluralName}\\\`, data, options); + } + + // Update existing \${lowerName} + async update(id: string, data: Update\${modelName}Input, options?: RequestOptions): Promise> { + return this.put<\${modelName}>(\\\`/\${pluralName}/\\\${id}\\\`, data, options); + } + + // Delete \${lowerName} + async delete(id: string, options?: RequestOptions): Promise> { + return this.delete(\\\`/\${pluralName}/\\\${id}\\\`, options); + } +} +\`; + } + + return content; +}`, + `function generateGraphQLClients(models: Record, config: APIClientConfig): string { + let content = '// GraphQL API Clients\\n'; + + content += \` +export class GraphQLClient extends BaseAPIClient { + private apolloClient: ApolloClient; + + constructor(baseUrl: string = '\${config.baseUrl || '/graphql'}') { + super(baseUrl); + this.apolloClient = new ApolloClient({ + uri: this.baseUrl, + cache: new InMemoryCache(), + }); + } + + private async executeQuery(query: DocumentNode, variables?: any): Promise> { + try { + const result = await this.apolloClient.query({ + query, + variables, + }); + return { success: true, data: result.data }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'GraphQL query failed', + }; + } + } + + private async executeMutation(mutation: DocumentNode, variables?: any): Promise> { + try { + const result = await this.apolloClient.mutate({ + mutation, + variables, + }); + return { success: true, data: result.data }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'GraphQL mutation failed', + }; + } + } +\`; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + const pluralName = \`\${lowerName}s\`; + + content += \` + // \${modelName} GraphQL operations + async get\${pluralName}(variables?: { limit?: number; offset?: number }): Promise> { + const query = gql\\\` + query Get\${pluralName}($limit: Int, $offset: Int) { + \${pluralName}(limit: $limit, offset: $offset) { + \${generateGraphQLFields(model)} + } + } + \\\`; + return this.executeQuery<\${modelName}[]>(query, variables); + } + + async get\${modelName}(id: string): Promise> { + const query = gql\\\` + query Get\${modelName}($id: ID!) { + \${lowerName}(id: $id) { + \${generateGraphQLFields(model)} + } + } + \\\`; + return this.executeQuery<\${modelName}>(query, { id }); + } + + async create\${modelName}(input: Create\${modelName}Input): Promise> { + const mutation = gql\\\` + mutation Create\${modelName}($input: \${modelName}Input!) { + create\${modelName}(input: $input) { + \${generateGraphQLFields(model)} + } + } + \\\`; + return this.executeMutation<\${modelName}>(mutation, { input }); + } + + async update\${modelName}(id: string, input: Update\${modelName}Input): Promise> { + const mutation = gql\\\` + mutation Update\${modelName}($id: ID!, $input: \${modelName}UpdateInput!) { + update\${modelName}(id: $id, input: $input) { + \${generateGraphQLFields(model)} + } + } + \\\`; + return this.executeMutation<\${modelName}>(mutation, { id, input }); + } + + async delete\${modelName}(id: string): Promise> { + const mutation = gql\\\` + mutation Delete\${modelName}($id: ID!) { + delete\${modelName}(id: $id) + } + \\\`; + return this.executeMutation(mutation, { id }); + } +\`; + } + + content += '}\\n'; + return content; +}`, + `plugin "./plugins/api-client.js" { + output "./generated/api-client.ts" + clientType "rest" + httpLibrary "fetch" + baseUrl "/api/v1" + authentication { + type "bearer" + headerName "Authorization" + } + generateTypes true + includeValidation false + errorHandling "return" +}`, + `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("USER") + active Boolean @default(true) + createdAt Date @default("now()") +} + +model Post { + id String @id @default("nanoid()") + title String @required + content String @required + authorId String @required + published Boolean @default(false) + createdAt Date @default("now()") +} + +plugin "./plugins/api-client.js" { + output "./api-client.ts" + clientType "rest" + httpLibrary "fetch" + baseUrl "/api/v1" + generateTypes true +}`, + `import APIClient from './api-client'; + +// Initialize client +const client = new APIClient('https://api.example.com'); + +// Set authentication token +client.setAuthToken('your-jwt-token'); + +// Use the client +async function example() { + // Get all users with pagination + const usersResponse = await client.user.getAll({ + page: 1, + limit: 10, + search: 'john' + }); + + if (usersResponse.success) { + console.log('Users:', usersResponse.data); + console.log('Total:', usersResponse.total); + } + + // Get user by ID + const userResponse = await client.user.getById('user-123'); + + if (userResponse.success) { + console.log('User:', userResponse.data); + } + + // Create new user + const newUserResponse = await client.user.create({ + email: 'john@example.com', + name: 'John Doe', + role: UserRole.USER + }); + + if (newUserResponse.success) { + console.log('Created user:', newUserResponse.data); + } + + // Update user + const updateResponse = await client.user.update('user-123', { + name: 'John Smith' + }); + + // Delete user + const deleteResponse = await client.user.delete('user-123'); +}`, + `// Bearer token authentication +authentication: { + type: "bearer", + headerName: "Authorization" +} + +// API key authentication +authentication: { + type: "apikey", + headerName: "X-API-Key" +} + +// Basic authentication +authentication: { + type: "basic", + headerName: "Authorization" +} + +// Custom authentication +authentication: { + type: "custom", + headerName: "X-Custom-Auth" +}`, + `// Return errors in response (default) +errorHandling: "return" +const response = await client.user.getById('123'); +if (!response.success) { + console.error(response.error); +} + +// Throw errors as exceptions +errorHandling: "throw" +try { + const user = await client.user.getById('123'); +} catch (error) { + console.error(error.message); +} + +// Use callback for error handling +errorHandling: "callback" +const response = await client.user.getById('123', { + onError: (error) => console.error(error) +});`, + `// Using AbortController for request cancellation +const controller = new AbortController(); + +const response = await client.user.getAll({}, { + signal: controller.signal +}); + +// Cancel the request +controller.abort();`, + `// Add custom headers to requests +const response = await client.user.getById('123', { + headers: { + 'X-Custom-Header': 'value', + 'Accept-Language': 'en-US' + } +});`, + `// Always use generated types +interface UserWithPosts extends User { + posts: Post[]; +} + +// Type-safe error handling +function handleUserResponse(response: APIResponse) { + if (response.success) { + // TypeScript knows response.data is User + console.log(response.data.email); + } else { + // TypeScript knows response.error exists + console.error(response.error); + } +}`, + `// Centralized error handling +class APIErrorHandler { + static handle(response: APIResponse) { + if (!response.success) { + if (response.errors) { + // Handle validation errors + Object.entries(response.errors).forEach(([field, messages]) => { + console.error(\`\${field}: \${messages.join(', ')}\`); + }); + } else { + // Handle general errors + console.error(response.error); + } + } + } +} + +// Usage +const response = await client.user.create(userData); +APIErrorHandler.handle(response);`, + `// Extend base client for custom behavior +class CustomAPIClient extends APIClient { + constructor(baseUrl?: string) { + super(baseUrl); + this.setupInterceptors(); + } + + private setupInterceptors() { + // Add request logging + const originalRequest = this.request; + this.request = async (method, url, data, options) => { + console.log(\`\${method} \${url}\`, data); + return originalRequest.call(this, method, url, data, options); + }; + } +}`, + `// Simple in-memory cache +class CachedAPIClient extends APIClient { + private cache = new Map(); + private cacheTimeout = 5 * 60 * 1000; // 5 minutes + + async getCached(key: string, fetcher: () => Promise>): Promise> { + const cached = this.cache.get(key); + + if (cached && Date.now() - cached.timestamp < this.cacheTimeout) { + return { success: true, data: cached.data }; + } + + const response = await fetcher(); + + if (response.success) { + this.cache.set(key, { + data: response.data, + timestamp: Date.now() + }); + } + + return response; + } +}`, + `// Ensure your API server allows CORS +// Add appropriate headers in your API configuration + +// For development, you might need to proxy requests +const client = new APIClient('/api/proxy');`, + `// Check token format and expiration +function isTokenValid(token: string): boolean { + try { + const payload = JSON.parse(atob(token.split('.')[1])); + return payload.exp * 1000 > Date.now(); + } catch { + return false; + } +} + +// Refresh token automatically +client.setAuthToken(await refreshToken());`, + `// Implement retry logic +async function withRetry( + operation: () => Promise>, + maxRetries: number = 3 +): Promise> { + for (let i = 0; i < maxRetries; i++) { + try { + const result = await operation(); + if (result.success) return result; + + if (i === maxRetries - 1) return result; + await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); + } catch (error) { + if (i === maxRetries - 1) throw error; + } + } + + throw new Error('Max retries exceeded'); +}`, + `// Add to base client +private logRequest(method: string, url: string, data?: any) { + if (process.env.NODE_ENV === 'development') { + console.group(\`API \${method} \${url}\`); + if (data) console.log('Data:', data); + console.groupEnd(); + } +}`, + `// Validate response structure +function validateResponse(response: any): response is APIResponse { + return ( + typeof response === 'object' && + typeof response.success === 'boolean' && + (response.success ? 'data' in response : 'error' in response) + ); +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('API Client Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates REST and GraphQL API clients from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    API Client Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates REST and GraphQL API clients from .idea schema files. The plugin will transform your schema models into type-safe API client libraries with full CRUD operations. +

    + +
    +

    1. Overview

    +

    + API clients provide a convenient interface for interacting with backend services. This plugin generates type-safe API clients from your .idea schema, including: +

    +
      +
    • REST Clients: HTTP-based API clients with fetch/axios
    • +
    • GraphQL Clients: Apollo Client or custom GraphQL clients
    • +
    • Type Safety: Full TypeScript support with generated types
    • +
    • CRUD Operations: Create, Read, Update, Delete methods
    • +
    • Authentication: Built-in auth handling
    • +
    • Error Handling: Comprehensive error management
    • +
    +
    + +
    +

    2. Prerequisites

    +

    + Before implementing the API client generator plugin, ensure you have the necessary development environment and dependencies. This section covers the essential requirements and setup needed to successfully create and use the plugin. +

    +
      +
    • Node.js 16+ and npm/yarn
    • +
    • TypeScript 4.0+
    • +
    • Basic understanding of REST and GraphQL APIs
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    + The plugin structure defines the core architecture and configuration interface for the API client generator. This includes the main plugin function, configuration types, and the overall organization of the generated client code. +

    + + {examples[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle API client generation. This includes configuration validation, content generation, file writing, and error handling throughout the generation process. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for API client generation. It orchestrates the entire process from configuration validation through content generation to file output, ensuring proper error handling and logging throughout. +

    + + {examples[1]} + + +

    4.2. Generation Functions

    +

    + The generation functions handle the creation of specific parts of the API client code. These utility functions generate file headers, imports, type definitions, base client classes, and model-specific client methods, ensuring consistent code structure and proper TypeScript typing. +

    + + {examples[2]} + + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + + + {examples[6]} + +
    + +
    +

    5. Schema Configuration

    +

    Add the API Client plugin to your .idea schema file:

    + + {examples[7]} + + +

    Configuration Options

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for the API client + + + clientType + 'rest'|'graphql'|'both' + Required + Type of client to generate + + + httpLibrary + 'fetch'|'axios' + 'fetch' + HTTP library to use + + + baseUrl + string + '/api' + Base URL for API requests + + + authentication + object + undefined + Authentication configuration + + + generateTypes + boolean + true + Generate TypeScript types + + + includeValidation + boolean + false + Include request validation + + + errorHandling + 'throw'|'return'|'callback' + 'return' + Error handling strategy + +
    +
    + +
    +

    6. Usage Examples

    +

    + This section demonstrates practical usage of the API client generator plugin with real-world examples. The examples show how to configure the plugin in schema files and how to use the generated client code in applications. +

    + +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate API clients. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces a functional REST API client. +

    + + {examples[8]} + + +

    6.2. Generated Client Usage

    +

    + The generated client provides a type-safe interface for interacting with your API endpoints. This example demonstrates how to initialize the client, set authentication, and perform common CRUD operations with proper error handling and TypeScript support. +

    + + {examples[9]} + +
    + +
    +

    7. Advanced Features

    +

    + Advanced features extend the basic API client functionality with sophisticated authentication, error handling, request management, and customization options. These features enable production-ready API clients that can handle complex scenarios and enterprise requirements. +

    + +

    7.1. Authentication Strategies

    + + {examples[10]} + + +

    7.2. Error Handling Strategies

    +

    + Error handling strategies determine how the API client responds to and manages different types of errors. The plugin supports multiple approaches including returning errors in responses, throwing exceptions, and using callback functions for flexible error management. +

    + + {examples[11]} + + +

    7.3. Request Cancellation

    +

    + Request cancellation allows you to abort ongoing API requests when they are no longer needed. This is essential for preventing unnecessary network traffic and improving application performance, especially in scenarios with user navigation or component unmounting. +

    + + {examples[12]} + + +

    7.4. Custom Headers

    +

    + Custom headers enable you to add additional metadata to API requests for features like localization, custom authentication, tracking, or API versioning. The client supports both global and per-request header configuration. +

    + + {examples[13]} + +
    + +
    +

    8. Best Practices

    +

    + Best practices ensure your API client implementation is maintainable, reliable, and follows industry standards. These guidelines cover type safety, error handling, performance optimization, and code organization for production-ready applications. +

    + +

    8.1. Type Safety

    +

    + Type safety is crucial for preventing runtime errors and improving developer experience. Always use the generated TypeScript types and interfaces to ensure compile-time validation and better IDE support with autocomplete and error detection. +

    + + {examples[14]} + + +

    8.2. Error Handling

    +

    + Proper error handling ensures your application can gracefully handle API failures, validation errors, and network issues. Implement centralized error handling patterns and provide meaningful feedback to users while logging appropriate details for debugging. +

    + + {examples[15]} + + +

    8.3. Request Interceptors

    +

    + Request interceptors allow you to modify requests before they are sent or responses before they are processed. This is useful for adding logging, authentication tokens, request transformation, or implementing cross-cutting concerns like analytics. +

    + + {examples[16]} + + +

    8.4. Caching Strategy

    +

    + Implementing a caching strategy reduces unnecessary API calls and improves application performance. Consider caching frequently accessed data with appropriate expiration times and cache invalidation strategies for data consistency. +

    + + {examples[17]} + +
    + +
    +

    9. Troubleshooting

    +

    + This section addresses common issues and debugging techniques when working with the generated API clients. Understanding these solutions helps resolve typical problems encountered during development and deployment. +

    + +

    9.1. Common Issues

    +

    + Common issues include CORS errors, authentication failures, and network timeouts. These problems often arise from configuration mismatches, expired tokens, or network connectivity issues that can be resolved with proper debugging and configuration. +

    + +

    1. CORS Errors

    + + {examples[18]} + + +

    2. Authentication Failures

    + + {examples[19]} + + +

    3. Network Timeouts

    + + {examples[20]} + + +

    9.2. Debugging Tips

    +

    + Debugging tips help identify and resolve issues during development and production. These techniques include request logging, response validation, and monitoring tools that provide visibility into API client behavior and performance. +

    + +

    1. Enable Request Logging

    + + {examples[21]} + + +

    2. Response Validation

    + + {examples[22]} + +
    + +
    +

    + This tutorial provides a comprehensive foundation for creating API clients from .idea files. The generated clients provide type-safe, feature-rich interfaces for interacting with REST and GraphQL APIs. +

    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/advance-tsmorph-pluginn.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/advance-tsmorph-pluginn.tsx new file mode 100644 index 0000000..889a773 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/advance-tsmorph-pluginn.tsx @@ -0,0 +1,142 @@ +import { H1, H2, P, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; +const examples = [ +`// Add a class with decorators +sourceFile.addClass({ + name: "UserController", + isExported: true, + decorators: [ + { + name: "Controller", + arguments: ["'users'"], + }, + ], + methods: [ + { + name: "getUser", + decorators: [ + { + name: "Get", + arguments: ["':id'"], + }, + ], + parameters: [ + { + name: "id", + type: "string", + decorators: [ + { + name: "Param", + arguments: ["'id'"], + }, + ], + }, + ], + returnType: "Promise", + statements: "return this.userService.findById(id);", + }, + ], +});`, +`// Generate mapped types +sourceFile.addTypeAlias({ + name: "PartialUser", + type: "{ [K in keyof User]?: User[K] }", +}); + +// Generate conditional types +sourceFile.addTypeAlias({ + name: "NonNullable", + typeParameters: [{ name: "T" }], + type: "T extends null | undefined ? never : T", +}); + +// Generate template literal types +sourceFile.addTypeAlias({ + name: "EventName", + typeParameters: [{ name: "T", constraint: "string" }], + type: \`on\${Capitalize}\`, +});`, +`// Add module declaration +sourceFile.addModule({ + name: "Express", + declarationKind: ModuleDeclarationKind.Module, + statements: [ + { + kind: StructureKind.Interface, + name: "Request", + properties: [ + { name: "user", type: "User", hasQuestionToken: true }, + ], + }, + ], +}); + +// Add ambient module +sourceFile.addModule({ + name: '"my-library"', + declarationKind: ModuleDeclarationKind.Module, + hasDeclareKeyword: true, + statements: [ + "export function myFunction(): void;", + ], +});`, +`// Find and modify existing interfaces +const existingInterface = sourceFile.getInterface("User"); +if (existingInterface) { + // Add new properties + existingInterface.addProperty({ + name: "lastLoginAt", + type: "Date", + hasQuestionToken: true, + }); + + // Modify existing properties + const emailProp = existingInterface.getProperty("email"); + if (emailProp) { + emailProp.setType("string & { readonly brand: 'Email' }"); + } + + // Add extends clause + existingInterface.addExtends("BaseEntity"); +} + +// Remove nodes +const deprecatedMethod = sourceFile.getFunction("oldFunction"); +deprecatedMethod?.remove();` +]; +export default function AdvanceTsMorphPlugin() { + + + return ( +
    +

    6. Advanced ts-morph Features

    +

    + Advanced ts-morph features enable sophisticated code generation scenarios including decorators, complex type systems, module declarations, and code manipulation. These features are essential for building production-ready plugins that handle enterprise-level requirements. +

    + +

    6.1. Working with Decorators

    +

    + Decorators are essential for modern TypeScript applications, especially when working with frameworks like Angular, NestJS, or TypeORM. ts-morph provides comprehensive support for generating classes and methods with decorators. +

    + {examples[0]} + +

    6.2. Generating Complex Types

    +

    + Complex type generation includes mapped types, conditional types, and template literal types that leverage TypeScript's advanced type system. These features enable the creation of sophisticated type-safe APIs and utility types. +

    + {examples[1]} + +

    6.3. Working with Modules

    +

    + Module declarations and ambient modules are crucial for creating type definitions and extending existing libraries. This section covers both namespace-style modules and modern ES module patterns. +

    + {examples[2]} + +

    6.4. Manipulating Existing Code

    +

    + Code manipulation capabilities allow plugins to modify existing TypeScript files, add new functionality, and refactor code structures. This is particularly useful for migration tools and code modernization plugins. +

    + {examples[3]} +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx new file mode 100644 index 0000000..86a16db --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx @@ -0,0 +1,203 @@ +import { H1, H2, P } from '../../../../components/index.js' +import Code from '../../../../components/Code.js' + +const examples = [ +`interface PluginOptions { + readonly input: string; + readonly output: string; + readonly strict?: boolean; +} + +function validateOptions(options: unknown): asserts options is PluginOptions { + if (typeof options !== 'object' || options === null) { + throw new Error('Options must be an object'); + } + + const opts = options as Record; + + if (typeof opts.input !== 'string') { + throw new Error('input must be a string'); + } + + if (typeof opts.output !== 'string') { + throw new Error('output must be a string'); + } +}`, +`class PluginError extends Error { + constructor( + message: string, + public readonly code: string, + public readonly details?: any + ) { + super(message); + this.name = 'PluginError'; + } +} + +async function safeGenerate(config: PluginConfig): Promise { + try { + await generator.generate(); + } catch (error) { + if (error instanceof SyntaxError) { + throw new PluginError( + 'Invalid JSON in input file', + 'INVALID_JSON', + { originalError: error.message } + ); + } + + if (error.code === 'ENOENT') { + throw new PluginError( + 'Input file not found', + 'FILE_NOT_FOUND', + { path: config.input } + ); + } + + throw error; + } +}`, +`class OptimizedGenerator { + private typeCache = new Map(); + private interfaceCache = new Map(); + + private getCachedType(property: SchemaProperty): string { + const cacheKey = JSON.stringify(property); + + if (this.typeCache.has(cacheKey)) { + return this.typeCache.get(cacheKey)!; + } + + const type = this.mapSchemaTypeToTypeScript(property); + this.typeCache.set(cacheKey, type); + + return type; + } + + private batchAddProperties( + interfaceDecl: InterfaceDeclaration, + properties: Record + ): void { + const propertyStructures = Object.entries(properties).map(([name, prop]) => ({ + name, + type: this.getCachedType(prop), + hasQuestionToken: !prop.required, + })); + + interfaceDecl.addProperties(propertyStructures); + } +}`, +`// generators/interface-generator.ts +export class InterfaceGenerator { + generate(schema: Schema): InterfaceDeclaration { + // Interface-specific logic + } +} + +// generators/type-generator.ts +export class TypeGenerator { + generate(schema: Schema): TypeAliasDeclaration { + // Type alias-specific logic + } +} + +// generators/enum-generator.ts +export class EnumGenerator { + generate(schema: EnumSchema): EnumDeclaration { + // Enum-specific logic + } +} + +// main-plugin.ts +export class MainPlugin { + constructor( + private interfaceGenerator: InterfaceGenerator, + private typeGenerator: TypeGenerator, + private enumGenerator: EnumGenerator + ) {} + + async generate(config: PluginConfig): Promise { + // Orchestrate all generators + } +}`, +`function generateJSDocComment( + property: SchemaProperty, + includeExamples: boolean = true +): string { + const parts: string[] = []; + + if (property.description) { + parts.push(property.description); + } + + if (property.default !== undefined) { + parts.push(\`@default \${JSON.stringify(property.default)}\`); + } + + if (includeExamples && property.example) { + parts.push(\`@example \${property.example}\`); + } + + if (property.deprecated) { + parts.push(\`@deprecated \${property.deprecated}\`); + } + + return parts.length > 0 ? parts.join('\\n') : ''; +}` +]; + +export default function BestPractices() { + return ( +
    +

    8. Best Practices

    +

    + Following best practices ensures your plugins are maintainable, performant, and reliable in production environments. These guidelines cover type safety, error handling, performance optimization, and code organization strategies. +

    + +

    8.1. Type Safety

    +

    + Type safety is fundamental to building reliable plugins that catch errors at compile time rather than runtime. Always use TypeScript interfaces and proper type validation throughout your plugin implementation. +

    +

    + Always use TypeScript interfaces for your plugin configuration and data structures: +

    + {examples[0]} + +

    8.2. Error Handling

    +

    + Comprehensive error handling provides clear feedback to users and helps with debugging when things go wrong. Implement custom error types and meaningful error messages to improve the developer experience. +

    +

    + Implement comprehensive error handling: +

    + {examples[1]} + +

    8.3. Performance Optimization

    +

    + Performance optimization becomes crucial when dealing with large schemas or generating substantial amounts of code. Implement caching strategies and batch processing to maintain reasonable execution times. +

    +

    + For large schemas, optimize performance: +

    + {examples[2]} + +

    8.4. Code Organization

    +

    + Proper code organization makes your plugin easier to maintain, test, and extend. Separate concerns into focused classes and modules that each handle specific aspects of the generation process. +

    +

    + Structure your plugin code for maintainability: +

    + {examples[3]} + +

    8.5. Documentation Generation

    +

    + Documentation generation ensures your generated code is self-documenting and provides valuable context for developers. Implement comprehensive JSDoc comment generation with examples and type information. +

    +

    + Add comprehensive JSDoc comments: +

    + {examples[4]} +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx new file mode 100644 index 0000000..cdaa8c4 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx @@ -0,0 +1,521 @@ +import { H1, H2, P, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const examples = [ + `// src/types.ts +export interface SchemaProperty { + type: string; + required?: boolean; + description?: string; + default?: any; + items?: SchemaProperty; // For arrays + properties?: Record; // For objects +} + +export interface Schema { + name: string; + description?: string; + properties: Record; + required?: string[]; +} + +export interface PluginConfig { + input: string; + output: string; + namespace?: string; + generateComments?: boolean; + generateUtilityTypes?: boolean; + exportType?: 'named' | 'default' | 'namespace'; +}`, + `// src/plugin.ts +import { Project, SourceFile, InterfaceDeclaration } from "ts-morph"; +import { Schema, SchemaProperty, PluginConfig } from "./types"; +import fs from "fs/promises"; +import path from "path"; + +export class TypeScriptInterfaceGenerator { + private project: Project; + private config: PluginConfig; + + constructor(config: PluginConfig) { + this.config = config; + this.project = new Project({ + compilerOptions: { + target: 99, // Latest + module: 1, // CommonJS + declaration: true, + strict: true, + }, + }); + } + + async generate(): Promise { + try { + // Read input schema + const schemas = await this.loadSchemas(); + + // Create source file + const sourceFile = this.project.createSourceFile( + this.config.output, + "", + { overwrite: true } + ); + + // Generate file header + this.addFileHeader(sourceFile); + + // Generate interfaces for each schema + for (const schema of schemas) { + this.generateInterface(sourceFile, schema); + } + + // Generate utility types if requested + if (this.config.generateUtilityTypes) { + this.generateUtilityTypes(sourceFile, schemas); + } + + // Wrap in namespace if specified + if (this.config.namespace) { + this.wrapInNamespace(sourceFile); + } + + // Save the file + await sourceFile.save(); + + console.log(\`✅ Generated TypeScript interfaces: \${this.config.output}\`); + } catch (error) { + console.error("❌ Generation failed:", error); + throw error; + } + } + + private async loadSchemas(): Promise { + const content = await fs.readFile(this.config.input, "utf-8"); + const data = JSON.parse(content); + + // Handle both single schema and array of schemas + return Array.isArray(data) ? data : [data]; + } + + private addFileHeader(sourceFile: SourceFile): void { + const timestamp = new Date().toISOString(); + sourceFile.insertText(0, \` +/** + * Generated TypeScript interfaces + * Generated at: \${timestamp} + * Source: \${this.config.input} + * + * This file is auto-generated. Do not edit manually. + */ +\`); + } + + private generateInterface(sourceFile: SourceFile, schema: Schema): void { + const interfaceDeclaration = sourceFile.addInterface({ + name: schema.name, + isExported: this.config.exportType !== 'namespace', + }); + + // Add JSDoc comment if enabled + if (this.config.generateComments && schema.description) { + interfaceDeclaration.addJsDoc({ + description: schema.description, + }); + } + + // Add properties + for (const [propName, propSchema] of Object.entries(schema.properties)) { + this.addProperty(interfaceDeclaration, propName, propSchema, schema.required); + } + } + + private addProperty( + interfaceDecl: InterfaceDeclaration, + name: string, + property: SchemaProperty, + requiredFields?: string[] + ): void { + const isRequired = requiredFields?.includes(name) ?? property.required ?? false; + const typeString = this.mapSchemaTypeToTypeScript(property); + + const propertySignature = interfaceDecl.addProperty({ + name, + type: typeString, + hasQuestionToken: !isRequired, + }); + + // Add JSDoc comment if enabled + if (this.config.generateComments) { + const jsdocParts: string[] = []; + + if (property.description) { + jsdocParts.push(property.description); + } + + if (property.default !== undefined) { + jsdocParts.push(\`@default \${JSON.stringify(property.default)}\`); + } + + if (jsdocParts.length > 0) { + propertySignature.addJsDoc({ + description: jsdocParts.join('\n'), + }); + } + } + } + + private mapSchemaTypeToTypeScript(property: SchemaProperty): string { + switch (property.type) { + case 'string': + return 'string'; + case 'number': + case 'integer': + return 'number'; + case 'boolean': + return 'boolean'; + case 'array': + if (property.items) { + const itemType = this.mapSchemaTypeToTypeScript(property.items); + return \`\${itemType}[]\`; + } + return 'any[]'; + case 'object': + if (property.properties) { + // Generate inline interface + const props = Object.entries(property.properties) + .map(([key, prop]) => { + const type = this.mapSchemaTypeToTypeScript(prop); + const optional = prop.required ? '' : '?'; + return \`\${key}\${optional}: \${type}\`; + }) + .join('; '); + return \`{ \${props} }\`; + } + return 'Record'; + default: + // Assume it's a reference to another interface + return property.type; + } + } + + private generateUtilityTypes(sourceFile: SourceFile, schemas: Schema[]): void { + sourceFile.addStatements("\n// Utility Types"); + + for (const schema of schemas) { + const interfaceName = schema.name; + + // Generate Create input type (omit auto-generated fields) + sourceFile.addTypeAlias({ + name: \`Create\${interfaceName}Input\`, + isExported: this.config.exportType !== 'namespace', + type: \`Omit<\${interfaceName}, 'id' | 'createdAt' | 'updatedAt'>\`, + }); + + // Generate Update input type (all fields optional) + sourceFile.addTypeAlias({ + name: \`Update\${interfaceName}Input\`, + isExported: this.config.exportType !== 'namespace', + type: \`Partial<\${interfaceName}>\`, + }); + + // Generate keys type + sourceFile.addTypeAlias({ + name: \`\${interfaceName}Keys\`, + isExported: this.config.exportType !== 'namespace', + type: \`keyof \${interfaceName}\`, + }); + } + + // Generate union type of all models + if (schemas.length > 1) { + const allTypes = schemas.map(s => s.name).join(' | '); + sourceFile.addTypeAlias({ + name: 'AnyModel', + isExported: this.config.exportType !== 'namespace', + type: allTypes, + }); + } + } + + private wrapInNamespace(sourceFile: SourceFile): void { + const content = sourceFile.getFullText(); + sourceFile.removeText(); + + // Extract header comments + const headerMatch = content.match(/^(\/\*\*[\s\S]*?\*\/\s*)/); + const header = headerMatch ? headerMatch[1] : ''; + const bodyContent = content.replace(header, ''); + + // Add header back + if (header) { + sourceFile.insertText(0, header); + } + + // Create namespace + const namespace = sourceFile.addNamespace({ + name: this.config.namespace!, + isExported: this.config.exportType === 'default' ? false : true, + }); + + // Add content to namespace + namespace.addStatements(bodyContent.trim()); + + // Add default export if specified + if (this.config.exportType === 'default') { + sourceFile.addExportAssignment({ + expression: this.config.namespace!, + isExportEquals: false, + }); + } + } +}`, + `// src/index.ts +import { TypeScriptInterfaceGenerator } from "./plugin"; +import { PluginConfig } from "./types"; + +export async function generateTypeScriptInterfaces(config: PluginConfig): Promise { + const generator = new TypeScriptInterfaceGenerator(config); + await generator.generate(); +} + +export * from "./types"; +export { TypeScriptInterfaceGenerator }; + +// CLI usage +if (require.main === module) { + const config: PluginConfig = { + input: process.argv[2] || "examples/input.json", + output: process.argv[3] || "examples/output.ts", + generateComments: true, + generateUtilityTypes: true, + exportType: 'named', + }; + + generateTypeScriptInterfaces(config).catch(console.error); +}`, + `// examples/input.json +[ + { + "name": "User", + "description": "Represents a user in the system", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the user" + }, + "email": { + "type": "string", + "description": "User's email address" + }, + "name": { + "type": "string", + "description": "User's full name" + }, + "age": { + "type": "number", + "description": "User's age in years" + }, + "isActive": { + "type": "boolean", + "description": "Whether the user account is active", + "default": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User's assigned roles" + }, + "profile": { + "type": "object", + "properties": { + "bio": { + "type": "string" + }, + "avatar": { + "type": "string" + } + }, + "description": "User's profile information" + }, + "createdAt": { + "type": "string", + "description": "Account creation timestamp" + } + }, + "required": ["id", "email", "name"] + }, + { + "name": "Post", + "description": "Represents a blog post", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the post" + }, + "title": { + "type": "string", + "description": "Post title" + }, + "content": { + "type": "string", + "description": "Post content" + }, + "authorId": { + "type": "string", + "description": "ID of the post author" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Post tags" + }, + "publishedAt": { + "type": "string", + "description": "Publication timestamp" + } + }, + "required": ["id", "title", "content", "authorId"] + } +]`, + `npx ts-node src/index.ts examples/input.json examples/output.ts`, + `// examples/output.ts +/** + * Generated TypeScript interfaces + * Generated at: 2024-01-15T10:30:00.000Z + * Source: examples/input.json + * + * This file is auto-generated. Do not edit manually. + */ + +/** + * Represents a user in the system + */ +export interface User { + /** + * Unique identifier for the user + */ + id: string; + /** + * User's email address + */ + email: string; + /** + * User's full name + */ + name: string; + /** + * User's age in years + */ + age?: number; + /** + * Whether the user account is active + * @default true + */ + isActive?: boolean; + /** + * User's assigned roles + */ + roles?: string[]; + /** + * User's profile information + */ + profile?: { bio?: string; avatar?: string }; + /** + * Account creation timestamp + */ + createdAt?: string; +} + +/** + * Represents a blog post + */ +export interface Post { + /** + * Unique identifier for the post + */ + id: string; + /** + * Post title + */ + title: string; + /** + * Post content + */ + content: string; + /** + * ID of the post author + */ + authorId: string; + /** + * Post tags + */ + tags?: string[]; + /** + * Publication timestamp + */ + publishedAt?: string; +} + +// Utility Types +export type CreateUserInput = Omit; + +export type UpdateUserInput = Partial; + +export type UserKeys = keyof User; + +export type CreatePostInput = Omit; + +export type UpdatePostInput = Partial; + +export type PostKeys = keyof Post; + +export type AnyModel = User | Post;` +]; + +export default function CreateFirstPlugin() { + return ( +
    +

    5. Creating Your First Plugin

    +

    + Creating your first plugin with ts-morph involves understanding the complete workflow from schema processing to code generation. This comprehensive example demonstrates building a TypeScript interface generator that transforms JSON schemas into properly typed interfaces with full feature support. +

    +

    + Let's create a plugin that generates TypeScript interfaces from JSON schema definitions. This will demonstrate the core concepts of using ts-morph for code generation. +

    + +

    5.1. Define the Plugin Interface

    +

    + Defining clear interfaces for your plugin ensures type safety and provides a solid foundation for implementation. This section establishes the data structures and configuration options that will guide the entire plugin development process. +

    +

    First, let's define the types for our plugin:

    + {examples[0]} + +

    5.2. Core Plugin Implementation

    +

    + The core plugin implementation orchestrates the entire code generation process, from loading input schemas to generating and saving TypeScript files. This comprehensive class demonstrates best practices for plugin architecture and error handling. +

    + {examples[1]} + +

    5.3. Plugin Entry Point

    +

    + The plugin entry point provides a clean API for consumers and handles CLI integration. This section shows how to create both programmatic and command-line interfaces for your plugin, making it accessible in different usage scenarios. +

    + {examples[2]} + +

    5.4. Example Usage

    +

    + Example usage demonstrates the plugin in action with realistic data structures. This comprehensive example shows how the plugin processes complex schemas with various property types, relationships, and validation rules. +

    +

    Create an example schema file:

    + {examples[3]} +

    Run the plugin:

    + {examples[4]} +

    Generated output:

    + {examples[5]} +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/installation.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/installation.tsx new file mode 100644 index 0000000..ce9b086 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/installation.tsx @@ -0,0 +1,40 @@ +import { H1, H2, P, C, SS } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const examples = [ + `# Using npm +npm install --save-dev ts-morph + +# Using yarn +yarn add --dev ts-morph + +# Using Deno +deno add ts-morph@jsr:@ts-morph/ts-morph` +] + +export default function installation() { + return ( +
    +

    2. Installation

    +

    + Before starting with ts-morph plugin development, ensure you have the necessary tools and knowledge. This section outlines the essential requirements for successful plugin creation and provides installation guidance. +

    + +

    Before starting, ensure you have:

    + +
      +
    • Node.js 16+ and npm/yarn installed
    • +
    • TypeScript 4.0+ knowledge
    • +
    • Basic understanding of Abstract Syntax Trees (AST)
    • +
    • Familiarity with TypeScript interfaces, classes, and modules
    • +
    + +

    Installing ts-morph is straightforward and can be done using your preferred package manager. The library is available through npm, yarn, and even Deno for different development environments.

    + +

    Install ts-morph in your project:

    + + {examples[0]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/introduction.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/introduction.tsx new file mode 100644 index 0000000..7fe429b --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/introduction.tsx @@ -0,0 +1,40 @@ +import { H1, H2, P, C, SS } from '../../../../components/index.js'; + +export default function Introduction() { + return ( +
    +

    1. Introduction

    +

    + ts-morph is a powerful TypeScript library that wraps the TypeScript Compiler API, making it much easier to work with TypeScript Abstract Syntax Trees (AST). This introduction covers the fundamental concepts and advantages of using ts-morph for plugin development. +

    +

    Unlike string-based code generation, ts-morph provides:

    +
      +
    • Type-safe code manipulation: Work with actual TypeScript nodes instead of strings
    • +
    • Automatic formatting: Generated code is properly formatted and follows TypeScript conventions
    • +
    • IntelliSense support: Full IDE support when writing your plugins
    • +
    • AST navigation: Easy traversal and modification of code structures
    • +
    • Validation: Automatic syntax validation of generated code
    • +
    + +

    Why Use ts-morph for Plugins?

    +

    + Understanding the advantages of ts-morph over traditional code generation approaches helps you make informed decisions about plugin architecture. This comparison highlights the key benefits that make ts-morph an excellent choice for TypeScript code generation. +

    +

    Traditional code generation often involves:

    +
      +
    • Concatenating strings to build code
    • +
    • Manual indentation and formatting
    • +
    • Error-prone syntax construction
    • +
    • Difficulty maintaining complex code structures
    • +
    + +

    With ts-morph, you can:

    +
      +
    • Create TypeScript constructs programmatically
    • +
    • Leverage the compiler's knowledge for validation
    • +
    • Generate properly formatted, syntactically correct code
    • +
    • Easily modify existing code structures
    • +
    +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/references.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/references.tsx new file mode 100644 index 0000000..1feede4 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/references.tsx @@ -0,0 +1,69 @@ +import { H1, H2, H3, P, A } from '../../../../components/index.js' + +export default function References() { + return ( +
    +

    10. References

    +

    + This section provides comprehensive resources for continued learning and development with ts-morph. These references include official documentation, community resources, and related tools that enhance the plugin development experience. +

    + +

    10.1. Official Documentation

    +

    + Official documentation provides authoritative information about ts-morph APIs, TypeScript compiler internals, and AST manipulation techniques. +

    +

    + ts-morph Documentation: https://ts-morph.com/ +

    +

    + TypeScript Compiler API: https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API +

    +

    + TypeScript AST Viewer: https://ts-ast-viewer.com/ +

    + +

    10.2. Useful Resources

    +

    + Additional resources provide practical examples, community insights, and tools that complement the official documentation for comprehensive plugin development. +

    +

    + ts-morph GitHub Repository: https://github.com/dsherret/ts-morph +

    +

    + TypeScript Handbook: https://www.typescriptlang.org/docs/ +

    +

    + AST Explorer: https://astexplorer.net/ +

    + +

    10.3. Community Examples

    +

    + Community examples showcase real-world usage patterns and provide inspiration for advanced plugin development techniques. +

    +

    + ts-morph Examples: https://github.com/dsherret/ts-morph/tree/latest/packages/ts-morph/scripts +

    +

    + Code Generation Patterns: https://github.com/topics/code-generation +

    + +

    Related Tools

    +

    + TypeScript ESLint: For linting generated code +

    +

    + Prettier: For formatting generated code +

    +

    + ts-node: For running TypeScript directly +

    +

    + Jest: For testing your plugins +

    + +

    + This comprehensive guide provides everything you need to create powerful code generation plugins using ts-morph. The library's type-safe approach to code manipulation makes it an excellent choice for building robust, maintainable code generators that produce high-quality TypeScript output. +

    +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/setting-up-project.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/setting-up-project.tsx new file mode 100644 index 0000000..067696a --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/setting-up-project.tsx @@ -0,0 +1,63 @@ +import { H1, H2, P, C, SS } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const examples = [ + `mkdir ts-morph-plugin-tutorial +cd ts-morph-plugin-tutorial +npm init -y +npm install --save-dev typescript ts-morph @types/node`, +`{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}`, +`ts-morph-plugin-tutorial/ +├── src/ +│ ├── index.ts +│ ├── plugin.ts +│ └── types.ts +├── examples/ +│ ├── input.json +│ └── output.ts +├── tests/ +│ └── plugin.test.ts +├── package.json +└── tsconfig.json` +] +export default function SettingUpProject() { + return ( +
    +

    3. Setting Up the Project

    +

    + Setting up a proper project structure is crucial for maintainable plugin development. This section guides you through creating a well-organized TypeScript project with all necessary configurations and dependencies +

    +

    Let's create a new TypeScript project for our plugin:

    + + {examples[0]} + + +

    Create a basic tsconfig.json:

    + + {examples[1]} + + +

    Create the project structure:

    + + {examples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx new file mode 100644 index 0000000..e54e9c1 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx @@ -0,0 +1,147 @@ + +import { H1, P, C, B } from '../../../../components/index.js' +import Code from '../../../../components/Code.js' + +const examples = [ +`// tests/plugin.test.ts +import { TypeScriptInterfaceGenerator } from "../src/plugin"; +import { PluginConfig, Schema } from "../src/types"; +import { Project } from "ts-morph"; +import fs from "fs/promises"; +import path from "path"; + +describe("TypeScriptInterfaceGenerator", () => { + const testOutputDir = path.join(__dirname, "output"); + + beforeAll(async () => { + await fs.mkdir(testOutputDir, { recursive: true }); + }); + + afterAll(async () => { + await fs.rmdir(testOutputDir, { recursive: true }); + }); + + test("should generate basic interface", async () => { + const schema: Schema = { + name: "TestUser", + properties: { + id: { type: "string" }, + name: { type: "string" }, + age: { type: "number" }, + }, + required: ["id", "name"], + }; + + const inputFile = path.join(testOutputDir, "test-input.json"); + const outputFile = path.join(testOutputDir, "test-output.ts"); + + await fs.writeFile(inputFile, JSON.stringify(schema, null, 2)); + + const config: PluginConfig = { + input: inputFile, + output: outputFile, + generateComments: true, + }; + + const generator = new TypeScriptInterfaceGenerator(config); + await generator.generate(); + + // Verify the output + const generatedContent = await fs.readFile(outputFile, "utf-8"); + + expect(generatedContent).toContain("export interface TestUser"); + expect(generatedContent).toContain("id: string;"); + expect(generatedContent).toContain("name: string;"); + expect(generatedContent).toContain("age?: number;"); + }); + + test("should generate utility types", async () => { + const schema: Schema = { + name: "Product", + properties: { + id: { type: "string" }, + name: { type: "string" }, + price: { type: "number" }, + }, + required: ["id", "name", "price"], + }; + + const inputFile = path.join(testOutputDir, "product-input.json"); + const outputFile = path.join(testOutputDir, "product-output.ts"); + + await fs.writeFile(inputFile, JSON.stringify(schema, null, 2)); + + const config: PluginConfig = { + input: inputFile, + output: outputFile, + generateUtilityTypes: true, + }; + + const generator = new TypeScriptInterfaceGenerator(config); + await generator.generate(); + + const generatedContent = await fs.readFile(outputFile, "utf-8"); + + expect(generatedContent).toContain("CreateProductInput"); + expect(generatedContent).toContain("UpdateProductInput"); + expect(generatedContent).toContain("ProductKeys"); + }); + + test("should validate generated TypeScript", async () => { + const schema: Schema = { + name: "ValidatedInterface", + properties: { + id: { type: "string" }, + data: { + type: "object", + properties: { + nested: { type: "boolean" }, + }, + }, + }, + }; + + const inputFile = path.join(testOutputDir, "validated-input.json"); + const outputFile = path.join(testOutputDir, "validated-output.ts"); + + await fs.writeFile(inputFile, JSON.stringify(schema, null, 2)); + + const config: PluginConfig = { + input: inputFile, + output: outputFile, + }; + + const generator = new TypeScriptInterfaceGenerator(config); + await generator.generate(); + + // Validate the generated TypeScript compiles + const project = new Project(); + const sourceFile = project.addSourceFileAtPath(outputFile); + + const diagnostics = sourceFile.getPreEmitDiagnostics(); + expect(diagnostics).toHaveLength(0); + }); +});`, +`npm test` +]; + +export default function TestingYourPlugin() { + return ( +
    +

    7. Testing Your Plugin

    +

    + Comprehensive testing ensures your plugin works correctly across different scenarios and maintains reliability as it evolves. This section covers unit testing, integration testing, and validation strategies for ts-morph plugins. +

    + +

    + Create comprehensive tests for your plugin: +

    + {examples[0]} + +

    + Run tests: +

    + {examples[1]} +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/troubleshooting.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/troubleshooting.tsx new file mode 100644 index 0000000..68c2a5a --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/troubleshooting.tsx @@ -0,0 +1,183 @@ +import { H1, H2, H3, P } from '../../../../components/index.js' +import Code from '../../../../components/Code.js' + +const examples = [ +`function validateGeneratedCode(sourceFile: SourceFile): void { + const diagnostics = sourceFile.getPreEmitDiagnostics(); + + if (diagnostics.length > 0) { + const errors = diagnostics.map(d => ({ + message: d.getMessageText(), + line: d.getLineNumber(), + file: d.getSourceFile()?.getFilePath() + })); + + throw new Error(\`Generated TypeScript has errors: \${JSON.stringify(errors, null, 2)}\`); + } +}`, +`function detectCircularReferences(schemas: Schema[]): string[] { + const graph = new Map>(); + const cycles: string[] = []; + + // Build dependency graph + for (const schema of schemas) { + const deps = new Set(); + + for (const prop of Object.values(schema.properties)) { + if (prop.type && schemas.some(s => s.name === prop.type)) { + deps.add(prop.type); + } + } + + graph.set(schema.name, deps); + } + + // Detect cycles using DFS + const visited = new Set(); + const recursionStack = new Set(); + + function hasCycle(node: string): boolean { + if (recursionStack.has(node)) { + cycles.push(node); + return true; + } + + if (visited.has(node)) { + return false; + } + + visited.add(node); + recursionStack.add(node); + + const deps = graph.get(node) || new Set(); + for (const dep of deps) { + if (hasCycle(dep)) { + return true; + } + } + + recursionStack.delete(node); + return false; + } + + for (const schema of schemas) { + hasCycle(schema.name); + } + + return cycles; +}`, +`class StreamingGenerator { + async generateLargeSchema(schemas: Schema[]): Promise { + const batchSize = 10; + + for (let i = 0; i < schemas.length; i += batchSize) { + const batch = schemas.slice(i, i + batchSize); + + // Process batch + await this.processBatch(batch); + + // Clear memory + if (global.gc) { + global.gc(); + } + } + } + + private async processBatch(schemas: Schema[]): Promise { + // Process smaller batches to avoid memory issues + } +}`, +`const DEBUG = process.env.DEBUG === 'true'; + +function debugLog(message: string, data?: any): void { + if (DEBUG) { + console.log(\`[DEBUG] \${message}\`, data ? JSON.stringify(data, null, 2) : ''); + } +} + +// Usage +debugLog('Processing schema', schema); +debugLog('Generated interface', interfaceDeclaration.getText());`, +`async function saveIntermediateResults( + sourceFile: SourceFile, + step: string +): Promise { + if (process.env.SAVE_INTERMEDIATE === 'true') { + const outputPath = \`debug-\${step}-\${Date.now()}.ts\`; + await fs.writeFile(outputPath, sourceFile.getFullText()); + console.log(\`Saved intermediate result: \${outputPath}\`); + } +}`, +`function validateStep( + sourceFile: SourceFile, + stepName: string +): void { + try { + const diagnostics = sourceFile.getPreEmitDiagnostics(); + if (diagnostics.length > 0) { + throw new Error(\`Step \${stepName} produced invalid TypeScript\`); + } + console.log(\`✅ Step \${stepName} completed successfully\`); + } catch (error) { + console.error(\`❌ Step \${stepName} failed:\`, error.message); + throw error; + } +}` +]; + +export default function Troubleshooting() { + return ( +
    +

    9. Troubleshooting

    +

    + Troubleshooting guides help developers quickly identify and resolve common issues encountered during plugin development. This section covers validation, debugging techniques, and solutions for typical problems. +

    + +

    9.1. Common Issues

    +

    + Common issues in ts-morph plugin development typically involve syntax validation, circular references, and memory management. Understanding these patterns helps prevent and resolve problems efficiently. +

    + +

    9.1.1. Invalid TypeScript Syntax

    +

    + Invalid TypeScript syntax can break the compilation process and prevent your plugin from generating usable code. Implement validation checks to catch syntax errors early in the generation process. +

    + {examples[0]} + +

    9.1.2. Circular Type References

    +

    + Circular type references can cause infinite loops and compilation errors. Detecting and handling these scenarios is crucial for plugins that work with complex, interconnected data structures. +

    + {examples[1]} + +

    9.1.3. Memory Issues with Large Schemas

    +

    + Memory management becomes important when processing large schemas or generating substantial amounts of code. Implement streaming and batching strategies to handle large-scale generation efficiently. +

    + {examples[2]} + +

    9.2. Debugging Tips

    +

    + Effective debugging techniques help identify issues quickly and understand the plugin's behavior during development. These tools and strategies provide visibility into the generation process. +

    + +

    9.2.1. Enable Verbose Logging

    +

    + Verbose logging provides detailed information about the plugin's execution flow, helping identify where issues occur and what data is being processed at each step. +

    + {examples[3]} + +

    9.2.2. Save Intermediate Results

    +

    + Saving intermediate results allows you to inspect the code generation process at different stages, making it easier to identify where problems occur and verify that each step produces the expected output. +

    + {examples[4]} + +

    9.2.3. Validate Each Step

    +

    + Step-by-step validation ensures that each phase of the generation process produces valid TypeScript code, helping catch issues early before they compound into larger problems. +

    + {examples[5]} +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/understanding-tsmorph-basics.tsx b/packages/www/plugins/docs/views/tutorials/components/ts-morph/understanding-tsmorph-basics.tsx new file mode 100644 index 0000000..51896ae --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/components/ts-morph/understanding-tsmorph-basics.tsx @@ -0,0 +1,344 @@ +import { H1, H2, P, C } from '../../../../components/index.js'; +import Code from '../../../../components/Code.js'; + +const examples = [ + `import { Project } from "ts-morph"; + +// Create a new project +const project = new Project({ + compilerOptions: { + target: ScriptTarget.ES2020, + module: ModuleKind.CommonJS, + }, +}); + +// Create a source file +const sourceFile = project.createSourceFile("example.ts", ""); + +// Add content to the file +sourceFile.addInterface({ + name: "User", + properties: [ + { name: "id", type: "string" }, + { name: "name", type: "string" }, + ], +}); + +// Get the generated code +console.log(sourceFile.getFullText()); +// Output: +// interface User { +// id: string; +// name: string; +// }`, +`// Add imports +sourceFile.addImportDeclaration({ + moduleSpecifier: "react", + namedImports: ["useState", "useEffect"], +}); + +// Add a class +sourceFile.addClass({ + name: "UserService", + isExported: true, + methods: [ + { + name: "getUser", + parameters: [{ name: "id", type: "string" }], + returnType: "Promise", + statements: "return fetch('/api/users/' + id).then(r => r.json());", + }, + ], +}); + +// Add a function +sourceFile.addFunction({ + name: "createUser", + isExported: true, + isAsync: true, + parameters: [{ name: "userData", type: "Partial" }], + returnType: "Promise", + statements: [ + "const response = await fetch('/api/users', {", + " method: 'POST',", + " headers: { 'Content-Type': 'application/json' },", + " body: JSON.stringify(userData)", + "});", + "return response.json();", + ], +}); + +// Add type aliases +sourceFile.addTypeAlias({ + name: "UserId", + isExported: true, + type: "string", +}); + +// Add enums +sourceFile.addEnum({ + name: "UserRole", + isExported: true, + members: [ + { name: "ADMIN", value: "admin" }, + { name: "USER", value: "user" }, + { name: "GUEST", value: "guest" }, + ], +});`, +`import { Project } from "ts-morph"; + +const project = new Project(); + +const source = project.createSourceFile("newFile.ts", null, { overwrite: true }); + +const myClass = source.addClass({ + name: "MyClass", +}); + +myClass.addMethod({ + name: "myMethod", + isDefaultExport: true + parameters: [{ name: "param1", type: "string" }], + returnType: "void", + statements: "console.log(param1);" +}); + +project.saveSync();`, +`export default class MyClass { + myMethod(param1: string): void { + console.log(param1); + } +}`, +`import { Project } from "ts-morph"; + +const project = new Project(); + +const source = project.createSourceFile("newFile.ts", null, { overwrite: true }); + +source.addFunction({ + name: "myFunction", + isExported: true, + isAsync: true, + parameters: [ + { name: "param1", type: "string" }, + { name: "param2", type: "number" } + ], + returnType: "void", + statements: [ + "console.log(param1);", + "console.log(param2);" + ] +}); + +project.saveSync();`, +`export async function myFunction(param1: string, param2: number): void { + console.log(param1); + console.log(param2); +}` +]; + +export default function UnderstandingTsMorphBasics() { + return ( +
    +

    4. Understanding ts-morph Basics

    +

    + Understanding the fundamental concepts of ts-morph is essential for effective plugin development. This section covers the core APIs, project management, source file manipulation, and code generation patterns that form the foundation of all ts-morph operations. +

    + +

    4.1. Project and Source Files

    +

    + The Project class is the entry point for all ts-morph operations, providing methods to create, load, and manage TypeScript source files. Understanding how to work with projects and source files is fundamental to building effective code generation plugins. +

    + + {examples[0]} + + +

    4.2. Adding Different Constructs

    +

    + ts-morph provides comprehensive APIs for adding various TypeScript constructs including imports, classes, functions, types, and enums. This section demonstrates the most commonly used patterns for generating different types of TypeScript code. +

    + + {examples[1]} + + +

    4.3. Exporting a Class

    +

    + Creating and exporting classes is a common requirement in TypeScript code generation. This example demonstrates the basic pattern for generating classes with methods, including proper export declarations and method implementations. +

    +

    A simple example of how to create a new TypeScript file with a class and a method using ts-morph looks like the following:

    + + {examples[2]} + + +

    This code will create a new TypeScript file newFile.ts with the following content:

    + + {examples[3]} + +

    You can use isExported or isDefaultExport to export or export default respectively. Also statements can be a string or an array of strings (string[]).

    + +

    4.4. Exporting a Function

    +

    + Function generation at the source file level provides flexibility for creating utility functions, API endpoints, and standalone operations. This section shows how to create functions with various configurations including async operations, parameters, and return types. +

    +

    Similar to adding a method to a class, you can use addFunction to add a function at the source file level. An example of how to use addFunction to add a function with arguments and a body looks like the following:

    + + {examples[4]} + +

    In the above example, myFunction takes two parameters, param1 of type string and param2 of type number. The function body contains two console.log statements.

    +

    After running the above code, the content of newFile.ts would look like the following:

    + + {examples[5]} + + +

    4.5. Exporting a Const

    +

    Constant declarations are essential for defining configuration values, default settings, and immutable data structures. The addVariableStatement method provides flexible options for creating various types of variable declarations with proper export handling.

    +

    To export a constant in ts-morph, you can utilize the addVariableStatement method on a SourceFile object. This method allows you to add a variable declaration to the file, including the capability to export the declaration.

    + + {`import { VariableDeclarationKind } from 'ts-morph'; + +source.addVariableStatement({ + isExported: true, + declarationKind: VariableDeclarationKind.Const, + declarations: [{ + name: "foo", + initializer: '\'bar\'' + }] +});`} + +

    The provided ts-morph script will generate the following code in the source file.

    + + {`export const foo = 'bar';`} + + +

    4.6. Exporting an Object

    +

    Export declarations provide a clean way to re-export multiple entities from other modules or to export collections of related functionality. This pattern is commonly used in index files and module aggregation scenarios.

    +

    To generate an export statement that directly exports multiple imported entities in a single line using ts-morph, you don't need to declare them as variables first. Instead, you can use the addExportDeclaration method directly after your imports. This approach is more straightforward and aligns with typical TypeScript import-export patterns.

    + + {`source.addExportDeclaration({ + namedExports: ['ComponentA', 'ComponentB', 'ComponentC'] +});`} + + +

    4.7. Exporting Types

    +

    Type exports are crucial for creating reusable type definitions that can be consumed by other modules. ts-morph provides dedicated methods for creating both type aliases and interfaces with proper export configurations.

    +

    To export a single type, you can use the addTypeAlias or addInterface method (depending on whether you are defining an alias or an interface), and set the isExported property to true. An example of exporting a type alias looks like the following:

    + + {`source.addTypeAlias({ + name: "ExampleType", + isExported: true, + type: "string | number" +});`} + +

    This will generate a file with the following content:

    + + {`export type ExampleType = string | number;`} + +

    To export multiple types at the same time, you can add multiple type declarations (either type aliases or interfaces) with the isExported property set to true for each. Alternatively, you can use the addExportDeclaration method to export previously declared types. An example of declaring and exporting multiple types looks like the following:

    + + {`source.addTypeAlias({ + name: "AnotherType", + isExported: true, + type: "boolean" +}); + +source.addInterface({ + name: "ExampleInterface", + isExported: true, + properties: [ + { name: "id", type: "number" }, + { name: "name", type: "string" } + ] +}); + +// Optionally, use addExportDeclaration to export all at once +source.addExportDeclaration({ + namedExports: ["ExampleType", "AnotherType", "ExampleInterface"] +});`} + +

    This will generate a file with the following content:

    + + {`export type ExampleType = string | number; +export type AnotherType = boolean; +export interface ExampleInterface { + id: number; + name: string; +}`} + + +

    4.8. Importing Values

    +

    Import declarations are essential for bringing external dependencies and modules into your generated code. The addImportDeclaration method provides comprehensive options for creating various types of import statements including named imports, default imports, and type imports.

    +

    To import a set of values from a module in ts-morph, you can use the addImportDeclaration method on a SourceFile object. This method allows you to add an import declaration to the code file you are working with. Here's how to use this method to import specific values from the react module:

    + + {`source.addImportDeclaration({ + moduleSpecifier: 'react', + namedImports: [ 'useState', 'useEffect' ] +});`} + +

    The provided ts-morph script will generate the following code in the source file:

    + + {`import { useState, useEffect } from 'react';`} + +

    You can also import types like the following:

    + + {`source.addImportDeclaration({ + moduleSpecifier: 'next', + namedImports: [ + 'NextApiRequest as Request', + 'NextApiResponse as as Response' + ] +});`} + +

    The above code renders the following:

    + + {`import type { + NextApiRequest as Request, + NextApiResponse as Response +} from 'next';`} + + +

    4.9. Importing Defaults

    +

    Default imports are commonly used for importing the main export from a module, such as React components or utility libraries. The same addImportDeclaration method handles default imports with a slightly different configuration.

    +

    To import a default from a module in ts-morph, you can also use the addImportDeclaration method:

    + + {`source.addImportDeclaration({ + moduleSpecifier: 'react', + defaultImport: 'React' +});`} + +

    This would create the following code:

    + + {`import React from 'react';`} + + +

    4.10. Working with Existing Code

    +

    Working with existing code is a powerful feature of ts-morph that allows you to modify, extend, and refactor existing TypeScript files. This capability is essential for plugins that need to augment or update existing codebases rather than generating new files from scratch.

    + + {`// Load existing files +project.addSourceFilesAtPaths("src/**/*.ts"); + +// Get a specific file +const existingFile = project.getSourceFile("src/models/User.ts"); + +// Find and modify existing constructs +const userInterface = existingFile?.getInterface("User"); +if (userInterface) { + // Add a new property + userInterface.addProperty({ + name: "email", + type: "string", + hasQuestionToken: true, // Makes it optional + }); + + // Add JSDoc comments + userInterface.addJsDoc({ + description: "Represents a user in the system", + tags: [ + { tagName: "example", text: "const user: User = { id: '1', name: 'John' };" }, + ], + }); +}`} + + +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/graphql-schema-plugin.tsx b/packages/www/plugins/docs/views/tutorials/graphql-schema-plugin.tsx new file mode 100644 index 0000000..940c46d --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/graphql-schema-plugin.tsx @@ -0,0 +1,892 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface GraphQLConfig { + output: string; + includeQueries?: boolean; + includeMutations?: boolean; + includeSubscriptions?: boolean; + customScalars?: Record; + generateInputTypes?: boolean; +} + +export default async function generateGraphQLSchema( + props: PluginProps<{ config: GraphQLConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`, + `export default async function generateGraphQLSchema( + props: PluginProps<{ config: GraphQLConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + if (!config.output) { + throw new Error('GraphQL plugin requires "output" configuration'); + } + + // Generate GraphQL schema + let schemaContent = ''; + + // Add custom scalars + schemaContent += generateCustomScalars(config.customScalars || {}); + + // Generate enums + if (schema.enum) { + schemaContent += generateEnums(schema.enum); + } + + // Generate types + if (schema.model) { + schemaContent += generateTypes(schema.model); + + if (config.generateInputTypes) { + schemaContent += generateInputTypes(schema.model); + } + } + + // Generate custom types + if (schema.type) { + schemaContent += generateCustomTypes(schema.type); + } + + // Generate root types + if (config.includeQueries) { + schemaContent += generateQueries(schema.model || {}); + } + + if (config.includeMutations) { + schemaContent += generateMutations(schema.model || {}); + } + + if (config.includeSubscriptions) { + schemaContent += generateSubscriptions(schema.model || {}); + } + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, schemaContent, 'utf8'); + + console.log(\`✅ GraphQL schema generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ GraphQL schema generation failed:', error.message); + throw error; + } +}`, + `function mapSchemaTypeToGraphQL(schemaType: string, customScalars: Record = {}): string { + // Check for custom scalar mappings first + if (customScalars[schemaType]) { + return customScalars[schemaType]; + } + + // Standard type mappings + const typeMap: Record = { + 'String': 'String', + 'Number': 'Float', + 'Integer': 'Int', + 'Boolean': 'Boolean', + 'Date': 'DateTime', + 'JSON': 'JSON', + 'ID': 'ID' + }; + + return typeMap[schemaType] || schemaType; +} + +function formatFieldType(column: any, customScalars: Record = {}): string { + let type = mapSchemaTypeToGraphQL(column.type, customScalars); + + // Handle arrays + if (column.multiple) { + type = \`[\${type}]\`; + } + + // Handle required fields + if (column.required) { + type += '!'; + } + + return type; +}`, + `function generateCustomScalars(customScalars: Record): string { + if (Object.keys(customScalars).length === 0) { + return \`# Custom Scalars +scalar DateTime +scalar JSON + +\`; + } + + let content = '# Custom Scalars\\n'; + content += 'scalar DateTime\\n'; + content += 'scalar JSON\\n'; + + for (const [name, description] of Object.entries(customScalars)) { + content += \`scalar \${name}\\n\`; + } + + return content + '\\n'; +} + +function generateEnums(enums: Record): string { + let content = '# Enums\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + content += \`enum \${enumName} {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateTypes(models: Record): string { + let content = '# Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`type \${modelName} {\\n\`; + + for (const column of model.columns || []) { + const fieldType = formatFieldType(column); + content += \` \${column.name}: \${fieldType}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +}`, + `function generateInputTypes(models: Record): string { + let content = '# Input Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + // Create input type + content += \`input \${modelName}Input {\\n\`; + + for (const column of model.columns || []) { + // Skip auto-generated fields like ID for input types + if (column.attributes?.id) continue; + + let fieldType = formatFieldType(column); + // Remove required constraint for input types (make them optional) + fieldType = fieldType.replace('!', ''); + + content += \` \${column.name}: \${fieldType}\\n\`; + } + + content += '}\\n\\n'; + + // Create update input type + content += \`input \${modelName}UpdateInput {\\n\`; + + for (const column of model.columns || []) { + let fieldType = formatFieldType(column); + // All fields are optional in update input + fieldType = fieldType.replace('!', ''); + + content += \` \${column.name}: \${fieldType}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateCustomTypes(types: Record): string { + let content = '# Custom Types\\n'; + + for (const [typeName, typeDef] of Object.entries(types)) { + content += \`type \${typeName} {\\n\`; + + for (const column of typeDef.columns || []) { + const fieldType = formatFieldType(column); + content += \` \${column.name}: \${fieldType}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +}`, + `function generateQueries(models: Record): string { + let content = '# Queries\\ntype Query {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Get single item + content += \` \${lowerName}(id: ID!): \${modelName}\\n\`; + + // Get multiple items + content += \` \${lowerName}s(limit: Int, offset: Int): [\${modelName}]\\n\`; + } + + content += '}\\n\\n'; + return content; +} + +function generateMutations(models: Record): string { + let content = '# Mutations\\ntype Mutation {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Create + content += \` create\${modelName}(input: \${modelName}Input!): \${modelName}\\n\`; + + // Update + content += \` update\${modelName}(id: ID!, input: \${modelName}UpdateInput!): \${modelName}\\n\`; + + // Delete + content += \` delete\${modelName}(id: ID!): Boolean\\n\`; + } + + content += '}\\n\\n'; + return content; +} + +function generateSubscriptions(models: Record): string { + let content = '# Subscriptions\\ntype Subscription {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Subscribe to changes + content += \` \${lowerName}Created: \${modelName}\\n\`; + content += \` \${lowerName}Updated: \${modelName}\\n\`; + content += \` \${lowerName}Deleted: ID\\n\`; + } + + content += '}\\n\\n'; + return content; +}`, + `plugin "./plugins/graphql-schema.js" { + output "./generated/schema.graphql" + includeQueries true + includeMutations true + includeSubscriptions false + generateInputTypes true + customScalars { + Email "String" + URL "String" + PhoneNumber "String" + } +}`, + `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("USER") + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/graphql-schema.js" { + output "./schema.graphql" + includeQueries true + includeMutations true +}`, + `# Custom Scalars +scalar DateTime +scalar JSON + +# Enums +enum UserRole { + ADMIN + USER + GUEST +} + +# Types +type User { + id: ID! + email: String! + name: String! + role: UserRole! + active: Boolean! + createdAt: DateTime! +} + +# Input Types +input UserInput { + email: String + name: String + role: UserRole + active: Boolean +} + +input UserUpdateInput { + email: String + name: String + role: UserRole + active: Boolean + createdAt: DateTime +} + +# Queries +type Query { + user(id: ID!): User + users(limit: Int, offset: Int): [User] +} + +# Mutations +type Mutation { + createUser(input: UserInput!): User + updateUser(id: ID!, input: UserUpdateInput!): User + deleteUser(id: ID!): Boolean +}`, + `// In your plugin configuration +customScalars: { + Email: "String", + URL: "String", + PhoneNumber: "String", + BigInt: "String" +}`, + `function handleRelationships(column: any, models: Record): string { + // Check if the column type is another model + if (models[column.type]) { + let type = column.type; + + if (column.multiple) { + type = \`[\${type}]\`; + } + + if (column.required) { + type += '!'; + } + + return type; + } + + return formatFieldType(column); +}`, + `function generateDirectives(column: any): string { + const directives: string[] = []; + + if (column.attributes?.unique) { + directives.push('@unique'); + } + + if (column.attributes?.deprecated) { + directives.push('@deprecated(reason: "Use alternative field")'); + } + + return directives.length > 0 ? \` \${directives.join(' ')}\` : ''; +}`, + `interface GraphQLColumn { + name: string; + type: string; + required: boolean; + multiple: boolean; + attributes?: Record; +} + +function validateColumn(column: any): column is GraphQLColumn { + return ( + typeof column.name === 'string' && + typeof column.type === 'string' && + typeof column.required === 'boolean' + ); +}`, + `function generateTypes(models: Record): string { + try { + let content = '# Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + if (!model.columns || !Array.isArray(model.columns)) { + console.warn(\`⚠️ Model \${modelName} has no valid columns\`); + continue; + } + + content += generateSingleType(modelName, model); + } + + return content; + } catch (error) { + throw new Error(\`Failed to generate GraphQL types: \${error.message}\`); + } +}`, + `function validateConfig(config: any): asserts config is GraphQLConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('GraphQL plugin requires "output" configuration as string'); + } + + if (config.customScalars && typeof config.customScalars !== 'object') { + throw new Error('customScalars must be an object'); + } +}`, + `// Cache type mappings +const typeCache = new Map(); + +function getCachedType(schemaType: string, customScalars: Record): string { + const cacheKey = \`\${schemaType}:\${JSON.stringify(customScalars)}\`; + + if (typeCache.has(cacheKey)) { + return typeCache.get(cacheKey)!; + } + + const mappedType = mapSchemaTypeToGraphQL(schemaType, customScalars); + typeCache.set(cacheKey, mappedType); + + return mappedType; +}`, + `function sanitizeGraphQLName(name: string): string { + // GraphQL names must match /^[_A-Za-z][_0-9A-Za-z]*$/ + return name.replace(/[^_A-Za-z0-9]/g, '_').replace(/^[0-9]/, '_$&'); +}`, + `function detectCircularDependencies(models: Record): string[] { + const visited = new Set(); + const recursionStack = new Set(); + const cycles: string[] = []; + + // Implementation for cycle detection... + + return cycles; +}`, + `function validateRequiredFields(model: any): void { + if (!model.columns || model.columns.length === 0) { + throw new Error(\`Model must have at least one column\`); + } +}`, + `const DEBUG = process.env.DEBUG === 'true'; + +function debugLog(message: string, data?: any) { + if (DEBUG) { + console.log(\`[GraphQL Plugin] \${message}\`, data || ''); + } +}`, + `import { buildSchema } from 'graphql'; + +function validateGeneratedSchema(schemaContent: string): void { + try { + buildSchema(schemaContent); + console.log('✅ Generated GraphQL schema is valid'); + } catch (error) { + throw new Error(\`Invalid GraphQL schema: \${error.message}\`); + } +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('GraphQL Schema Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates GraphQL type definitions from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    GraphQL Schema Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates GraphQL type definitions from .idea schema files. The plugin will transform your schema models, types, and enums into proper GraphQL schema definitions. +

    + +
    +

    1. Overview

    +

    + GraphQL is a query language and runtime for APIs that provides a complete and understandable description of the data in your API. This plugin transforms your .idea schema definitions into comprehensive GraphQL type definitions that enable type-safe API development with excellent tooling support. +

    +

    This plugin generates GraphQL type definitions from your .idea schema, including:

    +
      +
    • Types: GraphQL object types from schema models
    • +
    • Inputs: GraphQL input types for mutations
    • +
    • Enums: GraphQL enum types from schema enums
    • +
    • Scalars: Custom scalar types when needed
    • +
    • Queries and Mutations: Basic CRUD operations
    • +
    +
    + +
    +

    2. Prerequisites

    +

    + Before implementing the GraphQL schema generator plugin, ensure you have the necessary development environment and knowledge. This section covers the essential requirements for successful plugin creation and GraphQL integration. +

    +
      +
    • Node.js 16+ and npm/yarn
    • +
    • Basic understanding of GraphQL
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    + The plugin structure defines the core architecture and configuration interface for the GraphQL schema generator. This includes the main plugin function, configuration types, and the overall organization of the generated GraphQL schema definitions. +

    + + {examples[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle GraphQL schema generation. This includes configuration validation, content generation, file writing, and error handling throughout the generation process. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for GraphQL schema generation. It orchestrates the entire process from configuration validation through content generation to file output, ensuring proper error handling and logging throughout. +

    + + {examples[1]} + + +

    4.2. Type Mapping Functions

    +

    + Type mapping functions handle the conversion of .idea schema types to their GraphQL equivalents. These functions ensure proper type safety and handle complex scenarios like arrays, required fields, and custom scalar types. +

    + + {examples[2]} + + +

    4.3. Schema Generation Functions

    +

    + Schema generation functions create specific parts of the GraphQL schema including custom scalars, enums, types, input types, and root operation types. These functions handle proper GraphQL syntax construction and type relationships. +

    + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + +
    + +
    +

    5. Schema Configuration

    +

    + Schema configuration demonstrates how to integrate the GraphQL schema generator into your .idea schema files. This section covers plugin configuration options and their effects on the generated GraphQL schema definitions. +

    +

    Add the GraphQL plugin to your .idea schema file:

    + + {examples[6]} + + +

    Configuration Options

    +

    + Configuration options control how GraphQL schema definitions are generated, including operation types, input generation, and custom scalar handling. Understanding these options helps you customize the plugin to meet your specific GraphQL requirements. +

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for the GraphQL schema + + + includeQueries + boolean + false + Generate Query type with CRUD operations + + + includeMutations + boolean + false + Generate Mutation type with CRUD operations + + + includeSubscriptions + boolean + false + Generate Subscription type for real-time updates + + + generateInputTypes + boolean + true + Generate input types for mutations + + + customScalars + object + {} + Custom scalar type mappings. + +
    +
    + +
    +

    6. Usage Examples

    +

    + Usage examples demonstrate practical applications of the GraphQL schema generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated GraphQL schemas integrate into development workflows. +

    + +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate GraphQL type definitions. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces comprehensive GraphQL schemas. +

    + + {examples[7]} + + +

    6.2. Generated Output

    +

    + The generated output demonstrates the GraphQL schema produced by the plugin from the basic schema example. This shows how schema definitions are transformed into proper GraphQL type definitions with full type safety and operation support. +

    + + {examples[8]} + +
    + +
    +

    7. Advanced Features

    +

    + Advanced features extend the basic GraphQL schema generation with sophisticated type handling, relationship management, directive support, and custom scalar types. These features enable production-ready GraphQL schemas that handle complex requirements. +

    + +

    7.1. Custom Scalar Types

    +

    + Custom scalar types allow you to define specialized data types that map to specific validation or formatting requirements. This feature enables the creation of domain-specific types that enhance type safety and API clarity. +

    + + {examples[9]} + + +

    7.2. Relationship Handling

    +

    + Relationship handling manages references between different types and models in your schema. This ensures that type relationships are properly represented in the generated GraphQL schema with correct type references and nullability handling. +

    + + {examples[10]} + + +

    7.3. Directive Support

    +

    + Directive support enables the addition of GraphQL directives to fields and types, providing metadata and behavior hints for GraphQL servers and tools. This feature enhances schema expressiveness and enables advanced GraphQL features. +

    + + {examples[11]} + +
    + +
    +

    8. Best Practices

    +

    + Best practices ensure your generated GraphQL schemas are maintainable, performant, and follow GraphQL conventions. These guidelines cover type safety, error handling, configuration validation, and performance optimization. +

    + +

    8.1. Type Safety

    +

    + Type safety is crucial for preventing runtime errors and ensuring reliable GraphQL schema generation. Always validate input data and use proper TypeScript types throughout the plugin implementation to ensure consistent output. +

    + + {examples[12]} + + +

    8.2. Error Handling

    +

    + Proper error handling ensures that schema generation failures provide clear, actionable feedback to developers. Implement comprehensive error handling patterns and meaningful error messages to improve the debugging experience. +

    + + {examples[13]} + + +

    8.3. Configuration Validation

    +

    + Configuration validation ensures that plugin settings are correct and complete before schema generation begins. This prevents runtime errors and provides early feedback about configuration issues. +

    + + {examples[14]} + + +

    8.4. Performance Optimization

    +

    + Performance optimization techniques help maintain reasonable generation times when working with large schemas. Implement caching strategies and efficient algorithms to ensure the plugin scales well with complex type hierarchies. +

    + + {examples[15]} + +
    + +
    +

    9. Troubleshooting

    +

    + This section addresses common issues encountered when generating GraphQL schemas and provides solutions for debugging and resolving problems. Understanding these troubleshooting techniques helps ensure reliable schema generation. +

    + +

    9.1. Common Issues

    +

    + Common issues include invalid GraphQL identifiers, circular dependencies, and missing required fields. These problems typically arise from schema complexity or naming conflicts that can be resolved with proper validation and sanitization. +

    + +

    9.1.1. Invalid GraphQL Names

    +

    + Invalid GraphQL names occur when schema identifiers contain characters that are not valid in GraphQL. The plugin should validate and sanitize names to ensure they conform to GraphQL naming conventions. +

    + + {examples[16]} + + +

    9.1.2. Circular Dependencies

    +

    + Circular dependencies can cause infinite loops during generation or invalid GraphQL schemas. Detecting and handling these scenarios is essential for robust schema generation, especially with complex type relationships. +

    + + {examples[17]} + + +

    9.1.3. Missing Required Fields

    +

    + Missing required fields can result in invalid GraphQL types that fail validation. Ensure all models have proper field definitions and handle edge cases where schema definitions might be incomplete. +

    + + {examples[18]} + + +

    9.2. Debugging Tips

    +

    + Debugging tips help identify and resolve issues during GraphQL schema generation. These techniques provide visibility into the generation process and help diagnose problems with schema logic or output formatting. +

    + +

    9.2.1. Enable Verbose Logging

    +

    + Verbose logging provides detailed information about the schema generation process, helping identify where issues occur and what data is being processed at each step. +

    + + {examples[19]} + + +

    9.2.2. Validate Generated Schema

    +

    + Validating the generated GraphQL schema ensures that the output is syntactically correct and will work with GraphQL servers and tools. This validation step catches generation errors before deployment. +

    + + {examples[20]} + +
    + +
    +

    + This tutorial provides a comprehensive foundation for creating GraphQL schema generators from .idea files. The generated schemas can be used with any GraphQL server implementation like Apollo Server, GraphQL Yoga, or others. +

    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/html-form-plugin.tsx b/packages/www/plugins/docs/views/tutorials/html-form-plugin.tsx new file mode 100644 index 0000000..3bb6725 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/html-form-plugin.tsx @@ -0,0 +1,1358 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, P, SS, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('HTML Form Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates HTML forms from processed .idea schema definitions' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + + + +export function Body() { + const examples = [ + `// Example processed schema +{ + model: { + User: { + mutable: false, + columns: [ + { + name: 'name', + type: 'String', + required: true, + multiple: false, + attributes: { + field: { input: { type: 'text', placeholder: 'Enter your name' } }, + label: 'Full Name', + is: { required: true, minLength: 2, maxLength: 50 } + } + }, + { + name: 'email', + type: 'String', + required: true, + multiple: false, + attributes: { + field: { input: { type: 'email' } }, + label: 'Email Address', + is: { required: true, email: true } + } + }, + { + name: 'age', + type: 'Number', + required: false, + multiple: false, + attributes: { + field: { number: { min: 18, max: 100 } }, + label: 'Age', + is: { min: 18, max: 100 } + } + }, + { + name: 'role', + type: 'UserRole', + required: true, + multiple: false, + attributes: { + field: { select: true }, + label: 'User Role', + default: 'USER' + } + } + ] + } + }, + enum: { + UserRole: { + ADMIN: 'Administrator', + USER: 'Regular User', + GUEST: 'Guest User' + } + } +}`, + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface HTMLFormConfig { + output: string; + title?: string; + theme?: 'bootstrap' | 'tailwind' | 'custom'; + layout?: 'vertical' | 'horizontal' | 'inline'; + includeCSS?: boolean; + includeJS?: boolean; + submitUrl?: string; + method?: 'GET' | 'POST'; +} + +export default async function htmlFormPlugin( + props: PluginProps<{ config: HTMLFormConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // Validate configuration + if (!config.output) { + throw new Error('HTML Form Plugin requires "output" configuration'); + } + + // Set defaults + const options = { + title: config.title || 'Generated Form', + theme: config.theme || 'bootstrap', + layout: config.layout || 'vertical', + includeCSS: config.includeCSS !== false, + includeJS: config.includeJS !== false, + submitUrl: config.submitUrl || '#', + method: config.method || 'POST', + ...config + }; + + // Generate HTML content + const htmlContent = generateHTML(schema, options); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, htmlContent, 'utf8'); + + console.log(\`✅ HTML form generated: \${outputPath}\`); +}`, + `function generateFormElement(column: any, schema: any, options: any): string { + const { name, type, required, attributes = {} } = column; + const fieldConfig = attributes.field || {}; + const label = attributes.label || name; + const validation = attributes.is || {}; + + // Determine form element type + let element = ''; + + if (fieldConfig.input) { + element = generateInputElement(column, fieldConfig.input, options); + } else if (fieldConfig.textarea) { + element = generateTextareaElement(column, fieldConfig.textarea, options); + } else if (fieldConfig.select) { + element = generateSelectElement(column, schema, fieldConfig.select, options); + } else if (fieldConfig.checkbox) { + element = generateCheckboxElement(column, fieldConfig.checkbox, options); + } else if (fieldConfig.radio) { + element = generateRadioElement(column, schema, fieldConfig.radio, options); + } else if (fieldConfig.file) { + element = generateFileElement(column, fieldConfig.file, options); + } else { + // Auto-detect based on type and attributes + element = autoGenerateElement(column, schema, options); + } + + // Wrap in form group + return wrapFormGroup(element, label, name, required, validation, options); +} + +function generateInputElement(column: any, inputConfig: any, options: any): string { + const { name, required, attributes = {} } = column; + const validation = attributes.is || {}; + + const inputType = inputConfig.type || 'text'; + const placeholder = inputConfig.placeholder || ''; + const defaultValue = attributes.default || ''; + + let input = \`\${escapeHtml(defaultValue)}\`; + + return textarea; +} + +function generateSelectElement(column: any, schema: any, selectConfig: any, options: any): string { + const { name, type, required, attributes = {} } = column; + const defaultValue = attributes.default || ''; + + let select = \`'; + + return select; +} + +function generateCheckboxElement(column: any, checkboxConfig: any, options: any): string { + const { name, attributes = {} } = column; + const defaultValue = attributes.default || false; + const label = checkboxConfig.label || 'Check this box'; + + let checkbox = \`
    \\n\`; + checkbox += \` \${escapeHtml(label)}\\n\`; + checkbox += '
    '; + + return checkbox; +} + +function generateRadioElement(column: any, schema: any, radioConfig: any, options: any): string { + const { name, type, attributes = {} } = column; + const defaultValue = attributes.default || ''; + + let radio = \`
    \\n\`; + + // Generate radio options + if (schema.enum && schema.enum[type]) { + // Enum-based options + const enumValues = schema.enum[type]; + for (const [key, value] of Object.entries(enumValues)) { + const checked = defaultValue === key ? ' checked' : ''; + radio += \`
    \\n\`; + radio += \` \\n\`; + radio += \` \\n\`; + radio += '
    \\n'; + } + } else if (radioConfig.options) { + // Custom options + for (const option of radioConfig.options) { + const value = typeof option === 'string' ? option : option.value; + const label = typeof option === 'string' ? option : option.label; + const checked = defaultValue === value ? ' checked' : ''; + radio += \`
    \\n\`; + radio += \` \\n\`; + radio += \` \\n\`; + radio += '
    \\n'; + } + } + + radio += '
    '; + + return radio; +} + +function generateFileElement(column: any, fileConfig: any, options: any): string { + const { name, required } = column; + const accept = fileConfig.accept || ''; + const multiple = fileConfig.multiple || false; + + let file = \`*' : ''; + const helpText = generateHelpText(validation); + + switch (options.theme) { + case 'bootstrap': + return wrapBootstrapFormGroup(element, label, name, requiredMark, helpText, options); + case 'tailwind': + return wrapTailwindFormGroup(element, label, name, requiredMark, helpText, options); + default: + return wrapCustomFormGroup(element, label, name, requiredMark, helpText, options); + } +} + +function wrapBootstrapFormGroup(element: string, label: string, name: string, requiredMark: string, helpText: string, options: any): string { + let group = ''; + + if (options.layout === 'horizontal') { + group += '
    \\n'; + group += \` \\n\`; + group += '
    \\n'; + group += \` \${element}\\n\`; + if (helpText) { + group += \`
    \${helpText}
    \\n\`; + } + group += '
    \\n'; + group += '
    \\n'; + } else { + group += '
    \\n'; + group += \` \\n\`; + group += \` \${element}\\n\`; + if (helpText) { + group += \`
    \${helpText}
    \\n\`; + } + group += '
    \\n'; + } + + return group; +} + +function wrapTailwindFormGroup(element: string, label: string, name: string, requiredMark: string, helpText: string, options: any): string { + let group = ''; + + if (options.layout === 'horizontal') { + group += '
    \\n'; + group += \` \\n\`; + group += '
    \\n'; + group += \` \${element}\\n\`; + if (helpText) { + group += \`

    \${helpText}

    \\n\`; + } + group += '
    \\n'; + group += '
    \\n'; + } else { + group += '
    \\n'; + group += \` \\n\`; + group += \` \${element}\\n\`; + if (helpText) { + group += \`

    \${helpText}

    \\n\`; + } + group += '
    \\n'; + } + + return group; +} + +function wrapCustomFormGroup(element: string, label: string, name: string, requiredMark: string, helpText: string, options: any): string { + let group = '
    \\n'; + group += \` \\n\`; + group += \` \${element}\\n\`; + if (helpText) { + group += \`
    \${helpText}
    \\n\`; + } + group += '
    \\n'; + + return group; +} + +// CSS class generators for different themes +function getInputClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-control'; + case 'tailwind': + return 'block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500'; + default: + return 'form-input'; + } +} + +function getSelectClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-select'; + case 'tailwind': + return 'block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500'; + default: + return 'form-select'; + } +} + +function getTextareaClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-control'; + case 'tailwind': + return 'block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500'; + default: + return 'form-textarea'; + } +} + +function getCheckboxClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check-input'; + case 'tailwind': + return 'h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded'; + default: + return 'form-checkbox'; + } +} + +function getRadioClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check-input'; + case 'tailwind': + return 'h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300'; + default: + return 'form-radio'; + } +} + +function getFileClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-control'; + case 'tailwind': + return 'block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100'; + default: + return 'form-file'; + } +}`, + `function generateHTML(schema: any, options: any): string { + let html = generateHTMLHeader(options); + + // Generate forms for each model + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + html += generateFormHTML(modelName, model, schema, options); + html += '\\n'; + } + } + + html += generateHTMLFooter(options); + + return html; +} + +function generateHTMLHeader(options: any): string { + let html = '\\n'; + html += '\\n'; + html += '\\n'; + html += ' \\n'; + html += ' \\n'; + html += \` \${escapeHtml(options.title)}\\n\`; + + // Include CSS + if (options.includeCSS) { + html += generateCSS(options); + } + + html += '\\n'; + html += '\\n'; + html += '
    \\n'; + html += \`

    \${escapeHtml(options.title)}

    \\n\`; + + return html; +} + +function generateFormHTML(modelName: string, model: any, schema: any, options: any): string { + let html = \`
    \\n\`; + html += \`

    \${escapeHtml(modelName)} Form

    \\n\`; + html += \`
    \\n\`; + + // Generate form fields + for (const column of model.columns || []) { + // Skip hidden fields or system fields + if (column.attributes?.list?.hide || column.attributes?.view?.hide) { + continue; + } + + html += generateFormElement(column, schema, options); + } + + // Add submit button + html += generateSubmitButton(options); + + html += '
    \\n'; + html += '
    \\n'; + + return html; +} + +function generateSubmitButton(options: any): string { + let button = '
    \\n'; + button += ' \\n'; + button += ' \\n'; + break; + case 'tailwind': + button += 'mt-6">\\n'; + button += ' \\n'; + button += ' \\n'; + break; + default: + button += 'form-actions">\\n'; + button += ' \\n'; + button += ' \\n'; + } + + button += '
    \\n'; + + return button; +} + +function generateHTMLFooter(options: any): string { + let html = '
    \\n'; + + // Include JavaScript + if (options.includeJS) { + html += generateJavaScript(options); + } + + html += '\\n'; + html += '\\n'; + + return html; +} + +function generateCSS(options: any): string { + let css = ''; + + switch (options.theme) { + case 'bootstrap': + css += ' \\n'; + break; + case 'tailwind': + css += ' \\n'; + break; + default: + css += ' \\n'; + } + + return css; +} + +function generateCustomCSS(): string { + return \` + .container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + } + + .form-container { + background: #f9f9f9; + padding: 30px; + border-radius: 8px; + margin-bottom: 30px; + } + + .form-group { + margin-bottom: 20px; + } + + label { + display: block; + margin-bottom: 5px; + font-weight: bold; + } + + .required { + color: #e74c3c; + } + + .form-input, + .form-select, + .form-textarea { + width: 100%; + padding: 10px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + } + + .form-input:focus, + .form-select:focus, + .form-textarea:focus { + outline: none; + border-color: #3498db; + box-shadow: 0 0 5px rgba(52, 152, 219, 0.3); + } + + .form-checkbox, + .form-radio { + margin-right: 8px; + } + + .help-text { + font-size: 12px; + color: #666; + margin-top: 5px; + } + + .form-actions { + margin-top: 30px; + } + + .btn-primary, + .btn-secondary { + padding: 10px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + margin-right: 10px; + } + + .btn-primary { + background: #3498db; + color: white; + } + + .btn-primary:hover { + background: #2980b9; + } + + .btn-secondary { + background: #95a5a6; + color: white; + } + + .btn-secondary:hover { + background: #7f8c8d; + } + \`; +} + +function generateJavaScript(options: any): string { + let js = ''; + + switch (options.theme) { + case 'bootstrap': + js += ' \\n'; + break; + } + + // Add form validation JavaScript + js += ' \\n'; + + return js; +} + +function generateFormValidationJS(): string { + return \` + // Form validation and enhancement + document.addEventListener('DOMContentLoaded', function() { + const forms = document.querySelectorAll('form'); + + forms.forEach(function(form) { + form.addEventListener('submit', function(e) { + if (!validateForm(form)) { + e.preventDefault(); + return false; + } + }); + }); + + function validateForm(form) { + let isValid = true; + const inputs = form.querySelectorAll('input[required], select[required], textarea[required]'); + + inputs.forEach(function(input) { + if (!input.value.trim()) { + showError(input, 'This field is required'); + isValid = false; + } else { + clearError(input); + } + }); + + return isValid; + } + + function showError(input, message) { + clearError(input); + input.classList.add('error'); + + const errorDiv = document.createElement('div'); + errorDiv.className = 'error-message'; + errorDiv.textContent = message; + errorDiv.style.color = '#e74c3c'; + errorDiv.style.fontSize = '12px'; + errorDiv.style.marginTop = '5px'; + + input.parentNode.appendChild(errorDiv); + } + + function clearError(input) { + input.classList.remove('error'); + const errorMessage = input.parentNode.querySelector('.error-message'); + if (errorMessage) { + errorMessage.remove(); + } + } + }); + \`; +} + +// Utility functions +function escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; +} + +function generateHelpText(validation: any): string { + const hints: string[] = []; + + if (validation.minLength) { + hints.push(\`Minimum \${validation.minLength} characters\`); + } + if (validation.maxLength) { + hints.push(\`Maximum \${validation.maxLength} characters\`); + } + if (validation.min) { + hints.push(\`Minimum value: \${validation.min}\`); + } + if (validation.max) { + hints.push(\`Maximum value: \${validation.max}\`); + } + if (validation.pattern) { + hints.push('Must match the required format'); + } + + return hints.length > 0 ? hints.join('. ') : ''; +} + +function getFormClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'needs-validation'; + case 'tailwind': + return 'space-y-4'; + default: + return 'form'; + } +} + +function getCheckboxWrapperClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check'; + case 'tailwind': + return 'flex items-center'; + default: + return 'checkbox-wrapper'; + } +} + +function getCheckboxLabelClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check-label'; + case 'tailwind': + return 'ml-2 text-sm text-gray-700'; + default: + return 'checkbox-label'; + } +} + +function getRadioGroupClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return ''; + case 'tailwind': + return 'space-y-2'; + default: + return 'radio-group'; + } +} + +function getRadioWrapperClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check'; + case 'tailwind': + return 'flex items-center'; + default: + return 'radio-wrapper'; + } +} + +function getRadioLabelClasses(theme: string): string { + switch (theme) { + case 'bootstrap': + return 'form-check-label'; + case 'tailwind': + return 'ml-2 text-sm text-gray-700'; + default: + return 'radio-label'; + } +}`, + `// schema.idea +plugin "./plugins/html-form-plugin.js" { + output "./forms/user-form.html" + title "User Registration Form" + theme "bootstrap" + layout "vertical" + includeCSS true + includeJS true + submitUrl "/api/users" + method "POST" +} + +model User { + name String @label("Full Name") @field.input(Text) @is.required @is.minLength(2) @is.maxLength(50) + email String @label("Email Address") @field.input(Email) @is.required @is.email + age Number @label("Age") @field.number @is.min(18) @is.max(100) + role UserRole @label("User Role") @field.select @default("USER") + bio String @label("Biography") @field.textarea @is.maxLength(500) + active Boolean @label("Active Account") @field.checkbox @default(true) + created Date @label("Registration Date") @field.date @default("now()") +} + +enum UserRole { + ADMIN "Administrator" + USER "Regular User" + GUEST "Guest User" +}`, + ` + + + + + User Registration Form + + + +
    +

    User Registration Form

    +
    +

    User Form

    +
    +
    + + +
    Minimum 2 characters. Maximum 50 characters
    +
    + +
    + + +
    + +
    + + +
    Minimum value: 18. Maximum value: 100
    +
    + +
    + + +
    + +
    + + +
    Maximum 500 characters
    +
    + +
    + + +
    + +
    + + +
    +
    +
    +
    + + + + +`, + `export default async function htmlFormPlugin(props: PluginProps<{}>) { + const { config, schema, transformer, cwd } = props; + + try { + // Validate configuration + validateConfig(config); + + // Validate schema has models + if (!schema.model || Object.keys(schema.model).length === 0) { + console.warn('⚠️ No models found in schema. Skipping HTML form generation.'); + return; + } + + // Generate HTML + const htmlContent = generateHTML(schema, config); + + // Ensure output directory exists + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + + // Write file + await fs.writeFile(outputPath, htmlContent, 'utf8'); + + console.log(\`✅ HTML form generated: \${outputPath}\`); + console.log(\`📊 Generated forms for \${Object.keys(schema.model).length} model(s)\`); + + } catch (error) { + console.error(\`❌ HTML Form Plugin failed: \${error.message}\`); + throw error; + } +} + +function validateConfig(config: any): void { + if (!config.output) { + throw new Error('HTML Form Plugin requires "output" configuration'); + } + + if (config.theme && !['bootstrap', 'tailwind', 'custom'].includes(config.theme)) { + throw new Error(\`Unsupported theme: \${config.theme}\`); + } + + if (config.layout && !['vertical', 'horizontal', 'inline'].includes(config.layout)) { + throw new Error(\`Unsupported layout: \${config.layout}\`); + } + + if (config.method && !['GET', 'POST'].includes(config.method)) { + throw new Error(\`Unsupported HTTP method: \${config.method}\`); + } +}` + ]; + + return ( +
    +

    Tutorial: Creating an HTML Form Plugin

    +

    + This tutorial will guide you through creating a plugin that generates HTML forms from a processed .idea schema. You'll learn how to parse schema models, generate appropriate form elements, handle validation, and create responsive forms with multiple CSS framework support. +

    + +
    +

    1. Overview

    +

    + This section provides an overview of what the HTML Form Plugin accomplishes and its key features. The plugin transforms schema definitions into fully functional HTML forms with proper validation, styling, and accessibility features. +

    +

    + The HTML Form Plugin will: +

    +
      +
    • Parse schema models and their columns
    • +
    • Generate HTML form elements based on field types and attributes
    • +
    • Include validation attributes and constraints
    • +
    • Create responsive, accessible forms with proper styling
    • +
    • Support different form layouts and themes
    • +
    +
    + +
    +

    2. Prerequisites

    +

    + Before starting this tutorial, ensure you have the necessary knowledge and tools to successfully implement the HTML Form Plugin. These prerequisites will help you understand the concepts and follow along with the implementation. +

    +
      +
    • Basic understanding of TypeScript/JavaScript
    • +
    • Familiarity with HTML forms and CSS
    • +
    • Understanding of the idea-transformer plugin system
    • +
    +
    + +
    +

    3. Understanding the Schema Structure

    +

    + Understanding how schema attributes map to form elements is crucial for creating effective form generation. This section explains the processed schema structure and how different field types and attributes translate into HTML form elements. +

    +

    + Before creating the plugin, let's understand how schema attributes map to form elements: +

    + + {examples[0]} + +
    + +
    +

    4. Create the Plugin Structure

    +

    + The plugin structure provides the foundation for the HTML form generator. This section covers the main plugin function, configuration interface, and the basic workflow for processing schemas and generating HTML output. +

    +

    + Create a new file html-form-plugin.js: +

    + + {examples[1]} + +
    + +
    +

    5. Implement Form Element Generation

    +

    + Form element generation is the core functionality of the plugin. This section demonstrates how to create functions that generate different types of HTML form elements based on schema column definitions, including inputs, textareas, selects, checkboxes, radio buttons, and file inputs. +

    +

    + Create functions to generate different form elements: +

    + + {examples[2]} + +
    + +
    +

    6. Implement Form Layout and Styling

    +

    + Form layout and styling ensure that generated forms are visually appealing and work well with different CSS frameworks. This section covers how to implement support for Bootstrap, Tailwind CSS, and custom styling, along with different layout options like vertical, horizontal, and inline forms. +

    +

    + Create functions for different themes and layouts: +

    + + {examples[3]} + +
    + +
    +

    7. Generate Complete HTML Document

    +

    + Generating a complete HTML document involves combining all form elements into a properly structured HTML page. This section shows how to create the HTML structure, include necessary CSS and JavaScript files, and generate forms for multiple models within a single document. +

    +

    + Implement the main HTML generation function: +

    + + {examples[4]} + +
    + +
    +

    8. Usage in Schema

    +

    + This section demonstrates how to configure and use the HTML Form Plugin within your .idea schema files. You'll learn about the available configuration options and how to set up your schema to generate the desired form output. +

    +

    + To use this plugin in your schema file: +

    + + {examples[5]} + +
    + +
    +

    9. Generated Output

    +

    + The generated output section shows examples of the HTML code that the plugin produces. This helps you understand what to expect from the plugin and how the various configuration options affect the final output. +

    +

    + The plugin will generate HTML like this: +

    + + {examples[6]} + +
    + +
    +

    10. Error Handling and Best Practices

    +

    + Proper error handling and following best practices ensure that your plugin is robust and reliable. This section covers validation techniques, error reporting, and recommended patterns for plugin development. +

    +

    + Add proper error handling and validation: +

    + + {examples[7]} + +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/markdown-documentation-plugin.tsx b/packages/www/plugins/docs/views/tutorials/markdown-documentation-plugin.tsx new file mode 100644 index 0000000..49562d7 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/markdown-documentation-plugin.tsx @@ -0,0 +1,1447 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `// Example processed schema +{ + model: { + User: { + mutable: false, + columns: [ + { + name: 'id', + type: 'String', + required: true, + multiple: false, + attributes: { + id: true, + label: 'User ID', + default: 'nanoid()', + description: 'Unique identifier for the user' + } + }, + { + name: 'email', + type: 'String', + required: true, + multiple: false, + attributes: { + unique: true, + label: 'Email Address', + field: { input: { type: 'email' } }, + description: 'User email address for authentication' + } + } + ] + } + }, + enum: { + UserRole: { + ADMIN: 'Administrator', + USER: 'Regular User', + GUEST: 'Guest User' + } + }, + type: { + Address: { + mutable: true, + columns: [ + { + name: 'street', + type: 'String', + required: true, + multiple: false, + attributes: { + label: 'Street Address' + } + } + ] + } + }, + prop: { + Text: { + type: 'text', + placeholder: 'Enter text', + maxLength: 255 + } + } +}`, + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface MarkdownDocsConfig { + output: string; + title?: string; + format?: 'single' | 'multiple'; + includeIndex?: boolean; + includeExamples?: boolean; + includeAttributes?: boolean; + sections?: string[]; + template?: 'default' | 'api' | 'guide'; +} + +export default async function markdownDocsPlugin( + props: PluginProps<{ config: MarkdownDocsConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // Validate configuration + if (!config.output) { + throw new Error('Markdown Documentation Plugin requires "output" configuration'); + } + + // Set defaults + const options = { + title: config.title || 'Schema Documentation', + format: config.format || 'single', + includeIndex: config.includeIndex !== false, + includeExamples: config.includeExamples !== false, + includeAttributes: config.includeAttributes !== false, + sections: config.sections || ['models', 'types', 'enums', 'props'], + template: config.template || 'default', + ...config + }; + + // Generate documentation + if (options.format === 'single') { + await generateSingleFile(schema, options, transformer); + } else { + await generateMultipleFiles(schema, options, transformer); + } + + console.log(\`✅ Markdown documentation generated: \${options.output}\`); +}`, + `async function generateSingleFile(schema: any, options: any, transformer: any): Promise { + let content = generateHeader(options); + + // Generate table of contents + if (options.includeIndex) { + content += generateTableOfContents(schema, options); + } + + // Generate sections + for (const section of options.sections) { + switch (section) { + case 'models': + if (schema.model) { + content += generateModelsSection(schema.model, schema, options); + } + break; + case 'types': + if (schema.type) { + content += generateTypesSection(schema.type, schema, options); + } + break; + case 'enums': + if (schema.enum) { + content += generateEnumsSection(schema.enum, options); + } + break; + case 'props': + if (schema.prop) { + content += generatePropsSection(schema.prop, options); + } + break; + } + } + + // Add footer + content += generateFooter(options); + + // Write to file + const outputPath = await transformer.loader.absolute(options.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); +} + +async function generateMultipleFiles(schema: any, options: any, transformer: any): Promise { + const outputDir = path.dirname(await transformer.loader.absolute(options.output)); + await fs.mkdir(outputDir, { recursive: true }); + + // Generate index file + if (options.includeIndex) { + const indexContent = generateIndexFile(schema, options); + await fs.writeFile(path.join(outputDir, 'README.md'), indexContent, 'utf8'); + } + + // Generate individual files for each section + for (const section of options.sections) { + let content = ''; + let filename = ''; + + switch (section) { + case 'models': + if (schema.model) { + content = generateModelsFile(schema.model, schema, options); + filename = 'models.md'; + } + break; + case 'types': + if (schema.type) { + content = generateTypesFile(schema.type, schema, options); + filename = 'types.md'; + } + break; + case 'enums': + if (schema.enum) { + content = generateEnumsFile(schema.enum, options); + filename = 'enums.md'; + } + break; + case 'props': + if (schema.prop) { + content = generatePropsFile(schema.prop, options); + filename = 'props.md'; + } + break; + } + + if (content && filename) { + await fs.writeFile(path.join(outputDir, filename), content, 'utf8'); + } + } +} + +function generateHeader(options: any): string { + let header = \`# \${options.title}\\n\\n\`; + + switch (options.template) { + case 'api': + header += 'API Reference documentation for the schema definitions.\\n\\n'; + header += '## Overview\\n\\n'; + header += 'This document provides comprehensive API documentation for all schema elements including models, types, enums, and properties.\\n\\n'; + break; + case 'guide': + header += 'Developer guide for working with the schema definitions.\\n\\n'; + header += '## Getting Started\\n\\n'; + header += 'This guide will help you understand and work with the schema definitions in your application.\\n\\n'; + break; + default: + header += 'Comprehensive documentation for all schema definitions.\\n\\n'; + header += \`Generated on: \${new Date().toISOString()}\\n\\n\`; + } + + return header; +} + +function generateTableOfContents(schema: any, options: any): string { + let toc = '## Table of Contents\\n\\n'; + + for (const section of options.sections) { + switch (section) { + case 'models': + if (schema.model && Object.keys(schema.model).length > 0) { + toc += '- [Models](#models)\\n'; + for (const modelName of Object.keys(schema.model)) { + toc += \` - [\${modelName}](#\${modelName.toLowerCase()})\\n\`; + } + } + break; + case 'types': + if (schema.type && Object.keys(schema.type).length > 0) { + toc += '- [Types](#types)\\n'; + for (const typeName of Object.keys(schema.type)) { + toc += \` - [\${typeName}](#\${typeName.toLowerCase()})\\n\`; + } + } + break; + case 'enums': + if (schema.enum && Object.keys(schema.enum).length > 0) { + toc += '- [Enums](#enums)\\n'; + for (const enumName of Object.keys(schema.enum)) { + toc += \` - [\${enumName}](#\${enumName.toLowerCase()})\\n\`; + } + } + break; + case 'props': + if (schema.prop && Object.keys(schema.prop).length > 0) { + toc += '- [Props](#props)\\n'; + for (const propName of Object.keys(schema.prop)) { + toc += \` - [\${propName}](#\${propName.toLowerCase()})\\n\`; + } + } + break; + } + } + + return toc + '\\n'; +}`, + `function generateModelsSection(models: any, schema: any, options: any): string { + let content = '## Models\\n\\n'; + content += 'Models represent the main data structures in your application.\\n\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += generateModelDocumentation(modelName, model, schema, options); + } + + return content; +}`, + `function generateModelDocumentation(modelName: string, model: any, schema: any, options: any): string { + let content = \`### \${modelName}\\n\\n\`; + + // Add description if available + if (model.description) { + content += \`\${model.description}\\n\\n\`; + } + + // Add mutability information + content += \`**Mutability:** \${model.mutable ? 'Mutable' : 'Immutable'}\\n\\n\`; + + // Generate columns table + if (model.columns && model.columns.length > 0) { + content += '#### Columns\\n\\n'; + content += '| Name | Type | Required | Multiple | Description |\\n'; + content += '|------|------|----------|----------|-------------|\\n'; + + for (const column of model.columns) { + const name = column.name; + const type = formatType(column.type, column.multiple); + const required = column.required ? '✓' : '✗'; + const multiple = column.multiple ? '✓' : '✗'; + const description = column.attributes?.description || column.attributes?.label || '-'; + + content += \`| \${name} | \${type} | \${required} | \${multiple} | \${description} |\\n\`; + } + content += '\\n'; + + // Generate detailed column information + if (options.includeAttributes) { + content += '#### Column Details\\n\\n'; + + for (const column of model.columns) { + content += generateColumnDocumentation(column, schema, options); + } + } + } + + // Generate examples + if (options.includeExamples) { + content += generateModelExamples(modelName, model, schema, options); + } + + return content; +}`, + `function generateColumnDocumentation(column: any, schema: any, options: any): string { + let content = \`##### \${column.name}\\n\\n\`; + + const attributes = column.attributes || {}; + + // Basic information + content += \`- **Type:** \${formatType(column.type, column.multiple)}\\n\`; + content += \`- **Required:** \${column.required ? 'Yes' : 'No'}\\n\`; + + if (attributes.default !== undefined) { + content += \`- **Default:** \\\`\${attributes.default}\\\`\\n\`; + } + + if (attributes.description) { + content += \`- **Description:** \${attributes.description}\\n\`; + } + + // Validation rules + const validation = attributes.is || {}; + if (Object.keys(validation).length > 0) { + content += '- **Validation:**\\n'; + + if (validation.minLength) { + content += \` - Minimum length: \${validation.minLength}\\n\`; + } + if (validation.maxLength) { + content += \` - Maximum length: \${validation.maxLength}\\n\`; + } + if (validation.min) { + content += \` - Minimum value: \${validation.min}\\n\`; + } + if (validation.max) { + content += \` - Maximum value: \${validation.max}\\n\`; + } + if (validation.pattern) { + content += \` - Pattern: \\\`\${validation.pattern}\\\`\\n\`; + } + if (validation.email) { + content += ' - Must be a valid email address\\n'; + } + if (validation.url) { + content += ' - Must be a valid URL\\n'; + } + } + + // Field configuration + const field = attributes.field || {}; + if (Object.keys(field).length > 0) { + content += '- **Field Configuration:**\\n'; + + if (field.input) { + content += \` - Input type: \${field.input.type || 'text'}\\n\`; + if (field.input.placeholder) { + content += \` - Placeholder: "\${field.input.placeholder}"\\n\`; + } + } + if (field.select) { + content += ' - Rendered as: Select dropdown\\n'; + } + if (field.textarea) { + content += ' - Rendered as: Textarea\\n'; + } + if (field.checkbox) { + content += ' - Rendered as: Checkbox\\n'; + } + } + + // Database attributes + if (attributes.id) { + content += '- **Database:** Primary key\\n'; + } + if (attributes.unique) { + content += '- **Database:** Unique constraint\\n'; + } + if (attributes.index) { + content += '- **Database:** Indexed\\n'; + } + + content += '\\n'; + + return content; +}`, + `function generateModelExamples(modelName: string, model: any, schema: any, options: any): string { + let content = '#### Examples\\n\\n'; + + // Generate JSON example + content += '##### JSON Structure\\n\\n'; + content += '\`\`\`json\\n'; + content += generateJSONExample(model, schema); + content += '\\n\`\`\`\\n\\n'; + + // Generate schema definition example + content += '##### Schema Definition\\n\\n'; + content += '\`\`\`idea\\n'; + content += generateSchemaExample(modelName, model); + content += '\\n\`\`\`\\n\\n'; + + return content; +}`, + `function generateJSONExample(model: any, schema: any): string { + const example: any = {}; + + for (const column of model.columns || []) { + const value = generateExampleValue(column, schema); + if (value !== undefined) { + example[column.name] = value; + } + } + + return JSON.stringify(example, null, 2); +}`, + `function generateExampleValue(column: any, schema: any): any { + const { type, attributes = {} } = column; + + // Use default value if available + if (attributes.default !== undefined) { + return attributes.default; + } + + // Generate example based on type + switch (type) { + case 'String': + if (attributes.email) { + return 'user@example.com'; + } + if (attributes.url) { + return 'https://example.com'; + } + if (attributes.id) { + return 'abc123def456'; + } + return \`Example \${column.name}\`; + + case 'Number': + if (attributes.min && attributes.max) { + return Math.floor((attributes.min + attributes.max) / 2); + } + if (attributes.min) { + return attributes.min + 10; + } + if (attributes.max) { + return Math.floor(attributes.max / 2); + } + return 42; + + case 'Boolean': + return true; + + case 'Date': + return new Date().toISOString(); + + default: + // Check if it's an enum + if (schema.enum && schema.enum[type]) { + const enumValues = Object.keys(schema.enum[type]); + return enumValues[0]; + } + + // Check if it's a type + if (schema.type && schema.type[type]) { + return generateJSONExample(schema.type[type], schema); + } + + return null; + } +}`, + `function generateSchemaExample(modelName: string, model: any): string { + let schema = \`model \${modelName}\`; + + if (!model.mutable) { + schema += '!'; + } + + schema += ' {\\n'; + + for (const column of model.columns || []) { + schema += \` \${column.name} \${formatType(column.type, column.multiple)}\`; + + // Add common attributes + const attributes = column.attributes || {}; + if (attributes.id) { + schema += ' @id'; + } + if (attributes.unique) { + schema += ' @unique'; + } + if (attributes.default !== undefined) { + schema += \` @default("\${attributes.default}")\`; + } + if (!column.required) { + schema += ' @optional'; + } + + schema += '\\n'; + } + + schema += '}'; + + return schema; +}`, + `function generateTypesSection(types: any, schema: any, options: any): string { + let content = '## Types\\n\\n'; + content += 'Types define reusable data structures that can be embedded in models.\\n\\n'; + + for (const [typeName, type] of Object.entries(types)) { + content += generateTypeDocumentation(typeName, type, schema, options); + } + + return content; +} + +function generateTypeDocumentation(typeName: string, type: any, schema: any, options: any): string { + let content = \`### \${typeName}\\n\\n\`; + + // Add description if available + if (type.description) { + content += \`\${type.description}\\n\\n\`; + } + + // Add mutability information + content += \`**Mutability:** \${type.mutable ? 'Mutable' : 'Immutable'}\\n\\n\`; + + // Generate columns table (same as models) + if (type.columns && type.columns.length > 0) { + content += '#### Properties\\n\\n'; + content += '| Name | Type | Required | Multiple | Description |\\n'; + content += '|------|------|----------|----------|-------------|\\n'; + + for (const column of type.columns) { + const name = column.name; + const columnType = formatType(column.type, column.multiple); + const required = column.required ? '✓' : '✗'; + const multiple = column.multiple ? '✓' : '✗'; + const description = column.attributes?.description || column.attributes?.label || '-'; + + content += \`| \${name} | \${columnType} | \${required} | \${multiple} | \${description} |\\n\`; + } + content += '\\n'; + } + + // Generate examples + if (options.includeExamples) { + content += '#### Example\\n\\n'; + content += '\`\`\`json\\n'; + content += generateJSONExample(type, schema); + content += '\\n\`\`\`\\n\\n'; + } + + return content; +}`, + `function generateEnumsSection(enums: any, options: any): string { + let content = '## Enums\\n\\n'; + content += 'Enums define sets of named constants with associated values.\\n\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + content += generateEnumDocumentation(enumName, enumDef, options); + } + + return content; +} + +function generateEnumDocumentation(enumName: string, enumDef: any, options: any): string { + let content = \`### \${enumName}\\n\\n\`; + + // Generate values table + content += '#### Values\\n\\n'; + content += '| Key | Value | Description |\\n'; + content += '|-----|-------|-------------|\\n'; + + for (const [key, value] of Object.entries(enumDef)) { + content += \`| \${key} | \${value} | - |\\n\`; + } + content += '\\n'; + + // Generate examples + if (options.includeExamples) { + content += '#### Example\\n\\n'; + content += '\`\`\`idea\\n'; + content += \`enum \${enumName} {\\n\`; + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key} "\${value}"\\n\`; + } + content += '}\\n'; + content += '\`\`\`\\n\\n'; + + content += '\`\`\`json\\n'; + content += \`// Using in a model\\n\`; + content += \`{\\n\`; + content += \` "status": "\${Object.keys(enumDef)[0]}"\\n\`; + content += \`}\\n\`; + content += '\`\`\`\\n\\n'; + } + + return content; +}`, + `function generatePropsSection(props: any, options: any): string { + let content = '## Props\\n\\n'; + content += 'Props define reusable property configurations for form fields and validation.\\n\\n'; + + for (const [propName, propDef] of Object.entries(props)) { + content += generatePropDocumentation(propName, propDef, options); + } + + return content; +} + +function generatePropDocumentation(propName: string, propDef: any, options: any): string { + let content = \`### \${propName}\\n\\n\`; + + // Generate properties table + content += '#### Configuration\\n\\n'; + content += '| Property | Value | Description |\\n'; + content += '|----------|-------|-------------|\\n'; + + for (const [key, value] of Object.entries(propDef)) { + const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value); + content += \`| \${key} | \\\`\${valueStr}\\\` | - |\\n\`; + } + content += '\\n'; + + // Generate examples + if (options.includeExamples) { + content += '#### Example\\n\\n'; + content += '\`\`\`idea\\n'; + content += \`prop \${propName} {\\n\`; + for (const [key, value] of Object.entries(propDef)) { + const valueStr = typeof value === 'string' ? \`"\${value}"\` : JSON.stringify(value); + content += \` \${key} \${valueStr}\\n\`; + } + content += '}\\n\\n'; + content += \`// Usage in a model\\n\`; + content += \`model User {\\n\`; + content += \` name String @field.input(\${propName})\\n\`; + content += \`}\\n\`; + content += '\`\`\`\\n\\n'; + } + + return content; +}`, + `function formatType(type: string, multiple: boolean = false): string { + let formattedType = type; + + // Add array notation if multiple + if (multiple) { + formattedType += '[]'; + } + + // Add markdown formatting for built-in types + const builtInTypes = ['String', 'Number', 'Boolean', 'Date', 'JSON']; + if (builtInTypes.includes(type)) { + formattedType = \`\\\`\${formattedType}\\\`\`; + } else { + // Link to other types/enums + formattedType = \`[\${formattedType}](#\${type.toLowerCase()})\`; + } + + return formattedType; +}`, + `function generateFooter(options: any): string { + let footer = '\\n---\\n\\n'; + footer += \`*Documentation generated on \${new Date().toLocaleString()}*\\n\`; + + if (options.template === 'api') { + footer += '\\n## Support\\n\\n'; + footer += 'For questions or issues, please refer to the project documentation or contact the development team.\\n'; + } + + return footer; +}`, + `function generateIndexFile(schema: any, options: any): string { + let content = \`# \${options.title}\\n\\n\`; + content += 'Welcome to the schema documentation. This documentation is organized into the following sections:\\n\\n'; + + // Generate overview + const stats = { + models: schema.model ? Object.keys(schema.model).length : 0, + types: schema.type ? Object.keys(schema.type).length : 0, + enums: schema.enum ? Object.keys(schema.enum).length : 0, + props: schema.prop ? Object.keys(schema.prop).length : 0 + }; + + content += '## Overview\\n\\n'; + content += \`This schema contains:\\n\`; + content += \`- **\${stats.models}** models\\n\`; + content += \`- **\${stats.types}** types\\n\`; + content += \`- **\${stats.enums}** enums\\n\`; + content += \`- **\${stats.props}** props\\n\\n\`; + + // Generate navigation + content += '## Documentation Sections\\n\\n'; + + if (stats.models > 0) { + content += '### [Models](./models.md)\\n\\n'; + content += 'Main data structures and entities:\\n'; + for (const modelName of Object.keys(schema.model || {})) { + content += \`- [\${modelName}](./models.md#\${modelName.toLowerCase()})\\n\`; + } + content += '\\n'; + } + + if (stats.types > 0) { + content += '### [Types](./types.md)\\n\\n'; + content += 'Reusable data structures:\\n'; + for (const typeName of Object.keys(schema.type || {})) { + content += \`- [\${typeName}](./types.md#\${typeName.toLowerCase()})\\n\`; + } + content += '\\n'; + } + + if (stats.enums > 0) { + content += '### [Enums](./enums.md)\\n\\n'; + content += 'Named constants and value sets:\\n'; + for (const enumName of Object.keys(schema.enum || {})) { + content += \`- [\${enumName}](./enums.md#\${enumName.toLowerCase()})\\n\`; + } + content += '\\n'; + } + + if (stats.props > 0) { + content += '### [Props](./props.md)\\n\\n'; + content += 'Reusable property configurations:\\n'; + for (const propName of Object.keys(schema.prop || {})) { + content += \`- [\${propName}](./props.md#\${propName.toLowerCase()})\\n\`; + } + content += '\\n'; + } + + return content; +} + +function generateModelsFile(models: any, schema: any, options: any): string { + let content = generateHeader({ ...options, title: 'Models' }); + content += generateModelsSection(models, schema, options); + return content; +} + +function generateTypesFile(types: any, schema: any, options: any): string { + let content = generateHeader({ ...options, title: 'Types' }); + content += generateTypesSection(types, schema, options); + return content; +} + +function generateEnumsFile(enums: any, options: any): string { + let content = generateHeader({ ...options, title: 'Enums' }); + content += generateEnumsSection(enums, options); + return content; +} + +function generatePropsFile(props: any, options: any): string { + let content = generateHeader({ ...options, title: 'Props' }); + content += generatePropsSection(props, options); + return content; +}`, + `// schema.idea +plugin "./plugins/markdown-docs-plugin.js" { + output "./docs/schema.md" + title "My Application Schema" + format "single" + includeIndex true + includeExamples true + includeAttributes true + sections ["models", "types", "enums", "props"] + template "api" +} + +model User! { + id String @id @default("nanoid()") @description("Unique identifier for the user") + email String @unique @field.input(Email) @description("User email address for authentication") + name String @field.input(Text) @description("Full name of the user") + role UserRole @default("USER") @description("User's role in the system") + profile Profile? @description("Optional user profile information") + active Boolean @default(true) @description("Whether the user account is active") + created Date @default("now()") @description("Account creation timestamp") +} + +type Profile { + bio String @field.textarea @description("User biography") + avatar String @field.file @description("Profile picture URL") + website String @field.input(URL) @description("Personal website URL") +} + +enum UserRole { + ADMIN "Administrator" + USER "Regular User" + GUEST "Guest User" +} + +prop Email { + type "email" + placeholder "Enter your email address" + validation { + required true + email true + } +}`, + `# My Application Schema + +API Reference documentation for the schema definitions. + +## Overview + +This document provides comprehensive API documentation for all schema elements including models, types, enums, and properties. + +Generated on: 2024-01-15T10:30:00.000Z + +## Table of Contents + +- [Models](#models) + - [User](#user) +- [Types](#types) + - [Profile](#profile) +- [Enums](#enums) + - [UserRole](#userrole) +- [Props](#props) + - [Email](#email) + +## Models + +Models represent the main data structures in your application. + +### User + +**Mutability:** Immutable + +#### Columns + +| Name | Type | Required | Multiple | Description | +|------|------|----------|----------|-------------| +| id | \`String\` | ✓ | ✗ | Unique identifier for the user | +| email | \`String\` | ✓ | ✗ | User email address for authentication | +| name | \`String\` | ✓ | ✗ | Full name of the user | +| role | [UserRole](#userrole) | ✓ | ✗ | User's role in the system | +| profile | [Profile](#profile) | ✗ | ✗ | Optional user profile information | +| active | \`Boolean\` | ✓ | ✗ | Whether the user account is active | +| created | \`Date\` | ✓ | ✗ | Account creation timestamp | + +#### Column Details + +##### id + +- **Type:** \`String\` +- **Required:** Yes +- **Default:** \`nanoid()\` +- **Description:** Unique identifier for the user +- **Database:** Primary key + +##### email + +- **Type:** \`String\` +- **Required:** Yes +- **Description:** User email address for authentication +- **Validation:** + - Must be a valid email address +- **Field Configuration:** + - Input type: email +- **Database:** Unique constraint + +##### name + +- **Type:** \`String\` +- **Required:** Yes +- **Description:** Full name of the user +- **Field Configuration:** + - Input type: text + +##### role + +- **Type:** [UserRole](#userrole) +- **Required:** Yes +- **Default:** \`USER\` +- **Description:** User's role in the system +- **Field Configuration:** + - Rendered as: Select dropdown + +##### profile + +- **Type:** [Profile](#profile) +- **Required:** No +- **Description:** Optional user profile information + +##### active + +- **Type:** \`Boolean\` +- **Required:** Yes +- **Default:** \`true\` +- **Description:** Whether the user account is active +- **Field Configuration:** + - Rendered as: Checkbox + +##### created + +- **Type:** \`Date\` +- **Required:** Yes +- **Default:** \`now()\` +- **Description:** Account creation timestamp + +#### Examples + +##### JSON Structure + +\`\`\`json +{ + "id": "abc123def456", + "email": "user@example.com", + "name": "Example name", + "role": "ADMIN", + "profile": { + "bio": "Example bio", + "avatar": "Example avatar", + "website": "https://example.com" + }, + "active": true, + "created": "2024-01-15T10:30:00.000Z" +} +\`\`\` + +##### Schema Definition + +\`\`\`idea +model User! { + id String @id @default("nanoid()") + email String @unique @default("USER") + name String @optional + role UserRole @optional + profile Profile? @optional + active Boolean @optional + created Date @optional +} +\`\`\` + +## Types + +Types define reusable data structures that can be embedded in models. + +### Profile + +**Mutability:** Mutable + +#### Properties + +| Name | Type | Required | Multiple | Description | +|------|------|----------|----------|-------------| +| bio | \`String\` | ✓ | ✗ | User biography | +| avatar | \`String\` | ✓ | ✗ | Profile picture URL | +| website | \`String\` | ✓ | ✗ | Personal website URL | + +#### Example + +\`\`\`json +{ + "bio": "Example bio", + "avatar": "Example avatar", + "website": "https://example.com" +} +\`\`\` + +## Enums + +Enums define sets of named constants with associated values. + +### UserRole + +#### Values + +| Key | Value | Description | +|-----|-------|-------------| +| ADMIN | Administrator | - | +| USER | Regular User | - | +| GUEST | Guest User | - | + +#### Example + +\`\`\`idea +enum UserRole { + ADMIN "Administrator" + USER "Regular User" + GUEST "Guest User" +} +\`\`\` + +\`\`\`json +// Using in a model +{ + "status": "ADMIN" +} +\`\`\` + +## Props + +Props define reusable property configurations for form fields and validation. + +### Email + +#### Configuration + +| Property | Value | Description | +|----------|-------|-------------| +| type | \`"email"\` | - | +| placeholder | \`"Enter your email address"\` | - | +| validation | \`{"required":true,"email":true}\` | - | + +#### Example + +\`\`\`idea +prop Email { + type "email" + placeholder "Enter your email address" + validation {"required":true,"email":true} +} + +// Usage in a model +model User { + name String @field.input(Email) +} +\`\`\` + +--- + +*Documentation generated on 1/15/2024, 10:30:00 AM* + +## Support + +For questions or issues, please refer to the project documentation or contact the development team.`, + `export default async function markdownDocsPlugin(props: PluginProps<{}>) { + const { config, schema, transformer, cwd } = props; + + try { + // Validate configuration + validateConfig(config); + + // Validate schema has content + const hasContent = (schema.model && Object.keys(schema.model).length > 0) || + (schema.type && Object.keys(schema.type).length > 0) || + (schema.enum && Object.keys(schema.enum).length > 0) || + (schema.prop && Object.keys(schema.prop).length > 0); + + if (!hasContent) { + console.warn('⚠️ No schema content found. Skipping documentation generation.'); + return; + } + + // Generate documentation + if (options.format === 'single') { + await generateSingleFile(schema, options, transformer); + } else { + await generateMultipleFiles(schema, options, transformer); + } + + console.log(\`✅ Markdown documentation generated: \${options.output}\`); + + // Report statistics + const stats = { + models: schema.model ? Object.keys(schema.model).length : 0, + types: schema.type ? Object.keys(schema.type).length : 0, + enums: schema.enum ? Object.keys(schema.enum).length : 0, + props: schema.prop ? Object.keys(schema.prop).length : 0 + }; + + console.log(\`📊 Generated documentation for:\`); + console.log(\` - \${stats.models} model(s)\`); + console.log(\` - \${stats.types} type(s)\`); + console.log(\` - \${stats.enums} enum(s)\`); + console.log(\` - \${stats.props} prop(s)\`); + + } catch (error) { + console.error(\`❌ Markdown Documentation Plugin failed: \${error.message}\`); + throw error; + } +}`, + `function validateConfig(config: any): void { + if (!config.output) { + throw new Error('Markdown Documentation Plugin requires "output" configuration'); + } + + if (config.format && !['single', 'multiple'].includes(config.format)) { + throw new Error(\`Unsupported format: \${config.format}\`); + } + + if (config.template && !['default', 'api', 'guide'].includes(config.template)) { + throw new Error(\`Unsupported template: \${config.template}\`); + } + + if (config.sections && !Array.isArray(config.sections)) { + throw new Error('Sections must be an array'); + } + + const validSections = ['models', 'types', 'enums', 'props']; + if (config.sections) { + for (const section of config.sections) { + if (!validSections.includes(section)) { + throw new Error(\`Invalid section: \${section}. Valid sections are: \${validSections.join(', ')}\`); + } + } + } +}`, + `// Add support for custom templates +function loadCustomTemplate(templatePath: string): string { + // Implementation for loading custom templates + return ''; +} + +// Add support for cross-references +function generateCrossReferences(schema: any): Map { + const references = new Map(); + + // Find all type references in models + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + const refs: string[] = []; + for (const column of model.columns || []) { + if (schema.type && schema.type[column.type]) { + refs.push(column.type); + } + if (schema.enum && schema.enum[column.type]) { + refs.push(column.type); + } + } + if (refs.length > 0) { + references.set(modelName, refs); + } + } + } + + return references; +} + +// Add support for diagrams (Mermaid) +function generateMermaidDiagram(schema: any): string { + let diagram = 'erDiagram\\n'; + + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + diagram += \` \${modelName} {\\n\`; + for (const column of model.columns || []) { + const type = column.type.toLowerCase(); + const key = column.attributes?.id ? ' PK' : column.attributes?.unique ? ' UK' : ''; + diagram += \` \${type} \${column.name}\${key}\\n\`; + } + diagram += ' }\\n'; + } + } + + return diagram; +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Markdown Documentation Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates markdown documentation from schema definitions' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    Tutorial: Creating a Markdown Documentation Plugin

    +

    + This tutorial will guide you through creating a plugin that generates comprehensive markdown documentation from a processed .idea schema. +

    + +
    +

    1. Overview

    +

    The Markdown Documentation Plugin will:

    +
      +
    • Parse schema models, types, enums, and props
    • +
    • Generate structured markdown documentation
    • +
    • Include examples and usage notes
    • +
    • Create navigation and cross-references
    • +
    • Support different documentation formats and styles
    • +
    +
    + +
    +

    2. Prerequisites

    +
      +
    • Basic understanding of TypeScript/JavaScript
    • +
    • Familiarity with Markdown syntax
    • +
    • Understanding of the idea-transformer plugin system
    • +
    +
    + +
    +

    3. Understanding the Schema Structure

    +

    + Before creating the plugin, let's understand what documentation we can generate from a schema: +

    + + {examples[0]} + +
    + +
    +

    4. Create the Plugin Structure

    +

    Create a new file markdown-docs-plugin.js:

    + + {examples[1]} + +
    + +
    +

    5. Implement Documentation Generation

    +

    Create functions to generate different sections of documentation:

    + + {examples[2]} + +
    + +
    +

    6. Generate Models Documentation

    +

    Implement model documentation generation:

    + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + + + {examples[6]} + + + {examples[7]} + + + {examples[8]} + + + {examples[9]} + +
    + +
    +

    7. Generate Types, Enums, and Props Documentation

    +

    Implement documentation for other schema elements:

    + + {examples[10]} + + + {examples[11]} + + + {examples[12]} + +
    + +
    +

    8. Utility Functions

    +

    Implement helper functions for formatting and generation:

    + + {examples[13]} + + + {examples[14]} + + + {examples[15]} + +
    + +
    +

    9. Usage in Schema

    +

    To use this plugin in your schema file:

    + + {examples[16]} + +
    + +
    +

    10. Generated Output

    +

    The plugin will generate markdown documentation like this:

    + + {examples[17]} + +
    + +
    +

    11. Error Handling and Best Practices

    +

    Add proper error handling and validation:

    + + {examples[18]} + + + {examples[19]} + +
    + +
    +

    12. Advanced Features

    +

    Add support for advanced documentation features:

    + + {examples[20]} + +
    + +
    +

    Conclusion

    +

    This Markdown Documentation Plugin demonstrates how to:

    +
      +
    • Parse all schema elements (models, types, enums, props)
    • +
    • Generate comprehensive, structured documentation
    • +
    • Support multiple output formats (single file vs. multiple files)
    • +
    • Include examples, cross-references, and detailed attribute information
    • +
    • Provide flexible configuration options for different documentation needs
    • +
    +

    The plugin is highly customizable and can be extended to support:

    +
      +
    • Custom templates and themes
    • +
    • Diagram generation (Mermaid, PlantUML)
    • +
    • Integration with documentation sites (GitBook, Docusaurus)
    • +
    • API documentation formats (OpenAPI, GraphQL)
    • +
    • Multi-language documentation generation
    • +
    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx b/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx new file mode 100644 index 0000000..50c93ee --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx @@ -0,0 +1,914 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import {Table, Thead, Trow, Tcol} from 'frui/element/Table'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('MySQL Tables Plugin'); + const description = _( + 'A guide to creating a plugin that generates MySQL tables from schema definitions' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +const pluginStructureExample = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface GraphQLConfig { + output: string; + includeQueries?: boolean; + includeMutations?: boolean; + includeSubscriptions?: boolean; + customScalars?: Record; + generateInputTypes?: boolean; +} + +export default async function generateGraphQLSchema( + props: PluginProps<{ config: GraphQLConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}` +] + +const corePluginFunctionExample = [ + `export default async function generateGraphQLSchema( + props: PluginProps<{ config: GraphQLConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + if (!config.output) { + throw new Error('GraphQL plugin requires "output" configuration'); + } + + // Generate GraphQL schema + let schemaContent = ''; + + // Add custom scalars + schemaContent += generateCustomScalars(config.customScalars || {}); + + // Generate enums + if (schema.enum) { + schemaContent += generateEnums(schema.enum); + } + + // Generate types + if (schema.model) { + schemaContent += generateTypes(schema.model); + + if (config.generateInputTypes) { + schemaContent += generateInputTypes(schema.model); + } + } + + // Generate custom types + if (schema.type) { + schemaContent += generateCustomTypes(schema.type); + } + + // Generate root types + if (config.includeQueries) { + schemaContent += generateQueries(schema.model || {}); + } + + if (config.includeMutations) { + schemaContent += generateMutations(schema.model || {}); + } + + if (config.includeSubscriptions) { + schemaContent += generateSubscriptions(schema.model || {}); + } + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, schemaContent, 'utf8'); + + console.log(\`✅ GraphQL schema generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ GraphQL schema generation failed:', error.message); + throw error; + } +}`, + `function mapSchemaTypeToGraphQL(schemaType: string, customScalars: Record = {}): string { + // Check for custom scalar mappings first + if (customScalars[schemaType]) { + return customScalars[schemaType]; + } + + // Standard type mappings + const typeMap: Record = { + 'String': 'String', + 'Number': 'Float', + 'Integer': 'Int', + 'Boolean': 'Boolean', + 'Date': 'DateTime', + 'JSON': 'JSON', + 'ID': 'ID' + }; + + return typeMap[schemaType] || schemaType; +} + +function formatFieldType(column: any, customScalars: Record = {}): string { + let type = mapSchemaTypeToGraphQL(column.type, customScalars); + + // Handle arrays + if (column.multiple) { + type = \`[$\{type}\]\`; + } + + // Handle required fields + if (column.required) { + type += '!'; + } + + return type; +}`, + `function generateCustomScalars(customScalars: Record): string { + if (Object.keys(customScalars).length === 0) { + return \`# Custom Scalars +scalar DateTime +scalar JSON + +\`; + } + + let content = '# Custom Scalars\\n'; + content += 'scalar DateTime\\n'; + content += 'scalar JSON\\n'; + + for (const [name, description] of Object.entries(customScalars)) { + content += \`scalar $\{name}\\n\`; + } + + return content + '\\n'; +} + +function generateEnums(enums: Record): string { + let content = '# Enums\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + content += \`enum $\{enumName} {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` $\{key}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateTypes(models: Record): string { + let content = '# Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`type $\{modelName} {\\n\`; + + for (const column of model.columns || []) { + const fieldType = formatFieldType(column); + content += \` $\{column.name}: $\{fieldType}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateInputTypes(models: Record): string { + let content = '# Input Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + // Create input type + content += \`input $\{modelName}Input {\\n\`; + + for (const column of model.columns || []) { + // Skip auto-generated fields like ID for input types + if (column.attributes?.id) continue; + + let fieldType = formatFieldType(column); + // Remove required constraint for input types (make them optional) + fieldType = fieldType.replace('!', ''); + + content += \` $\{column.name}: $\{fieldType}\n\`; + } + + content += '}\\n\\n'; + + // Create update input type + content += \`input $\{modelName}UpdateInput {\n\`; + + for (const column of model.columns || []) { + let fieldType = formatFieldType(column); + // All fields are optional in update input + fieldType = fieldType.replace('!', ''); + + content += \` $\{column.name}: $\{fieldType}\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateCustomTypes(types: Record): string { + let content = '# Custom Types\\n'; + + for (const [typeName, typeDef] of Object.entries(types)) { + content += \`type $\{typeName} {\\n\`; + + for (const column of typeDef.columns || []) { + const fieldType = formatFieldType(column); + content += \` $\{column.name}: $\{fieldType}\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +} + +function generateQueries(models: Record): string { + let content = '# Queries\\ntype Query {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Get single item + content += \` $\{lowerName}(id: ID!): $\{modelName}\\n\`; + + // Get multiple items + content += \` $\{lowerName}s(limit: Int, offset: Int): [$\{modelName}]\\n\`; + } + + content += '}\\n\\n'; + return content; +} + +function generateMutations(models: Record): string { + let content = '# Mutations\\ntype Mutation {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Create + content += \` create$\{modelName}(input: $\{modelName}Input!): $\{modelName}\\n\`; + + // Update + content += \` update$\{modelName}(id: ID!, input: $\{modelName}UpdateInput!): $\{modelName}\\n\`; + + // Delete + content += \` delete$\{modelName}(id: ID!): Boolean\\n\`; + } + + content += '}\\n\\n'; + return content; +} + +function generateSubscriptions(models: Record): string { + let content = '# Subscriptions\\ntype Subscription {\\n'; + + for (const [modelName, model] of Object.entries(models)) { + const lowerName = modelName.toLowerCase(); + + // Subscribe to changes + content += \` $\{lowerName}Created: $\{modelName}\\n\`; + content += \` $\{lowerName}Updated: $\{modelName}\\n\`; + content += \` $\{lowerName}Deleted: ID\\n\`; + } + + content += '}\\n\\n'; + return content; +}` +] + +const schemaConfigurationExample = [ + `plugin "./plugins/graphql-schema.js" { + output "./generated/schema.graphql" + includeQueries true + includeMutations true + includeSubscriptions false + generateInputTypes true + customScalars { + Email "String" + URL "String" + PhoneNumber "String" + } +}` +] + +const basicSchemaExample = [ + `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("USER") + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/graphql-schema.js" { + output "./schema.graphql" + includeQueries true + includeMutations true +}`, +`# Custom Scalars +scalar DateTime +scalar JSON + +# Enums +enum UserRole { + ADMIN + USER + GUEST +} + +# Types +type User { + id: ID! + email: String! + name: String! + role: UserRole! + active: Boolean! + createdAt: DateTime! +} + +# Input Types +input UserInput { + email: String + name: String + role: UserRole + active: Boolean +} + +input UserUpdateInput { + email: String + name: String + role: UserRole + active: Boolean + createdAt: DateTime +} + +# Queries +type Query { + user(id: ID!): User + users(limit: Int, offset: Int): [User] +} + +# Mutations +type Mutation { + createUser(input: UserInput!): User + updateUser(id: ID!, input: UserUpdateInput!): User + deleteUser(id: ID!): Boolean +}` +] + +const advancedFeaturesExample = [ + `// In your plugin configuration +customScalars: { + Email: "String", + URL: "String", + PhoneNumber: "String", + BigInt: "String" +}`, + `function handleRelationships(column: any, models: Record): string { + // Check if the column type is another model + if (models[column.type]) { + let type = column.type; + + if (column.multiple) { + type = \`[\${type}]\`; + } + + if (column.required) { + type += '!'; + } + + return type; + } + + return formatFieldType(column); +}`, + `function generateDirectives(column: any): string { + const directives: string[] = []; + + if (column.attributes?.unique) { + directives.push('@unique'); + } + + if (column.attributes?.deprecated) { + directives.push('@deprecated(reason: "Use alternative field")'); + } + + return directives.length > 0 ? \` \${directives.join(' ')}\` : ''; +}` +] + +const bestPracticesExample = [ + `interface GraphQLColumn { + name: string; + type: string; + required: boolean; + multiple: boolean; + attributes?: Record; +} + +function validateColumn(column: any): column is GraphQLColumn { + return ( + typeof column.name === 'string' && + typeof column.type === 'string' && + typeof column.required === 'boolean' + ); +}`, + `function generateTypes(models: Record): string { + try { + let content = '# Types\\n'; + + for (const [modelName, model] of Object.entries(models)) { + if (!model.columns || !Array.isArray(model.columns)) { + console.warn(\`⚠️ Model \${modelName} has no valid columns\`); + continue; + } + + content += generateSingleType(modelName, model); + } + + return content; + } catch (error) { + throw new Error(\`Failed to generate GraphQL types: \${error.message}\`); + } +}`, + `function validateConfig(config: any): asserts config is GraphQLConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('GraphQL plugin requires "output" configuration as string'); + } + + if (config.customScalars && typeof config.customScalars !== 'object') { + throw new Error('customScalars must be an object'); + } +}`, + `// Cache type mappings +const typeCache = new Map(); + +function getCachedType(schemaType: string, customScalars: Record): string { + const cacheKey = \`\${schemaType}:\${JSON.stringify(customScalars)}\`; + + if (typeCache.has(cacheKey)) { + return typeCache.get(cacheKey)!; + } + + const mappedType = mapSchemaTypeToGraphQL(schemaType, customScalars); + typeCache.set(cacheKey, mappedType); + + return mappedType; +}` +] + +const troubleshootingExample = [ + `function sanitizeGraphQLName(name: string): string { + // GraphQL names must match /^[_A-Za-z][_0-9A-Za-z]*$/ + return name.replace(/[^_A-Za-z0-9]/g, '_').replace(/^[0-9]/, '_$&'); +}`, + `function detectCircularDependencies(models: Record): string[] { + const visited = new Set(); + const recursionStack = new Set(); + const cycles: string[] = []; + + // Implementation for cycle detection... + + return cycles; +}`, + `function validateRequiredFields(model: any): void { + if (!model.columns || model.columns.length === 0) { + throw new Error(\`Model must have at least one column\`); + } +}`, + `const DEBUG = process.env.DEBUG === 'true'; + +function debugLog(message: string, data?: any) { + if (DEBUG) { + console.log(\`[GraphQL Plugin] \${message}\`, data || ''); + } +}`, + `import { buildSchema } from 'graphql'; + +function validateGeneratedSchema(schemaContent: string): void { + try { + buildSchema(schemaContent); + console.log('✅ Generated GraphQL schema is valid'); + } catch (error) { + throw new Error(\`Invalid GraphQL schema: \${error.message}\`); + } +}` +] + +export function Body() { + + return ( +
    +

    GraphQL Schema Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates GraphQL type definitions from .idea schema files. The plugin will transform your schema models, types, and enums into proper GraphQL schema definitions. +

    + +
    +

    1. Overview

    +

    + GraphQL is a query language and runtime for APIs that provides a complete and understandable description of the data in your API. This plugin transforms your .idea schema definitions into comprehensive GraphQL type definitions that enable type-safe API development with excellent tooling support. +

    +

    This plugin generates GraphQL type definitions from your .idea schema, including:

    +
    + +
    +

    2. Prerequisites

    +

    Before implementing the GraphQL schema generator plugin, ensure you have the necessary development environment and knowledge. This section covers the essential requirements for successful plugin creation and GraphQL integration.

    + +
      +
    • Node.js 16+ and npm/yarn
    • +
    • Basic understanding of GraphQL
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    + The plugin structure defines the core architecture and configuration interface for the GraphQL schema generator. This includes the main plugin function, configuration types, and the overall organization of the generated GraphQL schema definitions. +

    + + + {pluginStructureExample[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle GraphQL schema generation. This includes configuration validation, content generation, file writing, and error handling throughout the generation process. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for GraphQL schema generation. It orchestrates the entire process from configuration validation through content generation to file output, ensuring proper error handling and logging throughout. +

    + + + {corePluginFunctionExample[0]} + + +

    4.2. Type Mapping Functions

    +

    + Type mapping functions handle the conversion of .idea schema types to their GraphQL equivalents. These functions ensure proper type safety and handle complex scenarios like arrays, required fields, and custom scalar types. +

    + + + {corePluginFunctionExample[1]} + + +

    4.3. Schema Generation Functions

    +

    Schema generation functions create specific parts of the GraphQL schema including custom scalars, enums, types, input types, and root operation types. These functions handle proper GraphQL syntax construction and type relationships.

    + + + {corePluginFunctionExample[2]} + +
    + +
    +

    5. Schema Configuration

    +

    + Schema configuration demonstrates how to integrate the GraphQL schema generator into your .idea schema files. This section covers plugin configuration options and their effects on the generated GraphQL schema definitions. +

    + +

    Add the GraphQL plugin to your .idea schema file:

    + + + {schemaConfigurationExample[0]} + + +

    Configuration Options

    +

    Configuration options control how GraphQL schema definitions are generated, including operation types, input generation, and custom scalar handling. Understanding these options helps you customize the plugin to meet your specific GraphQL requirements.

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for the GraphQL schema + + + includeQueries + boolean + false + Generate Query type with CRUD operations + + + includeMutations + boolean + false + Generate Mutation type with CRUD operations + + + includeSubscriptions + boolean + false + Generate Subscription type for real-time updates + + + generateInputTypes + boolean + true + Generate input types for mutations + + + customScalars + object + {} + Custom scalar type mappings. + +
    +
    + +
    +

    Usage Examples

    +

    + Usage examples demonstrate practical applications of the GraphQL schema generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated GraphQL schemas integrate into development workflows. +

    + +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate GraphQL type definitions. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces comprehensive GraphQL schemas. +

    + + + {basicSchemaExample[0]} + + +

    6.2. Generated Output

    +

    + The generated output demonstrates the GraphQL schema produced by the plugin from the basic schema example. This shows how schema definitions are transformed into proper GraphQL type definitions with full type safety and operation support. +

    + + + {basicSchemaExample[1]} + + +
    + +
    +

    7. Advanced Features

    +

    + Advanced features extend the basic GraphQL schema generation with sophisticated type handling, relationship management, directive support, and custom scalar types. These features enable production-ready GraphQL schemas that handle complex requirements. +

    + +

    7.1. Custom Scalar Types

    +

    + Custom scalar types allow you to define specialized data types that map to specific validation or formatting requirements. This feature enables the creation of domain-specific types that enhance type safety and API clarity. +

    + + + {advancedFeaturesExample[0]} + + +

    7.2. Relationship Handling

    +

    + Relationship handling manages references between different types and models in your schema. This ensures that type relationships are properly represented in the generated GraphQL schema with correct type references and nullability handling. +

    + + + {advancedFeaturesExample[1]} + + +

    7.3. Directive Support

    +

    + Directive support enables the addition of GraphQL directives to fields and types, providing metadata and behavior hints for GraphQL servers and tools. This feature enhances schema expressiveness and enables advanced GraphQL features. +

    + + + {advancedFeaturesExample[2]} + +
    + +
    +

    8. Best Practices

    +

    + Best practices ensure your generated GraphQL schemas are maintainable, performant, and follow GraphQL conventions. These guidelines cover type safety, error handling, configuration validation, and performance optimization. +

    + +

    8.1. Type Safety

    +

    + Type safety is crucial for preventing runtime errors and ensuring reliable GraphQL schema generation. Always validate input data and use proper TypeScript types throughout the plugin implementation to ensure consistent output. +

    + + + {bestPracticesExample[0]} + + +

    8.2. Error Handling

    +

    + Proper error handling ensures that schema generation failures provide clear, actionable feedback to developers. Implement comprehensive error handling patterns and meaningful error messages to improve the debugging experience. +

    + + + {bestPracticesExample[1]} + + +

    8.3. Configuration Validation

    +

    + Configuration validation ensures that plugin settings are correct and complete before schema generation begins. This prevents runtime errors and provides early feedback about configuration issues. +

    + + + {bestPracticesExample[2]} + + +

    8.4. Performance Optimization

    +

    + Performance optimization techniques help maintain reasonable generation times when working with large schemas. Implement caching strategies and efficient algorithms to ensure the plugin scales well with complex type hierarchies. +

    + + + {bestPracticesExample[3]} + +
    + +
    +

    9. Troubleshooting

    +

    + This section addresses common issues encountered when generating GraphQL schemas and provides solutions for debugging and resolving problems. Understanding these troubleshooting techniques helps ensure reliable schema generation. +

    + +

    9.1. Common Issues

    +

    + Common issues include invalid GraphQL identifiers, circular dependencies, and missing required fields. These problems typically arise from schema complexity or naming conflicts that can be resolved with proper validation and sanitization. +

    + +

    9.1.1. Invalid GraphQL Names

    +

    + Invalid GraphQL names occur when schema identifiers contain characters that are not valid in GraphQL. The plugin should validate and sanitize names to ensure they conform to GraphQL naming conventions. +

    + + + {troubleshootingExample[0]} + + +

    9.1.2. Circular Dependencies

    +

    + Circular dependencies can cause infinite loops during generation or invalid GraphQL schemas. Detecting and handling these scenarios is essential for robust schema generation, especially with complex type relationships. +

    + + + {troubleshootingExample[1]} + + +

    9.1.3. Missing Required Fields

    +

    + Missing required fields can result in invalid GraphQL types that fail validation. Ensure all models have proper field definitions and handle edge cases where schema definitions might be incomplete. +

    + + + {troubleshootingExample[2]} + + +

    9.2. Debugging Tips

    +

    + Debugging tips help identify and resolve issues during GraphQL schema generation. These techniques provide visibility into the generation process and help diagnose problems with schema logic or output formatting. +

    + +

    9.2.1. Enable Verbose Logging

    +

    + Verbose logging provides detailed information about the schema generation process, helping identify where issues occur and what data is being processed at each step. +

    + + + {troubleshootingExample[3]} + + +

    9.2.2. Validate Generated Schema

    +

    + Validating the generated GraphQL schema ensures that the output is syntactically correct and will work with GraphQL servers and tools. This validation step catches generation errors before deployment. +

    + + + {troubleshootingExample[4]} + + +

    + This tutorial provides a comprehensive foundation for creating GraphQL schema generators from .idea files. The generated schemas can be used with any GraphQL server implementation like Apollo Server, GraphQL Yoga, or others. +

    +
    + + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/openapi-specification-plugin.tsx b/packages/www/plugins/docs/views/tutorials/openapi-specification-plugin.tsx new file mode 100644 index 0000000..4453f2d --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/openapi-specification-plugin.tsx @@ -0,0 +1,1436 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `// plugins/openapi-spec.ts +import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface OpenAPIConfig { + output: string; + info?: { + title?: string; + version?: string; + description?: string; + contact?: { + name?: string; + email?: string; + url?: string; + }; + license?: { + name?: string; + url?: string; + }; + }; + servers?: Array<{ + url: string; + description?: string; + }>; + security?: { + apiKey?: boolean; + bearer?: boolean; + oauth2?: boolean; + }; + endpoints?: { + crud?: boolean; + custom?: Record; + }; +} + +export default async function generateOpenAPISpec( + props: PluginProps<{ config: OpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + // Validate configuration + if (!config.output) { + throw new Error('OpenAPI plugin requires "output" configuration'); + } + + // Generate OpenAPI specification + const spec = generateSpecification(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, JSON.stringify(spec, null, 2), 'utf8'); + + console.log(\`✅ Generated OpenAPI specification: \${outputPath}\`); +}`, + `function generateSpecification(schema: any, config: OpenAPIConfig) { + const spec: any = { + openapi: '3.0.3', + info: { + title: config.info?.title || 'API Documentation', + version: config.info?.version || '1.0.0', + description: config.info?.description || 'Generated API documentation', + ...config.info?.contact && { contact: config.info.contact }, + ...config.info?.license && { license: config.info.license } + }, + servers: config.servers || [ + { url: 'http://localhost:3000', description: 'Development server' } + ], + paths: {}, + components: { + schemas: {}, + securitySchemes: {} + } + }; + + // Generate schemas from models and types + if (schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + spec.components.schemas[name] = generateModelSchema(model); + } + } + + if (schema.type) { + for (const [name, type] of Object.entries(schema.type)) { + spec.components.schemas[name] = generateTypeSchema(type); + } + } + + if (schema.enum) { + for (const [name, enumDef] of Object.entries(schema.enum)) { + spec.components.schemas[name] = generateEnumSchema(enumDef); + } + } + + // Generate security schemes + if (config.security) { + generateSecuritySchemes(spec, config.security); + } + + // Generate CRUD endpoints + if (config.endpoints?.crud && schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + generateCRUDEndpoints(spec, name, model); + } + } + + // Add custom endpoints + if (config.endpoints?.custom) { + for (const [path, operation] of Object.entries(config.endpoints.custom)) { + spec.paths[path] = operation; + } + } + + return spec; +}`, + `function generateModelSchema(model: any): any { + const schema: any = { + type: 'object', + properties: {}, + required: [] + }; + + if (model.columns) { + for (const column of model.columns) { + const property = generatePropertySchema(column); + schema.properties[column.name] = property; + + if (column.required) { + schema.required.push(column.name); + } + } + } + + return schema; +} + +function generateTypeSchema(type: any): any { + const schema: any = { + type: 'object', + properties: {}, + required: [] + }; + + if (type.columns) { + for (const column of type.columns) { + const property = generatePropertySchema(column); + schema.properties[column.name] = property; + + if (column.required) { + schema.required.push(column.name); + } + } + } + + return schema; +} + +function generateEnumSchema(enumDef: any): any { + const values = Object.values(enumDef); + return { + type: 'string', + enum: values, + example: values[0] + }; +}`, + `function generatePropertySchema(column: any): any { + const property: any = {}; + + // Map idea types to OpenAPI types + switch (column.type) { + case 'String': + property.type = 'string'; + break; + case 'Number': + property.type = 'number'; + break; + case 'Integer': + property.type = 'integer'; + break; + case 'Boolean': + property.type = 'boolean'; + break; + case 'Date': + property.type = 'string'; + property.format = 'date-time'; + break; + case 'JSON': + property.type = 'object'; + break; + default: + // Reference to another schema + property.$ref = \`#/components/schemas/\${column.type}\`; + } + + // Handle arrays + if (column.multiple) { + property = { + type: 'array', + items: property + }; + } + + // Add validation from attributes + if (column.attributes) { + addValidationRules(property, column.attributes); + } + + return property; +} + +function addValidationRules(property: any, attributes: any): void { + // String validations + if (attributes.minLength) { + property.minLength = attributes.minLength; + } + if (attributes.maxLength) { + property.maxLength = attributes.maxLength; + } + if (attributes.pattern) { + property.pattern = attributes.pattern; + } + + // Number validations + if (attributes.minimum) { + property.minimum = attributes.minimum; + } + if (attributes.maximum) { + property.maximum = attributes.maximum; + } + + // Examples and descriptions + if (attributes.example) { + property.example = attributes.example; + } + if (attributes.description) { + property.description = attributes.description; + } + + // Format validations + if (attributes.format) { + property.format = attributes.format; + } +}`, + `// schema.idea +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec.json" + info { + title "User Management API" + version "2.0.0" + description "Comprehensive user management system API" + contact { + name "API Support" + email "support@example.com" + url "https://example.com/support" + } + license { + name "MIT" + url "https://opensource.org/licenses/MIT" + } + } + servers [ + { + url "https://api.example.com/v2" + description "Production server" + } + { + url "https://staging-api.example.com/v2" + description "Staging server" + } + { + url "http://localhost:3000" + description "Development server" + } + ] + security { + apiKey true + bearer true + oauth2 false + } + endpoints { + crud true + custom { + "/auth/login" { + post { + summary "User login" + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + email { + type "string" + format "email" + } + password { + type "string" + minLength 8 + } + } + required ["email" "password"] + } + } + } + } + responses { + "200" { + description "Login successful" + content { + "application/json" { + schema { + type "object" + properties { + token { + type "string" + } + user { + "$ref" "#/components/schemas/User" + } + } + } + } + } + } + "401" { + description "Invalid credentials" + } + } + } + } + } + } +}`, + `function generateSecuritySchemes(spec: any, security: any): void { + if (security.apiKey) { + spec.components.securitySchemes.ApiKeyAuth = { + type: 'apiKey', + in: 'header', + name: 'X-API-Key' + }; + } + + if (security.bearer) { + spec.components.securitySchemes.BearerAuth = { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT' + }; + } + + if (security.oauth2) { + spec.components.securitySchemes.OAuth2 = { + type: 'oauth2', + flows: { + authorizationCode: { + authorizationUrl: 'https://example.com/oauth/authorize', + tokenUrl: 'https://example.com/oauth/token', + scopes: { + read: 'Read access', + write: 'Write access', + admin: 'Admin access' + } + } + } + }; + } +}`, + `function generateCRUDEndpoints(spec: any, modelName: string, model: any): void { + const resourcePath = \`/\${modelName.toLowerCase()}s\`; + const itemPath = \`\${resourcePath}/{id}\`; + + // GET /resources - List all + spec.paths[resourcePath] = { + get: { + summary: \`List all \${modelName}s\`, + tags: [modelName], + parameters: [ + { + name: 'page', + in: 'query', + schema: { type: 'integer', minimum: 1, default: 1 }, + description: 'Page number' + }, + { + name: 'limit', + in: 'query', + schema: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + description: 'Items per page' + }, + { + name: 'sort', + in: 'query', + schema: { type: 'string' }, + description: 'Sort field' + }, + { + name: 'order', + in: 'query', + schema: { type: 'string', enum: ['asc', 'desc'], default: 'asc' }, + description: 'Sort order' + } + ], + responses: { + '200': { + description: \`List of \${modelName}s\`, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + data: { + type: 'array', + items: { $ref: \`#/components/schemas/\${modelName}\` } + }, + pagination: { + type: 'object', + properties: { + page: { type: 'integer' }, + limit: { type: 'integer' }, + total: { type: 'integer' }, + pages: { type: 'integer' } + } + } + } + } + } + } + } + }, + security: [{ BearerAuth: [] }] + }, + post: { + summary: \`Create a new \${modelName}\`, + tags: [modelName], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + responses: { + '201': { + description: \`\${modelName} created successfully\`, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + '400': { + description: 'Validation error', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string' }, + errors: { + type: 'object', + additionalProperties: { type: 'string' } + } + } + } + } + } + } + }, + security: [{ BearerAuth: [] }] + } + }; +}`, + `interface AdvancedOpenAPIConfig extends OpenAPIConfig { + formats?: ('json' | 'yaml' | 'html')[]; + validation?: { + strict?: boolean; + examples?: boolean; + }; + documentation?: { + includeExamples?: boolean; + includeSchemas?: boolean; + customTemplates?: string; + }; +} + +export default async function generateAdvancedOpenAPISpec( + props: PluginProps<{ config: AdvancedOpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + const spec = generateSpecification(schema, config); + + // Add validation and examples + if (config.validation?.examples) { + addExamples(spec, schema); + } + + if (config.validation?.strict) { + validateSpecification(spec); + } + + // Generate multiple formats + const formats = config.formats || ['json']; + const outputBase = config.output.replace(/\\.[^.]+$/, ''); + + for (const format of formats) { + await generateFormat(spec, format, outputBase, transformer); + } +}`, + `async function generateFormat( + spec: any, + format: string, + outputBase: string, + transformer: any +): Promise { + let content: string; + let extension: string; + + switch (format) { + case 'json': + content = JSON.stringify(spec, null, 2); + extension = '.json'; + break; + case 'yaml': + const yaml = await import('yaml'); + content = yaml.stringify(spec); + extension = '.yaml'; + break; + case 'html': + content = generateHTMLDocumentation(spec); + extension = '.html'; + break; + default: + throw new Error(\`Unsupported format: \${format}\`); + } + + const outputPath = await transformer.loader.absolute(\`\${outputBase}\${extension}\`); + await fs.writeFile(outputPath, content, 'utf8'); + console.log(\`✅ Generated \${format.toUpperCase()} specification: \${outputPath}\`); +}`, + `// schema.idea +enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @unique @format("email") + name String @minLength(2) @maxLength(100) + role UserRole @default("USER") + active Boolean @default(true) + created Date @default("now()") + updated Date @default("updated()") +} + +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec.json" + info { + title "User API" + version "1.0.0" + description "User management API" + } + endpoints { + crud true + } + security { + bearer true + } +}`, + `// schema.idea +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec" + formats ["json" "yaml" "html"] + info { + title "E-commerce API" + version "2.1.0" + description "Comprehensive e-commerce platform API" + contact { + name "API Team" + email "api@ecommerce.com" + url "https://ecommerce.com/api-support" + } + license { + name "Apache 2.0" + url "https://www.apache.org/licenses/LICENSE-2.0.html" + } + } + servers [ + { + url "https://api.ecommerce.com/v2" + description "Production server" + } + { + url "https://staging-api.ecommerce.com/v2" + description "Staging server" + } + ] + security { + apiKey true + bearer true + oauth2 true + } + endpoints { + crud true + custom { + "/auth/login" { + post { + summary "Authenticate user" + tags ["Authentication"] + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + email { type "string" format "email" } + password { type "string" minLength 8 } + remember { type "boolean" default false } + } + required ["email" "password"] + } + } + } + } + responses { + "200" { + description "Login successful" + content { + "application/json" { + schema { + type "object" + properties { + token { type "string" } + refreshToken { type "string" } + expiresIn { type "integer" } + user { "$ref" "#/components/schemas/User" } + } + } + } + } + } + "401" { + description "Invalid credentials" + content { + "application/json" { + schema { + type "object" + properties { + error { type "string" } + code { type "string" } + } + } + } + } + } + } + } + } + "/auth/refresh" { + post { + summary "Refresh access token" + tags ["Authentication"] + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + refreshToken { type "string" } + } + required ["refreshToken"] + } + } + } + } + responses { + "200" { + description "Token refreshed" + content { + "application/json" { + schema { + type "object" + properties { + token { type "string" } + expiresIn { type "integer" } + } + } + } + } + } + } + } + } + } + } + validation { + strict true + examples true + } +}`, + `# Generate OpenAPI specification +npm run transform + +# Serve documentation locally +npx swagger-ui-serve docs/api-spec.json + +# Validate specification +npx swagger-codegen validate -i docs/api-spec.json + +# Generate client SDKs +npx swagger-codegen generate -i docs/api-spec.json -l typescript-fetch -o ./sdk/typescript +npx swagger-codegen generate -i docs/api-spec.json -l python -o ./sdk/python`, + `// Always include detailed descriptions +function generateModelSchema(model: any): any { + const schema: any = { + type: 'object', + description: model.description || \`\${model.name} entity\`, + properties: {}, + required: [] + }; + + // Add property descriptions + if (model.columns) { + for (const column of model.columns) { + const property = generatePropertySchema(column); + + // Add description from attributes or generate one + if (column.attributes?.description) { + property.description = column.attributes.description; + } else { + property.description = generatePropertyDescription(column); + } + + schema.properties[column.name] = property; + } + } + + return schema; +} + +function generatePropertyDescription(column: any): string { + const descriptions: Record = { + id: 'Unique identifier', + email: 'Email address', + name: 'Full name', + created: 'Creation timestamp', + updated: 'Last update timestamp', + active: 'Active status flag' + }; + + return descriptions[column.name] || \`\${column.name} field\`; +}`, + `function generateErrorResponses(): any { + return { + '400': { + description: 'Bad Request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', description: 'Error message' }, + code: { type: 'string', description: 'Error code' }, + errors: { + type: 'object', + additionalProperties: { type: 'string' }, + description: 'Field-specific errors' + } + }, + required: ['error'] + } + } + } + }, + '401': { + description: 'Unauthorized', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Authentication required' } + } + } + } + } + }, + '403': { + description: 'Forbidden', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Insufficient permissions' } + } + } + } + } + }, + '404': { + description: 'Not Found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Resource not found' } + } + } + } + } + }, + '500': { + description: 'Internal Server Error', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Internal server error' } + } + } + } + } + } + }; +}`, + `function addSecurityToEndpoints(spec: any): void { + // Add security requirements to all endpoints + for (const [path, pathObj] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(pathObj)) { + // Skip public endpoints + if (isPublicEndpoint(path, method)) { + continue; + } + + // Add appropriate security scheme + if (!operation.security) { + operation.security = [{ BearerAuth: [] }]; + } + } + } +} + +function isPublicEndpoint(path: string, method: string): boolean { + const publicEndpoints = [ + { path: '/auth/login', method: 'post' }, + { path: '/auth/register', method: 'post' }, + { path: '/health', method: 'get' } + ]; + + return publicEndpoints.some(endpoint => + endpoint.path === path && endpoint.method === method.toLowerCase() + ); +}`, + `function addValidationExamples(spec: any): void { + // Add validation examples to request bodies + for (const [path, pathObj] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(pathObj)) { + if (operation.requestBody?.content?.['application/json']?.schema) { + const schema = operation.requestBody.content['application/json'].schema; + + // Add valid example + if (!schema.example) { + schema.example = generateValidExample(schema); + } + + // Add examples for validation errors + if (!schema.examples) { + schema.examples = { + valid: { + summary: 'Valid request', + value: generateValidExample(schema) + }, + invalid: { + summary: 'Invalid request (validation errors)', + value: generateInvalidExample(schema) + } + }; + } + } + } + } +}`, + `// Problem: Circular references in schemas +// Solution: Use allOf or oneOf patterns + +function handleCircularReferences(spec: any): void { + // Detect and resolve circular references + const visited = new Set(); + + function checkSchema(schema: any, path: string): void { + if (visited.has(path)) { + // Circular reference detected + console.warn(\`Circular reference detected: \${path}\`); + return; + } + + visited.add(path); + + if (schema.$ref) { + const refPath = schema.$ref.replace('#/components/schemas/', ''); + checkSchema(spec.components.schemas[refPath], refPath); + } + + if (schema.properties) { + for (const [propName, propSchema] of Object.entries(schema.properties)) { + checkSchema(propSchema, \`\${path}.\${propName}\`); + } + } + + visited.delete(path); + } + + for (const [name, schema] of Object.entries(spec.components.schemas)) { + checkSchema(schema, name); + } +}`, + `// Problem: Generated spec doesn't validate +// Solution: Add comprehensive validation + +function validateOpenAPISpec(spec: any): void { + const errors: string[] = []; + + // Check required fields + if (!spec.openapi) errors.push('Missing openapi version'); + if (!spec.info) errors.push('Missing info object'); + if (!spec.paths) errors.push('Missing paths object'); + + // Validate info object + if (spec.info) { + if (!spec.info.title) errors.push('Missing info.title'); + if (!spec.info.version) errors.push('Missing info.version'); + } + + // Validate paths + if (spec.paths) { + for (const [path, pathObj] of Object.entries(spec.paths)) { + if (!path.startsWith('/')) { + errors.push(\`Path must start with '/': \${path}\`); + } + + for (const [method, operation] of Object.entries(pathObj)) { + if (!operation.responses) { + errors.push(\`Missing responses for \${method.toUpperCase()} \${path}\`); + } + } + } + } + + // Validate components + if (spec.components?.schemas) { + for (const [name, schema] of Object.entries(spec.components.schemas)) { + if (!schema.type && !schema.$ref && !schema.allOf && !schema.oneOf) { + errors.push(\`Schema \${name} missing type definition\`); + } + } + } + + if (errors.length > 0) { + throw new Error(\`OpenAPI validation failed:\\n\${errors.join('\\n')}\`); + } + + console.log('✅ OpenAPI specification validation passed'); +}`, + `# Install required dependencies +npm install --save-dev yaml swagger-ui-dist + +# For validation +npm install --save-dev swagger-parser + +# For code generation +npm install --save-dev @openapitools/openapi-generator-cli`, + `// Problem: Large schemas cause performance issues +// Solution: Implement schema optimization + +function optimizeSchema(spec: any): any { + // Remove unused schemas + const usedSchemas = new Set(); + + // Find all schema references + function findReferences(obj: any): void { + if (typeof obj === 'object' && obj !== null) { + if (obj.$ref && obj.$ref.startsWith('#/components/schemas/')) { + const schemaName = obj.$ref.replace('#/components/schemas/', ''); + usedSchemas.add(schemaName); + } + + for (const value of Object.values(obj)) { + findReferences(value); + } + } + } + + findReferences(spec.paths); + + // Remove unused schemas + const optimizedSchemas: any = {}; + for (const schemaName of usedSchemas) { + if (spec.components.schemas[schemaName]) { + optimizedSchemas[schemaName] = spec.components.schemas[schemaName]; + } + } + + return { + ...spec, + components: { + ...spec.components, + schemas: optimizedSchemas + } + }; +}`, + `interface DebugOpenAPIConfig extends AdvancedOpenAPIConfig { + debug?: boolean; + logLevel?: 'info' | 'warn' | 'error'; +} + +export default async function generateOpenAPISpecWithDebug( + props: PluginProps<{ config: DebugOpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + if (config.debug) { + console.log('🔍 Debug mode enabled'); + console.log('Schema models:', Object.keys(schema.model || {})); + console.log('Schema types:', Object.keys(schema.type || {})); + console.log('Schema enums:', Object.keys(schema.enum || {})); + } + + try { + const spec = generateSpecification(schema, config); + + if (config.debug) { + console.log('Generated schemas:', Object.keys(spec.components.schemas)); + console.log('Generated paths:', Object.keys(spec.paths)); + } + + // Validate before writing + if (config.validation?.strict) { + validateOpenAPISpec(spec); + } + + // Optimize if needed + const optimizedSpec = config.debug ? optimizeSchema(spec) : spec; + + // Generate outputs + const formats = config.formats || ['json']; + const outputBase = config.output.replace(/\\.[^.]+$/, ''); + + for (const format of formats) { + await generateFormat(optimizedSpec, format, outputBase, transformer); + } + + if (config.debug) { + console.log('✅ OpenAPI generation completed successfully'); + } + + } catch (error) { + console.error('❌ OpenAPI generation failed:', error.message); + if (config.debug) { + console.error('Stack trace:', error.stack); + } + throw error; + } +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('OpenAPI Specification Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates OpenAPI 3.0 specifications from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    OpenAPI Specification Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin for @stackpress/idea-transformer that generates OpenAPI 3.0 specifications from .idea schema files. The plugin will create comprehensive API documentation with endpoints, schemas, and validation rules. +

    + +
    +

    1. Overview

    +

    + OpenAPI (formerly Swagger) specifications provide a standard way to document REST APIs. This plugin transforms your .idea schema definitions into comprehensive API documentation that follows industry standards and integrates seamlessly with existing API development workflows. +

    +

    This plugin will:

    +
      +
    • Generate OpenAPI 3.0 compliant specifications
    • +
    • Create schemas from idea models and types
    • +
    • Generate CRUD endpoints for models
    • +
    • Include validation rules and examples
    • +
    • Support custom endpoints and operations
    • +
    • Generate security schemes and authentication
    • +
    + +

    What You'll Learn

    +

    + This section outlines the key concepts and skills you'll acquire through this tutorial. Understanding these fundamentals will enable you to create robust API documentation that serves both developers and automated tooling. +

    +
      +
    • Processing idea schemas for API documentation
    • +
    • OpenAPI 3.0 specification structure
    • +
    • Schema generation and validation
    • +
    • Endpoint documentation patterns
    • +
    • Security and authentication schemes
    • +
    +
    + +
    +

    2. Basic Implementation

    +

    + The basic implementation provides the foundation for generating OpenAPI specifications from .idea schema files. This section covers the core plugin structure, configuration interface, and essential generation functions needed to create functional API documentation. +

    +

    Let's start with a basic OpenAPI specification generator:

    + +

    2.1. Plugin Structure

    +

    + The plugin structure defines the main entry point and configuration interface for the OpenAPI generator. This includes type definitions for configuration options, the primary plugin function, and the core specification generation logic. +

    + + {examples[0]} + + +

    2.2. Schema Generation

    +

    + Schema generation transforms .idea model and type definitions into OpenAPI-compliant schema objects. This process includes mapping data types, handling validation rules, and creating proper JSON Schema structures that integrate with OpenAPI tooling. +

    + + {examples[1]} + + + {examples[2]} + + + {examples[3]} + +
    + +
    +

    3. Configuration Options

    +

    + Configuration options control how the OpenAPI specification is generated, including output formats, API metadata, server definitions, and security schemes. Proper configuration ensures the generated documentation meets your specific requirements and integrates with your development workflow. +

    + + {examples[4]} + +
    + +
    +

    4. Schema Processing

    +

    + Schema processing handles the transformation of .idea definitions into OpenAPI components and endpoints. This includes generating security schemes, creating CRUD endpoints for models, and handling complex schema relationships and validations. +

    + + {examples[5]} + + + {examples[6]} + +
    + +
    +

    5. Multiple Output Formats

    +

    + Multiple output formats allow you to generate OpenAPI specifications in JSON, YAML, and HTML formats. This flexibility ensures compatibility with different tools and enables both machine-readable specifications and human-friendly documentation. +

    + + {examples[7]} + + + {examples[8]} + +
    + +
    +

    6. Usage Examples

    +

    + Usage examples demonstrate practical applications of the OpenAPI generator plugin with real-world scenarios. These examples show how to configure the plugin for different use cases and integrate the generated documentation into your development workflow. +

    + +

    6.1. Basic Usage

    +

    + Basic usage examples show the fundamental configuration needed to generate OpenAPI specifications from simple .idea schemas. This includes model definitions, plugin configuration, and the resulting API documentation structure. +

    + + {examples[9]} + + +

    6.2. Advanced Configuration

    +

    + Advanced configuration demonstrates comprehensive plugin setup with multiple output formats, detailed API metadata, custom endpoints, and security schemes. This example shows how to create production-ready API documentation with full feature coverage. +

    + + {examples[10]} + + +

    6.3. CLI Integration

    +

    + CLI integration shows how to incorporate the OpenAPI generator into your development workflow using command-line tools. This includes generating specifications, serving documentation locally, and integrating with API development tools. +

    + + {examples[11]} + +
    + +
    +

    7. Best Practices

    +

    + Best practices ensure your generated OpenAPI specifications are comprehensive, maintainable, and follow industry standards. These guidelines cover documentation quality, error handling, security implementation, and validation strategies. +

    + +

    7.1. Comprehensive Documentation

    +

    + Comprehensive documentation practices ensure your API specifications provide clear, detailed information for both human readers and automated tools. This includes proper descriptions, examples, and consistent formatting throughout the specification. +

    + + {examples[12]} + + +

    7.2. Consistent Error Responses

    +

    + Consistent error responses provide standardized error handling across your API endpoints. This approach ensures predictable error formats that client applications can handle reliably, improving the overall developer experience. +

    + + {examples[13]} + + +

    7.3. Security Best Practices

    +

    + Security best practices ensure your API documentation properly represents authentication and authorization requirements. This includes applying appropriate security schemes to endpoints and documenting access control patterns. +

    + + {examples[14]} + + +

    7.4. Validation and Testing

    +

    + Validation and testing practices ensure your generated OpenAPI specifications are accurate and functional. This includes adding validation examples, testing request/response formats, and verifying specification compliance. +

    + + {examples[15]} + +
    + +
    +

    8. Troubleshooting

    +

    + This section addresses common issues encountered when generating OpenAPI specifications and provides solutions for debugging and resolving problems. Understanding these troubleshooting techniques helps ensure reliable specification generation. +

    + +

    8.1. Common Issues

    +

    + Common issues include schema reference errors, validation failures, and performance problems with large specifications. These problems typically arise from circular references, invalid configurations, or missing dependencies. +

    + +

    8.1.1. Schema Reference Errors

    +

    + Schema reference errors occur when the generator encounters circular dependencies or invalid references between schema components. These issues can break the specification generation process and require careful handling of schema relationships. +

    + + {examples[16]} + + +

    8.1.2. Invalid OpenAPI Format

    +

    + Invalid OpenAPI format errors occur when the generated specification doesn't conform to OpenAPI standards. These validation failures can prevent the specification from working with OpenAPI tools and require comprehensive validation during generation. +

    + + {examples[17]} + + +

    8.1.3. Missing Dependencies

    +

    + Missing dependencies can cause the plugin to fail during execution or limit available features. Ensuring all required packages are installed and properly configured is essential for reliable operation. +

    + + {examples[18]} + + +

    8.1.4. Performance Issues

    +

    + Performance issues can occur when generating specifications for large schemas with many models and complex relationships. Optimization techniques help maintain reasonable generation times and manageable output file sizes. +

    + + {examples[19]} + + +

    8.2. Debug Mode

    +

    + Debug mode provides detailed logging and diagnostic information during specification generation. This feature helps identify issues, understand the generation process, and optimize plugin configuration for better results. +

    + + {examples[20]} + +
    + +
    +

    Conclusion

    +

    + This OpenAPI Specification Generator plugin provides a comprehensive solution for generating API documentation from .idea schema files. Key features include: +

    +
      +
    • Complete OpenAPI 3.0 Support: Generates fully compliant specifications
    • +
    • Automatic CRUD Endpoints: Creates standard REST endpoints for models
    • +
    • Security Integration: Supports multiple authentication schemes
    • +
    • Multiple Output Formats: JSON, YAML, and HTML documentation
    • +
    • Validation and Examples: Includes request/response examples and validation
    • +
    • Extensible Configuration: Highly customizable for different use cases
    • +
    + +

    + The plugin follows TypeScript best practices and provides comprehensive error handling, making it suitable for production use in API development workflows. +

    + +

    Next Steps

    +
      +
    • Extend Schema Mapping: Add support for more complex schema relationships
    • +
    • Custom Templates: Implement custom documentation templates
    • +
    • Integration Testing: Add automated testing for generated specifications
    • +
    • Performance Optimization: Implement caching and incremental generation
    • +
    • Plugin Ecosystem: Create complementary plugins for API testing and client generation
    • +
    + +

    + This tutorial provides a solid foundation for generating professional API documentation that can be used with tools like Swagger UI, Postman, and various code generators. +

    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/test-data-plugin.tsx b/packages/www/plugins/docs/views/tutorials/test-data-plugin.tsx new file mode 100644 index 0000000..7892b57 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/test-data-plugin.tsx @@ -0,0 +1,806 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface TestDataConfig { + output: string; + format: 'json' | 'typescript' | 'javascript'; + count?: number; + seed?: number; + locale?: string; + generateFactories?: boolean; + generateFixtures?: boolean; + customGenerators?: Record; + relationships?: boolean; +} + +export default async function generateTestData( + props: PluginProps<{ config: TestDataConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`, + `export default async function generateTestData( + props: PluginProps<{ config: TestDataConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate test data content + let content = ''; + + // Add file header and imports + content += generateFileHeader(config); + content += generateImports(config); + + // Generate data factories if requested + if (config.generateFactories) { + content += generateFactories(schema, config); + } + + // Generate mock data + if (schema.model) { + content += generateMockData(schema.model, config); + } + + // Generate fixtures if requested + if (config.generateFixtures) { + content += generateFixtures(schema, config); + } + + // Generate main export + content += generateMainExport(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ Test data generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ Test data generation failed:', error.message); + throw error; + } +}`, + `function generateFileHeader(config: TestDataConfig): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated Test Data and Fixtures + * Generated at: \${timestamp} + * Format: \${config.format} + * Count: \${config.count || 10} + * Seed: \${config.seed || 'random'} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateImports(config: TestDataConfig): string { + let imports = ''; + + if (config.format === 'typescript' || config.format === 'javascript') { + imports += \`import { faker } from '@faker-js/faker';\\n\\n\`; + + if (config.seed) { + imports += \`// Set seed for reproducible data\\nfaker.seed(\${config.seed});\\n\\n\`; + } + + if (config.locale && config.locale !== 'en') { + imports += \`// Set locale\\nfaker.setLocale('\${config.locale}');\\n\\n\`; + } + } + + return imports; +}`, + `function generateFactories(schema: any, config: TestDataConfig): string { + let content = '// Data Factories\\n'; + + // Generate enum factories + if (schema.enum) { + for (const [enumName, enumDef] of Object.entries(schema.enum)) { + content += generateEnumFactory(enumName, enumDef, config); + } + } + + // Generate model factories + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + content += generateModelFactory(modelName, model, config); + } + } + + return content + '\\n'; +} + +function generateEnumFactory(enumName: string, enumDef: any, config: TestDataConfig): string { + const values = Object.values(enumDef); + const valuesArray = values.map(v => \`"\${v}"\`).join(', '); + + return \`export function generate\${enumName}(): string { + return faker.helpers.arrayElement([\${valuesArray}]); +} + +\`; +} + +function generateModelFactory(modelName: string, model: any, config: TestDataConfig): string { + let content = \`export function generate\${modelName}(overrides: Partial<\${modelName}> = {}): \${modelName} { + return { +\`; + + for (const column of model.columns || []) { + const generator = generateFieldGenerator(column, config); + content += \` \${column.name}: \${generator},\\n\`; + } + + content += \` ...overrides, + }; +} + +export function generate\${modelName}Array(count: number = \${config.count || 10}): \${modelName}[] { + return Array.from({ length: count }, () => generate\${modelName}()); +} + +\`; + + return content; +}`, + `function generateFieldGenerator(column: any, config: TestDataConfig): string { + // Check for custom generators first + if (config.customGenerators && config.customGenerators[column.type]) { + return config.customGenerators[column.type]; + } + + // Handle arrays + if (column.multiple) { + const baseGenerator = getBaseGenerator(column, config); + const arraySize = column.attributes?.minLength || 1; + const maxSize = column.attributes?.maxLength || 5; + return \`faker.helpers.multiple(() => \${baseGenerator}, { count: { min: \${arraySize}, max: \${maxSize} } })\`; + } + + return getBaseGenerator(column, config); +} + +function getBaseGenerator(column: any, config: TestDataConfig): string { + const { type, attributes = {} } = column; + + // Handle custom field types based on attributes + if (attributes.email) { + return 'faker.internet.email()'; + } + + if (attributes.url) { + return 'faker.internet.url()'; + } + + if (attributes.uuid) { + return 'faker.string.uuid()'; + } + + if (attributes.phone) { + return 'faker.phone.number()'; + } + + if (attributes.color) { + return 'faker.internet.color()'; + } + + // Handle based on field name patterns + const fieldName = column.name.toLowerCase(); + + if (fieldName.includes('email')) { + return 'faker.internet.email()'; + } + + if (fieldName.includes('name')) { + if (fieldName.includes('first')) return 'faker.person.firstName()'; + if (fieldName.includes('last')) return 'faker.person.lastName()'; + if (fieldName.includes('full')) return 'faker.person.fullName()'; + return 'faker.person.fullName()'; + } + + if (fieldName.includes('address')) { + return 'faker.location.streetAddress()'; + } + + if (fieldName.includes('city')) { + return 'faker.location.city()'; + } + + if (fieldName.includes('country')) { + return 'faker.location.country()'; + } + + if (fieldName.includes('phone')) { + return 'faker.phone.number()'; + } + + if (fieldName.includes('company')) { + return 'faker.company.name()'; + } + + if (fieldName.includes('title')) { + return 'faker.lorem.sentence()'; + } + + if (fieldName.includes('description') || fieldName.includes('content')) { + return 'faker.lorem.paragraphs()'; + } + + if (fieldName.includes('image') || fieldName.includes('avatar')) { + return 'faker.image.url()'; + } + + if (fieldName.includes('price') || fieldName.includes('amount')) { + return 'faker.commerce.price()'; + } + + // Handle based on schema type + switch (type) { + case 'String': + if (attributes.min && attributes.max) { + return \`faker.lorem.words({ min: \${attributes.min}, max: \${attributes.max} })\`; + } + return 'faker.lorem.words()'; + + case 'Number': + case 'Integer': + const min = attributes.min || 1; + const max = attributes.max || 1000; + return \`faker.number.int({ min: \${min}, max: \${max} })\`; + + case 'Boolean': + return 'faker.datatype.boolean()'; + + case 'Date': + if (fieldName.includes('birth')) { + return 'faker.date.birthdate()'; + } + if (fieldName.includes('future')) { + return 'faker.date.future()'; + } + if (fieldName.includes('past')) { + return 'faker.date.past()'; + } + return 'faker.date.recent()'; + + case 'JSON': + return 'faker.datatype.json()'; + + case 'ID': + return 'faker.string.uuid()'; + + default: + // Check if it's an enum or custom type + if (type.endsWith('Role') || type.endsWith('Status') || type.endsWith('Type')) { + return \`generate\${type}()\`; + } + return 'faker.lorem.word()'; + } +}`, + `function generateMockData(models: Record, config: TestDataConfig): string { + if (config.format === 'json') { + return generateJSONMockData(models, config); + } + + let content = '// Mock Data\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`export const mock\${modelName}Data = generate\${modelName}Array(\${config.count || 10});\\n\`; + } + + return content + '\\n'; +} + +function generateJSONMockData(models: Record, config: TestDataConfig): string { + let content = ''; + const mockData: Record = {}; + + for (const [modelName, model] of Object.entries(models)) { + const data = []; + for (let i = 0; i < (config.count || 10); i++) { + const item: Record = {}; + + for (const column of model.columns || []) { + item[column.name] = generateMockValue(column, config); + } + + data.push(item); + } + + mockData[modelName.toLowerCase()] = data; + } + + return JSON.stringify(mockData, null, 2); +} + +function generateMockValue(column: any, config: TestDataConfig): any { + const { type, attributes = {} } = column; + + // Simple mock value generation for JSON format + switch (type) { + case 'String': + if (attributes.email) return 'user@example.com'; + if (attributes.url) return 'https://example.com'; + if (column.name.toLowerCase().includes('name')) return 'John Doe'; + return 'Sample Text'; + + case 'Number': + case 'Integer': + return Math.floor(Math.random() * 1000) + 1; + + case 'Boolean': + return Math.random() > 0.5; + + case 'Date': + return new Date().toISOString(); + + case 'ID': + return \`id_\${Math.random().toString(36).substr(2, 9)}\`; + + default: + return 'mock_value'; + } +}`, + `function generateFixtures(schema: any, config: TestDataConfig): string { + let content = '// Test Fixtures\\n'; + + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + content += generateModelFixtures(modelName, model, config); + } + } + + return content; +} + +function generateModelFixtures(modelName: string, model: any, config: TestDataConfig): string { + const lowerName = modelName.toLowerCase(); + + return \`export const \${lowerName}Fixtures = { + valid: generate\${modelName}({ + // Override with specific test values + }), + + minimal: generate\${modelName}({ + // Minimal required fields only + \${generateMinimalFields(model)} + }), + + invalid: { + // Invalid data for negative testing + \${generateInvalidFields(model)} + }, + + edge: generate\${modelName}({ + // Edge case values + \${generateEdgeCaseFields(model)} + }), +}; + +\`; +}`, + `function generateMinimalFields(model: any): string { + const requiredFields = model.columns?.filter((col: any) => + col.required && !col.attributes?.id && !col.attributes?.default + ) || []; + + return requiredFields.map((col: any) => { + const value = getMinimalValue(col); + return \`\${col.name}: \${value}\`; + }).join(',\\n '); +} + +function generateInvalidFields(model: any): string { + const fields = model.columns?.slice(0, 3) || []; // First 3 fields for example + + return fields.map((col: any) => { + const invalidValue = getInvalidValue(col); + return \`\${col.name}: \${invalidValue}\`; + }).join(',\\n '); +} + +function generateEdgeCaseFields(model: any): string { + const fields = model.columns?.slice(0, 3) || []; // First 3 fields for example + + return fields.map((col: any) => { + const edgeValue = getEdgeCaseValue(col); + return \`\${col.name}: \${edgeValue}\`; + }).join(',\\n '); +}`, + `function getMinimalValue(column: any): string { + switch (column.type) { + case 'String': + return '"a"'; + case 'Number': + case 'Integer': + return column.attributes?.min || '1'; + case 'Boolean': + return 'true'; + case 'Date': + return 'new Date()'; + default: + return '""'; + } +} + +function getInvalidValue(column: any): string { + switch (column.type) { + case 'String': + if (column.attributes?.email) return '"invalid-email"'; + if (column.attributes?.min) return '""'; // Too short + return 'null'; + case 'Number': + case 'Integer': + return '"not-a-number"'; + case 'Boolean': + return '"not-boolean"'; + case 'Date': + return '"invalid-date"'; + default: + return 'null'; + } +} + +function getEdgeCaseValue(column: any): string { + switch (column.type) { + case 'String': + if (column.attributes?.max) { + return \`"\${'a'.repeat(column.attributes.max)}"\`; + } + return '"very long string that might cause issues with processing or display"'; + case 'Number': + case 'Integer': + return column.attributes?.max || '999999'; + case 'Boolean': + return 'false'; + case 'Date': + return 'new Date("1900-01-01")'; + default: + return '""'; + } +}`, + `function generateMainExport(schema: any, config: TestDataConfig): string { + if (config.format === 'json') { + return ''; // JSON format doesn't need exports + } + + let content = '// Main Export\\nexport const testData = {\\n'; + + // Export factories + if (config.generateFactories && schema.model) { + content += ' factories: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName}: generate\${modelName},\\n\`; + content += \` \${modelName}Array: generate\${modelName}Array,\\n\`; + } + content += ' },\\n'; + } + + // Export mock data + if (schema.model) { + content += ' mockData: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName.toLowerCase()}: mock\${modelName}Data,\\n\`; + } + content += ' },\\n'; + } + + // Export fixtures + if (config.generateFixtures && schema.model) { + content += ' fixtures: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName.toLowerCase()}: \${modelName.toLowerCase()}Fixtures,\\n\`; + } + content += ' },\\n'; + } + + content += '};\\n\\nexport default testData;\\n'; + + return content; +} + +function validateConfig(config: any): asserts config is TestDataConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('Test Data plugin requires "output" configuration as string'); + } + + if (!config.format || !['json', 'typescript', 'javascript'].includes(config.format)) { + throw new Error('format must be one of: json, typescript, javascript'); + } + + if (config.count && (typeof config.count !== 'number' || config.count < 1)) { + throw new Error('count must be a positive number'); + } +}`, + `plugin "./plugins/test-data.js" { + output "./generated/test-data.ts" + format "typescript" + count 20 + seed 12345 + locale "en" + generateFactories true + generateFixtures true + relationships true + customGenerators { + Email "faker.internet.email()" + Password "faker.internet.password()" + Slug "faker.lorem.slug()" + } +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Test Data Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates mock data and test fixtures from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    Test Data Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates mock data and test fixtures from .idea schema files. The plugin will transform your schema models into realistic test data for development, testing, and prototyping. +

    + +
    +

    1. Overview

    +

    + Test data generation is crucial for development and testing workflows. This plugin generates realistic mock data from your .idea schema, including: +

    +
      +
    • Mock Data: Realistic test data based on schema types
    • +
    • Fixtures: Predefined test datasets for consistent testing
    • +
    • Factories: Data generation functions for dynamic testing
    • +
    • Relationships: Proper handling of model relationships
    • +
    • Customization: Custom data generators and constraints
    • +
    +
    + +
    +

    2. Prerequisites

    +

    Before creating this plugin, you should have the following knowledge and tools:

    +
      +
    • Node.js 16+ and npm/yarn
    • +
    • TypeScript 4.0+
    • +
    • Faker.js 8.0+ (for realistic data generation)
    • +
    • Basic understanding of testing concepts
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    The following code shows how to generally layout the plugin so you can focus on the implementation.

    + + {examples[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle test data generation. This includes the main plugin entry point, data generation functions, and configuration validation. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for test data generation. It orchestrates the entire process from configuration validation to file output, handling different formats and generation options. +

    + + {examples[1]} + + +

    4.2. Generation Functions

    +

    + The generation functions provide the core logic for creating different types of test data content. These utility functions handle file headers, imports, data factories, and various data generation patterns based on schema definitions. +

    + + {examples[2]} + + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + + + {examples[6]} + + + {examples[7]} + + + {examples[8]} + +
    + +
    +

    5. Schema Configuration

    +

    + The schema configuration section demonstrates how to integrate the test data plugin into your .idea schema files. This includes plugin declaration syntax, configuration options, and examples of how to customize the plugin behavior for different use cases. +

    +

    Add the Test Data plugin to your .idea schema file:

    + + {examples[9]} + + +

    5.1. Configuration Options

    +

    The following options will be processed by the test data plugin in this tutorial.

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for test data + + + format + 'json'|'typescript'|'javascript' + Required + Output format + + + count + number + 10 + Number of records to generate per model + + + seed + number + undefined + Seed for reproducible data generation + + + locale + string + 'en' + Locale for faker.js data generation + + + generateFactories + boolean + true + Generate data factory functions + + + generateFixtures + boolean + true + Generate test fixtures + + + customGenerators + object + {`{}`} + Custom data generators for specific types + + + relationships + boolean + false + Handle model relationships + +
    + +

    + This tutorial provides a comprehensive foundation for creating test data generation plugins that can handle complex schemas and generate realistic, useful test data for development and testing workflows. +

    +
    + +
    +

    Conclusion

    +

    + This tutorial provides a comprehensive foundation for creating test data generation plugins that can handle complex schemas and generate realistic, useful test data for development and testing workflows. +

    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/tsmorph-plugin-guide.tsx b/packages/www/plugins/docs/views/tutorials/tsmorph-plugin-guide.tsx new file mode 100644 index 0000000..a6c8c21 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/tsmorph-plugin-guide.tsx @@ -0,0 +1,134 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Introduction from './components/ts-morph/introduction.js'; +import Installation from './components/ts-morph/installation.js'; +import SettingUpProject from './components/ts-morph/setting-up-project.js'; +import UnderstandingTsMorphBasics from './components/ts-morph/understanding-tsmorph-basics.js'; +import CreateFirstPlugin from './components/ts-morph/create-first-plugin.js'; +import AdvanceTsMorphPlugin from './components/ts-morph/advance-tsmorph-pluginn.js'; +import TestingYourPlugin from './components/ts-morph/testing-your-plugin.js'; +import BestPractices from './components/ts-morph/best-practices.js'; +import Troubleshooting from './components/ts-morph/troubleshooting.js'; +import References from './components/ts-morph/references.js'; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('TSMorph Plugin Guide'); + const description = _( + 'A guide to creating powerful code generation plugins using TSMorph' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + return ( +
    +

    Creating Plugins with ts-morph: A Comprehensive Guide

    +

    + This guide demonstrates how to create powerful code generation plugins using ts-morph, a TypeScript library that provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code. We'll walk through creating a complete plugin that generates TypeScript interfaces from schema definitions. +

    + + + + + + + + + + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/typescript-interface-plugin.tsx b/packages/www/plugins/docs/views/tutorials/typescript-interface-plugin.tsx new file mode 100644 index 0000000..1b4a06f --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/typescript-interface-plugin.tsx @@ -0,0 +1,1097 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface TypeScriptConfig { + output: string; + namespace?: string; + exportType?: 'named' | 'default' | 'namespace'; + generateUtilityTypes?: boolean; + includeComments?: boolean; + strictNullChecks?: boolean; + generateEnums?: boolean; + enumType?: 'enum' | 'union' | 'const'; +} + +export default async function generateTypeScriptInterfaces( + props: PluginProps<{ config: TypeScriptConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`, + `export default async function generateTypeScriptInterfaces( + props: PluginProps<{ config: TypeScriptConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate TypeScript content + let content = ''; + + // Add file header + content += generateFileHeader(); + + // Generate enums + if (config.generateEnums !== false && schema.enum) { + content += generateEnums(schema.enum, config); + } + + // Generate custom types + if (schema.type) { + content += generateCustomTypes(schema.type, config); + } + + // Generate interfaces from models + if (schema.model) { + content += generateInterfaces(schema.model, config); + } + + // Generate utility types + if (config.generateUtilityTypes) { + content += generateUtilityTypes(schema, config); + } + + // Wrap in namespace if specified + if (config.namespace) { + content = wrapInNamespace(content, config.namespace, config.exportType); + } + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ TypeScript interfaces generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ TypeScript interface generation failed:', error.message); + throw error; + } +}`, + `function mapSchemaTypeToTypeScript( + schemaType: string, + strictNullChecks: boolean = true +): string { + const typeMap: Record = { + 'String': 'string', + 'Number': 'number', + 'Integer': 'number', + 'Boolean': 'boolean', + 'Date': 'Date', + 'JSON': 'any', + 'ID': 'string' + }; + + const baseType = typeMap[schemaType] || schemaType; + + // Handle strict null checks + if (!strictNullChecks && baseType !== 'any') { + return \`\${baseType} | null | undefined\`; + } + + return baseType; +} + +function formatPropertyType( + column: any, + config: TypeScriptConfig, + availableTypes: Set = new Set() +): string { + let type = column.type; + + // Check if it's a reference to another type + if (availableTypes.has(column.type)) { + type = column.type; + } else { + type = mapSchemaTypeToTypeScript(column.type, config.strictNullChecks); + } + + // Handle arrays + if (column.multiple) { + type = \`\${type}[]\`; + } + + // Handle optional properties + if (!column.required && config.strictNullChecks) { + type = \`\${type} | null\`; + } + + return type; +}`, + `function generateFileHeader(): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated TypeScript interfaces + * Generated at: \${timestamp} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateEnums( + enums: Record, + config: TypeScriptConfig +): string { + let content = '// Enums\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + if (config.includeComments) { + content += \`/**\\n * \${enumName} enumeration\\n */\\n\`; + } + + switch (config.enumType) { + case 'union': + content += generateUnionEnum(enumName, enumDef); + break; + case 'const': + content += generateConstEnum(enumName, enumDef); + break; + default: + content += generateStandardEnum(enumName, enumDef); + } + + content += '\\n'; + } + + return content + '\\n'; +}`, + `function generateStandardEnum(enumName: string, enumDef: any): string { + let content = \`export enum \${enumName} {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key} = "\${value}",\\n\`; + } + + content += '}'; + return content; +} + +function generateUnionEnum(enumName: string, enumDef: any): string { + const values = Object.values(enumDef).map(v => \`"\${v}"\`).join(' | '); + return \`export type \${enumName} = \${values};\`; +} + +function generateConstEnum(enumName: string, enumDef: any): string { + let content = \`export const \${enumName} = {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key}: "\${value}",\\n\`; + } + + content += '} as const;\\n\\n'; + content += \`export type \${enumName} = typeof \${enumName}[keyof typeof \${enumName}];\`; + + return content; +}`, + `function generateCustomTypes( + types: Record, + config: TypeScriptConfig +): string { + let content = '// Custom Types\\n'; + const availableTypes = new Set(Object.keys(types)); + + for (const [typeName, typeDef] of Object.entries(types)) { + if (config.includeComments) { + content += \`/**\\n * \${typeName} type definition\\n */\\n\`; + } + + content += \`export interface \${typeName} {\\n\`; + + for (const column of typeDef.columns || []) { + const propertyType = formatPropertyType(column, config, availableTypes); + const optional = !column.required ? '?' : ''; + + if (config.includeComments && column.description) { + content += \` /** \${column.description} */\\n\`; + } + + content += \` \${column.name}\${optional}: \${propertyType};\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +}`, + `function generateInterfaces( + models: Record, + config: TypeScriptConfig +): string { + let content = '// Model Interfaces\\n'; + const availableTypes = new Set([ + ...Object.keys(models), + ...(config.namespace ? [] : Object.keys(models)) + ]); + + for (const [modelName, model] of Object.entries(models)) { + if (config.includeComments) { + content += \`/**\\n * \${modelName} model interface\\n\`; + if (model.description) { + content += \` * \${model.description}\\n\`; + } + content += \` */\\n\`; + } + + content += \`export interface \${modelName} {\\n\`; + + for (const column of model.columns || []) { + const propertyType = formatPropertyType(column, config, availableTypes); + const optional = !column.required ? '?' : ''; + + if (config.includeComments) { + let comment = ''; + if (column.description) { + comment += column.description; + } + if (column.attributes?.default) { + comment += comment ? \` (default: \${column.attributes.default})\` : \`Default: \${column.attributes.default}\`; + } + if (comment) { + content += \` /** \${comment} */\\n\`; + } + } + + content += \` \${column.name}\${optional}: \${propertyType};\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +}`, + `function generateUtilityTypes( + schema: any, + config: TypeScriptConfig +): string { + let content = '// Utility Types\\n'; + + if (schema.model) { + const modelNames = Object.keys(schema.model); + + // Generate create input types (omit auto-generated fields) + for (const modelName of modelNames) { + const model = schema.model[modelName]; + const autoFields = model.columns + ?.filter((col: any) => col.attributes?.id || col.attributes?.default) + .map((col: any) => \`'\${col.name}'\`) + .join(' | '); + + if (autoFields) { + content += \`export type Create\${modelName}Input = Omit<\${modelName}, \${autoFields}>;\\n\`; + } else { + content += \`export type Create\${modelName}Input = \${modelName};\\n\`; + } + } + + content += '\\n'; + + // Generate update input types (all fields optional) + for (const modelName of modelNames) { + content += \`export type Update\${modelName}Input = Partial<\${modelName}>;\\n\`; + } + + content += '\\n'; + + // Generate union types + const allModels = modelNames.join(' | '); + content += \`export type AnyModel = \${allModels};\\n\\n\`; + + // Generate key types + for (const modelName of modelNames) { + content += \`export type \${modelName}Keys = keyof \${modelName};\\n\`; + } + + content += '\\n'; + } + + return content; +} + +function wrapInNamespace( + content: string, + namespace: string, + exportType?: string +): string { + const exportKeyword = exportType === 'default' ? 'export default' : 'export'; + + return \`\${exportKeyword} namespace \${namespace} { +\${content.split('\\n').map(line => line ? \` \${line}\` : line).join('\\n')} +} +\`; +}`, + `function validateConfig(config: any): asserts config is TypeScriptConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('TypeScript plugin requires "output" configuration as string'); + } + + if (config.exportType && !['named', 'default', 'namespace'].includes(config.exportType)) { + throw new Error('exportType must be one of: named, default, namespace'); + } + + if (config.enumType && !['enum', 'union', 'const'].includes(config.enumType)) { + throw new Error('enumType must be one of: enum, union, const'); + } +}`, + `plugin "./plugins/typescript-interfaces.js" { + output "./generated/types.ts" + namespace "MyApp" + exportType "named" + generateUtilityTypes true + includeComments true + strictNullChecks true + generateEnums true + enumType "enum" +}`, + `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +type Address { + street String @required + city String @required + country String @required + postal String +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("USER") + address Address? + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/typescript-interfaces.js" { + output "./types.ts" + generateUtilityTypes true + includeComments true +}`, + `/** + * Generated TypeScript interfaces + * Generated at: 2024-01-15T10:30:00.000Z + * + * This file is auto-generated. Do not edit manually. + */ + +// Enums +/** + * UserRole enumeration + */ +export enum UserRole { + ADMIN = "admin", + USER = "user", + GUEST = "guest", +} + +// Custom Types +/** + * Address type definition + */ +export interface Address { + street: string; + city: string; + country: string; + postal?: string | null; +} + +// Model Interfaces +/** + * User model interface + */ +export interface User { + /** Default: nanoid() */ + id: string; + email: string; + name: string; + /** Default: USER */ + role: UserRole; + address?: Address | null; + /** Default: true */ + active: boolean; + /** Default: now() */ + createdAt: Date; +} + +// Utility Types +export type CreateUserInput = Omit; + +export type UpdateUserInput = Partial; + +export type AnyModel = User; + +export type UserKeys = keyof User;`, + `// With namespace configuration +namespace: "MyApp" +exportType: "namespace" + +// Generated output: +export namespace MyApp { + export enum UserRole { + ADMIN = "admin", + USER = "user", + } + + export interface User { + id: string; + name: string; + role: UserRole; + } +}`, + `// Standard enum (default) +enumType: "enum" +export enum UserRole { + ADMIN = "admin", + USER = "user", +} + +// Union type +enumType: "union" +export type UserRole = "admin" | "user"; + +// Const assertion +enumType: "const" +export const UserRole = { + ADMIN: "admin", + USER: "user", +} as const; +export type UserRole = typeof UserRole[keyof typeof UserRole];`, + `function handleRelationships( + column: any, + config: TypeScriptConfig, + availableTypes: Set +): string { + // Check if the column type is another model/type + if (availableTypes.has(column.type)) { + let type = column.type; + + if (column.multiple) { + type = \`\${type}[]\`; + } + + if (!column.required && config.strictNullChecks) { + type = \`\${type} | null\`; + } + + return type; + } + + return formatPropertyType(column, config, availableTypes); +}`, + `function generateGenericTypes( + models: Record, + config: TypeScriptConfig +): string { + let content = '// Generic Types\\n'; + + // Generate paginated response type + content += \`export interface PaginatedResponse { + data: T[]; + total: number; + page: number; + limit: number; +}\\n\\n\`; + + // Generate API response type + content += \`export interface ApiResponse { + success: boolean; + data?: T; + error?: string; + errors?: Record; +}\\n\\n\`; + + return content; +}`, + `interface TypeScriptColumn { + name: string; + type: string; + required: boolean; + multiple: boolean; + description?: string; + attributes?: Record; +} + +function validateColumn(column: any): column is TypeScriptColumn { + return ( + typeof column.name === 'string' && + typeof column.type === 'string' && + typeof column.required === 'boolean' + ); +}`, + `function sanitizeTypeName(name: string): string { + // Ensure TypeScript-valid names + return name + .replace(/[^a-zA-Z0-9_]/g, '_') + .replace(/^[0-9]/, '_$&') + .replace(/^_+|_+$/g, ''); +} + +function toPascalCase(str: string): string { + return str + .split(/[-_\\s]+/) + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(''); +}`, + `function generateJSDocComment( + column: any, + includeAttributes: boolean = true +): string { + const lines: string[] = []; + + if (column.description) { + lines.push(column.description); + } + + if (includeAttributes && column.attributes) { + if (column.attributes.default) { + lines.push(\`@default \${column.attributes.default}\`); + } + if (column.attributes.example) { + lines.push(\`@example \${column.attributes.example}\`); + } + } + + if (lines.length === 0) return ''; + + if (lines.length === 1) { + return \` /** \${lines[0]} */\\n\`; + } + + return \` /**\\n\${lines.map(line => \` * \${line}\`).join('\\n')}\\n */\\n\`; +}`, + `// Cache type mappings +const typeCache = new Map(); + +function getCachedTypeMapping( + schemaType: string, + strictNullChecks: boolean +): string { + const cacheKey = \`\${schemaType}:\${strictNullChecks}\`; + + if (typeCache.has(cacheKey)) { + return typeCache.get(cacheKey)!; + } + + const mappedType = mapSchemaTypeToTypeScript(schemaType, strictNullChecks); + typeCache.set(cacheKey, mappedType); + + return mappedType; +}`, + `function validateTypeName(name: string): void { + if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) { + throw new Error(\`Invalid TypeScript identifier: \${name}\`); + } +}`, + `function detectCircularReferences( + types: Record +): string[] { + const visited = new Set(); + const recursionStack = new Set(); + const cycles: string[] = []; + + function visit(typeName: string): void { + if (recursionStack.has(typeName)) { + cycles.push(typeName); + return; + } + + if (visited.has(typeName)) return; + + visited.add(typeName); + recursionStack.add(typeName); + + // Check type dependencies... + + recursionStack.delete(typeName); + } + + for (const typeName of Object.keys(types)) { + visit(typeName); + } + + return cycles; +}`, + `function validateTypeDependencies( + schema: any +): void { + const availableTypes = new Set([ + ...Object.keys(schema.model || {}), + ...Object.keys(schema.type || {}), + ...Object.keys(schema.enum || {}) + ]); + + // Validate all type references... +}`, + `const VERBOSE = process.env.TS_PLUGIN_VERBOSE === 'true'; + +function verboseLog(message: string, data?: any) { + if (VERBOSE) { + console.log(\`[TypeScript Plugin] \${message}\`, data || ''); + } +}`, + `import { transpile, ScriptTarget } from 'typescript'; + +function validateGeneratedTypeScript(content: string): void { + try { + transpile(content, { + target: ScriptTarget.ES2020, + strict: true + }); + console.log('✅ Generated TypeScript is valid'); + } catch (error) { + throw new Error(\`Invalid TypeScript: \${error.message}\`); + } +}` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('TypeScript Interface Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates TypeScript interfaces from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    TypeScript Interface Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates TypeScript interfaces and types from .idea schema files. The plugin will transform your schema models, types, and enums into proper TypeScript definitions with full type safety. +

    + +
    +

    1. Overview

    +

    + TypeScript interfaces provide compile-time type checking and excellent IDE support. This plugin transforms your .idea schema definitions into comprehensive TypeScript type definitions that integrate seamlessly with your development workflow and provide robust type safety throughout your application. +

    +

    This plugin generates TypeScript definitions from your .idea schema, including:

    +
      +
    • Interfaces: TypeScript interfaces from schema models
    • +
    • Types: Type aliases from schema types
    • +
    • Enums: TypeScript enums from schema enums
    • +
    • Utility Types: Helper types for common operations
    • +
    • Namespace Support: Organized type definitions
    • +
    +
    + +
    +

    2. Prerequisites

    +

    + Before implementing the TypeScript interface generator plugin, ensure you have the necessary development environment and knowledge. This section covers the essential requirements for successful plugin creation and TypeScript integration. +

    +
      +
    • Node.js 16+ and npm/yarn
    • +
    • TypeScript 4.0+
    • +
    • Basic understanding of TypeScript
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    + The plugin structure defines the core architecture and configuration interface for the TypeScript interface generator. This includes the main plugin function, configuration types, and the overall organization of the generated TypeScript code. +

    + + {examples[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle TypeScript interface generation. This includes configuration validation, content generation, file writing, and error handling throughout the generation process. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for TypeScript interface generation. It orchestrates the entire process from configuration validation through content generation to file output, ensuring proper error handling and logging throughout. +

    + + {examples[1]} + + +

    4.2. Type Mapping Functions

    +

    + Type mapping functions handle the conversion of .idea schema types to their TypeScript equivalents. These functions ensure proper type safety and handle complex scenarios like nullable types, arrays, and custom type references. +

    + + {examples[2]} + + +

    4.3. Generation Functions

    +

    + Generation functions create specific parts of the TypeScript output including enums, interfaces, and utility types. These functions handle formatting, documentation generation, and proper TypeScript syntax construction. +

    + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + + + {examples[6]} + + + {examples[7]} + + +

    4.4. Validation Functions

    +

    + Validation functions ensure that the plugin configuration is correct and that the generated TypeScript code meets quality standards. These functions catch configuration errors early and prevent invalid output generation. +

    + + {examples[8]} + +
    + +
    +

    5. Schema Configuration

    +

    + Schema configuration demonstrates how to integrate the TypeScript interface generator into your .idea schema files. This section covers plugin configuration options and their effects on the generated TypeScript output. +

    +

    Add the TypeScript plugin to your .idea schema file:

    + + {examples[9]} + + +

    Configuration Options

    +

    + Configuration options control how TypeScript interfaces are generated, including output formatting, type handling, and feature enablement. Understanding these options helps you customize the plugin to meet your specific project requirements. +

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for TypeScript definitions + + + namespace + string + undefined + Wrap types in a namespace + + + exportType + 'named'|'default'|'namespace' + 'named' + Export style for types + + + generateUtilityTypes + boolean + false + Generate helper utility types + + + includeComments + boolean + false + Include JSDoc comments + + + strictNullChecks + boolean + true + Handle null/undefined types + + + generateEnums + boolean + true + Generate enum definitions + + + enumType + 'enum'|'union'|'const' + 'enum' + Enum generation style + +
    +
    + +
    +

    6. Usage Examples

    +

    + Usage examples demonstrate practical applications of the TypeScript interface generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated TypeScript code integrates into development workflows. +

    + +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate TypeScript interfaces. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces clean, type-safe TypeScript code. +

    + + {examples[10]} + + +

    6.2. Generated Output

    +

    + The generated output demonstrates the TypeScript code produced by the plugin from the basic schema example. This shows how schema definitions are transformed into proper TypeScript interfaces with full type safety and documentation. +

    + + {examples[11]} + +
    + +
    +

    7. Advanced Features

    +

    + Advanced features extend the basic TypeScript interface generation with sophisticated organization, multiple enum types, relationship handling, and generic type support. These features enable production-ready TypeScript definitions that handle complex scenarios. +

    + +

    7.1. Namespace Support

    +

    + Namespace support allows you to organize generated types within TypeScript namespaces, preventing naming conflicts and providing better code organization. This feature is particularly useful for large projects with multiple schema files. +

    + + {examples[12]} + + +

    7.2. Different Enum Types

    +

    + Different enum types provide flexibility in how enumerations are represented in TypeScript. The plugin supports standard enums, union types, and const assertions, each with different runtime characteristics and use cases. +

    + + {examples[13]} + + +

    7.3. Relationship Handling

    +

    + Relationship handling manages references between different types and models in your schema. This ensures that type relationships are properly represented in the generated TypeScript code with correct type references and nullability handling. +

    + + {examples[14]} + + +

    7.4. Generic Type Support

    +

    + Generic type support enables the generation of reusable type definitions that work with multiple data types. This includes common patterns like paginated responses and API response wrappers that enhance type safety across your application. +

    + + {examples[15]} + +
    + +
    +

    8. Best Practices

    +

    + Best practices ensure your generated TypeScript interfaces are maintainable, reliable, and follow industry standards. These guidelines cover type safety, naming conventions, documentation generation, and performance optimization. +

    + +

    8.1. Type Safety

    +

    + Type safety is crucial for preventing runtime errors and improving developer experience. Always validate input data and use proper TypeScript types throughout the plugin implementation to ensure reliable code generation. +

    + + {examples[16]} + + +

    8.2. Naming Conventions

    +

    + Naming conventions ensure that generated TypeScript identifiers are valid and follow established patterns. Proper naming improves code readability and prevents conflicts with reserved keywords or invalid characters. +

    + + {examples[17]} + + +

    8.3. Documentation Generation

    +

    + Documentation generation creates comprehensive JSDoc comments that provide context and examples for the generated types. This improves the developer experience by providing inline documentation in IDEs and code editors. +

    + + {examples[18]} + + +

    8.4. Performance Optimization

    +

    + Performance optimization techniques help maintain reasonable generation times when working with large schemas. Caching strategies and efficient algorithms ensure the plugin scales well with complex type hierarchies. +

    + + {examples[19]} + +
    + +
    +

    9. Troubleshooting

    +

    + This section addresses common issues encountered when generating TypeScript interfaces and provides solutions for debugging and resolving problems. Understanding these troubleshooting techniques helps ensure reliable interface generation. +

    + +

    9.1. Common Issues

    +

    + Common issues include invalid TypeScript identifiers, circular type references, and missing dependencies. These problems typically arise from schema complexity or configuration mismatches that can be resolved with proper validation and error handling. +

    + +

    9.1.1. Invalid TypeScript Names

    +

    + Invalid TypeScript names occur when schema identifiers contain characters that are not valid in TypeScript. The plugin should validate and sanitize names to ensure they conform to TypeScript identifier rules. +

    + + {examples[20]} + + +

    9.1.2. Circular Type References

    +

    + Circular type references can cause infinite loops during generation or compilation errors in the generated TypeScript code. Detecting and handling these scenarios is essential for robust type generation. +

    + + {examples[21]} + + +

    9.1.3. Missing Type Dependencies

    +

    + Missing type dependencies occur when a type references another type that doesn't exist in the schema. Validating type dependencies ensures all references are resolvable and prevents compilation errors. +

    + + {examples[22]} + + +

    9.2. Debugging Tips

    +

    + Debugging tips help identify and resolve issues during TypeScript interface generation. These techniques provide visibility into the generation process and help diagnose problems with schema processing or output generation. +

    + +

    9.2.1. Enable Verbose Output

    +

    + Verbose output provides detailed logging during the generation process, helping identify where issues occur and what data is being processed at each step. +

    + + {examples[23]} + + +

    9.2.2. Validate Generated TypeScript

    +

    + Validating generated TypeScript ensures that the output is syntactically correct and will compile successfully. This validation step catches generation errors before the code is used in development. +

    + + {examples[24]} + +
    + +
    +

    + This tutorial provides a comprehensive foundation for creating TypeScript interface generators from .idea files. The generated types can be used throughout your TypeScript projects for compile-time type checking and enhanced IDE support. +

    +
    + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/validation-plugin.tsx b/packages/www/plugins/docs/views/tutorials/validation-plugin.tsx new file mode 100644 index 0000000..e4d53b9 --- /dev/null +++ b/packages/www/plugins/docs/views/tutorials/validation-plugin.tsx @@ -0,0 +1,974 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; +import Layout from '../../components/Layout.js'; +import Code from '../../components/Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +//code examples +const examples = [ + `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface ZodConfig { + output: string; + generateTypes?: boolean; + includeEnums?: boolean; + customValidators?: Record; + errorMessages?: Record; + strictMode?: boolean; + exportStyle?: 'named' | 'default' | 'namespace'; +} + +export default async function generateZodSchemas( + props: PluginProps<{ config: ZodConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`, + `export default async function generateZodSchemas( + props: PluginProps<{ config: ZodConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate Zod content + let content = ''; + + // Add file header and imports + content += generateFileHeader(); + content += generateImports(config); + + // Generate enums if requested + if (config.includeEnums && schema.enum) { + content += generateEnumSchemas(schema.enum, config); + } + + // Generate custom type schemas + if (schema.type) { + content += generateTypeSchemas(schema.type, config); + } + + // Generate model schemas + if (schema.model) { + content += generateModelSchemas(schema.model, config); + } + + // Generate utility schemas + content += generateUtilitySchemas(schema, config); + + // Generate main export + content += generateMainExport(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ Zod validation schemas generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ Zod schema generation failed:', error.message); + throw error; + } +}`, + `function generateFileHeader(): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated Zod Validation Schemas + * Generated at: \${timestamp} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateImports(config: ZodConfig): string { + let imports = \`import { z } from 'zod';\\n\\n\`; + + if (config.generateTypes) { + imports += \`// Type inference helpers\\ntype Infer = z.infer;\\n\\n\`; + } + + return imports; +}`, + `function generateEnumSchemas(enums: Record, config: ZodConfig): string { + let content = '// Enum Schemas\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + const values = Object.values(enumDef); + const zodValues = values.map(v => \`"\${v}"\`).join(', '); + + content += \`export const \${enumName}Schema = z.enum([\${zodValues}]);\\n\`; + + if (config.generateTypes) { + content += \`export type \${enumName} = z.infer;\\n\`; + } + + content += '\\n'; + } + + return content + '\\n'; +}`, + `function generateTypeSchemas(types: Record, config: ZodConfig): string { + let content = '// Type Schemas\\n'; + + for (const [typeName, typeDef] of Object.entries(types)) { + content += \`export const \${typeName}Schema = z.object({\\n\`; + + for (const column of typeDef.columns || []) { + const fieldSchema = generateFieldSchema(column, config); + content += \` \${column.name}: \${fieldSchema},\\n\`; + } + + content += '})'; + + // Add strict mode if enabled + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type \${typeName} = z.infer;\\n\`; + } + + content += '\\n'; + } + + return content; +}`, + `function generateModelSchemas(models: Record, config: ZodConfig): string { + let content = '// Model Schemas\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`export const \${modelName}Schema = z.object({\\n\`; + + for (const column of model.columns || []) { + const fieldSchema = generateFieldSchema(column, config); + content += \` \${column.name}: \${fieldSchema},\\n\`; + } + + content += '})'; + + // Add strict mode if enabled + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type \${modelName} = z.infer;\\n\`; + } + + // Generate input schemas + content += generateInputSchemas(modelName, model, config); + + content += '\\n'; + } + + return content; +}`, + `function generateFieldSchema(column: any, config: ZodConfig): string { + let schema = mapTypeToZod(column.type, config); + + // Handle arrays + if (column.multiple) { + schema = \`z.array(\${schema})\`; + } + + // Handle optional fields + if (!column.required) { + schema += '.optional()'; + } + + // Add custom validations based on attributes + if (column.attributes) { + schema = addAttributeValidations(schema, column.attributes, config); + } + + return schema; +} + +function mapTypeToZod(schemaType: string, config: ZodConfig): string { + // Check for custom validators first + if (config.customValidators && config.customValidators[schemaType]) { + return config.customValidators[schemaType]; + } + + const typeMap: Record = { + 'String': 'z.string()', + 'Number': 'z.number()', + 'Integer': 'z.number().int()', + 'Boolean': 'z.boolean()', + 'Date': 'z.date()', + 'JSON': 'z.any()', + 'ID': 'z.string()' + }; + + return typeMap[schemaType] || \`\${schemaType}Schema\`; +}`, + `plugin "./plugins/zod-validation.js" { + output "./generated/validation.ts" + generateTypes true + includeEnums true + strictMode true + exportStyle "named" + customValidators { + Email "z.string().email()" + Password "z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)/)" + PhoneNumber "z.string().regex(/^\\\\+?[1-9]\\\\d{1,14}$/)" + } + errorMessages { + email "Please enter a valid email address" + password "Password must be at least 8 characters with uppercase, lowercase, and number" + required "This field is required" + } +}`, + `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @email @required + name String @min(2) @max(50) @required + age Number @min(18) @max(120) + role UserRole @default("USER") + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/zod-validation.js" { + output "./validation.ts" + generateTypes true + strictMode true +}`, + `import { + UserSchema, + CreateUserSchema, + UpdateUserSchema, + UserRole +} from './validation'; + +// Validate complete user object +const validateUser = (data: unknown) => { + try { + const user = UserSchema.parse(data); + console.log('Valid user:', user); + return { success: true, data: user }; + } catch (error) { + console.error('Validation failed:', error.errors); + return { success: false, errors: error.errors }; + } +}; + +// Validate user creation data +const validateCreateUser = (data: unknown) => { + const result = CreateUserSchema.safeParse(data); + + if (result.success) { + console.log('Valid create data:', result.data); + return result.data; + } else { + console.error('Validation errors:', result.error.errors); + throw new Error('Invalid user data'); + } +}; + +// Validate user update data +const validateUpdateUser = (data: unknown) => { + return UpdateUserSchema.parse(data); +}; + +// Example usage +const userData = { + email: 'john@example.com', + name: 'John Doe', + age: 30, + role: 'user' as UserRole +}; + +const validUser = validateCreateUser(userData);`, + `import { CreateUserSchema } from './validation'; + +// React form validation +function UserForm() { + const [errors, setErrors] = useState>({}); + + const handleSubmit = (formData: FormData) => { + const data = Object.fromEntries(formData); + + const result = CreateUserSchema.safeParse(data); + + if (!result.success) { + const fieldErrors: Record = {}; + + result.error.errors.forEach((error) => { + const field = error.path[0] as string; + fieldErrors[field] = error.message; + }); + + setErrors(fieldErrors); + return; + } + + // Submit valid data + submitUser(result.data); + }; + + return ( +
    + + {errors.email && {errors.email}} + + + {errors.name && {errors.name}} + + + {errors.age && {errors.age}} + + +
    + ); +}`, + `// In plugin configuration +customValidators: { + Email: "z.string().email().transform(val => val.toLowerCase())", + Password: "z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)/)", + Slug: "z.string().regex(/^[a-z0-9-]+$/)", + Color: "z.string().regex(/^#[0-9A-F]{6}$/i)", + JSON: "z.string().transform(val => JSON.parse(val))" +}`, + `// Generated schema with conditional validation +export const UserSchema = z.object({ + id: z.string(), + email: z.string().email(), + role: UserRoleSchema, + adminCode: z.string().optional(), +}).refine((data) => { + // Admin users must have admin code + if (data.role === 'admin' && !data.adminCode) { + return false; + } + return true; +}, { + message: "Admin users must provide an admin code", + path: ["adminCode"], +});`, + `// Add transforms to generated schemas +function addTransforms(schema: string, column: any): string { + if (column.attributes?.transform) { + switch (column.attributes.transform) { + case 'lowercase': + return schema + '.transform(val => val.toLowerCase())'; + case 'uppercase': + return schema + '.transform(val => val.toUpperCase())'; + case 'trim': + return schema + '.transform(val => val.trim())'; + case 'slug': + return schema + '.transform(val => val.toLowerCase().replace(/\\\\s+/g, "-"))'; + } + } + + return schema; +}`, + `// Generate async validation schemas +export const UserSchemaAsync = UserSchema.extend({ + email: z.string().email().refine(async (email) => { + // Check if email is unique + const exists = await checkEmailExists(email); + return !exists; + }, { + message: "Email already exists", + }), +}); + +// Usage +const validateUserAsync = async (data: unknown) => { + try { + const user = await UserSchemaAsync.parseAsync(data); + return { success: true, data: user }; + } catch (error) { + return { success: false, errors: error.errors }; + } +};`, + `// Centralized validation error handling +class ValidationError extends Error { + constructor(public errors: z.ZodError) { + super('Validation failed'); + this.name = 'ValidationError'; + } + + getFieldErrors(): Record { + const fieldErrors: Record = {}; + + this.errors.errors.forEach((error) => { + const field = error.path.join('.'); + fieldErrors[field] = error.message; + }); + + return fieldErrors; + } +} + +// Usage +function validateWithErrorHandling(schema: z.ZodSchema, data: unknown): T { + const result = schema.safeParse(data); + + if (!result.success) { + throw new ValidationError(result.error); + } + + return result.data; +}`, + `// Compose schemas for reusability +const BaseEntitySchema = z.object({ + id: z.string(), + createdAt: z.date(), + updatedAt: z.date(), +}); + +const UserSchema = BaseEntitySchema.extend({ + email: z.string().email(), + name: z.string().min(1), +}); + +const PostSchema = BaseEntitySchema.extend({ + title: z.string().min(1), + content: z.string(), + authorId: z.string(), +});`, + `// Generate type guards from schemas +export const isUser = (data: unknown): data is User => { + return UserSchema.safeParse(data).success; +}; + +export const isCreateUserInput = (data: unknown): data is CreateUserInput => { + return CreateUserSchema.safeParse(data).success; +}; + +// Usage +function processUserData(data: unknown) { + if (isUser(data)) { + // TypeScript knows data is User + console.log(data.email); + } +}`, + `// Middleware for API validation +function validateBody(schema: z.ZodSchema) { + return (req: Request, res: Response, next: NextFunction) => { + const result = schema.safeParse(req.body); + + if (!result.success) { + return res.status(400).json({ + success: false, + error: 'Validation failed', + errors: result.error.errors.reduce((acc, err) => { + const field = err.path.join('.'); + acc[field] = err.message; + return acc; + }, {} as Record) + }); + } + + req.body = result.data; + next(); + }; +} + +// Usage +app.post('/users', validateBody(CreateUserSchema), (req, res) => { + // req.body is now typed and validated + const user = req.body; // Type: CreateUserInput +});`, + `// Handle circular references with lazy evaluation +const UserSchema: z.ZodSchema = z.lazy(() => z.object({ + id: z.string(), + posts: z.array(PostSchema), +})); + +const PostSchema: z.ZodSchema = z.lazy(() => z.object({ + id: z.string(), + author: UserSchema, +}));`, + `// Use refinements for complex validation +const PasswordSchema = z.string() + .min(8, "Password must be at least 8 characters") + .refine((password) => /[A-Z]/.test(password), { + message: "Password must contain at least one uppercase letter", + }) + .refine((password) => /[a-z]/.test(password), { + message: "Password must contain at least one lowercase letter", + }) + .refine((password) => /\\d/.test(password), { + message: "Password must contain at least one number", + });`, + `// Use preprocess for expensive operations +const OptimizedSchema = z.preprocess( + (data) => { + // Expensive preprocessing + return normalizeData(data); + }, + z.object({ + // Schema definition + }) +);`, + `// Test schemas with various inputs +describe('UserSchema', () => { + it('should validate valid user data', () => { + const validData = { + email: 'test@example.com', + name: 'Test User', + age: 25 + }; + + expect(() => UserSchema.parse(validData)).not.toThrow(); + }); + + it('should reject invalid email', () => { + const invalidData = { + email: 'invalid-email', + name: 'Test User', + age: 25 + }; + + expect(() => UserSchema.parse(invalidData)).toThrow(); + }); +});`, + `// Customize error messages for better UX +const UserSchema = z.object({ + email: z.string().email("Please enter a valid email address"), + age: z.number().min(18, "You must be at least 18 years old"), +});` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Validation Schema Generator Plugin Tutorial'); + const description = _( + 'A comprehensive guide to creating a plugin that generates Zod validation schemas from .idea schema files' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('On this page')} +
    + +
    + ); +} + +export function Body() { + + return ( +
    +

    Validation Schema Generator Plugin Tutorial

    +

    + This tutorial demonstrates how to create a plugin that generates Zod validation schemas from .idea schema files. The plugin will transform your schema models into type-safe validation schemas with comprehensive validation rules. +

    + +
    +

    1. Overview

    +

    + Zod is a TypeScript-first schema validation library that provides runtime type checking and validation. This plugin transforms your .idea schema definitions into comprehensive Zod validation schemas that provide robust runtime validation with excellent TypeScript integration. +

    +

    This plugin generates Zod schemas from your .idea schema, including:

    +
      +
    • Schema Validation: Zod schemas for all models and types
    • +
    • Type Inference: TypeScript types inferred from Zod schemas
    • +
    • Custom Validators: Support for custom validation rules
    • +
    • Error Messages: Customizable validation error messages
    • +
    • Nested Validation: Support for nested objects and arrays
    • +
    +
    + +
    +

    2. Prerequisites

    +

    + Before implementing the Zod validation schema generator plugin, ensure you have the necessary development environment and knowledge. This section covers the essential requirements for successful plugin creation and Zod integration. +

    +
      +
    • Node.js 16+ and npm/yarn
    • +
    • TypeScript 4.0+
    • +
    • Zod 3.0+
    • +
    • Basic understanding of validation concepts
    • +
    • Familiarity with the @stackpress/idea-transformer library
    • +
    • Understanding of .idea schema format
    • +
    +
    + +
    +

    3. Plugin Structure

    +

    + The plugin structure defines the core architecture and configuration interface for the Zod validation schema generator. This includes the main plugin function, configuration types, and the overall organization of the generated validation code. +

    + + {examples[0]} + +
    + +
    +

    4. Implementation

    +

    + The implementation section covers the core plugin function and supporting utilities that handle Zod schema generation. This includes configuration validation, content generation, file writing, and error handling throughout the generation process. +

    + +

    4.1. Core Plugin Function

    +

    + The core plugin function serves as the main entry point for Zod schema generation. It orchestrates the entire process from configuration validation through content generation to file output, ensuring proper error handling and logging throughout. +

    + + {examples[1]} + + +

    4.2. Generation Functions

    +

    + Generation functions create specific parts of the Zod validation output including enum schemas, type schemas, model schemas, and utility schemas. These functions handle proper Zod syntax construction and validation rule application. +

    + + {examples[2]} + + + {examples[3]} + + + {examples[4]} + + + {examples[5]} + + + {examples[6]} + +
    + +
    +

    5. Schema Configuration

    +

    + Schema configuration demonstrates how to integrate the Zod validation generator into your .idea schema files. This section covers plugin configuration options and their effects on the generated validation schemas. +

    +

    Add the Zod validation plugin to your .idea schema file:

    + + {examples[7]} + + +

    Configuration Options

    +

    + Configuration options control how Zod validation schemas are generated, including output formatting, validation strictness, and feature enablement. Understanding these options helps you customize the plugin to meet your specific validation requirements. +

    + + + Option + Type + Default + Description + + output + string + Required + Output file path for validation schemas + + + generateTypes + boolean + true + Generate TypeScript types from schemas + + + includeEnums + boolean + true + Generate enum validation schemas + + + customValidators + object + {`{}`} + Custom Zod validators for specific types + + + errorMessages + object + {`{}`} + Custom error messages for validation + + + strictMode + boolean + false + Use strict object validation + + + exportStyle + 'named'|'default'|'namespace' + 'named' + Export style for schemas + +
    +
    + +
    +

    6. Usage Examples

    +

    + Usage examples demonstrate practical applications of the Zod validation generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated validation schemas integrate into development workflows. +

    + +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate Zod validation schemas. This includes model definitions with proper validation attributes and plugin configuration that produces comprehensive validation rules. +

    + + {examples[8]} + + +

    6.2. Generated Validation Usage

    +

    + The generated validation usage demonstrates how to use the Zod schemas produced by the plugin in real applications. This shows practical patterns for data validation, error handling, and type safety in TypeScript applications. +

    + + {examples[9]} + + +

    6.3. Form Validation Example

    +

    + Form validation examples show how to integrate the generated Zod schemas with frontend frameworks for user input validation. This demonstrates real-world usage patterns for form handling and user feedback. +

    + + {examples[10]} + +
    + +
    +

    7. Advanced Features

    +

    + Advanced features extend the basic Zod schema generation with sophisticated validation patterns, conditional logic, data transformation, and asynchronous validation. These features enable production-ready validation that handles complex business requirements. +

    + +

    7.1. Custom Validators

    +

    + Custom validators allow you to define specialized validation logic for specific data types or business rules. This feature enables the creation of reusable validation patterns that can be applied across multiple schema definitions. +

    + + {examples[11]} + + +

    7.2. Conditional Validation

    +

    + Conditional validation enables complex validation logic that depends on the values of other fields. This feature is essential for implementing business rules that require cross-field validation and context-dependent constraints. +

    + + {examples[12]} + + +

    7.3. Transform and Preprocess

    +

    + Transform and preprocess capabilities allow you to modify data during validation, enabling data normalization, formatting, and cleanup. This feature ensures data consistency and proper formatting before validation. +

    + + {examples[13]} + + +

    7.4. Async Validation

    +

    + Async validation enables validation rules that require external data sources or API calls, such as checking for unique values or validating against external services. This feature is crucial for comprehensive data validation in real applications. +

    + + {examples[14]} + +
    + +
    +

    8. Best Practices

    +

    + Best practices ensure your generated Zod validation schemas are maintainable, performant, and provide excellent developer experience. These guidelines cover error handling, schema composition, type safety, and API integration patterns. +

    + +

    8.1. Error Handling

    +

    + Proper error handling ensures that validation failures provide clear, actionable feedback to users and developers. Implement centralized error handling patterns and meaningful error messages to improve the overall user experience. +

    + + {examples[15]} + + +

    8.2. Schema Composition

    +

    + Schema composition enables the creation of reusable validation components that can be combined to build complex validation schemas. This approach promotes code reuse and maintains consistency across your validation logic. +

    + + {examples[16]} + + +

    8.3. Type Guards

    +

    + Type guards provide runtime type checking that integrates seamlessly with TypeScript's type system. Generated type guards enable safe type narrowing and improve code reliability by ensuring data conforms to expected types. +

    + + {examples[17]} + + +

    8.4. API Integration

    +

    + API integration patterns show how to use generated Zod schemas for request validation in web applications. This includes middleware creation, error response formatting, and type-safe request handling. +

    + + {examples[18]} + +
    + +
    +

    9. Troubleshooting

    +

    + This section addresses common issues encountered when generating Zod validation schemas and provides solutions for debugging and resolving problems. Understanding these troubleshooting techniques helps ensure reliable validation schema generation. +

    + +

    9.1. Common Issues

    +

    + Common issues include circular dependencies, complex validation rules, and performance problems with large schemas. These problems typically arise from schema complexity or validation requirements that need specialized handling. +

    + +

    9.1.1. Circular Dependencies

    +

    + Circular dependencies occur when schemas reference each other in a way that creates infinite loops. Zod provides lazy evaluation to handle these scenarios while maintaining type safety and validation integrity. +

    + + {examples[19]} + + +

    9.1.2. Complex Validation Rules

    +

    + Complex validation rules require sophisticated logic that goes beyond simple type checking. Use Zod's refinement capabilities to implement business rules and cross-field validation while maintaining clear error messages. +

    + + {examples[20]} + + +

    9.1.3. Performance Issues

    +

    + Performance issues can arise when validation schemas are complex or when processing large amounts of data. Optimize validation performance using preprocessing, caching, and efficient schema design patterns. +

    + + {examples[21]} + + +

    9.2. Debugging Tips

    +

    + Debugging tips help identify and resolve issues during Zod schema generation and usage. These techniques provide visibility into validation behavior and help diagnose problems with schema logic or performance. +

    + +

    9.2.1. Schema Testing

    +

    + Schema testing ensures that your validation logic works correctly across different input scenarios. Comprehensive testing helps catch edge cases and ensures validation behaves as expected in production. +

    + + {examples[22]} + + +

    9.2.2. Error Message Customization

    +

    + Error message customization improves user experience by providing clear, actionable feedback when validation fails. Well-crafted error messages help users understand what went wrong and how to fix it. +

    + + {examples[23]} + +
    + +
    +

    + This tutorial provides a comprehensive foundation for creating Zod validation schemas from .idea files. The generated schemas provide runtime type checking and validation with excellent TypeScript integration. +

    +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/public/favicon.ico b/packages/www/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e93fedb622f649482ab24d9585926904533e116a GIT binary patch literal 15086 zcmeI333Qd!5yvMa5ZMGoL97*QK{-|gi@30eTC`Nu)&;eS1*?Z@p@?q*7qq;Ot-bqZ8RY@r`mRnK_mswKtmH1t>GAU*D z>+$JQnv>zN{w-y88JYR5TwY*(=f4GVT)fgKr+|GY*-^us6JR)W4(LF1%Oy-T7p-!|_m+!vLSVHkx>U|L8oc+*o?7 zzBZ)edQqNLA=N|3vKkeqQE+namWJG9_Vu@ zkA7z(r#|Cd`0il9<;T#>T9Lc9s}A?2?0L}n=vF`EDmQe(tkoKacBR^WA~mr`DK}cg zmCW~ArgidBJ2Q-Su7cD)Ig=Wm|KpULWKkQ|2fH;2`*pD^@oqHV`XyNsW$TtLVdpYG z{}V9`Lumgw`aSH1YAuP0Z{+4=chAc7Y|DZLru~2Z`JO2Hf0e#lp_Wc`1R1Qz&dTf& z?*0o4^5vbSOC>EO`BZ$xIL2WP^l&Gd$G3_2sR8SXi@f@SKxLr*iLpHk{`iak%#skl z(;Yd#B_`xi{=8(1CD3j>mRG%_%?s&sKYbY9h%#2nU#WT+uCy*SUMf>RidmbSdgF@Z zw5Op39_UYNl2h*}NKJ^%O9@~9lZ)+gb+LWmxB~lImlW6wpnMNhK$&G%7TJF|q3D<& z3snwkTd})WVQ=kTe5h&DTkylvDI03H&ieP_!-rybkL?=z{wff@UCUC}%9`T#3v%mZ zMn%2f5ESp!5?fznnC#kKFu&2864sG}UDt))fT)k74(ny>RQjv$v{o`@8%W-Q41S|) zsK4)S@Yc2S+uY5_X^nHO|FW)mrE2mK<8frs8#(@gK6f#mUe^J9|B|u`6*qE{7q&Zs?%S+*(|ViS zUuloR9}K7M$B;)lHuY2bItU$tYIv8+S|N@yqu4{~rt61rr@2-2veniiwB7USBHKB{ z{iERVB7P6UU-xE@L+}~l?lz+B;qMKjwjUI07&Yyb8*Lcw=-DV%2V%5|#3{9kOm3&4 zXjm6AznkT?uAyyc+l@o%*f4ZIlr2)31$FFG4Cmqd^qrGHPENM4kI^k9C3!f3{6ykt zk3_uvlbr0Vm~ii91S`~CJ9kPvd*I-j0`^^CuZQd&sGc(WlarF}UHbN$QeL(`*lxpC zZ_Ab{S@QB?VQ=CUFnis@Fu${hkyu<**hBY!PIjuU-YTnCtyKBXY?rw&9$Mfv4ih6K z>xxe{d}sfh-w6A2vFv3{1=~X@NtXHUh;Q@Z^R~>4^uFn7sV5yfcm*5-z;!P=u`t<^ zxPbk&r+ksKEPI9Q37*YwIk12K3Fl>fX^FE>u>?bG@8#MT#-q zOD$W!J_ZbH1HtTC7F$%Fm6>@Ox)&*!9^2hmQ6VdqeW3GpIyiQN%iZ3&$9I;*_}T#opxky!L5 z-aF6GP81Ul5wFRzgL;k~*BMiw&%~B*$8BqfzT1yI#BlJZ>lWQNK=vaT|80Td?OdKQ zI6zE(1#>~x9B2v$M6Ye=KHi-h?57~NH#%bp_8IISvo|>4=K=2Ldj;y|qwW532LXq_65} zq_CUqBBwI^!P&Y`8IH7svl;HV2y(d{`81gQL^5Z7Jt?aX$s=1s-y_7w%3T}mJ&}E4 zBr&_T%@|a2HZTO=9P$w8J}b6<9Jc;YiP4s)K-ceJ36Kq_{4#5!U1n7{bw5k-!;g{3xsi^8k8^^M#|Is%s zG_@J{goxWwaF^hR`-QTedyVtCUde|wPWiLy&pj3O1~IP@haFOWBB=WYarN@WyBngp z9}$SiyOh=O;~eY;ur}zu4Lvi?IoJ|$AHcctydQH`yn26VF%5oP?+y>f2343kRNK;K z%-QUS*ch7t#Mwc=?V5pWceZ0p@nKgu}MZnU8{2(=p!QYfcf^`{3=Ix^fgrY z&iZOciS2%bE^W~<(EB%smSsu=-;B*4ONbO;Wv$-`^Y-{Bt)uqJ?aoeS#I z?!zx5vyf~Ob1Vg$IY`Gl5(zt`_vZ$&wpyuUprrphP;F~<^0DO8#-Q=*TMlxOjJH9R${B2;*0Q&{BCA0azgGi>mc0<=h zGOfhk7n}4LdbC&VlJXJgniN?dM&Fkp59j}vyjl~Qtq+86_ON7bm7^QBVk~2^6f6gH zUYL62Emz#=;9BhawanA*H-sTh39zk9%dt273?g7Z1U=jRM~l=*M{WLPq01 z&Sov!v*1vRyuf{&@6&ff0_d=+vBv4`xn3gD=Z^g7<)mZJ?ccS`QHs-CFC)1=xBoWF zbbL3y90Qxj>=JK?j8NtY?Snzbjmt81+W)-S#BbZlKplvm9k!g zhXy{ydA0Aiu%(5wv*|Oh4F{(e>HP%MDsz8XZy;Ge=6qESrhm$ch)C%e+)6uKGPrCY zM-U=7nGd_9KU@Xm@arJE0tm#<%bVb6lma1JD23wx&pzsHIki@9KH0RSt`&23jkM|yq#l67I<#f|!1}n6pfOnE8R354*l<^RR#06~ zqU7`}o6BPyXasD8mzNIWLB4n)NQ2jGze^Bo}^85M^8ezvw6`P^%~d<~L$Z)6ALp6B&od-368%EX?M*zl?SCteSzPyP4Awvjv<&E=CDiyCsY+;L1Ze(c~BS{ zp<$WIb9?&Zc1;XqOY!jQO}|Ad0yZ2lrEqCRU<{|>&Ir+X7i2X9e-#pBtR(xPnvy^jgR;S!9u#?ExN{E>c4zL5S=c>p`jb1BLhkr7eFB z;E!L%ArzIQqJF56ZZAFvZlM|7pwU@*{L&S#@s(wj&QDui{hbV&Yzw@VVVN+cs^Kol z&Z?xzkF8aFbogO7+PRO0!%AV(pFZ3$V9=`>OgVubeHz~EN@ro`V zxJVJdU=ThJu`op(&JZlP*R<+X{nK@6Bow{U+&=N*?FQaQhqy(Q-{pshy5m;=5}z0rU|gm-WXe4W^R6gqZj(u<$W4)k?pnfs5f}a>m^zT z8(H;hpHenFojKc*Ft~*Ay3HUjoM~JO!W{e=k%-ZaeD2XCn_8DfnLj%^^l7%Q7?7mf zjP~JBFhfux#b=0xlKk`&5oA#Shj8Yp^I&AaKzF!+Dn0ydQm}`5&OKPSwiK6Gxc-;m z;Lt4HZ5?6-EEEqtmJ^(q10@C-fCO;9f?Wual;U2Q=SpD|dx{Vc+oT~Sk_*aG1F5a*fU7+0*$;cXi;HvD;W&wU`IVX=;m>RIc;RUGE``IPdWZPjI^w^(%}p# zkiD{&6QxTsfKvc^WlMn94XXazNXGWm@HvRJGk4|LlAL%CjtJ54S7Y(o(r-jDHkYg! z3mtZjqtgaLbMJ}r3@XG(+e)&sdeBqk+kZ%h4}#{GW;-fRuxj}bkkngimU2{z_(#yK zv%OU@?xAZv+U2&fX=m(ZI63|(NQ}thy>+TUOeM;Fz~S5N3&@_LVq=|VqaMyqRND_D zd;W555npYZ+6-JXj0Idv!*>*Ar^`66TSlQaH?K)D~YT*BBlc@*EQ?yhwkm4S%v_b|POlfrr2Hz4q+;&xH zdkGR0E~vo?zA9ni4}C>N1Pa|I5oZ#tZ}y%3z>s>QsmV8|URj^GwzD9Xkzt|BqM*Z~ z(5PoMHZZyQkYU-#E)F_NWHzG{Q0oEbmg{ac??JZQr@grkzAXsG0PXVJ?v7lg6hh5a@H9;BvoTFIA;+wVWgZb~wioZ#oy)e4?@Kl?U_rbuM z@CgOXxbUCyCexTjRtY--f~+2!Q5!8wzYQdJ=g#9FqOzS1_zOq$G!=Xf@2JDKBs1h4 z9;leTtTOKw&L68MrJ@zxeEj3om17 zk4NHUw3fS02#x}TDlNhm^t5d+dCXDFES-k|{&uaZ`+cUZe0^Ebl2= zF+dLq-$I-inMBSFo-RRjgV`vJ#U-rEnh(9iIV8XMmny?^u3&(3IuujJ~#Ftx<0_MO?hkQ zpT}7>QG2s%rYl`9YvjAmtWTG!llv%k7n6#`YrOh-)oDnpXQ^mL!Dglc1ckq=L)Ebf zf=kxPEKSniuo%+$?{j^}?YIub5%mG=i=Fv4i2|V?XzRSt_i>4VS+~D>lkFjO8l4XKtCq$2l75Dm_}ZTCt7`gk=t^hW>FXl5P>>rVxn@Qn$*$D=P=(-h0ShH#A6TECeL{1a@LC$;)EKht}r-{x3^~A zql1wIIGttRf4o%Pj2Qi}VyYK#aX=k2uhdl>m?0>CtD8%ZfjgQ4lH%lw>Pk|DfLwET z!NCVn6#ti%KE7hB^Vb$br4R_zq-@D7U zR%_?#>kqgLMmSi}Aec}!13l5NA3z8#17SFqc=cAK<|KR>y2p-c&pD1N&uJql4Mpq> zOTDw2J6nBmHDV4N8S~B6vW1I9DYOl|B#m_PB;A{dGFlCiyqkG8)-~UqR`8L?;|}W{ ze1|AHr~+>stsc~FS$l3;8@R2R!+)7qgCp*`_F;SS{NXlE6#5|1Z(dNBU#!+kd&|tZ zu7-*Pp=eO?t1@YeXP|G4C4Y5YMU|H2W$sx&>$%0`uQ*N$3WgY5(3=p6Cz7#-e#?iI z=OL{Q_gOH}9vi(2%Ob&1)Ypo##e-fY>SyJ)2Q(~(-zB0V1?_L5#+1Be zXkwO54ILPk`rL3O@bK+T{~!md?HJU< zbsAwqy+^sq_@!8ZvEhJ~v{uSAaNj@|?vu~wg!;X^aOwG!1Ix&Qb&eoj%ale9L0!Ma zgJ2F6`$dKkF?ZjZeaqqoEo9m9=imbA@mkMF;{nAnDr%y2%H5w}d-W$k`4 zSMPe8$a;=b@UIv|*7t-@&<0Qu`NDK3&*VRf^Ma^zzKDm4Y^S zHt47Qi!am;Yn@I`8S~03J&RU1_Tp@eH)6b3VhDPl*IgTTj`{6mV(D4di@LeZkFoim zVgrzWo*2g4(I^;P3;MS_PD^kIbfui#$VlqrBblYH^>p)le0uPl&oO|ZZ64Mv9*9FN z1I}U}s;*B1j-{Zy6qG{9+@4=(G1VaRy1-GxJld*(z+&T_L(7Mu!XR^e_z02UvWE&` zjWH=}?I8Pmg7O$+_e9_2iMey6bW4!Mzf6!6Nfwt@Lp|f&di*(l+>YnDexqTT{$i%S zXM&woA#$Glyg2#zf&4hF+Yq=3C?^VGZ27`CYHj9+#|p-KZuW<4kqH&1FR`{b=7-(ot1i|Aq@<-_rZ&=nkp9S@gIbkryE*Uw~BU zWMyTlCe5Y@Rt5ZGo<)av%;4cX4*c3ED^lJgere+hdDx8UpXIKX2rnx^bR{=mA5^P zc^9kaZCCk+B+r&ES-`$@4piojI((W@X>lOf`e#T!v3BlW_}4L^Ki$}iI)}$~#A1T= zTvGy7nO4iR*XvO28<>T*aq8KhG3=UdEoOA02>YisZ*;O1*S0IK-%Uh+Js6PBTs0^d zbD5)SjtcQOZfk0gY{tv+tQ``fx$U$LhFryr)*6Y_Y&k7Y4rCT(pquou=U66cIZmOU zJvc<5r-9q;tlg(9;>6^bca3LNmoAm_N=2&LK_r;f$7^*J{@JV!*$#VGnwyj5Ap-`2 z2UmUt|5BYqVP^WjG60QSXF*Ybzn|t^v~OvgH#Ao~e=67zwf+e3dcI=ro~LO7Bs~4{ zO)6dPhN&+99=Po8;>)lJmA?`?IpCX&7b?34_NXgmxe+xEz%VlmY1RkJ<@kX@bp}*S zHYJE5ynUE&Vtpn77rPR2*D8980U>-&X#RqKU?WnBJ>bOulAAv%aCEFW=g1W0kHtn6 z%J@C$K9ya+xLFuj61rBat)3>F1();_yCmUC8suSSCAj!Amvd@E8m_q}+|LbX^>M@M ztpG7nnC-e87M*C}H~hV~-tdV@at#U(m;zk7KhydjEyM78R&CrcJeNjlE@JtHUhXmD z;Nw^g+-7mKXjVp&p_vIEaKzO<=>$MfZtoAbFy!hex<0j=&0ns~1S-#`oy5)Ynf#wcHQ7

    V z8o+#?DM;SUf%DfL|804dwbNq_BV&G-`^%82Pm!zkJ`gJ_wKY-2!QrcW)533f(v zOnp`_6T(m}$ny@rk0NcJdi_*=zAaUDkU>f0IHH23(T29*15K81C6Uo@!Z8`BQ%28y z{4?z)`gmN(n^FUN{Q5tNcD8#ePLM-XBHc8jrvI+c*E9Q*@hB(Yhzq7yKGR%9$)Gf%ePEs zQE9xT%JR9loZ+AhOQ7vic2$6ZDn@`b_Fcs2%23Sc8;Oei6&7(umH(ZbXoL+gKpATk zfMyO=Y2mjvUdJosuD^vzqI!nh{F%@JYg zkiL^7DK@4#9CCrm`V*WDXmavkDQmsx_5;n66gUH*on6|+&Z5?@$JQ>^ z-LgkP(#+6?ocqx?r%<+*CDr{R%yE4^($a z_j0S0pAB}w&T(w$#&m>D^q&}Rhc`Q2BMwlX7g#JmN@n3^;l%yP5?;uHrxifsP>dkU zHU6;;!rvh*Q9*oYiTfL{g?2FPYwIC+QB=KV3=&^Ax=*VH0gXuJ5J;Nd&{UlaWajmg zn<^3FWG$)MUmFu1zP(EYe4Q>t{{ADiOX>m5hYf0xhMVaZMy-N`)wcNheAq)H2G8s>e?*`Za;cGQ67*;k;;0h(2=?ZshCEfT?Bq4vd z^G|3+KRK$+oW?t3COBGp&HPY2+AvT&9rc%G_D_6s&L@w*>kVojAr<|}PLHm*d?u=B zeNU(&!xstk7m3`yp_y`j=rL=GM@IL*1J@BF9o1`Ht^8!pH?X1)upbEZZ?KWJ^a}Jj zzF<>G!-0T~h5mp+J#PeFU1wt=2=-f9kfQ-oPwzC2I~^QJps`W7q)HojivkYVd-LUd zrK(-x?v}@ynMa(b%OAjv!Z8-BYlMH~R)@}uZA%s$3dTyz?J68*cfwDs`5S+jCeIQ~ zKOFXV^pipj!Wl?fwSLy`lq-y6m+KV1V5O=3WSpc>79NHRT4e;{4=pUcXilqf-iB}J zHqXd+o7~~FC(tcGbE*`ng)(U^Z2MD%kqT)uriclkUfGt_-dH%`h%`+QK#If$sgu+T znXxqrN^{%VmmjKUVI&wE5(|GHl~<)9p434~$S1jYX|~t_5aLpl&r{lZCcU$Y#`aB; zAMoU{GFS*%x3i=-{?`p_T;IDWw(ZH>ishEWk#&*gec)?a_2aLbF`M0n&(|ay|9IBy z#S60%3e!Mr6MajJMe)#)CK3Few$+H=0vu;#)ySLn|AYz8Hk>GLA99o$(#?v5S_VCm0>(q z1{n*a1@bzLX*x@!aGc?&-(;(U04!US8pRQ=8RBtYLg^aISEo=EIn2Oi-(m7hd&`NY zbR_5+@K$;vC_ewDUBA3(65lhoUV8|DiHL7-VQKo6PlSaR3B?pC!TfaNSxwvq zV;Cqk7e85C32KYXE~wkom1hbDF{l9l{b+TFsz}NQQQ3sFl82Wt;!y9gs$ID&m&OS^ ztoqmEN%YV8XK8Cq=;+}QLbXpP$~^(ZO5mUDD_2gECP4AJJb=~AcRhAASEWq1Z}3)a zPk8vDFo}fG@%cr^2zhq>IdRKd^Gh2viLM`I@4mOi)=@|)OSov+dO3bD=E5t4+Jthi z$631JjY2?KP0eF9t%Wr0m8CFg>>wmKqZ?`GwoA9Nd-0XC*z9=SL6t10hGWm4(&>?G z&+KC3;fG>pVw$$H+gqmI-tt@Loz+-*kQkSnwUf~GMwmt2)Y5lIgi<8;k#hC9;g5bp z?||~my@Zd8JTAR`JWNB{#dZ92fZSkRk)`uq{Eqiv(sRTd#%JG|K9ziN%F1Xy~ucmfJ ze|pD%RC6J97u-SQS0)!6LnKVkzM)t0{3ta89~AxmS$xc2mlr2+OSdzRBh0TAlGxx7 z(RL{=QS~*B1jDXXS=rV?M<4A0U5y(>mHK%}PEg zde50WyOtS?8FG%&5knLD z_7VZ5GG(}Rw7*|_BQVe&qI#bt*zq^M+jD~!a>d~mF}9P>bJxO@J%7SHF3jarMut7A zuMM$U*~_AGN$UJ%9zgaGlM=1U&8kZSI0E2LO_?e((uY(S|5B6_i?g)pJb?+pD2@3a z5xNg7*}djL%s%<@pNC1)1lsfhV?2)8zIJsZ&kZf-N<+{yflGX^l2KjOIq1cW55K;s z2W)ujiBwX5o=4MWSv)g)1_sWMk>2yUS^ie0p};Njdd#ku{J-le%mVY(tUh|ab+$;& zDi|6;`5Df*(wSd{Zg=8D{R%5>Mp$h&snRkd9GSuSqV-S0%bLvZU&V1=f9$77-(~MP z@8~%G*owt5s9F=VmN|XH?-vQ_!(UJnIXyoQD1zyL zlf*c_-ZBC*h4VS?y`W-AAxRRvr322YWioS6^cGr29W>y=dfJ{84bx=A(-$4#++1=ANJJV+tqHX^zgle&`pRV1(^Z*%*W4+7<2CMz=GYsdhdw+9XOS z++iqFgQ@X1(@OHvGl}EEl6ozb|0GITO>gKE63w4UU9w7)2G8%{FW^WeE%W61cj2!+ z(5HD8G+8Z1eAz7Y@N*{bm&=xLmwyH0IQ4GNL2<-;HMf7{s?ycp4j5!KiKnA4WS?5H zG29C2w=-Oa%cTh@CV8_@V^BcK+qrxs9nGLJ{QZW2^U2aN4f<9q_RnlpU=LDAOnA?j z5S4`RD74*dK{ZrYpQ~11i(_#-ek7xt9Ss-@QfWk$%Tz&e1ZBSu8eMGm4TC*)3eDdS z`masJmyxv93^iMUpHKFs7(Z#rgImrWu`{Bc8scL;FoB%_27R~lAB)4)EV111%g6sd z@rUf`DsWY}(THy0C(ax#setBnLNJ0cUSx)d@o}Jj!RKD(G zaa`LxZW^6&#^6tx%_cMb+Vihm5R&?tRQ|E8S0s4Rp3(^g3H}vp{p1VT>ZHi%H@Je# zDHG6tV%3BxTz@{jJ+bB~T7i=3s1aEQL*IvVl6zVnH(NHO0rTT;@f;ou z%c6kYaJG+QJv=s@B>^Bv-Fqx_oeLKetq%{s3L}BDmFcAg5Y!_8hI(f{_E5jeQ7BZl z32Rt7nr^=q_H&2xO(*%CDiJaTJHFFcE$_E8wWvs!$Nr-VdrKC1X!2b z4%VrckoKNU-MY%xt!p(d6fcou9;0YiMdb9saV8OJG;IUue<2UUB7#RQGsnX|{*=># zK@g-G5QIs+2+L!3Qvg){YkG%KxuYib{7~f?B-;-*UhjkRAf~gy?aAg!!kGWezgJUD z*E}v`gt@J%1@2^yam6wBxH0($vC-d#Nwn@)DXe@YPV3(pRm#-EnPM5v!AQeIulF4s z?t#`pP2kFYUS4HH3s*WO1@36fQ#V>j=52~WP<3zMSUR*{c%IeQBeS&YxLo@p1DkGR@4Z!eMA zF%Xa2c+C6lnAo+Ago3O-Ny?f}YiaU37GuM%F9%)l#%1guYfyL&s#s~jl^J_mEYu?Y z4TXt_H1;RsK>WY60F;_ZEeGtQ%N}6iM}S$LZa+YM@%Gr<`W5sI3ts(+#q+xE_0n%u zo2XZfB#oM3>E6iEd0}&eDiAyjRKGOyV{GIZgogIo*#Er4UyWXelh)VaW#Ar+72qFg z$MgRRn~$B)zs1BfSdE@aco1YiYQDz8!lm6>V`nr7f+&4>xB8`4Vg=0H7J z`tA3Mi4ecR(YKjnvZ#z7Sw}|ya(7AD1-XEOiO6=MUU4OIc~tQ{d|;F+^TifReLAn+ zObc8*&1j>1Bk@@8C@|C*&d@fTju14x9r6gl-o{d}p!jptVuR=Bri4)aDTx&6iV8%k z$v9P4!wY%8x3=1@rh$^ZZ|8B_Gfe^qiaWD=zHyNu4k}dreUeC?ce;dP%>UF(t>FQ` z$ZY(Keek9K%9|@tMIMCPY_ot;Y>?V`cM%a8ixwT-$h0o?3u*B>f;_*V%H}YUyO#t? zZ~R%q(R+I-U+Q~_A=xlpQjxLI6M>pbsLQ!C1XC*y;T`@Pyy*)xk*}5ihTh!L*w|@a zzvo|IEL3Og$cp>}dwq(E3>$0>ce#Db^zdx0mdZpHJ2`?~wZQ}qd&`ol;=|db_=`!G z4flBwg|cuZsngP>%HuO`?=Mq^geIlDz9Ztl7CAvZVD^a>V~}Pt{%8XWK*HYk`hC;* zLUX$_8KHT-;bXqfv#TU=Oo^MAiQ~CkpSed5ROz(G@mP|oTRK&|EEup&WB1L0sQ6fZ z_5E+T5ptb_Yu@f&UavAPNuNRxGA_NY>Gci1mj^N4d4d0G0SZ?uTU2(H;o$1giPL^! zoiWO7PzX}c=FK{LYp>lkXtQvt_{)(s9m}>lg}GOIqh2e%lZ@8VzXV#VW=$WGqmX)t zk6YbiGe;O^@qDL!GqU(soW_3ql=H>Oxee=is$>Xdrq_iwAVf)AEkE$A6-`8X4&p% zyOTPg30JA$5gx}pfkR6}x7L5yI=Ln_33HGHD?2At;`pCpf2Tl=Swi>*tRIDJh&H4F zAcTO{lrYki3=||Xw|mN>mBJDr|IL@&W4!Ch$!rY`z5|T{wv>=Z4##xSZzM#%PBUBd z+&j{y6|eH)vVmwQ#a^gZ4QbwFf+j8V?U&uAL!t%u!Koj_&o4Fae^k3uk#^Xpl2|R= zF^Pdlo9@B(kj#o`rKU*8$@3sn=tx6)69si0Yuc?yaNAr}Zu=*n0V|^3UO3G6WDoWm z1bxOiXC5hIagq-Krf5)ux8(9=&{SsKl}V+OS(E=cD-K*D z^{2;5zIS1e@nU%tm3eT~`vrb$!A2m3$kb1Fik&1$ivi^?)-%S22d(}a=i>((d!eJI zC)i$S`^e?>Oe>$G^j-!npXt?qt5oIyp9L{FW;I`>1)9t84A5b;po)!OqYF0QV+qsk zX*Z>tKj-|ZKN=S#x!gBj#sua*5RdN2tg1%hbHe9t$zR4wQzqW!!hTR_210$WOlg3}$c$Ycal=PX9)6IdMQV8|nq5xzRCU+ehc%A78)sdZ<3>)AM?cotK zg2!5!<@0N`D(PpmYFzFIGV9s)@OxbY`GG*sG#W}f-OGTmDmSkHFoAKLv{DgdW zmJG~cd!0*7=%*e+b}tD>jEqb{nKo9bL8WqjO-4SOUbU_xv`p^Jki}h%5@{bAH_JzA z7r2_men9ul)HY*V!7@i}0W+WA&*bo)u+NWD!yjL7-uLCNpL<3WT4;_B*F^Aa?aIio z`p@-`q`aS|;7rf{2za-F^b2VN2%PL+c@9gaW_PjJt9w_FIxN1h)i8i|+d+)ehZMef5M&8^MAP0B+`j+#Qob}sv_|d7BCH6au8sRTy3FDeIc85l~nO*m~ z*-iT?KAozHNBqS7Dda$oMCwmB3gd46F=%pI7Bu#A9p%~Zu)A;`tSlZPmUW>zn+9go zx@c~H^=q-E-+ULkSUVxAbR_fCtFBj!W!}GDm_NYa=Oc(bQ2|IqP+|Ceo!TNtsI)1{uGj6F1nEe;$5b zG`id+tb*_z!Gtdq3Kkb=Yf4fKGJ(Y(xvYuuUS4`S25zV+M)orXEf^r|z6{IcA*mng%ss88X zHLF&CMfrkDo71=`iY6WrUk6jHo=jwXxC%v5=UtpcTUL7f+}#WKYFb-fa=4KJ#1D&N zq2{npw&cl0)kEWE{?c>4Ec491;_pUsEE0VRPMn@99R>3_$?XZ!whPDyd93g(S7%tG zQB1_wZotx8?;%#jK4}Ko)hF$a<9-VPg!maa`6p~clFuOn;PAlHRK6hnnF)03;-vW^ zxn@Vnj@Fj^Tgs%T;ArnuEiT=rI&f|ZeLKsHj^E8mxm8(O2V@KL? zuXE6%*m8j#$uJKPzBC9KiHVyFf0Od)9_#sw9Aff$D`Ot+N^_DSckHKSzSGW6fs^F~ zPL8x_Bh(`NFE){2b&SP5b^;?|XPp{mQf2zf;npQ)R+$32;e3u=Hl2NFlbmB}1a&Ph}+ z9W-9AiKjEGYl+^{hcP!0H~zL6bf&B&8r^{hn_f389r2jUYRjD~I=l+}GF1W0ebk<( zED|}LTeofo#tyXr!4pX7^3jo6|!;gO%0QguV>lrEcQ zun#UVGmRE_0CBu*1%BEkXj)FeE z!%eHuCny_8E}mc8o)en&VNzBwW6-H6)McN!pgmc1Xj<}{vJ{$JSngOTP7|(Z!e&xz zkt*0Ygkjc9_SO~tKv%@d6zulmE^CiWGnnJ<6o_6nYq{75rs=`bnY8Dg`=kXwS4g>J zr~AE-#2~kq;rvmW+{6d}-3kxld6mu&&X2&Nl>ToX2c_yt5A;>lg%iRHu zuwL;-!b`hZU>K`B!tUZ4>YM&I$J^$^!ml(Jij{xq+AFrT4t2>9@0laMHIdhfW*(r* zk6lA4QrPN9mo-tGryM5o9{jX_#Fc2?-Ckt(Fx`c*$qc`cPue)0rPB4H(l0vs=A`#L zKyfz#eoWDobvIop*HVf7VCdQU~Vh0Ke^o?5&w0*X|6F6zo#u;RU zyPjhLDA?|VHkuYEtSpo9Ii3Fcg7(sOpHC@_=320a<$u-4$5WF~6jC52pMMEX`|HuW z2r;QEHn;xMJiM>?dOLjEKfLQcotH$L`j7!+3$Hx_w)k4nB;G$JVUN2}CUkS0)Wl@= zY0<0rlcj5prBO-bmLwjmNZU#b<+zr+fYHs>voQqG9jwa(v%n`R*hv|b79S8C@1}^W z8BtWLQPx#sPlX42^vD-;UZ5^?Ew3ol(*UUMe^-pDugTE1QO(P^hG^VxFQJ7KQ0>m| zFLAeEKs3*Opvpq{K9@=&E6zhyQ&$iRKRHKfGvOp2 z#rk|Jg`wcz7@WpZgq0=e_{?c^Lk>!i;@|$OhZN8rjHWJgjlIAkS?f@(n7}ERPus9> zd$vR&cDI>qyvlhH&kq2-3Ark5#{yrUo{%orEaiDc|gQWHO zAQ|tl#kk~)!^iHe(OZ`@oAF?1xRiO#w}q2daFV#fr8zkbS*hK1resi|41uxym-DMj zS!m9`SPDb2i_%v5{~Xq8Wap&KR6Wluq}gq$UHZm>Q-$>xbh^ z%xKdKIL-PAv|kzx#VxJbcV43#SY3n3WO8Aj`w_8)rjlqc*WpN-eO=z%7ajKt5Q0*D zvM|E!AqM1SEp0xz`9!EET#-1|RXQG>N1tOc_TBlsxF6`&o-92ea59!B*}K3v;=D*2 zx(Q(GOo~L~a?Ih|hUJOYJS4p7(_2gum7{6^N(VCDfXVx?__dj02bnsiqOmHh*PN!4 z!j8tUtX~#X$=-h0@qzHUp+(}3!%Sw*5>QwtL3BZz+ zWI=zHHxcSTK0foBlaYk-d0-%>3-G#a^H~T>d~uB@?O7GJ56oIxyY!;?R}?N-kE9>$JK#KE(ULG{@y>MmpnNrY-pQX#wN0lY~npye-}xz z(i=;{8n-?hf14gJt1R6qb)kWHMlkGNowU}JTxkuN6}Y%)^kd8XvP$I$=F%XjKk~&% zSin<4dxm$tL+rj#4joN2qX_gZtJcBmp@6i=TF*a^4p%1koj8eq<`i@c!e=FdfI<7i z8S;|C)wU`|R+V_+MJG89?pFhYc*3G?lB#dez4u{cS7x{Q1(c}+ zM@o$%2{fQxVQ-AN-S!D{!Dx)A0ru_J+{_?g;vRWa6`+O3R|#Pal?XuvTHy1XD&@JZ zzu*2BnA6XHLR|{9Y2B7-ReYFL*0x2(3cmz=T-J=uFS{`pCgd~4i@BMsZb91N*=^9X z8udX46B@CKkyFO#lkEMypakGNk%^#GEcXDm0#P!z8C06t;_4op+FjSq{giL_-{U;IA4N1h=WZt~giVhNTT9Kujlk;Lx_~H6X=O^r2h!TMG$Q)q} z8S9G^t#Q~rBAEJ%59+k@x>&*kzv?(?wL==1LlUCQC;Rc?57GRg5-jh_?|mPx)!aw$ zkrj{rJ)Ji+c>%nO!f=%@WsqZwSi9ImgvtBB{FKS6Z;gUxc&1bB=&p< z9XJ5br}+DqL(P9&se+o*lMbzXJ!CNEJ2pG-moH^vt&baz`p>DOzgJNK>5X#u0wD|6 z*mlmIDcV;Z$MU+D&Db_q)HchVu_aY|44P3H&YbFkQu38)AkAe@Vi@aGVqRR^}}}_05GR))B4UiZ0Q{1r4ACoXLrCf?D@V8AxrBdm;US!gtavwXD^5tlQ>u$MVJz z8e5j8=kilE|4RG_**Y0s2KHFakw{23Y>*!E3Q__`1?bN=e4^W^-h5`WF!I;8jEI1N z#i!WCYS8ae>|2PP#8zGP+vD>?7oA&rAbEZIe^T_t{6cy=TF4@K*cp@ zTk`Tw&S2XtVaV$-H7CoxZcB#pAXR)I;?CLpKtsH%epY|GCts(+hzN@ zPXSY@w%KtSn6xffoqSSsX$qQBoK8nOYuaptNI%FTWGmwhycd7g_o)Q~ly^Zc>jAi% zFQ*O6CoS@Ic|cd=3C&UASudI%>H z>WJMPLznmy?4YD{!KV`Po;{U)&-Q-hV| zh#1C$D1Zrlr!L&)I?F*6b%r2Lur?u^7%t#>2t;57sq|};h}mwCDJY9$iNsdJfmk)U z3f@Q)8k43C+-mzjf>o?Wp~6ThEJM6wCPTL2Euu?QW3jZbgIi7TRk$3q&9j8?Yf}3J+xe93tXbA&plttF2lK80d`>kW0xO=E+^gN7_UgQ0NhPLvY;f zedGh?rA$zPjdGY~4fwtyp=$%+GUVztv<@P}h3qhi1-#)$bGk%XH8hJSDxijdcZPog z*+Qp+CEY!MxJxud4pXtk}-|h zLOR~oM!|vtFDt8J^T!-54O*z zygVPsr1)uru$XD6V+O8+k^v>4xDWsfifeiv?I7{2uW|Qho$~&3K^3%$Es*6^t z;3q)j;E&oDbFhX|uxH-wHgUZ=ovjwz7_LycQT4#8HNegNqP znuF3Q`xFDg44-3Z*9R6PY1&k$JKGk@4=z#sx@jpwj#c5Tx(qRPGRHDXg3}OdMmg^C zu)TFdi}ykydc$UzBP$nnK&EEA6KIKiHd45t0}Rq6pDrTMynU&{J7Rm~s1L**cyDzq}g zO68UWsn>^Y!Rub^*(IJ835!_3IPrI-U}HICwD4$gil*2Y+~Wo@i3Uxr4AoqFb_JRs zSCVf65ERyEoJOxlfG$sf#K@SH<%~D{{F3URK0u1qR_KV;-cg_Wq=BI29Mn+j|c$ zK+yvA1wjqIrx;1947?-j_5`nA*4b5YaIyNP`A)Az`B2O@||ZHmS1kwWPM|n9-$7BAOhW*02AGvSrx2WZ^(N7Lo#Ny_XzAP`X)!(Nck(=uXqF_AjEf8sn{8Fmbxm}8Ij2T z70b5WO0SLkHSaD7)ch>jd_1Px*P);17o<7k3J!!EO2%_0m*0CHU#{^CW z{sJTE;foWr5>Mu^kU|$~z6W^oFBRr?7=cQL=B=mGPdz2Gv;QHE3cH}SBJ1tVb9$FdO!wXMKl$Y^qO8)<0tD@fv3!1Fk#ttmA zN5jg6C4c3cidy(9qB~~dk;J(;taPB@7B8G1{TGGz6-!bk4m9|Jpou)|p0D75MZn!tA@ou69Q!JfYw3UHlqjwLiO6zs!B=R=V8YuU7ibEAAoG?#csUw_0x2!1^`_?!NqB)< zZmWt$=C2t?rh}tX?r-cE!$*l(34myQs~i`Vta@oMXKy_o--sGNygZTui)n%05h3%4 zW6+UMqkfA}iHRB@moN6E3_m2%r_03qa8c6qQBBhTbb?Hp_N=pVHQH&hcB#m7Kvx~_ z(13(TKRmEI_|TMx4SQb)xyZBz1_dab^_v%HD48!z+VOZ^~o;(v|2=&lWGU(Skmwc@BxUAB(83QG9*Nt19FS zSfB!A6elQpO9V1CNzQjh|8E-4Zg1D|d(>LFf^zg<>)E=LB@=lN)Pfccbz*F;NN8~Y zSS^Ld+Z_1kiAQ*Bp&#Cs^FJ>`-B+ww`1JqH0+0=bK&~OZz`WTB^3kP@xWURciAP~P zX+?Suj;(wD#fy$fa<*@n2kHk&b;&kJ{C68$s_$Be<|Lpx8yEKx6pFv`0#WkdSGh$M zI{c;1^nb5Z! z&trwr@216{Rs9_Fx*Ln%yV@}mpto{%M9kKi%64hm?gU9FXx~hU6BwA?{3U*^w5oH5 zlKz&Uhjxhc=TD+YGn(mZ=@nJdnH)@)f;I(Kcd+2p0R)dc-U6JMcUyif{}r6CO;CR0 z$mTvAnxmmD!I=+$E!sbD(|QoADlelH?t*wXljH`cU@|VqC(hvS??`$+2j7hBc&;+0 z2O)}IWs`53tWFXS(uhk1@C z@M$pXt-#)ly$CCh z=7TPcaXHKC{~D%oz5nD!kuct7d{I%|Bt`fCDefvCs_LHZA*7|dJETFnyFow@5a|>I zq?NdINH<8glz=oyBOwjajihv4`rh~O{Qij74}LnEv-iyGnYGsJeUE%Ul_V?mKvFcVt2-fV8e}jO?#ee;kPwV)WV}6#gBsLyvS5ipY ziANRabn>ycM$BxlNR5g*9CC{7%(yatP8>K{v=4n%$4*~#+igd~xU&h)U+Sdb_JzAe zko?vud4rZH&l6MRtRAtQRPfY`e+FR9SCLwf16K`;r9wwHY4bB}9iA=bT#5U5 zuD(6FJ33y1K;s^5VHraF_p6ly(BJ3L13#=X64kZqt)hxlR0x^A6nO`-D4zm>{gbEx zk_TfW5%VO5GXU$UT~@ZCP49n($%doioSCq|*(}K$#=}8;iD6nk zw(y+$B%CtbvVwJBh;>M(@)*o`}wFYx8JHBE4*eLW|=5m`&7)o?vuO zY1`DHKH7VrBA~NXf=+~pus-#c+IP>BN!N3b&F|3mhxe6R|M45_R2K~kYy@en!9!?D zCwi*$-lm>b#qX#loxi8#^ucTZV8B%3cTPiwpK(TJ_;Y9XFqI_+Qt*xt&Eh$NG)LAi z_jK*R5od^Yk&ybg{z<$k4Q5Sq)#m^g?=d0lEV5{~&2J7K!EagZ`aYs)E<9@T87|N# z^Gc#Zh;BK*DXT|s{M+K{Fq;9Z{4jt90PBf-Rt4Ki8a+q3DSkpQ0+C|5$#bb3rFRGj z(v-q2b-o0f-&o(>eluQnuX``yLsf@wfDQzxsSzw44e}K#`0qMwL62ho0Svq?4rU1@ z>||{#Hr1@g9dTAN8%3Nzb3HOy6>GUtBDpxnozv%eJC8phQ3m%X^yvr@2n6amSD9vX znuE*MT4f_)OYRLX27|IL`;nZ?uj3Rvr)6J~iWokiZa!Hq;;_-p zo4}aC(6^`TsBN_RXKQS|r}DZSDnODM{RJkE3ipT9C46?Ml;R*(5QPk&!2ZXwx zkG+E?>%#iRgZ5F6nKwiXAV>jG;X|*Ki;NhvT;+DW9ul*9DC9Bh;qTB8q~Gu}{uHPd zLuy*38G~)<_Opf;0%o`IfG;z`I-*55YdVVsv-W(8mQAC$jLe6zn<%?&t`Hz^iEL$k zqWN1T6J5YEcA7-PpJ#I2k;ei&MZYF0r-sz6g=NO%oMx$*-X$;J_{If1$Y+Bei|GSHY;D-18Iu5l(Xzq!&&WKx(#; zbDhc4TFZzcc_uOGZJTty))EwhJNcRF9E_l!AKf=|H{#`OE-DIqmx7@aG=y{qPH2F| zdXW31qJwrTEO#q1*UwN0`-Gkf%_7Da0Ga`;43|jx_ak1eZ*y!jB+cfh8EgK`kKzKC z*c3_}5mN$jua1tupJ;%3THuc?KtHVjz^&qBUd%CPtmOok?wxVbWD;;oOBUO?mpP6-#m9qUE`5 zqr~y$ic8h^j+V)rfqRvlqmR7+@O3f#K7_IEt?lwgTPKt2TPUd|{Fx%W9pDFQyGU*n z)UsBfaRuJL>NtKZ5+B#3v;lzrh#gro-)?6rI?zx@M{G^_kxrGEdEY}KJ+PK6!_)FAdqN)~uP638WYF4v%OS>(Q$sIW`w5uh(1 zVL$4edEQX$m#D8i@!CVWk@r7xK{D_t18}-=h!0`^t$`m}kz?z%elj#6{{G8 zPswt5*_z};1I9sbl+}n|luH zwGq%RYC5Ko*DmqP+FOCO^!8Q7$0iZq?sfXz=4Z{?I zh+OXHS*oA+ZHL&Du_Y|Lc6%!679WCPgHUt6XZ<;hT9PzBilKU~fFtIFh|I}z~Zg0Otev_I-9;En}iuX>p zJ3ed%1|&H*L(b_niMIP@QQXq>`+GGssS2*)l0MwFP2yc)Sm~x#46KOlv z?xm`Et1OsrR#{xd))*Pw#n^E10BKj3`?G2R`x$zXoBeQk^Ia+YC<5rs8uViCQSm4p zVUG#z%%baT)_7Bhx4g`Irf|fTln{2Wef-RQHfKp6mi;`^0z)FbKn&``8iTd&t+ zHpj}Pcx~Z?2n#A=fN=9xxP!7-`|j{zDysGVB72O~eVb_3FoxGn{U8nSS<7}yOQvl- zZfVYa76!{5?l|yQr=N*NL{i4$K3H55^3JAzSDBL@4cHUO zexTN)kT@wod)gxB^V8hZcwko~ewY^1E5cL3SM^`+32> zHSUO}B@Q(#^ot7#rv>s@SPRT@|SL^rm;!9fXd>R0bKrA;ME49>kv(CxS~DJ<7j zoD;Jilw*Xm5Q6@R82{Qfy9k-3x;uoNc|5|WX6CBRf3NPvlK;m;kUdMv!&_tRq& z5~kKo4<*>U8uu;1>yksbK$j0075VgC{)pp(eD`vmlcp1+O)SPUb3fd?sCi3Yfs8vm zS5(Q{R{qNjIM=k?c)}ox&T-c+894GDt%B3*$oa8hFdDll*7qV#ohONfnlUyN=@ly) z?P}`qgWwQy9pk-ImOF|QoFakRCq(%*tEyN}B{gj?=4#p~y839Fga2Rd6@gAqnqiA5 zqk+PP9w=w9y7x_!x_6~cU5g9n` zcJ$y$t!`!Tf|pUk4htD|!+JuYWkG0&fJI2*o3@K;+)~BV<&ANOZjmDVOT@%&@4YO5 zi%FUL#{HG_gbHmUG?%E>cb4j51oAQL820JXL+{rGGOggvpTV_U2G2VRa6X*}*sG6v zp6958tRqd}cziP~`TLKSLGAP^yX5pUw9~?i3oIOR&@lfUY)E&p8Cx-NPTLSQld3j7 zo(&?PpS?0gGD0A-&_(v}M@l5v%U^G>M^fRW;36C+1fV6hc=@$a58b-)F{fY*^2sv@ z(esPc$GL~EmaiYB_7-99plU~N(Fjz4ihj+-GA2HH4HGyEO%hV>O}UF2calE&kmsrS z=~mcv?Zd>)%w#)si0mez=@^NJ}ro*jCeyU~CtS4!AJo*LxnM!-;UAyb_INCna zZZS*f4kus7uOosfk0$Y-wwQWTz)shO53S=U5;Yq6KlR5?#*9(mYir^}-6TVaP0pgL zyNg4a0AU~IZ}CfT3EQn43m1+XsgX^Gw?n-0d}|AI0n)&F!58RV(;%|i7M35B&H3RP zZpz|yOAyx1%ngARh_AZeUx#Vl8*g5qe=tA{a4YN;E$u({7^Z=L9Xv^owxK-wSU9;K z)LaE{iA!D$&OYbsrXPZ3=3MtfcD1s4j%gB|AePSg z$q{-za*EspOnkPg6%(()^DOrTkzU+}u3SiL!cv4D)D##~z=xOYJo#71=F z+Uj2(#yUMwPj0wMmCE~bqg+AY4;U*KJlfaQIliDB`yjO!13!Q(70to<6Uxl3aCQ+9 zfGirZ_QCo!s@opZR=I2O!DOclmoonC2wGtM!2`p6Aw+70e(XcW=`3s~_sdAw34u0I zwp127BSODS{hH*l{Jq~|5X10p#FA-)mes#Tt5b)ui4{}c(fw{SsFK&KdBQC#d_O}3 zE-bv~=Y|3id=xAz3EZ#-hfzfUdG?arY+4Or;)~P zk*;YG>;gAv+lC*Pl&!E4e0Q2gl-VdBOWtX>aO~zJ_7)X>xTah4x~~^~T^voNL`12d zEv&%zZycC}g;cDVW3VHFT0H4!br`eg+G?o{VJ`Y0eF6@g3=j?IHuSAOui)r1m@Xb^ zJ@%etxbUj+1-laj)G-f+c+gMNvOrdbR|h+9N;r=FW9Erhg#FZVnHvR!9rI~|$H^)w z5d#eN^1rRviSfIn>lT`BjNI7hmMxpRtMQbIT_NzuA{gL_-LDDD{_x($^Ew9Rm=$|_tzmJR@y&z~H5)$QtM{4bUpyzct40#dtrbDq@p?{VkZXMy-=_GQ-&dZNB z?I+j}*!>Up>0m~;3;BPqKju!GqE&8C(gFcda;QdIjZ*)xRxX72ycW#c{D$T^Y!nk{ z1Fq*(enev22oxZ{E%ohXC~$xDnjfN3V8J0FM+BPfqS1|9*P)$mD3XuwJbyd!UpjFr28e+0lEzFBvc_dHj}WSZ@+(2qvNy>4Yzw^goB0jxw1loV2!KMHLEjkaje3~PY zF}ls>rBR|LO+pfjAl*l&X?EB3>9yG_xwpN)qtcQjxC5ro;D!Jfli1)J4U6jeQ$@(Z zTY8B*ze2rdx^S1;r#fmPCZS~&q1&Q6q%x8}a&l94+<9cPO|v3h)gsi|Sn ztOp%yXoQ`<=_pshv)5@Qozm7*tT>1l6Hu{Md(RFgaALCUWGC+_knjX^xS1!j_m&== z4eTOw@gM`dT}~qCQpHDy6k}aSaj%3S4Uj#GPNmiadPCvAT8NBc&jUWFm=-ES-@(Ib^gS#d260VmXELU0er%8E)6r0~4qYrD0Va9Q#zhu$d`QYfSz+b<#Fp-Icm zPj*VlF-~n=t~_9Z)T)=+xcr|HW}DSUqBMYu+M_Xu^WHJFZUrjL!bfqE_RB$vitDI_ zp`46%>f3Vwod7>nZ?i{_z;(Uxq;3vQY`>QEBJ;V+$0q>u&W~S2s&dpZ76Z9>?MzV; z{+x<(tK_Qf&&YBo-h+*AUy`LN-C(NKp_tZu0O)Ha-IP$kxvP!QSSnOfLKzS z$gtzg|D9BgoSsQ*U<~&n5h7U&FwvW?JQuMAh-_y$DwN*crvak=RIQFCF9zmIz@T8V-T)W$F4 zNF9iZ6dyn;4+!Qm`n#)`)7cm5kb%!?wjb6)tX``PZXOF+`43mRAHcD5<$j%*PL2VIz4sk>lH11c z{KWydGfa=U;o1LM7`+b>x-5DOLU(BXTJ!Iztdxc&t|GJ4o+k6chUwd`nBGBb2lu-E z?$yg90}~(8qn#8G0+g#Vk`|s;Lp3ECTce+?LVts6VY_ zL>%8gq^b4u0q&U0h5!08JO&h;?g=<_P{B=pjZ+&0x(f>h<;1!G`Gu!i(vRi?g%$DU z(QihQRV+!nucvBgQ$PxvIJfQB zA7U@QHeov4R)C<4yf%p`VeOo&EtH`j870>(f&w(TS>k8%btRrK--M-05TjA&-}Q~{ zA^i4^kX>GQgbQqr-2Kg3`Vp=hT-S#$#MOuW#G5cyx-#Z#bhG03uc{q(8!}nH5f*IY zD_ToOh^){inD|JS%pO{2l$q^gY=YV$*05MlVtk zX}`ZF{1f%(24SO0M4C~~@iAN&qzp(U9vu4`r-6rIfM!fbe_1WkvUu}?-8N5tB6;7N z*RVM@3e9RCrK0{=Jh6z^bg54^<~Y{;OyG+qM=x;q!-;yKA{Dya-}+BJ!IRT)BEpOS4Q?hG~hb_(d%iaAt*= zcsp!Dq-oxX&dxcaFJla*>}T#4G!axfDH8IPI763v<}+W(=`oP;@LA|$qa`L2<^AU{ zx1M)cM#v!pxNpEDnCBtB&w1KyfZq_C;G*grIgg>&k`k<07@cNn9BgJ19(7nU=l*xSp!<(h9|+V) zC)Bu^+R-J+#rl|y8Ji%HAM`z5S}^^Nq?^GM<>`e9cb!$<+)v@a`qayxwQ?#L=}YzIfAV;ZSo$Ti0a?cRP;MrD!oGTSL6>M>$YdY=cGRD} zCB`58^2~iBgnd+Ch`OMHHe|QNtSlOcL-%qS!)3Qjw%Ri6F6SRc1q4Eb++V#}wJUhw zc1Kz+<~8dH1>+NgH(_Mt%jI4@{(e9`w@Q)d6@ZJ@^?vf`K2Dd@^}a;UBe(yM(ETY* znf*ge0#|7@TxmmMXchb8?fXOsM@%e@J~#OZ697T+ThN{Fz!Kmg;sL(04wiF_;hXK~7u6bWN zgZyuZuSO*uHR=Nqb*pN=s{5dK5tqAS5^bd5#Pf0*PfFX&f?m~+wa)APrSP7z zlC%m-rFSG6fuu5MOf%UIHJ~(9H_Ou2Y)KMl!_4<3njJ$L(}%uBZ1 zi;GlgxW(SXdH({fAP=BDK0S>_V#&QE7RD6(n;Vyulxr#YCEAl`F=(dS%KaXfmTn~= z*Wn0%X5+e<<_1TkC zzdSw6pyQFSboXWOLk8L|#L(u5Kk}t2QZJKDgu2;@5|eA@^~cYT)cD_f^a7j$L0l^Q z@2A;zNJ7SQ?jf)r6{6_ zc&Wv#oWm$S02HC%Fk)jKQu+_~%@MJ`{}kO#AYg@p>o^wC1V z7&(^(aATI8*&BPO$KPr?Pht1v@@yJg#QA?cjZaI#rTW4MCHV4O-ZQ*=E4{8#{%gjKX?}VzpXbV_c`(Z-d_

    AnX ztX4bdnlY3D-M%c`K%Nh%q^(-W%Jr;_JDpXF)SanR`yLELOF;_D+dWdSca&7-rmd2# zI2L;{qCcjm8(>1qx3GV*W2V6q+w)D+%{DZkieT@ZA|4xTmH{iE8!oAR2rIB(^sTz_ zb-Kl!?NSSEY<^zw>O~tq3~g`@y1~o;w3H!v3g&Ut>`G~tywvrYBZhbTL`I@--Q(#@l#4n6dnboV*#0`N{TyP z_J;Fi!L#V}km`0wL4g#|{xl8odt8#xl|HA8Xh?*5Ght%6f{KZt3@!q|!2(+l#V`4Y zTtJ2|| zBek@$y3D;K{mkuh!Jn7z++gm-)p@b6;i8#Nd9D#@^f@b;D*;#YQh-?|@VL;%A@D~P z0*0TQ=%BV{t9+|ECnQT&O6vud^8T0wz<{P)us!isRYpfS(IUXrB$Ak%Liqs8I;eq> zRjFe^<~ucmAktR7IKDA68?s0iLuBOZJsmK$((<%``&tAqtgIy5US*eU;tQpxGAW)! ztV65jMGQttJ7vQI-g|+}mzzZqzgYFY`u%y|@NLpgyTaNQ0}Jd@(MB$^-0&Aq+p8Aq zY=y}?{0Mf>a}}v=4*TsNCeBb+Fu+RlS$pc+TmIysoxzku*B&`=8)1Ugf~N#;Jd$c3 zQ-^VgMFT;_RXILd@iOu2mTNF&0{t(}DLzIv^_NE{H8g&sM4Wtl(m=e~FhT%(I;G$i z8jBH1&2`v2=0pyaA9C0N%8E@9*=#O_)}>H|9}AGo(CevFpWzB z*{u-VXExAuL%zD2TZl5EI-lT3WriU-oiAMWhhca2sjWQHk;6sIsYboK&OB zHB^{XJEI|X9^U&iW2MxHfEXolIEQ(3B#^fx|8?{0ve!_|Zf?9YME-F;H>Uj$$nEH0 zkTEXhV$$99^86G>3lhs5ogGuPw*OE#NjYmo(jaJWdFg5>Eep>z7R0MDsb&{LG85V! z86D;PWb$57wWV|By~L<`9RCHL&3E$T!vN|a0QjtG%a}X4XiOEhVH-;$<)3+S|7PwW zCXm){&dYfmBjVcq4xE=mi|(9J5^vah0rFHGCy#f#{fdPj9k|l&twb|F@g04VN|^Fv zDHnY4b1q8@Ct6Gm?i_Q) zvtRjsx_jR-{l1~`b;Zo{1xIM(#7SH0>wow8yPu?NcSK&&xQj*mSmdpKV`)bpi#+P9 zm?77DL4?u!N}2Ac_YTJ3 zBXskvrKRQC{t5S5uBy*HzsX{A&NXZeOOi0?bS9h(*n8%A=sC0e@Ia%br3F`PFydSa zkJ|mjSR5_-uuakxF7ilS+ue0usZAQTb#K0NbN2Vm%=?Cf7z#nGm@2Br7o|7ZIJcfa zZ5RNw8u?JroERAxKdhCOl)&`bP0||wdc70+oW7Jm(bZyvjpj&ecEXma^rODMey6KD zQYtyt(P}yaK7RGn{w0q)1IXk9QqtYJk1Tx^+0{}YVgdqJOQZT~B~$kJlcHRr{>?6_ zw(*X%@#DK?Mio#hapAM@7Dwpd*U3reA0~Yqw#9Mq#c1;7%uH ztgJGyy<8I#lk)l7)3d2a$E2b}9}%RtAv{Hlg^!7eIX5;w?#G-q{8)8@N_VXEAArkS zaC`!ABg|$3)d{>Y8=Lu2n9n70R%9oZ$WZw_A4ZrZS5Mh9=m-S z=LW%mGn)yZ0Gg|4NqgLgTAw-nAw@%?)37Rxg6d(lqw^;7SvibF63#K16 z@+h8sKos^wSNLUzdH#H_dYoo*CQIxgHBa`$dVwgH_O$S+ZfgTJx)2*S+29`#Tsbhi z;bqEtNrN*kOHKp11uvWRu!FaNO@6e@j9x@ID>+eR5kn@c3i=8n=q5XH9{uPTd$jI4 z9aSl`AUhV|90ZF+xE%+g{QabiSN}8a)n|#PwFfD%WA&1aUzCs96o!BYBbLquU$d>K za;2?QG;|Y7{}12G(B%XYzix{FFAjqjRb2Xze`p{)QC zT3DB9!%vH|EZ}+lFZ+GFzcQH{lf%)1(IHULjgr%d65yU?!KX~R!h>C4~2Upi&= zr3S1cBitNYDLRvEfk4`n>oe&J1J(}SmprHO@qE&+F#a<}k&Y86YE+`p1;IKxO2fm# z{3Sb^g{fbpsH#LJkQnO-o?`XJ|5!Ne>FVlA`ekwUjt<#Lc8~mttC;t>=objQVO!%& z8(uqMC$2U%F#g#i8Igbqq+#o>qxQ*u+t}F1{cc#dgSwbL!Rniu@AKr|wSmTsI%_4P zVx9e=7z!c(-KwTF*cy3Ef6Y6Tu2kvf`9ld}Kbz;%X7DZthTh&a^Kq^5wANM&7>!;LpyE7M@L>HAM3a^TjMY8=NueRO9Yeg`-7gQo96r!b z8Z*x8P9e^g@34Sco2IJuVYPl=Ywr8Idz|kF`iFDzAigh+5 zE!Cer$6f&;(8SE)B7`m%;y1jb0g<)(v$eHF;=6WI3gtuK;xgvR=7+Owe{#zd`T+AR zONNK>zKkReb9&O!c|5$G3T*g~D8I-`Uia*1P{4z63wXi&S*%zmGNnQ+f8X<|c32~u ziWy7^8qljN2_8|=JKL+zSJ~S>!zd`t<9SO@3ufchk$BS|`#ZWIKI8nhr$d862qs3? z7dcc`w)S0!+#yAW>>sjW=bh-Y$hVQ!iwRrj#8cCd51ot8|F(|FO6E${IIXl+&-}Z( zr-Z3FlIAF)x%5yB8_sCti004f;s=vt*XhRwK*I`aaLP=Ib8hSEBWAXIFa^;G`-{~%LqwfLc{jvT zQQu|KiKTddYygOt22V56LQ|EtwSQ123Lb9u{aT5NMMi}NVYWK~^@`b2O6TLc84ONmFjq&Zsj zvkz4IMRtMovp?Sizh!YJ?H045$>DpxZ*_x7zkao21q4j)-sf19#ZJK{^#1qou9k1(_Sem2-* zEY5uspHPbV97P_3f}Sad8#Xz|%MMI{h$ipvpNO?rrY-WJIynzEVrL`qG6R#=scFw0 zfi%t1Z$Ato8z1gDrS3$(voKO20?I$ZX}OESe0jBAye33ur#@TC>0_ez5jXx#nlxpk z#+*8cAPgBsy&|=Ar1NhZJjsRX(9CoV55N3-Fq`;S*nPdL+wQji`f=<^ffg77YXH8( zr^oqIA2Aq@ofZ*9zOzf4>bd2V(Sf$*2(#r#v(Eb?9c%lE>$moNTkhCt5`VdSe|vbE zxU{d@u@%4gexO;#BmQ3ex`x*#F~UYvk6P-oi2Ci-B+BPZ!4J`}+x5Um);-K#Kus)O z8Po|sri%IBzexR(%)Pa`bOw28vx7jts9&aEjpYmRYS3RhzK4a;qV?O_+D=#LAJl7Z z_cEa0*fnx~=!Y;T(N+C%Bt=I37js89=Yd0NnZr`x6=_F<$LaS+=xqlVh0uox|LpYi z2*hB;`d}asU_=G&g?v9Uw-|pQvL(!?dOU2yKl$ynP!wi|(K5|jv!1nfF2r}iQr_@8 zO^Y(Ot#HyV;v2Ix3&n~j^Y??CGr#rah3(Hi&kwFdK~zlP`<&GByBlSiYVoFV#e#3a zf}`*F$81w&Hf)Eg-Z=6<+^C2Yg6@cca^Nx4JfkWLMF1a+&&$f~2Gb?Bw(oLN2`@W5 zqfx?83p61j><_*3u`Hr5mD!iNcN+w~M%8KVO?OCkoY8w}9h9ycu>)|Av?WDjqrzL> zp{`%9|3)!MQ7wk}`@`l+OG{5EX-w}Q!FnX+Eclp)C}l?!6&mL&#ex)gbx>gH&_Iq( zr=^KvR>5-l0wmsUsiil?f8%+-p5IcY4Euqzc=?Y9QA)UiCL`kr|FX5LtPJ9|H<7Sr zFPKRY!y8-miiD`x-2EYKYX3uf){wL9JK17a0)lY=I-{x&q!bkQ<;j~g5#MU3ni?Pc zypER19zTPlS?wn-e(p)$%}Ak69Q{XC6z>b(m3z6^#oyhjYKPN!+;uN_+?Ce0Ka7

    wdh>7{Ak%lcy3KTL~j(A1b!yH%FT~Ryz zA8&j*{14|N?bujTRNHqs5Cfb-#e`7~TbZ*u_qtayn2#MP#Hvq*f)pwy7kPO<-oUej z-A|h`M{OiiRF&3fHitZad-~+g%*|cTeoYX7X#ZpPm&n%SCO*HldkGo4MiPC%#5iiX zdpa1J{_3Z+C=OxfAqmkxi2>B;M<36A+RNax{jv;*7%%S`H^r#UDshs`E)7IbsmrAE z_V)Hef4Y>Xu~PB$e)WREz3-}c2`qnZ-5%vsG6c7!Wue71SJ-_|$RWn4JC^c8zewLw zS&^0y#_Wrf-?N|xq?`mZoA}+x({R=a!Ly=(BJtUzq1H}IOG_p;mFS(=%zF>@yV`QQwq0 z1X~rCkhof)J-v|4yEw6d5=v)MOkp8P2uQej)f)KHB@IbN#!-SFq76uL++BMwu+nmS z%U(Y7@ADUEnq`|Qw@VQrCT3LA>xzaWS<&$Xu-&wT{KPBj?5Qm!uYBFPo5DL=#JufaUW?xK!xxD)v$~jZ% zF{q{%^`>Zg{|MZuUD(FTqE8BVa_pmzI>pV*U#D$KI}_Cv34hL!i}nCzs+i*AOK*Z4ImYc6TNZ?bXUA* z@L$JaE7r;pM{Vyl8K=ei5&L(`ZGi*dnf459@kloqJ+T&1pG}$sw)+lK14#|s&rurZ zuT@3VlRr|DkdWfzfQx>aIST4E<#h-Fy#2cQ_y%_;?*tFHU;n-e2Eg}GgYR=OHV&Jy zNduyJ>D2NQC|BD=)g%U6L;FC=dKN!w14{c9u^AsqUtJqlhwA?D(Y3W7P-e?4@M}lF z2X881SxpNUIW{OD02k=vZX}|02=gfOmdQF>qCd!x{j2m@QZAvu6WQ3a+w4v_Z{Gbh z;3yg}OHNWeFrTNXYM3OeKlCd7zh{66x?;!TpMR1Meydg#e}TG7AENA0K}pw>Grx{( zyP{GKlrgqT0N~mYK$K4Rimq6vOo%^YL~PXNfLxYOTFcxfY1HN#8|(Sc#`>BNCO}yn z^i6=QG%p_hwp+{Y-SBoP2?>c8+st>g2&S*cwzh8KT|`>6J!+`YLOVS6?;jzj<@C2NixmHwm0kwqFeQv zJ2NZm!J8HlD$c#HF|F6bQ~y>hxH~XVDFk;--$;u+8it@Liwz#foKRdU4zLw+UcDq? za8NWs59+Ens|=+v4Cvillmi47P=Y$(8#js zjqYAte^_p=r7M0Y3=RE70g^4FfKg28;x6wRnT+h!Iimx0W;Y8vyS@C{+S<;+ZP#%I zGbC>ahy^8OSDU$myL{!WOvX+lUo*P@ZHZ?BXHmu`woBN&*p&Jc{@k+ z1O^5^`i1uRWf&j7?N9e>U%>!&Q9&$+!CGweOLl{|b4HXjY{R5@goQn&xB?_o={l-h zs0f32%{TtV7ecbCQrW5+sdsnK%d~rH*P;iRitTZzCp(Y@UN``3W$YiFY7HL1!^Jyz za~}TfCe>@i$lZ6eXsW7Z1-#53?isTfTt2!ZR!XZH63KFi#`0&5@8XmiUzdTax+h5` z#<|=af9}Fd3xJ0f8yiO|pzC>{?@v_NoQw<%e%gQhcy_K|A%GuduIO-N?z0>EYh*EJ ze(%$&tY~)5;O<2=aa8CoMrcpewC=RhQmF{2Xa2wZ>td3XhfAdf6SIj+)f7BUK}A7R K{=2MM(EkBw&5cF? literal 0 HcmV?d00001 diff --git a/packages/www/public/styles/global.css b/packages/www/public/styles/global.css new file mode 100644 index 0000000..fd2c15d --- /dev/null +++ b/packages/www/public/styles/global.css @@ -0,0 +1,452 @@ +@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap'); + +/* Default Theme +---------------------------------*/ +:root { + --primary: #1474FC !important; + --secondary: #F43980 !important; + --black: #000000 !important; + --white: #FFFFFF !important; + --info: #1474FC !important; + --error: #DC3545 !important; + --warning: #FF7B07 !important; + --success: #28A745 !important; + --muted: #666666 !important; + --bg0: #EFEFEF !important; + --bg1: #CFCFCF !important; + --bg2: #AFAFAF !important; + --bg3: #BABABA !important; + --bg4: #9F9F9F !important; + --bd0: #EFEFEF !important; + --bd1: #CFCFCF !important; + --bd2: #AFAFAF !important; + --bd3: #BABABA !important; + --bd4: #9F9F9F !important; + --bgi: #333333 !important; + --tx0: #000000 !important; + --tx1: #333333 !important; + --txi: #CFCFCF !important; + /* This fixes FOUC */ + display: none; +} + +.dark { + --muted: #999999 !important; + --bg0: #121212 !important; + --bg1: #222222 !important; + --bg2: #323232 !important; + --bg3: #424242 !important; + --bg4: #525252 !important; + --bd0: #121212 !important; + --bd1: #222222 !important; + --bd2: #323232 !important; + --bd3: #424242 !important; + --bd4: #525252 !important; + --bgi: #DBDBDB !important; + --tx0: #FFFFFF !important; + --tx1: #CFCFCF !important; + --txi: #222222 !important; +} + +/* Reset (normalize.css) +---------------------------------*/ + +html, body, #root { + font-family: "Open Sans", Arial, sans-serif; + font-size: 14px; + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; + position: relative; + width: 100%; +} + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +2. [UnoCSS]: allow to override the default border color with css var `--un-default-border-color` +*/ + +*, +::before, +::after { + box-sizing: border-box; /* 1 */ + border-width: 0; /* 2 */ + border-style: solid; /* 2 */ + border-color: var(--un-default-border-color, #e5e7eb); /* 2 */ +} + +::before, +::after { + --un-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS. +*/ + +html, +:host { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -moz-tab-size: 4; /* 3 */ + tab-size: 4; /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ + font-feature-settings: normal; /* 5 */ + font-variation-settings: normal; /* 6 */ + -webkit-tap-highlight-color: transparent; /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; /* 1 */ + line-height: inherit; /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ + font-feature-settings: normal; /* 2 */ + font-variation-settings: normal; /* 3 */ + font-size: 1em; /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ + font-size: 100%; /* 1 */ + font-weight: inherit; /* 1 */ + line-height: inherit; /* 1 */ + color: inherit; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 1 */ + background-color: transparent; /* 2 */ + background-image: none; /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::placeholder, +textarea::placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* +Make elements with the HTML hidden attribute stay hidden by default. +*/ + +[hidden]:where(:not([hidden="until-found"])) { + display: none; +} \ No newline at end of file diff --git a/packages/www/public/v1.html b/packages/www/public/v1.html new file mode 100644 index 0000000..4d03027 --- /dev/null +++ b/packages/www/public/v1.html @@ -0,0 +1,461 @@ + + + + + + StackPress - Open Source on the Edge of Technology + + + + + + + + + + + + + + + + + +

    + StackPress icon +
    + StackPress text +
    Foundation
    +
    + + +
    +
    +
    + >  We are building an open source stack on the edge of technology. +
    +
    +
    + incept icon +

    Stackpress

    + + + + +
    +
    +

    + A full stack content management framework. Build apps faster. Deploy anywhere. +

    +
      +
    • Build apps in days, not months.
    • +
    • MySQL, PostGreSQL, SQLite, Neon, CockroachDB, Supabase supported
    • +
    • Feature rich modern admin builder generated by Ideas
    • +
    • Deploy to AWS Lambda, GCP Functions, Azure Functions, Vercel, Netlify
    • +
    • Included template engine with native web components
    • +
    • Included user, auth, session, API, email plugins
    • +
    • Event driven and pluggable design
    • +
    + +
    +
    +
    +
    + ingest icon +

    Ingest

    + + + + +
    +
    +

    + An event driven serverless framework that can be deployed on + AWS, GCP, Azure, Netlify, and Vercel. A framework optimized + specifically for serverless functions. Smaller footprint, + and smaller builds. Publish and manage multiple containers + in one repo. Deploy only what was changed. +

    + +
    +
    +
    +
    + inquire icon +

    Inquire

    + + + + +
    +
    +

    + Super lightweight generic typed SQL query builder, SQL + dialects and composite engine. Schema builder, but no ORM. + Bring your own database library. +

    +
      +
    • Works with Node MySQL2
    • +
    • Works with Better SQLite3
    • +
    • Works with Node PostGres (pg)
    • +
    • Works with PGLite
    • +
    • Works with CockroachDB
    • +
    • Works with NeonDB
    • +
    • Works with Supabase
    • +
    + +
    +
    +
    +
    + reactus icon +

    Reactus

    + + + + +
    +
    +

    + A reactive React template engine for server and serverless + frameworks for next generation server focused web applications. +

    +
      +
    • Works with ExpressJS
    • +
    • Works with Fastify
    • +
    • Works with Hapi
    • +
    • Works with Koa
    • +
    • Works with NestJS
    • +
    + +
    +
    +
    +
    + idea icon +

    Idea

    + + + + +
    +
    +

    + Generates app code based on a schema file. Highly pluggable. + Bring your own generator. The purpose of this is to streamline + and automate major parts of software development that follow + a common pattern and therefore can be rendered. Some example + code that can be generated using .idea files including the + following. +

    +
      +
    • Database calls with any ORM
    • +
    • API, REST, or GraphQL endpoints
    • +
    • React components
    • +
    • TypeScript type safety
    • +
    • Admin pages
    • +
    • more than 70% of the code you produce
    • +
    + +
    +
    +
    + + + \ No newline at end of file diff --git a/packages/www/tsconfig.json b/packages/www/tsconfig.json new file mode 100644 index 0000000..bb8e4a8 --- /dev/null +++ b/packages/www/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "stackpress/tsconfig/esm", + "compilerOptions": { + "module": "nodenext", + "moduleResolution": "nodenext", + "outDir": ".build", + }, + "include": [ + "config/**/*.ts", + "plugins/**/*.ts", + "plugins/**/*.tsx", + "scripts/**/*.ts" +, "archives/api.tsx" ], + "exclude": [ "dist", "node_modules", "tests" ] +} \ No newline at end of file diff --git a/packages/www/uno.config.ts b/packages/www/uno.config.ts new file mode 100644 index 0000000..84edf95 --- /dev/null +++ b/packages/www/uno.config.ts @@ -0,0 +1,19 @@ +import { defineConfig, presetWind3 } from 'unocss'; +import presetStackpress from 'stackpress/unocss'; + +export default defineConfig({ + content: { + pipeline: { + include: [ + // include js/ts files + 'plugins/**/*.{js,ts,tsx}' + ], + // exclude files + // exclude: [] + }, + }, + presets: [ + presetWind3(), + presetStackpress() + ] +}) \ No newline at end of file diff --git a/packages/www/yarn.lock b/packages/www/yarn.lock new file mode 100644 index 0000000..0d654c8 --- /dev/null +++ b/packages/www/yarn.lock @@ -0,0 +1,3511 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@antfu/install-pkg@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-1.0.0.tgz#2912a150fc8b35ec912f583f90074ee98f64d66a" + integrity sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw== + dependencies: + package-manager-detector "^0.2.8" + tinyexec "^0.3.2" + +"@antfu/utils@^8.1.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-8.1.1.tgz#95b1947d292a9a2efffba2081796dcaa05ecedfb" + integrity sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ== + +"@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/compat-data@^7.26.8": + version "7.26.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367" + integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== + +"@babel/core@^7.23.9", "@babel/core@^7.26.10": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.10.tgz#5c876f83c8c4dcb233ee4b670c0606f2ac3000f9" + integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.10" + "@babel/helper-compilation-targets" "^7.26.5" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.10" + "@babel/parser" "^7.26.10" + "@babel/template" "^7.26.9" + "@babel/traverse" "^7.26.10" + "@babel/types" "^7.26.10" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.26.10", "@babel/generator@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.0.tgz#764382b5392e5b9aff93cadb190d0745866cbc2c" + integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw== + dependencies: + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.26.5": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz#de0c753b1cd1d9ab55d473c5a5cf7170f0a81880" + integrity sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA== + dependencies: + "@babel/compat-data" "^7.26.8" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-plugin-utils@^7.25.9": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" + integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helpers@^7.26.10": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.0.tgz#53d156098defa8243eab0f32fa17589075a1b808" + integrity sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg== + dependencies: + "@babel/template" "^7.27.0" + "@babel/types" "^7.27.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.26.10", "@babel/parser@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.0.tgz#3d7d6ee268e41d2600091cbd4e145ffee85a44ec" + integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== + dependencies: + "@babel/types" "^7.27.0" + +"@babel/plugin-transform-react-jsx-self@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz#c0b6cae9c1b73967f7f9eb2fca9536ba2fad2858" + integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-react-jsx-source@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz#4c6b8daa520b5f155b5fb55547d7c9fa91417503" + integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/runtime@^7.3.1": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762" + integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.26.9", "@babel/template@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4" + integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + +"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.0.tgz#11d7e644779e166c0442f9a07274d02cd91d4a70" + integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.27.0" + "@babel/parser" "^7.27.0" + "@babel/template" "^7.27.0" + "@babel/types" "^7.27.0" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.0.tgz#ef9acb6b06c3173f6632d993ecb6d4ae470b4559" + integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@codemirror/autocomplete@^6.0.0": + version "6.18.6" + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz#de26e864a1ec8192a1b241eb86addbb612964ddb" + integrity sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + +"@codemirror/commands@^6.0.0": + version "6.8.1" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.1.tgz#639f5559d2f33f2582a2429c58cb0c1b925c7a30" + integrity sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.4.0" + "@codemirror/view" "^6.27.0" + "@lezer/common" "^1.1.0" + +"@codemirror/language@^6.0.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.11.0.tgz#5ae90972601497f4575f30811519d720bf7232c9" + integrity sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.23.0" + "@lezer/common" "^1.1.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + style-mod "^4.0.0" + +"@codemirror/lint@^6.0.0": + version "6.8.5" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.5.tgz#9edaa808e764e28e07665b015951934c8ec3a418" + integrity sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.35.0" + crelt "^1.0.5" + +"@codemirror/search@^6.0.0": + version "6.5.10" + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.10.tgz#7367bfc88094d078b91c752bc74140fb565b55ee" + integrity sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + +"@codemirror/state@^6.0.0", "@codemirror/state@^6.4.0", "@codemirror/state@^6.5.0": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.5.2.tgz#8eca3a64212a83367dc85475b7d78d5c9b7076c6" + integrity sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA== + dependencies: + "@marijn/find-cluster-break" "^1.0.0" + +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0": + version "6.36.5" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.36.5.tgz#bb99b971322b9a3f8c7013f0ef6c4a511c0d750a" + integrity sha512-cd+FZEUlu3GQCYnguYm3EkhJ8KJVisqqUsCOKedBoAt/d9c76JUUap6U0UrpElln5k6VyrEOYliMuDAKIeDQLg== + dependencies: + "@codemirror/state" "^6.5.0" + style-mod "^4.1.0" + w3c-keyname "^2.2.4" + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@esbuild/aix-ppc64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz#014180d9a149cffd95aaeead37179433f5ea5437" + integrity sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ== + +"@esbuild/android-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz#649e47e04ddb24a27dc05c395724bc5f4c55cbfe" + integrity sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ== + +"@esbuild/android-arm@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.3.tgz#8a0f719c8dc28a4a6567ef7328c36ea85f568ff4" + integrity sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A== + +"@esbuild/android-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.3.tgz#e2ab182d1fd06da9bef0784a13c28a7602d78009" + integrity sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ== + +"@esbuild/darwin-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz#c7f3166fcece4d158a73dcfe71b2672ca0b1668b" + integrity sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w== + +"@esbuild/darwin-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz#d8c5342ec1a4bf4b1915643dfe031ba4b173a87a" + integrity sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A== + +"@esbuild/freebsd-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz#9f7d789e2eb7747d4868817417cc968ffa84f35b" + integrity sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw== + +"@esbuild/freebsd-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz#8ad35c51d084184a8e9e76bb4356e95350a64709" + integrity sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q== + +"@esbuild/linux-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz#3af0da3d9186092a9edd4e28fa342f57d9e3cd30" + integrity sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A== + +"@esbuild/linux-arm@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz#e91cafa95e4474b3ae3d54da12e006b782e57225" + integrity sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ== + +"@esbuild/linux-ia32@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz#81025732d85b68ee510161b94acdf7e3007ea177" + integrity sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw== + +"@esbuild/linux-loong64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz#3c744e4c8d5e1148cbe60a71a11b58ed8ee5deb8" + integrity sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g== + +"@esbuild/linux-mips64el@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz#1dfe2a5d63702db9034cc6b10b3087cc0424ec26" + integrity sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag== + +"@esbuild/linux-ppc64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz#2e85d9764c04a1ebb346dc0813ea05952c9a5c56" + integrity sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg== + +"@esbuild/linux-riscv64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz#a9ea3334556b09f85ccbfead58c803d305092415" + integrity sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA== + +"@esbuild/linux-s390x@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz#f6a7cb67969222b200974de58f105dfe8e99448d" + integrity sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ== + +"@esbuild/linux-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz#a237d3578ecdd184a3066b1f425e314ade0f8033" + integrity sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA== + +"@esbuild/netbsd-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz#4c15c68d8149614ddb6a56f9c85ae62ccca08259" + integrity sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA== + +"@esbuild/netbsd-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz#12f6856f8c54c2d7d0a8a64a9711c01a743878d5" + integrity sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g== + +"@esbuild/openbsd-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz#ca078dad4a34df192c60233b058db2ca3d94bc5c" + integrity sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ== + +"@esbuild/openbsd-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz#c9178adb60e140e03a881d0791248489c79f95b2" + integrity sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w== + +"@esbuild/sunos-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz#03765eb6d4214ff27e5230af779e80790d1ee09f" + integrity sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA== + +"@esbuild/win32-arm64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz#f1c867bd1730a9b8dfc461785ec6462e349411ea" + integrity sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ== + +"@esbuild/win32-ia32@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz#77491f59ef6c9ddf41df70670d5678beb3acc322" + integrity sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew== + +"@esbuild/win32-x64@0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz#b17a2171f9074df9e91bfb07ef99a892ac06412a" + integrity sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg== + +"@iconify/types@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@iconify/types/-/types-2.0.0.tgz#ab0e9ea681d6c8a1214f30cd741fe3a20cc57f57" + integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg== + +"@iconify/utils@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@iconify/utils/-/utils-2.3.0.tgz#1bbbf8c477ebe9a7cacaea78b1b7e8937f9cbfba" + integrity sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA== + dependencies: + "@antfu/install-pkg" "^1.0.0" + "@antfu/utils" "^8.1.0" + "@iconify/types" "^2.0.0" + debug "^4.4.0" + globals "^15.14.0" + kolorist "^1.8.0" + local-pkg "^1.0.0" + mlly "^1.7.4" + +"@inquirer/checkbox@^4.0.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-4.1.5.tgz#891bb32ca98eb6ee2889f71d79722705e2241161" + integrity sha512-swPczVU+at65xa5uPfNP9u3qx/alNwiaykiI/ExpsmMSQW55trmZcwhYWzw/7fj+n6Q8z1eENvR7vFfq9oPSAQ== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/figures" "^1.0.11" + "@inquirer/type" "^3.0.6" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/confirm@^5.0.2": + version "5.1.9" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.9.tgz#c858b6a3decb458241ec36ca9a9117477338076a" + integrity sha512-NgQCnHqFTjF7Ys2fsqK2WtnA8X1kHyInyG+nMIuHowVTIgIuS10T4AznI/PvbqSpJqjCUqNBlKGh1v3bwLFL4w== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + +"@inquirer/core@^10.1.10": + version "10.1.10" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.10.tgz#222a374e3768536a1eb0adf7516c436d5f4a291d" + integrity sha512-roDaKeY1PYY0aCqhRmXihrHjoSW2A00pV3Ke5fTpMCkzcGF64R8e0lw3dK+eLEHwS4vB5RnW1wuQmvzoRul8Mw== + dependencies: + "@inquirer/figures" "^1.0.11" + "@inquirer/type" "^3.0.6" + ansi-escapes "^4.3.2" + cli-width "^4.1.0" + mute-stream "^2.0.0" + signal-exit "^4.1.0" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/editor@^4.1.0": + version "4.2.10" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-4.2.10.tgz#45e399313ee857857248bd539b8e832aa0fb60b3" + integrity sha512-5GVWJ+qeI6BzR6TIInLP9SXhWCEcvgFQYmcRG6d6RIlhFjM5TyG18paTGBgRYyEouvCmzeco47x9zX9tQEofkw== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + external-editor "^3.1.0" + +"@inquirer/expand@^4.0.2": + version "4.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-4.0.12.tgz#1e4554f509a435f966e2b91395a503d77df35c17" + integrity sha512-jV8QoZE1fC0vPe6TnsOfig+qwu7Iza1pkXoUJ3SroRagrt2hxiL+RbM432YAihNR7m7XnU0HWl/WQ35RIGmXHw== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.11.tgz#4744e6db95288fea1dead779554859710a959a21" + integrity sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw== + +"@inquirer/input@^4.0.2": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-4.1.9.tgz#e93888d48c89bdb7f8e10bdd94572b636375749a" + integrity sha512-mshNG24Ij5KqsQtOZMgj5TwEjIf+F2HOESk6bjMwGWgcH5UBe8UoljwzNFHqdMbGYbgAf6v2wU/X9CAdKJzgOA== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + +"@inquirer/number@^3.0.2": + version "3.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-3.0.12.tgz#e027d27425ee2a81a7ccb9fdc750129edd291067" + integrity sha512-7HRFHxbPCA4e4jMxTQglHJwP+v/kpFsCf2szzfBHy98Wlc3L08HL76UDiA87TOdX5fwj2HMOLWqRWv9Pnn+Z5Q== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + +"@inquirer/password@^4.0.2": + version "4.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-4.0.12.tgz#f1a663bc5cf88699643cf6c83626a1ae77e580b5" + integrity sha512-FlOB0zvuELPEbnBYiPaOdJIaDzb2PmJ7ghi/SVwIHDDSQ2K4opGBkF+5kXOg6ucrtSUQdLhVVY5tycH0j0l+0g== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + ansi-escapes "^4.3.2" + +"@inquirer/prompts@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-7.1.0.tgz#a55ee589c0eed0ca2ee0fbc7fc63f42f4c31a24e" + integrity sha512-5U/XiVRH2pp1X6gpNAjWOglMf38/Ys522ncEHIKT1voRUvSj/DQnR22OVxHnwu5S+rCFaUiPQ57JOtMFQayqYA== + dependencies: + "@inquirer/checkbox" "^4.0.2" + "@inquirer/confirm" "^5.0.2" + "@inquirer/editor" "^4.1.0" + "@inquirer/expand" "^4.0.2" + "@inquirer/input" "^4.0.2" + "@inquirer/number" "^3.0.2" + "@inquirer/password" "^4.0.2" + "@inquirer/rawlist" "^4.0.2" + "@inquirer/search" "^3.0.2" + "@inquirer/select" "^4.0.2" + +"@inquirer/rawlist@^4.0.2": + version "4.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-4.0.12.tgz#97b9540199590d2b197836ba3a5658addd406479" + integrity sha512-wNPJZy8Oc7RyGISPxp9/MpTOqX8lr0r+lCCWm7hQra+MDtYRgINv1hxw7R+vKP71Bu/3LszabxOodfV/uTfsaA== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/type" "^3.0.6" + yoctocolors-cjs "^2.1.2" + +"@inquirer/search@^3.0.2": + version "3.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-3.0.12.tgz#e86f91ea598ccb39caf9a17762b839a9b950e16d" + integrity sha512-H/kDJA3kNlnNIjB8YsaXoQI0Qccgf0Na14K1h8ExWhNmUg2E941dyFPrZeugihEa9AZNW5NdsD/NcvUME83OPQ== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/figures" "^1.0.11" + "@inquirer/type" "^3.0.6" + yoctocolors-cjs "^2.1.2" + +"@inquirer/select@^4.0.2": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-4.1.1.tgz#0496b913514149171cf6351f0acb6d4243a39fdf" + integrity sha512-IUXzzTKVdiVNMA+2yUvPxWsSgOG4kfX93jOM4Zb5FgujeInotv5SPIJVeXQ+fO4xu7tW8VowFhdG5JRmmCyQ1Q== + dependencies: + "@inquirer/core" "^10.1.10" + "@inquirer/figures" "^1.0.11" + "@inquirer/type" "^3.0.6" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/type@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.6.tgz#2500e435fc2014c5250eec3279f42b70b64089bd" + integrity sha512-/mKVCtVpyBu3IDarv0G+59KC4stsD5mDsGpYh+GKs1NZT88Jh52+cuoA1AtLk2Q0r/quNl+1cSUyLRHBFeD0XA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@lezer/common@^1.0.0", "@lezer/common@^1.1.0": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.3.tgz#138fcddab157d83da557554851017c6c1e5667fd" + integrity sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA== + +"@lezer/highlight@^1.0.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.1.tgz#596fa8f9aeb58a608be0a563e960c373cbf23f8b" + integrity sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/lr@^1.0.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.2.tgz#931ea3dea8e9de84e90781001dae30dea9ff1727" + integrity sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA== + dependencies: + "@lezer/common" "^1.0.0" + +"@marijn/find-cluster-break@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8" + integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g== + +"@noble/hashes@^1.1.5": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@paralleldrive/cuid2@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz#7f91364d53b89e2c9cb9e02e8dd0f129e834455f" + integrity sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA== + dependencies: + "@noble/hashes" "^1.1.5" + +"@peculiar/asn1-schema@^2.3.13", "@peculiar/asn1-schema@^2.3.8": + version "2.3.15" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz#e926bfdeed51945a06f38be703499e7d8341a5d3" + integrity sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w== + dependencies: + asn1js "^3.0.5" + pvtsutils "^1.3.6" + tslib "^2.8.1" + +"@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + +"@peculiar/webcrypto@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz#9e57174c02c1291051c553600347e12b81469e10" + integrity sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg== + dependencies: + "@peculiar/asn1-schema" "^2.3.8" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.3.5" + tslib "^2.6.2" + webcrypto-core "^1.8.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.29" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.29.tgz#5a40109a1ab5f84d6fd8fc928b19f367cbe7e7b1" + integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww== + +"@rollup/rollup-android-arm-eabi@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3" + integrity sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg== + +"@rollup/rollup-android-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz#9b5e130ecc32a5fc1e96c09ff371743ee71a62d3" + integrity sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w== + +"@rollup/rollup-darwin-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz#ef439182c739b20b3c4398cfc03e3c1249ac8903" + integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ== + +"@rollup/rollup-darwin-x64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz#d7380c1531ab0420ca3be16f17018ef72dd3d504" + integrity sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA== + +"@rollup/rollup-freebsd-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz#cbcbd7248823c6b430ce543c59906dd3c6df0936" + integrity sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg== + +"@rollup/rollup-freebsd-x64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz#96bf6ff875bab5219c3472c95fa6eb992586a93b" + integrity sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw== + +"@rollup/rollup-linux-arm-gnueabihf@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz#d80cd62ce6d40f8e611008d8dbf03b5e6bbf009c" + integrity sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA== + +"@rollup/rollup-linux-arm-musleabihf@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz#75440cfc1e8d0f87a239b4c31dfeaf4719b656b7" + integrity sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg== + +"@rollup/rollup-linux-arm64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz#ac527485ecbb619247fb08253ec8c551a0712e7c" + integrity sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg== + +"@rollup/rollup-linux-arm64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz#74d2b5cb11cf714cd7d1682e7c8b39140e908552" + integrity sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ== + +"@rollup/rollup-linux-loongarch64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz#a0a310e51da0b5fea0e944b0abd4be899819aef6" + integrity sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg== + +"@rollup/rollup-linux-powerpc64le-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz#4077e2862b0ac9f61916d6b474d988171bd43b83" + integrity sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw== + +"@rollup/rollup-linux-riscv64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz#5812a1a7a2f9581cbe12597307cc7ba3321cf2f3" + integrity sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA== + +"@rollup/rollup-linux-riscv64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz#973aaaf4adef4531375c36616de4e01647f90039" + integrity sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ== + +"@rollup/rollup-linux-s390x-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz#9bad59e907ba5bfcf3e9dbd0247dfe583112f70b" + integrity sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw== + +"@rollup/rollup-linux-x64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz#68b045a720bd9b4d905f462b997590c2190a6de0" + integrity sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ== + +"@rollup/rollup-linux-x64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz#8e703e2c2ad19ba7b2cb3d8c3a4ad11d4ee3a282" + integrity sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw== + +"@rollup/rollup-win32-arm64-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz#c5bee19fa670ff5da5f066be6a58b4568e9c650b" + integrity sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ== + +"@rollup/rollup-win32-ia32-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz#846e02c17044bd922f6f483a3b4d36aac6e2b921" + integrity sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA== + +"@rollup/rollup-win32-x64-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76" + integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ== + +"@stackpress/idea-parser@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/idea-parser/-/idea-parser-0.6.1.tgz#0591e353e7403851f47356f835542e13ff490565" + integrity sha512-djf3JY4BOHBqT+VAMvLDHpT55thbdxnM3IHTuHr77JiJIsJqzue4IaKEQeWSDwEvHD2DPhAbT16Q/k0w91lzzw== + dependencies: + "@stackpress/lib" "0.6.1" + +"@stackpress/idea-transformer@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/idea-transformer/-/idea-transformer-0.6.1.tgz#76daa1380036f9a3b7e80546ff567196d2b16c15" + integrity sha512-FGKlShUsoXZTi5IwI6sRR894jviGI0wNkKMduA5BuSZpPM2PfZSvH4F2vmUD0bKokxDVRUsm7wYFPnQRLgYMzQ== + dependencies: + "@stackpress/idea-parser" "0.6.1" + "@stackpress/lib" "0.6.1" + +"@stackpress/ingest@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/ingest/-/ingest-0.6.1.tgz#20ba2a33a1d4a1573ed49774f887db2b0086fb35" + integrity sha512-i69p2fDHhEDQkWNfBiNp5pf74Gp0MQz6PkgrH0Nzf2I6L2d/5e25gQNeAAt9Qet9FPk0K0MlSgg46iMpXtQ4mQ== + dependencies: + "@stackpress/lib" "0.6.1" + "@whatwg-node/server" "0.6.7" + +"@stackpress/inquire@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/inquire/-/inquire-0.6.1.tgz#ab8c5842fdcbdce6cd7c5d8bdefc207511f36312" + integrity sha512-SjbNrRuVVwNboMO5Bv6swZpK49z41sB1U2iYKKO2RrsLZPMdvpEZtjL7JxIDW37fm1Gh4PXkVTuYgvZ5qma2zQ== + dependencies: + "@stackpress/lib" "0.6.1" + +"@stackpress/lib@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@stackpress/lib/-/lib-0.6.1.tgz#56b65e66daaeb1e4a2a67cb8d743cd784bc8ed14" + integrity sha512-wAbMqAkO+nHFXwy2/ze++RuKtMgidKTa/FyrEcTrz36nTfeKmj7+1iXfvjrimLHljitUy2LZ42DUBFnrvlUKgg== + dependencies: + "@inquirer/prompts" "7.1.0" + +"@ts-morph/common@~0.26.0": + version "0.26.1" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.26.1.tgz#a346188e59d2befe4c71f66a7d626d81b1abe2a8" + integrity sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA== + dependencies: + fast-glob "^3.3.2" + minimatch "^9.0.4" + path-browserify "^1.0.1" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.7.tgz#968cdc2366ec3da159f61166428ee40f370e56c2" + integrity sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng== + dependencies: + "@babel/types" "^7.20.7" + +"@types/chai@5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.1.tgz#85687a58b27eac736ec0e87e5cb98f21e57a0bb1" + integrity sha512-iu1JLYmGmITRzUgNiLMZD3WCoFzpYtueuyAgHTXqgwSRAMIlFTnZqG6/xenkpUGRJEzSfklUTI4GNSzks/dc0w== + dependencies: + "@types/deep-eql" "*" + +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + +"@types/estree@1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +"@types/hast@^2.0.0": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + +"@types/mocha@10.0.10": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== + +"@types/node@22.14.1": + version "22.14.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.1.tgz#53b54585cec81c21eee3697521e31312d6ca1e6f" + integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw== + dependencies: + undici-types "~6.21.0" + +"@types/react-dom@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.2.tgz#bd1fe3b8c28a3a2e942f85314dcfb71f531a242f" + integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw== + +"@types/react-syntax-highlighter@15.5.13": + version "15.5.13" + resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz#c5baf62a3219b3bf28d39cfea55d0a49a263d1f2" + integrity sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.2.tgz#11df86f66f188f212c90ecb537327ec68bfd593f" + integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw== + dependencies: + csstype "^3.0.2" + +"@types/unist@^2": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + +"@unocss/astro@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/astro/-/astro-66.0.0.tgz#6564ef14c9d7c1346769c222c6e525d7d8995c98" + integrity sha512-GBhXT6JPqXjDXoJZTXhySk83NgOt0UigChqrUUdG4x7Z+DVYkDBION8vZUJjw0OdIaxNQ4euGWu4GDsMF6gQQg== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/reset" "66.0.0" + "@unocss/vite" "66.0.0" + +"@unocss/cli@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/cli/-/cli-66.0.0.tgz#4cd4b6e14a6743354fe532f6dc390bab30e04e35" + integrity sha512-KVQiskoOjVkLVpNaG6WpLa4grPplrZROYZJVIUYSTqZyZRFNSvjttHcsCwpoWUEUdEombPtVZl8FrXePjY5IiQ== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/preset-uno" "66.0.0" + cac "^6.7.14" + chokidar "^3.6.0" + colorette "^2.0.20" + consola "^3.4.0" + magic-string "^0.30.17" + pathe "^2.0.3" + perfect-debounce "^1.0.0" + tinyglobby "^0.2.10" + unplugin-utils "^0.2.4" + +"@unocss/config@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/config/-/config-66.0.0.tgz#16ff6da705cd7b97813d62a887adbf354ee423c8" + integrity sha512-nFRGop/guBa4jLkrgXjaRDm5JPz4x3YpP10m5IQkHpHwlnHUVn1L9smyPl04ohYWhYn9ZcAHgR28Ih2jwta8hw== + dependencies: + "@unocss/core" "66.0.0" + unconfig "~7.0.0" + +"@unocss/core@66.0.0", "@unocss/core@^66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/core/-/core-66.0.0.tgz#2a316f4e0e17bd3f77788479401ca84eaf52e847" + integrity sha512-PdVbSMHNDDkr++9nkqzsZRAkaU84gxMTEgYbqI7dt2p1DXp/5tomVtmMsr2/whXGYKRiUc0xZ3p4Pzraz8TcXA== + +"@unocss/extractor-arbitrary-variants@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/extractor-arbitrary-variants/-/extractor-arbitrary-variants-66.0.0.tgz#8bd37b36cc4e568db809d7d460f65ff3f4830b30" + integrity sha512-vlkOIOuwBfaFBJcN6o7+obXjigjOlzVFN/jT6pG1WXbQDTRZ021jeF3i9INdb9D/0cQHSeDvNgi1TJ5oUxfiow== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/inspector@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/inspector/-/inspector-66.0.0.tgz#98d9e4bf83abb4a4b119eea89c464aef066439ec" + integrity sha512-mkIxieVm0kMOKw+E4ABpIerihYMdjgq9A92RD5h2+W/ebpxTEw5lTTK1xcMLiAlmOrVYMQKjpgPeu3vQmDyGZQ== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + colorette "^2.0.20" + gzip-size "^6.0.0" + sirv "^3.0.0" + vue-flow-layout "^0.1.1" + +"@unocss/postcss@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/postcss/-/postcss-66.0.0.tgz#686a74de9de91809d02ae715b60b1470d2705826" + integrity sha512-6bi+ujzh8I1PJwtmHX71LH8z/H9+vPxeYD4XgFihyU1k4Y6MVhjr7giGjLX4yP27IP+NsVyotD22V7by/dBVEA== + dependencies: + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + css-tree "^3.1.0" + postcss "^8.5.2" + tinyglobby "^0.2.10" + +"@unocss/preset-attributify@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-attributify/-/preset-attributify-66.0.0.tgz#e319503c7ffb5a482cafb09744d33424db97167e" + integrity sha512-eYsOgmcDoiIgGAepIwRX+DKGYxc/wm0r4JnDuZdz29AB+A6oY/FGHS1BVt4rq9ny4B5PofP4p6Rty+vwD9rigw== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/preset-icons@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-icons/-/preset-icons-66.0.0.tgz#97d9e9e110a343e2c5b6de37070019ac05de1221" + integrity sha512-6ObwTvEGuPBbKWRoMMiDioHtwwQTFI5oojFLJ32Y8tW6TdXvBLkO88d7qpgQxEjgVt4nJrqF1WEfR4niRgBm0Q== + dependencies: + "@iconify/utils" "^2.3.0" + "@unocss/core" "66.0.0" + ofetch "^1.4.1" + +"@unocss/preset-mini@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-mini/-/preset-mini-66.0.0.tgz#8b1b5ee36aaa8d1226ff34179622d4433a872130" + integrity sha512-d62eACnuKtR0dwCFOQXgvw5VLh5YSyK56xCzpHkh0j0GstgfDLfKTys0T/XVAAvdSvAy/8A8vhSNJ4PlIc9V2A== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/extractor-arbitrary-variants" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-tagify@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-tagify/-/preset-tagify-66.0.0.tgz#8629c466ffdcdf771e79d19cca92f8a4b13bfb3f" + integrity sha512-GGYGyWxaevh0jN0NoATVO1Qe7DFXM3ykLxchlXmG6/zy963pZxItg/njrKnxE9la4seCdxpFH7wQBa68imwwdA== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/preset-typography@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-typography/-/preset-typography-66.0.0.tgz#85c62a0fa57e538f23ab9f56e68a8ac3bc4ed116" + integrity sha512-apjckP5nPU5mtaHTCzz5u/dK9KJWwJ2kOFCVk0+a/KhUWmnqnzmjRYZlEuWxxr5QxTdCW+9cIoRDSA0lYZS5tg== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-uno@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-uno/-/preset-uno-66.0.0.tgz#37633290c6594de40a40fc158504fa22c02c6ab7" + integrity sha512-qgoZ/hzTI32bQvcyjcwvv1X/dbPlmQNehzgjUaL7QFT0q0/CN/SRpysfzoQ8DLl2se9T+YCOS9POx3KrpIiYSQ== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + +"@unocss/preset-web-fonts@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-web-fonts/-/preset-web-fonts-66.0.0.tgz#39c936ad69f6777df1077ffff40d6694cf9368e9" + integrity sha512-9MzfDc6AJILN4Kq7Z91FfFbizBOYgw3lJd2UwqIs3PDYWG5iH5Zv5zhx6jelZVqEW5uWcIARYEEg2m4stZO1ZA== + dependencies: + "@unocss/core" "66.0.0" + ofetch "^1.4.1" + +"@unocss/preset-wind3@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-wind3/-/preset-wind3-66.0.0.tgz#3f17da21cea683d75d4adefbd4f9c95172eeb1bb" + integrity sha512-WAGRmpi1sb2skvYn9DBQUvhfqrJ+VmQmn5ZGsT2ewvsk7HFCvVLAMzZeKrrTQepeNBRhg6HzFDDi8yg6yB5c9g== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/rule-utils" "66.0.0" + +"@unocss/preset-wind@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/preset-wind/-/preset-wind-66.0.0.tgz#eeb22cd66a32dc896c6263dc0eeb8be0c6c9b090" + integrity sha512-FtvGpHnGC7FiyKJavPnn5y9lsaoWRhXlujCqlT5Bw63kKhMNr0ogKySBpenUhJOhWhVM0OQXn2nZ3GZRxW2qpw== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + +"@unocss/reset@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/reset/-/reset-66.0.0.tgz#8e3301206ab315d3287fb133be6f03e60a3ebdd4" + integrity sha512-YLFz/5yT7mFJC8JSmIUA5+bS3CBCJbtztOw+8rWzjQr/BEVSGuihWUUpI2Df6VVxXIXxKanZR6mIl59yvf+GEA== + +"@unocss/rule-utils@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/rule-utils/-/rule-utils-66.0.0.tgz#5fd1c7bd2372e9f3724ed6858263a703a9ae064a" + integrity sha512-UJ51YHbwxYTGyj35ugsPlOT4gaa7tCbXdywZ3m5Nn0JgywwIqGmBFyiN9ZjHBHfJuDxmmPd6lxojoBscih/WMQ== + dependencies: + "@unocss/core" "^66.0.0" + magic-string "^0.30.17" + +"@unocss/transformer-attributify-jsx@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-attributify-jsx/-/transformer-attributify-jsx-66.0.0.tgz#f93168db7fd7efbccfa75cd3ea5f3457d1aee8eb" + integrity sha512-jS7szFXXC6RjTv9wo0NACskf618w981bkbyQ5izRO7Ha47sNpHhHDpaltnG7SR9qV4cCtGalOw4onVMHsRKwRg== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/transformer-compile-class@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-compile-class/-/transformer-compile-class-66.0.0.tgz#baa303da481e6df25d963436c4536479b620025b" + integrity sha512-ytUIE0nAcHRMACuTXkHp8auZ483DXrOZw99jk3FJ+aFjpD/pVSFmX14AWJ7bqPFObxb4SLFs6KhQma30ESC22A== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/transformer-directives@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-directives/-/transformer-directives-66.0.0.tgz#7cfff36c2b196937a54f107a76803aeb7236d0d8" + integrity sha512-utcg7m2Foi7uHrU5WHadNuJ0a3qWG8tZNkQMi+m0DQpX6KWfuDtDn0zDZ1X+z5lmiB3WGSJERRrsvZbj1q50Mw== + dependencies: + "@unocss/core" "66.0.0" + "@unocss/rule-utils" "66.0.0" + css-tree "^3.1.0" + +"@unocss/transformer-variant-group@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/transformer-variant-group/-/transformer-variant-group-66.0.0.tgz#255ae998dd75c379df6af09f0b9f10a5dc0a5ad1" + integrity sha512-1BLjNWtAnR1JAcQGw0TS+nGrVoB9aznzvVZRoTx23dtRr3btvgKPHb8LrD48eD/p8Dtw9j3WfuxMDKXKegKDLg== + dependencies: + "@unocss/core" "66.0.0" + +"@unocss/vite@66.0.0": + version "66.0.0" + resolved "https://registry.yarnpkg.com/@unocss/vite/-/vite-66.0.0.tgz#e0e4e50288d8b5ef6e53af85ae35149ce2a60b73" + integrity sha512-IVcPX8xL+2edyXKt4tp9yu5A6gcbPVCsspfcL0XgziCr01kS+4qSoZ90F3IUs3hXc/AyO5eCpRtGFMPLpOjXQg== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@unocss/config" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/inspector" "66.0.0" + chokidar "^3.6.0" + magic-string "^0.30.17" + tinyglobby "^0.2.10" + unplugin-utils "^0.2.4" + +"@vitejs/plugin-react@4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz#d7d1e9c9616d7536b0953637edfee7c6cbe2fe0f" + integrity sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w== + dependencies: + "@babel/core" "^7.26.10" + "@babel/plugin-transform-react-jsx-self" "^7.25.9" + "@babel/plugin-transform-react-jsx-source" "^7.25.9" + "@types/babel__core" "^7.20.5" + react-refresh "^0.17.0" + +"@whatwg-node/events@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.0.3.tgz#13a65dd4f5893f55280f766e29ae48074927acad" + integrity sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA== + +"@whatwg-node/fetch@^0.8.1": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.8.8.tgz#48c6ad0c6b7951a73e812f09dd22d75e9fa18cae" + integrity sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg== + dependencies: + "@peculiar/webcrypto" "^1.4.0" + "@whatwg-node/node-fetch" "^0.3.6" + busboy "^1.6.0" + urlpattern-polyfill "^8.0.0" + web-streams-polyfill "^3.2.1" + +"@whatwg-node/node-fetch@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz#e28816955f359916e2d830b68a64493124faa6d0" + integrity sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA== + dependencies: + "@whatwg-node/events" "^0.0.3" + busboy "^1.6.0" + fast-querystring "^1.1.1" + fast-url-parser "^1.1.3" + tslib "^2.3.1" + +"@whatwg-node/server@0.6.7": + version "0.6.7" + resolved "https://registry.yarnpkg.com/@whatwg-node/server/-/server-0.6.7.tgz#14f5d0aca49308759d64fc7faa3cbfc20162a1ee" + integrity sha512-M4zHWdJ6M1IdcxnZBdDmiUh1bHQ4gPYRxzkH0gh8Qf6MpWJmX6I/MNftqem3GNn+qn1y47qqlGSed7T7nzsRFw== + dependencies: + "@whatwg-node/fetch" "^0.8.1" + tslib "^2.3.1" + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.14.0, acorn@^8.4.1: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +append-transform@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" + integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== + dependencies: + default-require-extensions "^3.0.0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +asn1js@^3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.6.tgz#53e002ebe00c5f7fd77c1c047c3557d7c04dce25" + integrity sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.3" + tslib "^2.8.1" + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.24.0: + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +caching-transform@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" + integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== + dependencies: + hasha "^5.0.0" + make-dir "^3.0.0" + package-hash "^4.0.0" + write-file-atomic "^3.0.0" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001688: + version "1.0.30001715" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz#bd325a37ad366e3fe90827d74062807a34fbaeb2" + integrity sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw== + +chai@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.2.0.tgz#1358ee106763624114addf84ab02697e411c9c05" + integrity sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== + +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +code-block-writer@^13.0.3: + version "13.0.3" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-13.0.3.tgz#90f8a84763a5012da7af61319dd638655ae90b5b" + integrity sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg== + +codemirror@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29" + integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +consola@^3.4.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.2.tgz#5af110145397bb67afdab77013fdc34cae590ea7" + integrity sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA== + +convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +crelt@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + +cross-spawn@^7.0.0, cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-tree@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd" + integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w== + dependencies: + mdn-data "2.12.2" + source-map-js "^1.0.1" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.5, debug@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +default-require-extensions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.1.tgz#bfae00feeaeada68c2ae256c62540f60b80625bd" + integrity sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw== + dependencies: + strip-bom "^4.0.0" + +defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + +destr@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb" + integrity sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +dotenv-cli@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-8.0.0.tgz#cea1519f5a06c7372a1428fca4605fcf3d50e1cf" + integrity sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw== + dependencies: + cross-spawn "^7.0.6" + dotenv "^16.3.0" + dotenv-expand "^10.0.0" + minimist "^1.2.6" + +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + +dotenv@^16.3.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.5.0.tgz#092b49f25f808f020050051d1ff258e404c78692" + integrity sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg== + +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.5.73: + version "1.5.140" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz#91d9279fe72963f22c5784cc7f3461b5fed34786" + integrity sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +es6-error@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + +esbuild@^0.25.0, esbuild@~0.25.0: + version "0.25.3" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.3.tgz#371f7cb41283e5b2191a96047a7a89562965a285" + integrity sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.3" + "@esbuild/android-arm" "0.25.3" + "@esbuild/android-arm64" "0.25.3" + "@esbuild/android-x64" "0.25.3" + "@esbuild/darwin-arm64" "0.25.3" + "@esbuild/darwin-x64" "0.25.3" + "@esbuild/freebsd-arm64" "0.25.3" + "@esbuild/freebsd-x64" "0.25.3" + "@esbuild/linux-arm" "0.25.3" + "@esbuild/linux-arm64" "0.25.3" + "@esbuild/linux-ia32" "0.25.3" + "@esbuild/linux-loong64" "0.25.3" + "@esbuild/linux-mips64el" "0.25.3" + "@esbuild/linux-ppc64" "0.25.3" + "@esbuild/linux-riscv64" "0.25.3" + "@esbuild/linux-s390x" "0.25.3" + "@esbuild/linux-x64" "0.25.3" + "@esbuild/netbsd-arm64" "0.25.3" + "@esbuild/netbsd-x64" "0.25.3" + "@esbuild/openbsd-arm64" "0.25.3" + "@esbuild/openbsd-x64" "0.25.3" + "@esbuild/sunos-x64" "0.25.3" + "@esbuild/win32-arm64" "0.25.3" + "@esbuild/win32-ia32" "0.25.3" + "@esbuild/win32-x64" "0.25.3" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +exsolve@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.5.tgz#1f5b6b4fe82ad6b28a173ccb955a635d77859dcf" + integrity sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg== + +external-editor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-glob@3.3.3, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fast-querystring@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.2.tgz#a6d24937b4fc6f791b4ee31dcb6f53aeafb89f53" + integrity sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== + dependencies: + fast-decode-uri-component "^1.0.1" + +fast-url-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== + dependencies: + punycode "^1.3.2" + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + +fdir@^6.4.3, fdir@^6.4.4: + version "6.4.4" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9" + integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + +foreground-child@^3.1.0, foreground-child@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== + +fromentries@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" + integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== + +frui@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/frui/-/frui-0.1.8.tgz#b04f534f0b6b0f942054388031b8fc3b8418f144" + integrity sha512-gz09LCW8xTeN4eMHI+zYOm3yByWq+NNVZ9naL1G0mSaEj2po3pnQFK5EZzNq+gJDzDcBnf0/BNrRAJMG9xBKIA== + dependencies: + codemirror "6.0.1" + inputmask "5.0.9" + markdown-to-jsx "7.7.4" + moment "2.30.1" + react-syntax-highlighter "15.6.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-tsconfig@^4.7.5: + version "4.10.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.0.tgz#403a682b373a823612475a4c2928c7326fc0f6bb" + integrity sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^10.4.5: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^15.14.0: + version "15.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== + +graceful-fs@^4.1.15: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasha@^5.0.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1" + integrity sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ== + dependencies: + is-stream "^2.0.0" + type-fest "^0.8.0" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +highlightjs-vue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz#fdfe97fbea6354e70ee44e3a955875e114db086d" + integrity sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inputmask@5.0.9: + version "5.0.9" + resolved "https://registry.yarnpkg.com/inputmask/-/inputmask-5.0.9.tgz#7bf4e83f5e199c88c0edf28545dc23fa208ef4be" + integrity sha512-s0lUfqcEbel+EQXtehXqwCJGShutgieOaIImFKC/r4reYNvX3foyrChl6LOEvaEgxEbesePIrw1Zi2jhZaDZbQ== + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-hook@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" + integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== + dependencies: + append-transform "^2.0.0" + +istanbul-lib-instrument@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-processinfo@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz#366d454cd0dcb7eb6e0e419378e60072c8626169" + integrity sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg== + dependencies: + archy "^1.0.0" + cross-spawn "^7.0.3" + istanbul-lib-coverage "^3.2.0" + p-map "^3.0.0" + rimraf "^3.0.0" + uuid "^8.3.2" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + +jose@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/jose/-/jose-6.0.10.tgz#52d96e1a671b4c02e13b71e0d35abea2e774712b" + integrity sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +local-pkg@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd" + integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg== + dependencies: + mlly "^1.7.4" + pkg-types "^2.0.1" + quansync "^0.2.8" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.3.tgz#042a8f7986d77f3d0f98ef7990a2b2fef18b0fd2" + integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug== + +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +make-dir@^3.0.0, make-dir@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +markdown-to-jsx@7.7.4: + version "7.7.4" + resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.7.4.tgz#507d17c15af72ddf970fca84a95f0243244fcfa9" + integrity sha512-1bSfXyBKi+EYS3YY+e0Csuxf8oZ3decdfhOav/Z7Wrk89tjudyL5FOmwZQUoy0/qVXGUl+6Q3s2SWtpDEWITfQ== + +mdn-data@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.2.tgz#9ae6c41a9e65adf61318b32bff7b64fbfb13f8cf" + integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +mlly@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" + integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== + dependencies: + acorn "^8.14.0" + pathe "^2.0.1" + pkg-types "^1.3.0" + ufo "^1.5.4" + +mocha@11.2.2: + version "11.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.2.2.tgz#2dfefc9652de746389f5286888034239b6486231" + integrity sha512-VlSBxrPYHK4YNOEbFdkCxHQbZMoNzBkoPprqtZRW6311EUF/DlSxoycE2e/2NtRk4WKkIXzyrXDTrlikJMWgbw== + dependencies: + browser-stdout "^1.3.1" + chokidar "^4.0.1" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^10.4.5" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + picocolors "^1.1.1" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^17.7.2" + yargs-parser "^21.1.1" + yargs-unparser "^2.0.0" + +moment@2.30.1: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + +mrmime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc" + integrity sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mustache@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" + integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== + +mute-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" + integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== + +nanoid@3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== + +nanoid@^3.3.8: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +node-fetch-native@^1.6.4: + version "1.6.6" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.6.tgz#ae1d0e537af35c2c0b0de81cbff37eedd410aa37" + integrity sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ== + +node-preload@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" + integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== + dependencies: + process-on-spawn "^1.0.0" + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +nodemailer@6.9.16: + version "6.9.16" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.16.tgz#3ebdf6c6f477c571c0facb0727b33892635e0b8b" + integrity sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +nyc@17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-17.1.0.tgz#b6349a401a62ffeb912bd38ea9a018839fdb6eb1" + integrity sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ== + dependencies: + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + caching-transform "^4.0.0" + convert-source-map "^1.7.0" + decamelize "^1.2.0" + find-cache-dir "^3.2.0" + find-up "^4.1.0" + foreground-child "^3.3.0" + get-package-type "^0.1.0" + glob "^7.1.6" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-hook "^3.0.0" + istanbul-lib-instrument "^6.0.2" + istanbul-lib-processinfo "^2.0.2" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + make-dir "^3.0.0" + node-preload "^0.2.1" + p-map "^3.0.0" + process-on-spawn "^1.0.0" + resolve-from "^5.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + spawn-wrap "^2.0.0" + test-exclude "^6.0.0" + yargs "^15.0.2" + +ofetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.4.1.tgz#b6bf6b0d75ba616cef6519dd8b6385a8bae480ec" + integrity sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw== + dependencies: + destr "^2.0.3" + node-fetch-native "^1.6.4" + ufo "^1.5.4" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-hash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" + integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== + dependencies: + graceful-fs "^4.1.15" + hasha "^5.0.0" + lodash.flattendeep "^4.4.0" + release-zalgo "^1.0.0" + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +package-manager-detector@^0.2.8: + version "0.2.11" + resolved "https://registry.yarnpkg.com/package-manager-detector/-/package-manager-detector-0.2.11.tgz#3af0b34f99d86d24af0a0620603d2e1180d05c9c" + integrity sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ== + dependencies: + quansync "^0.2.7" + +papaparse@5.5.1: + version "5.5.1" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.5.1.tgz#4322da01e85d8e9e282c1e4387793a5978b5a0a1" + integrity sha512-EuEKUhyxrHVozD7g3/ztsJn6qaKse8RPfR6buNB2dMJvdtXNhcw8jccVi/LxNEY3HVrV6GO6Z4OoeCG9Iy9wpA== + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +pathe@^2.0.1, pathe@^2.0.2, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + +perfect-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a" + integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-types@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.1.0.tgz#70c9e1b9c74b63fdde749876ee0aa007ea9edead" + integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== + dependencies: + confbox "^0.2.1" + exsolve "^1.0.1" + pathe "^2.0.3" + +postcss@^8.5.2, postcss@^8.5.3: + version "8.5.3" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" + integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== + dependencies: + nanoid "^3.3.8" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prettier@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +prismjs@^1.27.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" + integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== + +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + +process-on-spawn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.1.0.tgz#9d5999ba87b3bf0a8acb05322d69f2f5aa4fb763" + integrity sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q== + dependencies: + fromentries "^1.2.0" + +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +pvtsutils@^1.3.5, pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + +quansync@^0.2.7, quansync@^0.2.8: + version "0.2.10" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.10.tgz#32053cf166fa36511aae95fc49796116f2dc20e1" + integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +r22n@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/r22n/-/r22n-1.0.10.tgz#bab4b5888bcdb3f44d93ac076acfe6cec5ab102d" + integrity sha512-2jFDC6oCe5UhzL4s8iAMN+7FbAtaxK9SjzZ6HxYm8O7+zmxZsiSSqjZD7iFfsjJtJkPx760p7Nc6jTXjc+Yd2w== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +react-dom@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" + integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== + dependencies: + scheduler "^0.26.0" + +react-refresh@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53" + integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== + +react-syntax-highlighter@15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz#fa567cb0a9f96be7bbccf2c13a3c4b5657d9543e" + integrity sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + highlightjs-vue "^1.0.0" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-toastify@11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.0.5.tgz#ce4c42d10eeb433988ab2264d3e445c4e9d13313" + integrity sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA== + dependencies: + clsx "^2.1.1" + +react@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" + integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== + +reactus@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/reactus/-/reactus-0.6.1.tgz#fea94424481052ba298e511ad8f7e6e53dbff084" + integrity sha512-+NP6BJYMYrk79NkIvgd094ghxHQ4zTDCVFvuSBZJRePYpXEHNkoqjIGl+2IUGGbO+gVGGqNTfALZEnJ13pvh7A== + dependencies: + "@stackpress/lib" "0.6.1" + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +release-zalgo@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" + integrity sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA== + dependencies: + es6-error "^4.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^4.34.9: + version "4.40.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920" + integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w== + dependencies: + "@types/estree" "1.0.7" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.40.0" + "@rollup/rollup-android-arm64" "4.40.0" + "@rollup/rollup-darwin-arm64" "4.40.0" + "@rollup/rollup-darwin-x64" "4.40.0" + "@rollup/rollup-freebsd-arm64" "4.40.0" + "@rollup/rollup-freebsd-x64" "4.40.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.40.0" + "@rollup/rollup-linux-arm-musleabihf" "4.40.0" + "@rollup/rollup-linux-arm64-gnu" "4.40.0" + "@rollup/rollup-linux-arm64-musl" "4.40.0" + "@rollup/rollup-linux-loongarch64-gnu" "4.40.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.40.0" + "@rollup/rollup-linux-riscv64-gnu" "4.40.0" + "@rollup/rollup-linux-riscv64-musl" "4.40.0" + "@rollup/rollup-linux-s390x-gnu" "4.40.0" + "@rollup/rollup-linux-x64-gnu" "4.40.0" + "@rollup/rollup-linux-x64-musl" "4.40.0" + "@rollup/rollup-win32-arm64-msvc" "4.40.0" + "@rollup/rollup-win32-ia32-msvc" "4.40.0" + "@rollup/rollup-win32-x64-msvc" "4.40.0" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== + +semver@^6.0.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sirv@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.1.tgz#32a844794655b727f9e2867b777e0060fbe07bf3" + integrity sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + +source-map-js@^1.0.1, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + +spawn-wrap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" + integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== + dependencies: + foreground-child "^2.0.0" + is-windows "^1.0.2" + make-dir "^3.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + which "^2.0.1" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stackpress@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/stackpress/-/stackpress-0.6.1.tgz#2609acfc3d063b20ca614b5bbaa9afd379dde79d" + integrity sha512-y0xUvvlXR2Tfkq4ZHy7R5KsNL3e7PjpEy563YGWVTm294AxwAO7jjNa0/tbfpuxFhKp+kxougz78nrSIVjJpeA== + dependencies: + "@paralleldrive/cuid2" "2.2.2" + "@stackpress/idea-transformer" "0.6.1" + "@stackpress/ingest" "0.6.1" + "@stackpress/inquire" "0.6.1" + "@stackpress/lib" "0.6.1" + jose "6.0.10" + mustache "4.2.0" + nanoid "3.3.8" + nodemailer "6.9.16" + papaparse "5.5.1" + r22n "1.0.10" + react-toastify "11.0.5" + reactus "0.6.1" + universal-cookie "8.0.1" + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-mod@^4.0.0, style-mod@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67" + integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.10, tinyglobby@^0.2.12: + version "0.2.13" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e" + integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + +ts-mocha@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-11.1.0.tgz#d8336ec0146bd6f36cca2555f4cfc7df85bd1586" + integrity sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ== + +ts-morph@25.0.1: + version "25.0.1" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-25.0.1.tgz#7de0b60fcc6e86955c8766831bcd2c5d87ffbd4f" + integrity sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ== + dependencies: + "@ts-morph/common" "~0.26.0" + code-block-writer "^13.0.3" + +ts-node@10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.0.0, tslib@^2.3.1, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tsx@4.19.3: + version "4.19.3" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.3.tgz#2bdbcb87089374d933596f8645615142ed727666" + integrity sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ== + dependencies: + esbuild "~0.25.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typescript@5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +ufo@^1.5.4: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +unconfig@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/unconfig/-/unconfig-7.0.0.tgz#0c917fbbeb9ac49341b4bc56b155351646dd6ff2" + integrity sha512-G5CJSoG6ZTxgzCJblEfgpdRK2tos9+UdD2WtecDUVfImzQ0hFjwpH5RVvGMhP4pRpC9ML7NrC4qBsBl0Ttj35A== + dependencies: + "@antfu/utils" "^8.1.0" + defu "^6.1.4" + jiti "^2.4.2" + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +universal-cookie@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-8.0.1.tgz#19263fcda6889978a081c610a90fc395eeaeec64" + integrity sha512-B6ks9FLLnP1UbPPcveOidfvB9pHjP+wekP2uRYB9YDfKVpvcjKgy1W5Zj+cEXJ9KTPnqOKGfVDQBmn8/YCQfRg== + dependencies: + cookie "^1.0.2" + +unocss@66.0.0: + version "66.0.0" + resolved "https://registry.yarnpkg.com/unocss/-/unocss-66.0.0.tgz#4f6842b54fc1a1a1c7d86d925b972ba035e03c4f" + integrity sha512-SHstiv1s7zGPSjzOsADzlwRhQM+6817+OqQE3Fv+N/nn2QLNx1bi3WXybFfz5tWkzBtyTZlwdPmeecsIs1yOCA== + dependencies: + "@unocss/astro" "66.0.0" + "@unocss/cli" "66.0.0" + "@unocss/core" "66.0.0" + "@unocss/postcss" "66.0.0" + "@unocss/preset-attributify" "66.0.0" + "@unocss/preset-icons" "66.0.0" + "@unocss/preset-mini" "66.0.0" + "@unocss/preset-tagify" "66.0.0" + "@unocss/preset-typography" "66.0.0" + "@unocss/preset-uno" "66.0.0" + "@unocss/preset-web-fonts" "66.0.0" + "@unocss/preset-wind" "66.0.0" + "@unocss/preset-wind3" "66.0.0" + "@unocss/transformer-attributify-jsx" "66.0.0" + "@unocss/transformer-compile-class" "66.0.0" + "@unocss/transformer-directives" "66.0.0" + "@unocss/transformer-variant-group" "66.0.0" + "@unocss/vite" "66.0.0" + +unplugin-utils@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz#56e4029a6906645a10644f8befc404b06d5d24d0" + integrity sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA== + dependencies: + pathe "^2.0.2" + picomatch "^4.0.2" + +update-browserslist-db@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +urlpattern-polyfill@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5" + integrity sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +vite@6.3.2: + version "6.3.2" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.2.tgz#4c1bb01b1cea853686a191657bbc14272a038f0a" + integrity sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.3" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.12" + optionalDependencies: + fsevents "~2.3.3" + +vue-flow-layout@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/vue-flow-layout/-/vue-flow-layout-0.1.1.tgz#4095d9e79b80e845f110d4d015de6faf2c71f735" + integrity sha512-JdgRRUVrN0Y2GosA0M68DEbKlXMqJ7FQgsK8CjQD2vxvNSqAU6PZEpi4cfcTVtfM2GVOMjHo7GKKLbXxOBqDqA== + +w3c-keyname@^2.2.4: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + +web-streams-polyfill@^3.2.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + +webcrypto-core@^1.8.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.8.1.tgz#09d5bd8a9c48e9fbcaf412e06b1ff1a57514ce86" + integrity sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A== + dependencies: + "@peculiar/asn1-schema" "^2.3.13" + "@peculiar/json-schema" "^1.1.12" + asn1js "^3.0.5" + pvtsutils "^1.3.5" + tslib "^2.7.0" + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^15.0.2: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== From fa73afd01f105facbc6df20381f2c88af6ddbe4c Mon Sep 17 00:00:00 2001 From: NJ veneracion Date: Mon, 8 Sep 2025 11:42:40 +0800 Subject: [PATCH 03/14] created idea website 4d --- .../views/specifications/plugin-system.tsx | 231 +++++++++--------- .../views/tutorials/mysql-table-plugin.tsx | 46 ++-- 2 files changed, 138 insertions(+), 139 deletions(-) diff --git a/packages/www/plugins/docs/views/specifications/plugin-system.tsx b/packages/www/plugins/docs/views/specifications/plugin-system.tsx index beb0d2d..04074a1 100644 --- a/packages/www/plugins/docs/views/specifications/plugin-system.tsx +++ b/packages/www/plugins/docs/views/specifications/plugin-system.tsx @@ -1,48 +1,48 @@ //modules import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; - import Code from '../../components/Code.js'; - import Layout from '../../components/Layout.js'; - import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Plugin System'); - const description = _( - 'The plugin system enables extensible code generation from your schema definitions.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'stackpress/view/client'; +//docs +import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; - const pluginDeclaration = [ - `plugin "./path/to/plugin.js" { +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin System'); + const description = _( + 'The plugin system enables extensible code generation from your schema definitions.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +const pluginDeclaration = [ + `plugin "./path/to/plugin.js" { output "./generated/output.ts" format "typescript" options { @@ -50,7 +50,7 @@ import type { comments true } }`, -`import type { PluginProps } from '@stackpress/idea-transformer/types'; + `import type { PluginProps } from '@stackpress/idea-transformer/types'; export default async function myPlugin(props: PluginProps<{}>) { const { config, schema, transformer } = props; @@ -62,81 +62,80 @@ export default async function myPlugin(props: PluginProps<{}>) { const outputPath = await transformer.loader.absolute(config.output); await writeFile(outputPath, content); }` - ] - - export function Body() { - return ( -
    -

    Plugin System

    -

    The plugin system enables extensible code generation from your schema definitions.

    +] -

    Plugin Declaration

    - - {pluginDeclaration[0]} - +export function Body() { + return ( +
    +

    Plugin System

    +

    The plugin system enables extensible code generation from your schema definitions.

    -

    Common Plugin Types

    - - Plugin Type - Purpose - Output - - TypeScript Generator - Generate interfaces and types - .ts files - - - Database Schema - Generate SQL DDL - .sql files - - - API Documentation - Generate OpenAPI Specs - .json/.yaml files - - - Form Generator - Generate HTML Forms - .html files - - - Validation Schema - Generate Zod/Joi schemas - .ts files - - - Mock Data - Generate test fixtures - .json files - -
    +

    Plugin Declaration

    + + {pluginDeclaration[0]} + -

    Plugin Development

    +

    Common Plugin Types

    + + Plugin Type + Purpose + Output + + TypeScript Generator + Generate interfaces and types + .ts files + + + Database Schema + Generate SQL DDL + .sql files + + + API Documentation + Generate OpenAPI Specs + .json/.yaml files + + + Form Generator + Generate HTML Forms + .html files + + + Validation Schema + Generate Zod/Joi schemas + .ts files + + + Mock Data + Generate test fixtures + .json files + +
    - - {pluginDeclaration[1]} - +

    Plugin Development

    -
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } - \ No newline at end of file + + {pluginDeclaration[1]} + + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx b/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx index 50c93ee..437e224 100644 --- a/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx +++ b/packages/www/plugins/docs/views/tutorials/mysql-table-plugin.tsx @@ -8,7 +8,7 @@ import { useLanguage } from 'stackpress/view/client'; import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; import Layout from '../../components/Layout.js'; import Code from '../../components/Code.js'; -import {Table, Thead, Trow, Tcol} from 'frui/element/Table'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; export function Head(props: ServerPageProps) { //props @@ -398,7 +398,7 @@ plugin "./plugins/graphql-schema.js" { includeQueries true includeMutations true }`, -`# Custom Scalars + `# Custom Scalars scalar DateTime scalar JSON @@ -689,7 +689,7 @@ export function Body() { includeQueries boolean - false + false Generate Query type with CRUD operations @@ -720,29 +720,29 @@ export function Body() {
    -

    Usage Examples

    -

    - Usage examples demonstrate practical applications of the GraphQL schema generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated GraphQL schemas integrate into development workflows. -

    +

    Usage Examples

    +

    + Usage examples demonstrate practical applications of the GraphQL schema generator with real-world scenarios. These examples show how to configure the plugin for different use cases and how the generated GraphQL schemas integrate into development workflows. +

    -

    6.1. Basic Schema

    -

    - A basic schema example shows the fundamental structure needed to generate GraphQL type definitions. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces comprehensive GraphQL schemas. -

    +

    6.1. Basic Schema

    +

    + A basic schema example shows the fundamental structure needed to generate GraphQL type definitions. This includes model definitions with proper attributes, enum declarations, and plugin configuration that produces comprehensive GraphQL schemas. +

    - - {basicSchemaExample[0]} - + + {basicSchemaExample[0]} + -

    6.2. Generated Output

    -

    - The generated output demonstrates the GraphQL schema produced by the plugin from the basic schema example. This shows how schema definitions are transformed into proper GraphQL type definitions with full type safety and operation support. -

    +

    6.2. Generated Output

    +

    + The generated output demonstrates the GraphQL schema produced by the plugin from the basic schema example. This shows how schema definitions are transformed into proper GraphQL type definitions with full type safety and operation support. +

    + + + {basicSchemaExample[1]} + - - {basicSchemaExample[1]} - -
    @@ -887,7 +887,7 @@ export function Body() { This tutorial provides a comprehensive foundation for creating GraphQL schema generators from .idea files. The generated schemas can be used with any GraphQL server implementation like Apollo Server, GraphQL Yoga, or others.

    - + ); } diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx new file mode 100644 index 0000000..1800854 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx @@ -0,0 +1,44 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; + +export default function AdvancedFeatures() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Advanced Features')}

    +

    + + The plugin can be extended with additional features: + +

    +
      +
    • + + Custom templates and themes + +
    • +
    • + + Diagram generation (Mermaid, PlantUML) + +
    • +
    • + + Integration with documentation sites (GitBook, Docusaurus) + +
    • +
    • + + API documentation formats (OpenAPI, GraphQL) + +
    • +
    • + + Multi-language documentation generation + +
    • +
    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx new file mode 100644 index 0000000..5544b40 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx @@ -0,0 +1,53 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; + +export default function Conclusion() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Conclusion')}

    +

    + + This Markdown Documentation Plugin demonstrates how to: + +

    +
      +
    • + + Parse all schema elements (models, types, enums, props) + +
    • +
    • + + Generate comprehensive, structured documentation + +
    • +
    • + + Support multiple output formats (single file vs. multiple files) + +
    • +
    • + + Include examples, cross-references, and detailed attribute + information + +
    • +
    • + + Provide flexible configuration options for different + documentation needs + +
    • +
    +

    + + The plugin is highly customizable and can be extended to support + additional features like custom templates, diagram generation, + and integration with documentation platforms. + +

    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx new file mode 100644 index 0000000..15c4385 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx @@ -0,0 +1,68 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C } from '../index.js'; +import Code from '../Code.js'; + +const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface MarkdownDocsConfig { + output: string; + title?: string; + format?: 'single' | 'multiple'; + includeIndex?: boolean; + includeExamples?: boolean; + includeAttributes?: boolean; + sections?: string[]; + template?: 'default' | 'api' | 'guide'; +} + +export default async function markdownDocsPlugin( + props: PluginProps<{ config: MarkdownDocsConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // Validate configuration + if (!config.output) { + throw new Error('Markdown Documentation Plugin requires "output" configuration'); + } + + // Set defaults + const options = { + title: config.title || 'Schema Documentation', + format: config.format || 'single', + includeIndex: config.includeIndex !== false, + includeExamples: config.includeExamples !== false, + includeAttributes: config.includeAttributes !== false, + sections: config.sections || ['models', 'types', 'enums', 'props'], + template: config.template || 'default', + ...config + }; + + // Generate documentation + if (options.format === 'single') { + await generateSingleFile(schema, options, transformer); + } else { + await generateMultipleFiles(schema, options, transformer); + } + + console.log(\`✅ Markdown documentation generated: \${options.output}\`); +}`; + +export default function CreatePluginStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Create the Plugin Structure')}

    +

    + + Create a new file markdown-docs-plugin.js: + +

    + + {pluginStructureExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx new file mode 100644 index 0000000..a030990 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx @@ -0,0 +1,41 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const errorHandlingExample = `function validateConfig(config: any): void { + if (!config.output) { + throw new Error('Markdown Documentation Plugin requires "output" configuration'); + } + + if (config.format && !['single', 'multiple'].includes(config.format)) { + throw new Error(\`Unsupported format: \${config.format}\`); + } + + if (config.template && !['default', 'api', 'guide'].includes(config.template)) { + throw new Error(\`Unsupported template: \${config.template}\`); + } +}`; + +export default function ErrorHandlingAndBestPractices() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Error Handling and Best Practices')}

    +

    + + Add proper error handling and validation: + +

    + + {errorHandlingExample} + +

    + + Always validate configuration parameters and provide meaningful + error messages to help users troubleshoot issues. + +

    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx new file mode 100644 index 0000000..9f61898 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx @@ -0,0 +1,33 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const modelsGenerationExample = +`function generateModelsSection(models: any, schema: any, options: any): string { + let content = '## Models\\n\\n'; + content += 'Models represent the main data structures in your application.\\n\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += generateModelDocumentation(modelName, model, schema, options); + } + + return content; +}`; + +export default function GenerateModelsDocumentation() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Generate Models Documentation')}

    +

    + + Implement model documentation generation: + +

    + + {modelsGenerationExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx new file mode 100644 index 0000000..46b47c3 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx @@ -0,0 +1,26 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; + +export default function GenerateTypesEnumsProps() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Generate Types, Enums, and Props')}

    +

    + + Similar to models, you can implement generation functions for + types, enums, and props. Each follows the same pattern of + creating markdown sections with tables and descriptions. + +

    +

    + + Types define reusable data structures, enums define sets of + named constants, and props define reusable property + configurations for form fields and validation. + +

    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx new file mode 100644 index 0000000..f2fc397 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx @@ -0,0 +1,73 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const generatedOutputExample = `# My Application Schema + +API Reference documentation for the schema definitions. + +## Overview + +This document provides comprehensive API documentation for all schema elements including models, types, enums, and properties. + +Generated on: 2024-01-15T10:30:00.000Z + +## Table of Contents + +- [Models](#models) + - [User](#user) +- [Enums](#enums) + - [UserRole](#userrole) + +## Models + +Models represent the main data structures in your application. + +### User + +**Mutability:** Immutable + +#### Columns + +| Name | Type | Required | Multiple | Description | +|------|------|----------|----------|-------------| +| id | \`String\` | ✓ | ✗ | Unique identifier for the user | +| email | \`String\` | ✓ | ✗ | User email address for authentication | +| name | \`String\` | ✓ | ✗ | Full name of the user | +| role | [UserRole](#userrole) | ✓ | ✗ | User's role in the system | + +## Enums + +Enums define sets of named constants with associated values. + +### UserRole + +#### Values + +| Key | Value | Description | +|-----|-------|-----------| +| ADMIN | Administrator | - | +| USER | Regular User | - | +| GUEST | Guest User | - | + +--- + +*Documentation generated on 1/15/2024, 10:30:00 AM*`; + +export default function GeneratedOutput() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Generated Output')}

    +

    + + The plugin will generate markdown documentation like this: + +

    + + {generatedOutputExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx new file mode 100644 index 0000000..1add44d --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx @@ -0,0 +1,64 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const documentationGenerationExample = `async function generateSingleFile(schema: any, options: any, transformer: any): Promise { + let content = generateHeader(options); + + // Generate table of contents + if (options.includeIndex) { + content += generateTableOfContents(schema, options); + } + + // Generate sections + for (const section of options.sections) { + switch (section) { + case 'models': + if (schema.model) { + content += generateModelsSection(schema.model, schema, options); + } + break; + case 'types': + if (schema.type) { + content += generateTypesSection(schema.type, schema, options); + } + break; + case 'enums': + if (schema.enum) { + content += generateEnumsSection(schema.enum, options); + } + break; + case 'props': + if (schema.prop) { + content += generatePropsSection(schema.prop, options); + } + break; + } + } + + // Add footer + content += generateFooter(options); + + // Write to file + const outputPath = await transformer.loader.absolute(options.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); +}`; + +export default function ImplementDocumentationGeneration() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Implement Documentation Generation')}

    +

    + + Create functions to generate different sections of documentation: + +

    + + {documentationGenerationExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx new file mode 100644 index 0000000..2d8f0ad --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx @@ -0,0 +1,21 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Creating a Markdown Documentation Plugin')}

    +

    + + This tutorial will guide you through creating a plugin that + generates comprehensive markdown documentation from a processed + .idea schema. You'll learn how to parse schema models, + types, enums, and props to create structured documentation with + examples and cross-references. + +

    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx new file mode 100644 index 0000000..0053eca --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx @@ -0,0 +1,44 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Overview')}

    +

    + + The Markdown Documentation Plugin will: + +

    +
      +
    • + + Parse schema models, types, enums, and props + +
    • +
    • + + Generate structured markdown documentation + +
    • +
    • + + Include examples and usage notes + +
    • +
    • + + Create navigation and cross-references + +
    • +
    • + + Support different documentation formats and styles + +
    • +
    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx new file mode 100644 index 0000000..2af6577 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx @@ -0,0 +1,29 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, C } from '../index.js'; + +export default function Prerequisites() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Prerequisites')}

    +
      +
    • + + Basic understanding of TypeScript/JavaScript + +
    • +
    • + + Familiarity with Markdown syntax + +
    • +
    • + + Understanding of the idea-transformer plugin system + +
    • +
    +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx new file mode 100644 index 0000000..a0b9d3f --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx @@ -0,0 +1,87 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const exampleProcessedSchema = `// Example processed schema +{ + model: { + User: { + mutable: false, + columns: [ + { + name: 'id', + type: 'String', + required: true, + multiple: false, + attributes: { + id: true, + label: 'User ID', + default: 'nanoid()', + description: 'Unique identifier for the user' + } + }, + { + name: 'email', + type: 'String', + required: true, + multiple: false, + attributes: { + unique: true, + label: 'Email Address', + field: { input: { type: 'email' } }, + description: 'User email address for authentication' + } + } + ] + } + }, + enum: { + UserRole: { + ADMIN: 'Administrator', + USER: 'Regular User', + GUEST: 'Guest User' + } + }, + type: { + Address: { + mutable: true, + columns: [ + { + name: 'street', + type: 'String', + required: true, + multiple: false, + attributes: { + label: 'Street Address' + } + } + ] + } + }, + prop: { + Text: { + type: 'text', + placeholder: 'Enter text', + maxLength: 255 + } + } +}`; + +export default function UnderstandingSchemaStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Understanding the Schema Structure')}

    +

    + + Before creating the plugin, let's understand what documentation + we can generate from a schema: + +

    + + {exampleProcessedSchema} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx new file mode 100644 index 0000000..45a128d --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx @@ -0,0 +1,48 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const schemaUsageExample = `// schema.idea +plugin "./plugins/markdown-docs-plugin.js" { + output "./docs/schema.md" + title "My Application Schema" + format "single" + includeIndex true + includeExamples true + includeAttributes true + sections ["models", "types", "enums", "props"] + template "api" +} + +model User! { + id String @id @default("nanoid()") @description("User ID") + email String @unique @field.input(Email) @description("Email") + name String @field.input(Text) @description("Full name") + role UserRole @default("USER") @description("User's role") + active Boolean @default(true) @description("Active status") + created Date @default("now()") @description("Creation date") +} + +enum UserRole { + ADMIN "Administrator" + USER "Regular User" + GUEST "Guest User" +}`; + +export default function UsageInSchema() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Usage in Schema')}

    +

    + + To use this plugin in your schema file: + +

    + + {schemaUsageExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx new file mode 100644 index 0000000..d763d3c --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx @@ -0,0 +1,41 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const utilityFunctionsExample = `function formatType(type: string, multiple: boolean = false): string { + let formattedType = type; + + // Add array notation if multiple + if (multiple) { + formattedType += '[]'; + } + + // Add markdown formatting for built-in types + const builtInTypes = ['String', 'Number', 'Boolean', 'Date', 'JSON']; + if (builtInTypes.includes(type)) { + formattedType = \`\\\`\${formattedType}\\\`\`; + } else { + // Link to other types/enums + formattedType = \`[\${formattedType}](#\${type.toLowerCase()})\`; + } + + return formattedType; +}`; + +export default function UtilityFunctions() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Utility Functions')}

    +

    + + Create helper functions for formatting and processing: + +

    + + {utilityFunctionsExample} + +
    + ) +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx new file mode 100644 index 0000000..41beba8 --- /dev/null +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx @@ -0,0 +1,14 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Overview } from './Overview.js'; +export { default as Prerequisites } from './Prerequisites.js'; +export { default as UnderstandingSchemaStructure } from './UnderstandingSchemaStructure.js'; +export { default as CreatePluginStructure } from './CreatePluginStructure.js'; +export { default as ImplementDocumentationGeneration } from './ImplementDocumentationGeneration.js'; +export { default as GenerateModelsDocumentation } from './GenerateModelsDocumentation.js'; +export { default as GenerateTypesEnumsProps } from './GenerateTypesEnumsProps.js'; +export { default as UtilityFunctions } from './UtilityFunctions.js'; +export { default as UsageInSchema } from './UsageInSchema.js'; +export { default as GeneratedOutput } from './GeneratedOutput.js'; +export { default as ErrorHandlingAndBestPractices } from './ErrorHandlingAndBestPractices.js'; +export { default as AdvancedFeatures } from './AdvancedFeatures.js'; +export { default as Conclusion } from './Conclusion.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx new file mode 100644 index 0000000..a1c9b9c --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx @@ -0,0 +1,72 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2 ,P } from '../index.js'; +import Code from '../Code.js'; + +const enhancedErrorHandling = `export default async function mysqlTablesPlugin(props: PluginProps<{}>) { + const { config, schema, transformer, cwd } = props; + + try { + // Validate configuration + validateConfig(config); + + // Validate schema has models + if (!schema.model || Object.keys(schema.model).length === 0) { + console.warn('⚠️ No models found in schema. Skipping MySQL table generation.'); + return; + } + + // Generate SQL + const sqlContent = generateSQL(schema, config); + + // Ensure output directory exists + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + + // Write file + await fs.writeFile(outputPath, sqlContent, 'utf8'); + + console.log(\`✅ MySQL tables generated: \${outputPath}\`); + console.log(\`📊 Generated \${Object.keys(schema.model).length} table(s)\`); + + } catch (error) { + console.error(\`❌ MySQL Tables Plugin failed: \${error.message}\`); + throw error; + } +}`; + +const configValidation = `function validateConfig(config: any): void { + if (!config.output) { + throw new Error('MySQL Tables Plugin requires "output" configuration'); + } + + if (config.engine && !['InnoDB', 'MyISAM', 'Memory'].includes(config.engine)) { + throw new Error(\`Unsupported MySQL engine: \${config.engine}\`); + } +}`; + +export default function BestPractices() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('9. Error Handling and Best Practices')}

    +

    + + Add proper error handling and validation to make your plugin + robust and user-friendly. + +

    + +

    {_('9.1. Enhanced Error Handling')}

    + {enhancedErrorHandling} + +

    {_('9.2. Configuration Validation')}

    + + {configValidation} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx new file mode 100644 index 0000000..4e8dac2 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx @@ -0,0 +1,50 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P } from '../index.js'; + +export default function Conclusion() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('10. Conclusion')}

    +

    + + This MySQL Tables Plugin demonstrates how to: + +

    +
      +
    • + + Parse schema models and columns + +
    • +
    • + + Map schema types to database-specific types + +
    • +
    • + + Generate SQL DDL statements + +
    • +
    • + + Handle constraints, indexes, and foreign keys + +
    • +
    • + + Provide proper error handling and validation + +
    • +
    +

    + + The plugin is flexible and can be extended to support additional + MySQL features like partitioning, triggers, or stored procedures. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx new file mode 100644 index 0000000..33d9a3c --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx @@ -0,0 +1,68 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const basicPluginStructure = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface MySQLPluginConfig { + output: string; + database?: string; + engine?: string; + charset?: string; + collation?: string; +} + +export default async function mysqlTablesPlugin( + props: PluginProps<{ config: MySQLPluginConfig }> +) { + const { config, schema, transformer, cwd } = props; + + // Validate configuration + if (!config.output) { + throw new Error('MySQL Tables Plugin requires "output" configuration'); + } + + // Set defaults + const options = { + database: config.database || 'app_database', + engine: config.engine || 'InnoDB', + charset: config.charset || 'utf8mb4', + collation: config.collation || 'utf8mb4_unicode_ci', + ...config + }; + + // Generate SQL content + const sqlContent = generateSQL(schema, options); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, sqlContent, 'utf8'); + + console.log(\`✅ MySQL tables generated: \${outputPath}\`); +}`; + +export default function CreatePluginStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('4. Create the Plugin Structure')}

    +

    + + Create a new file mysql-tables-plugin.js. This will be the main + entry point for our plugin that handles configuration validation + and orchestrates the SQL generation process. + +

    +

    {_('Basic Plugin Structure')}

    + {basicPluginStructure} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx new file mode 100644 index 0000000..32a7ab8 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx @@ -0,0 +1,194 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const mainSQLGeneration = `function generateSQL(schema: any, options: any): string { + let sql = ''; + + // Add header comment + sql += \`-- Generated MySQL Tables\\n\`; + sql += \`-- Database: \${options.database}\\n\`; + sql += \`-- Generated at: \${new Date().toISOString()}\\n\\n\`; + + // Create database if specified + if (options.database) { + sql += \`CREATE DATABASE IF NOT EXISTS \\\`\${options.database}\\\`;\\n\`; + sql += \`USE \\\`\${options.database}\\\`;\\n\\n\`; + } + + // Generate tables for each model + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + sql += generateTableSQL(modelName, model, options); + sql += '\\n'; + } + } + + return sql; +}`; + +const tableSQLGeneration = `function generateTableSQL(tableName: string, model: any, options: any): string { + const columns: string[] = []; + const indexes: string[] = []; + const foreignKeys: string[] = []; + let primaryKey = ''; + + // Process each column + for (const column of model.columns || []) { + const columnDef = generateColumnDefinition(column, options); + columns.push(columnDef.definition); + + // Handle constraints + if (columnDef.isPrimary) { + primaryKey = column.name; + } + if (columnDef.isUnique) { + indexes.push(\`UNIQUE KEY \\\`uk_\${tableName}_\${column.name}\\\` (\\\`\${column.name}\\\`)\`); + } + if (columnDef.isIndex) { + indexes.push(\`KEY \\\`idx_\${tableName}_\${column.name}\\\` (\\\`\${column.name}\\\`)\`); + } + if (columnDef.foreignKey) { + foreignKeys.push(columnDef.foreignKey); + } + } + + // Build CREATE TABLE statement + let sql = \`CREATE TABLE \\\`\${tableName}\\\` (\\n\`; + + // Add columns + sql += columns.map(col => \` \${col}\`).join(',\\n'); + + // Add primary key + if (primaryKey) { + sql += \`,\\n PRIMARY KEY (\\\`\${primaryKey}\\\`)\`; + } + + // Add indexes + if (indexes.length > 0) { + sql += ',\\n ' + indexes.join(',\\n '); + } + + // Add foreign keys + if (foreignKeys.length > 0) { + sql += ',\\n ' + foreignKeys.join(',\\n '); + } + + sql += \`\\n) ENGINE=\${options.engine} DEFAULT CHARSET=\${options.charset} COLLATE=\${options.collation};\\n\`; + + return sql; +}`; + +const columnDefinitionGeneration = `function generateColumnDefinition(column: any, options: any): any { + const { name, required, attributes = {} } = column; + const mysqlType = mapSchemaTypeToMySQL(column); + + let definition = \`\\\`\${name}\\\` \${mysqlType}\`; + + // Handle NULL/NOT NULL + if (required || attributes.id) { + definition += ' NOT NULL'; + } else { + definition += ' NULL'; + } + + // Handle AUTO_INCREMENT + if (attributes.id && attributes.autoIncrement !== false) { + if (mysqlType.includes('INT')) { + definition += ' AUTO_INCREMENT'; + } + } + + // Handle DEFAULT values + if (attributes.default !== undefined) { + const defaultValue = attributes.default; + if (defaultValue === 'now()' || defaultValue === 'CURRENT_TIMESTAMP') { + definition += ' DEFAULT CURRENT_TIMESTAMP'; + } else if (defaultValue === 'updated()') { + definition += ' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'; + } else if (typeof defaultValue === 'string') { + definition += \` DEFAULT '\${defaultValue}'\`; + } else { + definition += \` DEFAULT \${defaultValue}\`; + } + } + + // Handle COMMENT + if (attributes.label) { + const comment = Array.isArray(attributes.label) + ? attributes.label[0] + : attributes.label; + definition += \` COMMENT '\${comment.replace(/'/g, "''")}'\`; + } + + return { + definition, + isPrimary: !!attributes.id, + isUnique: !!attributes.unique, + isIndex: !!attributes.index || !!attributes.searchable || !!attributes.filterable, + foreignKey: generateForeignKey(column, options) + }; +}`; + +const foreignKeyGeneration = `function generateForeignKey(column: any, options: any): string | null { + const { name, type, attributes = {} } = column; + + // Check if this column references another model + if (schema.model && schema.model[type]) { + const referencedTable = type; + const referencedColumn = 'id'; // Assuming 'id' is the primary key + + return \`CONSTRAINT \\\`fk_\${name}\\\` FOREIGN KEY (\\\`\${name}\\\`) REFERENCES \\\`\${referencedTable}\\\` (\\\`\${referencedColumn}\\\`) ON DELETE \${attributes.onDelete || 'CASCADE'} ON UPDATE \${attributes.onUpdate || 'CASCADE'}\`; + } + + return null; +}`; + +export default function GenerateSqlStatements() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('6. Generate SQL Statements')}

    +

    + + Implement the main SQL generation function. This section contains + the core logic for creating MySQL CREATE TABLE statements from + the processed schema. + +

    + +

    {_('6.1. Main SQL Generation')}

    + + {mainSQLGeneration} + + +

    {_('6.2. Table SQL Generation')}

    + + {tableSQLGeneration} + + +

    {_('6.3. Column Definition Generation')}

    + + {columnDefinitionGeneration} + + +

    {_('6.4. Foreign Key Generation')}

    + + {foreignKeyGeneration} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx new file mode 100644 index 0000000..5ad6650 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx @@ -0,0 +1,47 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const generatedOutputExample = `-- Generated MySQL Tables +-- Database: my_app +-- Generated at: 2024-01-15T10:30:00.000Z + +CREATE DATABASE IF NOT EXISTS \`my_app\`; +USE \`my_app\`; + +CREATE TABLE \`User\` ( + \`id\` VARCHAR(255) NOT NULL COMMENT 'ID', + \`email\` VARCHAR(255) NOT NULL COMMENT 'Email', + \`name\` VARCHAR(255) NOT NULL COMMENT 'Name', + \`age\` TINYINT UNSIGNED NULL COMMENT 'Age', + \`role\` ENUM('admin', 'user') NOT NULL DEFAULT 'user' COMMENT 'Role', + \`active\` BOOLEAN NOT NULL DEFAULT true COMMENT 'Active', + \`created\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Created', + \`updated\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Updated', + PRIMARY KEY (\`id\`), + UNIQUE KEY \`uk_User_email\` (\`email\`), + KEY \`idx_User_age\` (\`age\`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`; + +export default function GeneratedOutput() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('8. Generated Output')}

    +

    + + The plugin will generate SQL like this. The output includes + proper MySQL syntax with constraints, indexes, and foreign keys. + +

    +

    {_('Example Generated SQL')}

    + + {generatedOutputExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx new file mode 100644 index 0000000..7a246f4 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx @@ -0,0 +1,100 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const typeMappingFunction = `function mapSchemaTypeToMySQL(column: any): string { + const { type, attributes = {} } = column; + + switch (type) { + case 'String': + // Check for specific string constraints + if (attributes.id) { + return 'VARCHAR(255)'; // Primary key strings + } + if (attributes.email || attributes.url) { + return 'VARCHAR(255)'; + } + if (attributes.text || attributes.textarea) { + return 'TEXT'; + } + if (attributes.maxLength) { + return \`VARCHAR(\${attributes.maxLength})\`; + } + return 'VARCHAR(255)'; // Default string length + + case 'Number': + if (attributes.unsigned) { + if (attributes.max && attributes.max <= 255) { + return 'TINYINT UNSIGNED'; + } + if (attributes.max && attributes.max <= 65535) { + return 'SMALLINT UNSIGNED'; + } + if (attributes.max && attributes.max <= 16777215) { + return 'MEDIUMINT UNSIGNED'; + } + return 'INT UNSIGNED'; + } + if (attributes.float || attributes.decimal) { + const precision = attributes.precision || 10; + const scale = attributes.scale || 2; + return \`DECIMAL(\${precision},\${scale})\`; + } + return 'INT'; + + case 'Boolean': + return 'BOOLEAN'; + + case 'Date': + if (attributes.time) { + return 'DATETIME'; + } + if (attributes.timestamp) { + return 'TIMESTAMP'; + } + return 'DATE'; + + case 'JSON': + return 'JSON'; + + default: + // Check if it's an enum type + if (schema.enum && schema.enum[type]) { + const enumValues = Object.values(schema.enum[type]) + .map(value => \`'\${value}'\`) + .join(', '); + return \`ENUM(\${enumValues})\`; + } + + // Check if it's a foreign key (another model) + if (schema.model && schema.model[type]) { + return 'VARCHAR(255)'; // Assuming string-based foreign keys + } + + return 'VARCHAR(255)'; // Default fallback + } +}`; + +export default function ImplementTypeMapping() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('5. Implement Type Mapping')}

    +

    + + Create a function to map schema types to MySQL types. This + function handles the conversion between idea schema types and + their corresponding MySQL data types. + +

    +

    {_('Type Mapping Function')}

    + + {typeMappingFunction} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx new file mode 100644 index 0000000..296dd08 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx @@ -0,0 +1,19 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Creating a MySQL Tables Plugin')}

    +

    + + This tutorial will guide you through creating a plugin that + generates MySQL CREATE TABLE statements from a processed .idea + schema. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx new file mode 100644 index 0000000..df955cd --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx @@ -0,0 +1,44 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('1. Overview')}

    +

    + + The MySQL Tables Plugin will: + +

    +
      +
    • + + Parse schema models and their columns + +
    • +
    • + + Map schema types to MySQL data types + +
    • +
    • + + Generate SQL CREATE TABLE statements + +
    • +
    • + + Handle primary keys, foreign keys, and indexes + +
    • +
    • + + Output SQL files that can be executed to create database tables + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx new file mode 100644 index 0000000..ceb29ef --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx @@ -0,0 +1,35 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P } from '../index.js'; + +export default function Prerequisites() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('2. Prerequisites')}

    +

    + + Before creating this plugin, you should have the following + knowledge and tools: + +

    +
      +
    • + + Basic understanding of TypeScript/JavaScript + +
    • +
    • + + Familiarity with MySQL and SQL syntax + +
    • +
    • + + Understanding of the idea-transformer plugin system + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx new file mode 100644 index 0000000..eb0d4a6 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx @@ -0,0 +1,76 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const schemaStructureExample = `// Example processed schema +{ + model: { + User: { + mutable: false, + columns: [ + { + name: 'id', + type: 'String', + required: true, + multiple: false, + attributes: { + id: true, + default: 'nanoid()' + } + }, + { + name: 'email', + type: 'String', + required: true, + multiple: false, + attributes: { + unique: true, + field: { input: { type: 'email' } } + } + }, + { + name: 'age', + type: 'Number', + required: false, + multiple: false, + attributes: { + unsigned: true, + min: 0, + max: 150 + } + } + ] + } + }, + enum: { + UserRole: { + ADMIN: 'admin', + USER: 'user' + } + } +}`; + +export default function UnderstandingSchemaStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('3. Understanding the Schema Structure')}

    +

    + + Before creating the plugin, let's understand what a processed + schema looks like. The schema structure contains models, enums, + and other configuration data that our plugin will process. + +

    +

    {_('Example Schema Structure')}

    + + {schemaStructureExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx new file mode 100644 index 0000000..fd27a0b --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx @@ -0,0 +1,51 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const schemaUsageExample = `// schema.idea +plugin "./plugins/mysql-tables-plugin.js" { + output "./database/tables.sql" + database "my_app" + engine "InnoDB" + charset "utf8mb4" + collation "utf8mb4_unicode_ci" +} + +model User { + id String @id @default("nanoid()") + email String @unique @field.input(Email) + name String @field.input(Text) + age Number @unsigned @min(0) @max(150) + role UserRole @default("USER") + active Boolean @default(true) + created Date @default("now()") + updated Date @default("updated()") +} + +enum UserRole { + ADMIN "admin" + USER "user" +}`; + +export default function UsageInSchema() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('7. Usage in Schema')}

    +

    + + To use this plugin in your schema file, add the plugin + declaration with appropriate configuration options. + +

    +

    {_('Schema Configuration')}

    + + {schemaUsageExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx new file mode 100644 index 0000000..fc2b4b7 --- /dev/null +++ b/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx @@ -0,0 +1,11 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Overview } from './Overview.js'; +export { default as Prerequisites } from './Prerequisites.js'; +export { default as UnderstandingSchemaStructure } from './UnderstandingSchemaStructure.js'; +export { default as CreatePluginStructure } from './CreatePluginStructure.js'; +export { default as ImplementTypeMapping } from './ImplementTypeMapping.js'; +export { default as GenerateSqlStatements } from './GenerateSqlStatements.js'; +export { default as UsageInSchema } from './UsageInSchema.js'; +export { default as GeneratedOutput } from './GeneratedOutput.js'; +export { default as BestPractices } from './BestPractices.js'; +export { default as Conclusion } from './Conclusion.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx new file mode 100644 index 0000000..50230ed --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx @@ -0,0 +1,259 @@ +const advancedConfigExample = `interface AdvancedOpenAPIConfig extends OpenAPIConfig { + formats?: ('json' | 'yaml' | 'html')[]; + validation?: { + strict?: boolean; + examples?: boolean; + }; + documentation?: { + includeExamples?: boolean; + includeSchemas?: boolean; + customTemplates?: string; + }; +} + +export default async function generateAdvancedOpenAPISpec( + props: PluginProps<{ config: AdvancedOpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + const spec = generateSpecification(schema, config); + + // Add validation and examples + if (config.validation?.examples) { + addExamples(spec, schema); + } + + if (config.validation?.strict) { + validateSpecification(spec); + } + + // Generate multiple formats + const formats = config.formats || ['json']; + const outputBase = config.output.replace(/\\.[^.]+$/, ''); + + for (const format of formats) { + await generateFormat(spec, format, outputBase, transformer); + } +}`; + +const formatGenerationExample = `async function generateFormat( + spec: any, + format: string, + outputBase: string, + transformer: any +): Promise { + let content: string; + let extension: string; + + switch (format) { + case 'json': + content = JSON.stringify(spec, null, 2); + extension = '.json'; + break; + case 'yaml': + const yaml = await import('yaml'); + content = yaml.stringify(spec); + extension = '.yaml'; + break; + case 'html': + content = generateHTMLDocumentation(spec); + extension = '.html'; + break; + default: + throw new Error(\`Unsupported format: \${format}\`); + } + + const outputPath = await transformer.loader.absolute(\`\${outputBase}\${extension}\`); + await fs.writeFile(outputPath, content, 'utf8'); + console.log(\`✅ Generated \${format.toUpperCase()} specification: \${outputPath}\`); +}`; + +const exampleGenerationExample = `function addExamples(spec: any, schema: any): void { + // Add examples to schemas + for (const [name, schemaObj] of Object.entries(spec.components.schemas)) { + if (schemaObj.type === 'object') { + schemaObj.example = generateExample(schemaObj, schema); + } + } + + // Add examples to endpoints + for (const [path, pathObj] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(pathObj)) { + if (operation.requestBody?.content?.['application/json']?.schema) { + const schema = operation.requestBody.content['application/json'].schema; + if (!schema.example) { + schema.example = generateExample(schema, schema); + } + } + } + } +} + +function generateExample(schemaObj: any, fullSchema: any): any { + if (schemaObj.$ref) { + const refName = schemaObj.$ref.split('/').pop(); + return generateExample(fullSchema.components?.schemas?.[refName] || {}, fullSchema); + } + + if (schemaObj.type === 'object') { + const example: any = {}; + for (const [propName, propSchema] of Object.entries(schemaObj.properties || {})) { + example[propName] = generatePropertyExample(propSchema); + } + return example; + } + + if (schemaObj.type === 'array') { + return [generateExample(schemaObj.items, fullSchema)]; + } + + return generatePropertyExample(schemaObj); +} + +function generatePropertyExample(propSchema: any): any { + if (propSchema.example !== undefined) { + return propSchema.example; + } + + if (propSchema.enum) { + return propSchema.enum[0]; + } + + switch (propSchema.type) { + case 'string': + if (propSchema.format === 'email') return 'user@example.com'; + if (propSchema.format === 'date-time') return new Date().toISOString(); + if (propSchema.format === 'date') return new Date().toISOString().split('T')[0]; + return 'string'; + case 'number': + return 42.5; + case 'integer': + return 42; + case 'boolean': + return true; + case 'array': + return [generatePropertyExample(propSchema.items)]; + case 'object': + return {}; + default: + return null; + } +}`; + +const validationExample = `function validateSpecification(spec: any): void { + // Basic validation + if (!spec.openapi) { + throw new Error('OpenAPI version is required'); + } + + if (!spec.info?.title) { + throw new Error('API title is required'); + } + + if (!spec.info?.version) { + throw new Error('API version is required'); + } + + // Validate paths + for (const [path, pathObj] of Object.entries(spec.paths)) { + if (!path.startsWith('/')) { + throw new Error(\`Path must start with '/': \${path}\`); + } + + for (const [method, operation] of Object.entries(pathObj)) { + if (!operation.responses) { + throw new Error(\`Operation \${method.toUpperCase()} \${path} must have responses\`); + } + } + } + + console.log('✅ OpenAPI specification validation passed'); +}`; + +const htmlGenerationExample = `function generateHTMLDocumentation(spec: any): string { + return \` + + + + + + \${spec.info.title} - API Documentation + + + + +
    + + + + +\`; +}`; + +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +export default function AdvancedFeatures() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('5. Multiple Output Formats')}

    +

    + + Multiple output formats allow you to generate OpenAPI + specifications in JSON, YAML, and HTML formats. This + flexibility ensures compatibility with different tools and + enables both machine-readable specifications and human-friendly + documentation. + +

    + + {advancedConfigExample} + + + {formatGenerationExample} + + + {exampleGenerationExample} + + + {validationExample} + + + {htmlGenerationExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx new file mode 100644 index 0000000..52302fa --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx @@ -0,0 +1,313 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C } from '../index.js'; +import Code from '../Code.js'; + +const basicPluginExample = `// plugins/openapi-spec.ts +import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface OpenAPIConfig { + output: string; + info?: { + title?: string; + version?: string; + description?: string; + contact?: { + name?: string; + email?: string; + url?: string; + }; + license?: { + name?: string; + url?: string; + }; + }; + servers?: Array<{ + url: string; + description?: string; + }>; + security?: { + apiKey?: boolean; + bearer?: boolean; + oauth2?: boolean; + }; + endpoints?: { + crud?: boolean; + custom?: Record; + }; +} + +export default async function generateOpenAPISpec( + props: PluginProps<{ config: OpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + // Validate configuration + if (!config.output) { + throw new Error('OpenAPI plugin requires "output" configuration'); + } + + // Generate OpenAPI specification + const spec = generateSpecification(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, JSON.stringify(spec, null, 2), 'utf8'); + + console.log(\`✅ Generated OpenAPI specification: \${outputPath}\`); +}`; + +const schemaGenerationExample = `function generateSpecification(schema: any, config: OpenAPIConfig) { + const spec: any = { + openapi: '3.0.3', + info: { + title: config.info?.title || 'API Documentation', + version: config.info?.version || '1.0.0', + description: config.info?.description || 'Generated API documentation', + ...config.info?.contact && { contact: config.info.contact }, + ...config.info?.license && { license: config.info.license } + }, + servers: config.servers || [ + { url: 'http://localhost:3000', description: 'Development server' } + ], + paths: {}, + components: { + schemas: {}, + securitySchemes: {} + } + }; + + // Generate schemas from models and types + if (schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + spec.components.schemas[name] = generateModelSchema(model); + } + } + + if (schema.type) { + for (const [name, type] of Object.entries(schema.type)) { + spec.components.schemas[name] = generateTypeSchema(type); + } + } + + if (schema.enum) { + for (const [name, enumDef] of Object.entries(schema.enum)) { + spec.components.schemas[name] = generateEnumSchema(enumDef); + } + } + + // Generate security schemes + if (config.security) { + generateSecuritySchemes(spec, config.security); + } + + // Generate CRUD endpoints + if (config.endpoints?.crud && schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + generateCRUDEndpoints(spec, name, model); + } + } + + // Add custom endpoints + if (config.endpoints?.custom) { + for (const [path, operation] of Object.entries(config.endpoints.custom)) { + spec.paths[path] = operation; + } + } + + return spec; +}`; + +const modelSchemaExample = `function generateModelSchema(model: any): any { + const schema: any = { + type: 'object', + properties: {}, + required: [] + }; + + if (model.columns) { + for (const column of model.columns) { + const property = generatePropertySchema(column); + schema.properties[column.name] = property; + + if (column.required) { + schema.required.push(column.name); + } + } + } + + return schema; +} + +function generateTypeSchema(type: any): any { + const schema: any = { + type: 'object', + properties: {}, + required: [] + }; + + if (type.columns) { + for (const column of type.columns) { + const property = generatePropertySchema(column); + schema.properties[column.name] = property; + + if (column.required) { + schema.required.push(column.name); + } + } + } + + return schema; +} + +function generateEnumSchema(enumDef: any): any { + const values = Object.values(enumDef); + return { + type: 'string', + enum: values, + example: values[0] + }; +}`; + +const propertySchemaExample = `function generatePropertySchema(column: any): any { + const property: any = {}; + + // Map idea types to OpenAPI types + switch (column.type) { + case 'String': + property.type = 'string'; + break; + case 'Number': + property.type = 'number'; + break; + case 'Integer': + property.type = 'integer'; + break; + case 'Boolean': + property.type = 'boolean'; + break; + case 'Date': + property.type = 'string'; + property.format = 'date-time'; + break; + case 'JSON': + property.type = 'object'; + break; + default: + // Reference to another schema + property.$ref = \`#/components/schemas/\${column.type}\`; + } + + // Handle arrays + if (column.multiple) { + property = { + type: 'array', + items: property + }; + } + + // Add validation from attributes + if (column.attributes) { + addValidationRules(property, column.attributes); + } + + return property; +} + +function addValidationRules(property: any, attributes: any): void { + // String validations + if (attributes.minLength) { + property.minLength = attributes.minLength; + } + if (attributes.maxLength) { + property.maxLength = attributes.maxLength; + } + if (attributes.pattern) { + property.pattern = attributes.pattern; + } + + // Number validations + if (attributes.minimum) { + property.minimum = attributes.minimum; + } + if (attributes.maximum) { + property.maximum = attributes.maximum; + } + + // Examples and descriptions + if (attributes.example) { + property.example = attributes.example; + } + if (attributes.description) { + property.description = attributes.description; + } + + // Format validations + if (attributes.format) { + property.format = attributes.format; + } +}`; + + +export default function BasicImplementation() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('2. Basic Implementation')}

    +

    + + The basic implementation provides the foundation for generating + OpenAPI specifications from + .idea + schema files. This section covers the core plugin structure, + configuration interface, and essential generation functions + needed to create functional API documentation. + +

    +

    + + Let's start with a basic OpenAPI specification generator: + +

    + +

    {_('2.1. Plugin Structure')}

    +

    + + The plugin structure defines the main entry point and + configuration interface for the OpenAPI generator. This + includes type definitions for configuration options, the + primary plugin function, and the core specification + generation logic. + +

    + + {basicPluginExample} + + + {schemaGenerationExample} + + +

    {_('2.2. Schema Generation')}

    +

    + + Schema generation transforms + .idea + model and type definitions into OpenAPI-compliant schema + objects. This process includes mapping data types, handling + validation rules, and creating proper JSON Schema structures + that integrate with OpenAPI tooling. + +

    + + {modelSchemaExample} + + + {propertySchemaExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx new file mode 100644 index 0000000..a3193f5 --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx @@ -0,0 +1,285 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const documentationBestPracticesExample = `// Always include detailed descriptions +function generateModelSchema(model: any): any { + const schema: any = { + type: 'object', + description: model.description || \`\${model.name} entity\`, + properties: {}, + required: [] + }; + + // Add property descriptions + if (model.columns) { + for (const column of model.columns) { + const property = generatePropertySchema(column); + + // Add description from attributes or generate one + if (column.attributes?.description) { + property.description = column.attributes.description; + } else { + property.description = generatePropertyDescription(column); + } + + schema.properties[column.name] = property; + } + } + + return schema; +} + +function generatePropertyDescription(column: any): string { + const descriptions: Record = { + id: 'Unique identifier', + email: 'Email address', + name: 'Full name', + created: 'Creation timestamp', + updated: 'Last update timestamp', + active: 'Active status flag' + }; + + return descriptions[column.name] || \`\${column.name} field\`; +}`; + +const errorResponsesExample = `function generateErrorResponses(): any { + return { + '400': { + description: 'Bad Request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', description: 'Error message' }, + code: { type: 'string', description: 'Error code' }, + errors: { + type: 'object', + additionalProperties: { type: 'string' }, + description: 'Field-specific errors' + } + }, + required: ['error'] + } + } + } + }, + '401': { + description: 'Unauthorized', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Authentication required' } + } + } + } + } + }, + '403': { + description: 'Forbidden', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Insufficient permissions' } + } + } + } + } + }, + '404': { + description: 'Not Found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Resource not found' } + } + } + } + } + }, + '500': { + description: 'Internal Server Error', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Internal server error' } + } + } + } + } + } + }; +}`; + +const securityBestPracticesExample = `function addSecurityToEndpoints(spec: any): void { + // Add security requirements to all endpoints + for (const [path, pathObj] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(pathObj)) { + // Skip public endpoints + if (isPublicEndpoint(path, method)) { + continue; + } + + // Add appropriate security scheme + if (!operation.security) { + operation.security = [{ BearerAuth: [] }]; + } + } + } +} + +function isPublicEndpoint(path: string, method: string): boolean { + const publicEndpoints = [ + { path: '/auth/login', method: 'post' }, + { path: '/auth/register', method: 'post' }, + { path: '/health', method: 'get' } + ]; + + return publicEndpoints.some(endpoint => + endpoint.path === path && endpoint.method === method.toLowerCase() + ); +}`; + +const validationExamplesExample = `function addValidationExamples(spec: any): void { + // Add validation examples to request bodies + for (const [path, pathObj] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(pathObj)) { + if (operation.requestBody?.content?.['application/json']?.schema) { + const schema = operation.requestBody.content['application/json'].schema; + + // Add valid example + if (!schema.example) { + schema.example = generateValidExample(schema); + } + + // Add examples for validation errors + if (!schema.examples) { + schema.examples = { + valid: { + summary: 'Valid request', + value: generateValidExample(schema) + }, + invalid: { + summary: 'Invalid request (validation errors)', + value: generateInvalidExample(schema) + } + }; + } + } + } + } +} + +function generateValidExample(schema: any): any { + // Generate a valid example based on schema + if (schema.$ref) { + return { id: '123', name: 'Example' }; + } + + const example: any = {}; + for (const [propName, propSchema] of Object.entries(schema.properties || {})) { + example[propName] = generatePropertyExample(propSchema); + } + + return example; +} + +function generateInvalidExample(schema: any): any { + // Generate an invalid example to show validation errors + const example: any = {}; + for (const [propName, propSchema] of Object.entries(schema.properties || {})) { + // Intentionally create invalid values + if (propSchema.type === 'string' && propSchema.format === 'email') { + example[propName] = 'invalid-email'; + } else if (propSchema.type === 'string' && propSchema.minLength) { + example[propName] = 'x'; // Too short + } else if (propSchema.type === 'number' && propSchema.minimum) { + example[propName] = propSchema.minimum - 1; // Below minimum + } else { + example[propName] = null; // Invalid type + } + } + + return example; +}`; + +export default function BestPractices() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('7. Best Practices')}

    +

    + + Best practices ensure your generated OpenAPI specifications + are comprehensive, maintainable, and follow industry + standards. These guidelines cover documentation quality, + error handling, security implementation, and validation + strategies. + +

    + +

    {_('7.1. Comprehensive Documentation')}

    +

    + + Comprehensive documentation practices ensure your API + specifications provide clear, detailed information for both + human readers and automated tools. This includes proper + descriptions, examples, and consistent formatting throughout + the specification. + +

    + + {documentationBestPracticesExample} + + +

    {_('7.2. Consistent Error Responses')}

    +

    + + Consistent error responses provide standardized error + handling across your API endpoints. This approach ensures + predictable error formats that client applications can + handle reliably, improving the overall developer experience. + +

    + + {errorResponsesExample} + + +

    {_('7.3. Security Best Practices')}

    +

    + + Security best practices ensure your API documentation + properly represents authentication and authorization + requirements. This includes applying appropriate security + schemes to endpoints and documenting access control patterns. + +

    + + {securityBestPracticesExample} + + +

    {_('7.4. Validation and Testing')}

    +

    + + Validation and testing practices ensure your generated + OpenAPI specifications are accurate and functional. This + includes adding validation examples, testing request/response + formats, and verifying specification compliance. + +

    + + {validationExamplesExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx new file mode 100644 index 0000000..564090e --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx @@ -0,0 +1,109 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C, SS } from '../index.js'; + +export default function Conclusion() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('Conclusion')}

    +

    + + This OpenAPI Specification Generator plugin provides a + comprehensive solution for generating API documentation from + .idea schema files. Key features include: + +

    +
      +
    • + Complete OpenAPI 3.0 Support: + + Generates fully compliant specifications + +
    • +
    • + Automatic CRUD Endpoints: + + Creates standard REST endpoints for models + +
    • +
    • + Security Integration: + + Supports multiple authentication schemes + +
    • +
    • + Multiple Output Formats: + + JSON, YAML, and HTML documentation + +
    • +
    • + Validation and Examples: + + Includes request/response examples and validation + +
    • +
    • + Extensible Configuration: + + Highly customizable for different use cases + +
    • +
    + +

    + + The plugin follows TypeScript best practices and provides + comprehensive error handling, making it suitable for + production use in API development workflows. + +

    + +

    {_('Next Steps')}

    +
      +
    • + Extend Schema Mapping: + + Add support for more complex schema relationships + +
    • +
    • + Custom Templates: + + Implement custom documentation templates + +
    • +
    • + Integration Testing: + + Add automated testing for generated specifications + +
    • +
    • + Performance Optimization: + + Implement caching and incremental generation + +
    • +
    • + Plugin Ecosystem: + + Create complementary plugins for API testing and + client generation + +
    • +
    + +

    + + This tutorial provides a solid foundation for generating + professional API documentation that can be used with tools + like Swagger UI, Postman, and various code generators. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx new file mode 100644 index 0000000..baaced1 --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx @@ -0,0 +1,118 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const configurationExample = `// schema.idea +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec.json" + info { + title "User Management API" + version "2.0.0" + description "Comprehensive user management system API" + contact { + name "API Support" + email "support@example.com" + url "https://example.com/support" + } + license { + name "MIT" + url "https://opensource.org/licenses/MIT" + } + } + servers [ + { + url "https://api.example.com/v2" + description "Production server" + } + { + url "https://staging-api.example.com/v2" + description "Staging server" + } + { + url "http://localhost:3000" + description "Development server" + } + ] + security { + apiKey true + bearer true + oauth2 false + } + endpoints { + crud true + custom { + "/auth/login" { + post { + summary "User login" + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + email { + type "string" + format "email" + } + password { + type "string" + minLength 8 + } + } + required ["email" "password"] + } + } + } + } + responses { + "200" { + description "Login successful" + content { + "application/json" { + schema { + type "object" + properties { + token { + type "string" + } + user { + "$ref" "#/components/schemas/User" + } + } + } + } + } + } + "401" { + description "Invalid credentials" + } + } + } + } + } + } +}`; + +export default function ConfigurationOptions() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('3. Configuration Options')}

    +

    + + Configuration options control how the OpenAPI specification + is generated, including output formats, API metadata, server + definitions, and security schemes. Proper configuration + ensures the generated documentation meets your specific + requirements and integrates with your development workflow. + +

    + + {configurationExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx new file mode 100644 index 0000000..8f50aed --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx @@ -0,0 +1,26 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('OpenAPI Specification Generator Plugin Tutorial')}

    +

    + + This tutorial demonstrates how to create a plugin for + + @stackpress/idea-transformer + + that generates OpenAPI 3.0 specifications from + + .idea + + schema files. The plugin will create comprehensive API + documentation with endpoints, schemas, and validation rules. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx new file mode 100644 index 0000000..6f93d7f --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx @@ -0,0 +1,95 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('1. Overview')}

    +

    + + OpenAPI (formerly Swagger) specifications provide a standard + way to document REST APIs. This plugin transforms your + .idea schema definitions into comprehensive API + documentation that follows industry standards and integrates + seamlessly with existing API development workflows. + +

    +

    + + This plugin will: + +

    +
      +
    • + + Generate OpenAPI 3.0 compliant specifications + +
    • +
    • + + Create schemas from idea models and types + +
    • +
    • + + Generate CRUD endpoints for models + +
    • +
    • + + Include validation rules and examples + +
    • +
    • + + Support custom endpoints and operations + +
    • +
    • + + Generate security schemes and authentication + +
    • +
    + +

    {_('What You\'ll Learn')}

    +

    + + This section outlines the key concepts and skills you'll + acquire through this tutorial. Understanding these fundamentals + will enable you to create robust API documentation that serves + both developers and automated tooling. + +

    +
      +
    • + + Processing idea schemas for API documentation + +
    • +
    • + + OpenAPI 3.0 specification structure + +
    • +
    • + + Schema generation and validation + +
    • +
    • + + Endpoint documentation patterns + +
    • +
    • + + Security and authentication schemes + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx new file mode 100644 index 0000000..67431e4 --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx @@ -0,0 +1,262 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C } from '../index.js'; +import Code from '../Code.js'; + +const securitySchemesExample = +`function generateSecuritySchemes(spec: any, security: any): void { + if (security.apiKey) { + spec.components.securitySchemes.ApiKeyAuth = { + type: 'apiKey', + in: 'header', + name: 'X-API-Key' + }; + } + + if (security.bearer) { + spec.components.securitySchemes.BearerAuth = { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT' + }; + } + + if (security.oauth2) { + spec.components.securitySchemes.OAuth2 = { + type: 'oauth2', + flows: { + authorizationCode: { + authorizationUrl: 'https://example.com/oauth/authorize', + tokenUrl: 'https://example.com/oauth/token', + scopes: { + read: 'Read access', + write: 'Write access', + admin: 'Admin access' + } + } + } + }; + } +}`; + +const crudEndpointsExample = +`function generateCRUDEndpoints(spec: any, modelName: string, model: any): void { + const resourcePath = \`/\${modelName.toLowerCase()}s\`; + const itemPath = \`\${resourcePath}/{id}\`; + + // GET /resources - List all + spec.paths[resourcePath] = { + get: { + summary: \`List all \${modelName}s\`, + tags: [modelName], + parameters: [ + { + name: 'page', + in: 'query', + schema: { type: 'integer', minimum: 1, default: 1 }, + description: 'Page number' + }, + { + name: 'limit', + in: 'query', + schema: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + description: 'Items per page' + }, + { + name: 'sort', + in: 'query', + schema: { type: 'string' }, + description: 'Sort field' + }, + { + name: 'order', + in: 'query', + schema: { type: 'string', enum: ['asc', 'desc'], default: 'asc' }, + description: 'Sort order' + } + ], + responses: { + '200': { + description: \`List of \${modelName}s\`, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + data: { + type: 'array', + items: { $ref: \`#/components/schemas/\${modelName}\` } + }, + pagination: { + type: 'object', + properties: { + page: { type: 'integer' }, + limit: { type: 'integer' }, + total: { type: 'integer' }, + pages: { type: 'integer' } + } + } + } + } + } + } + } + }, + security: [{ BearerAuth: [] }] + }, + post: { + summary: \`Create a new \${modelName}\`, + tags: [modelName], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + responses: { + '201': { + description: \`\${modelName} created successfully\`, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + '400': { + description: 'Validation error', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string' }, + errors: { + type: 'object', + additionalProperties: { type: 'string' } + } + } + } + } + } + } + }, + security: [{ BearerAuth: [] }] + } + }; + + // GET /resources/{id} - Get by ID + spec.paths[itemPath] = { + get: { + summary: \`Get \${modelName} by ID\`, + tags: [modelName], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'string' }, + description: \`\${modelName} ID\` + } + ], + responses: { + '200': { + description: \`\${modelName} details\`, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + '404': { + description: \`\${modelName} not found\` + } + }, + security: [{ BearerAuth: [] }] + }, + put: { + summary: \`Update \${modelName}\`, + tags: [modelName], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'string' }, + description: \`\${modelName} ID\` + } + ], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + responses: { + '200': { + description: \`\${modelName} updated successfully\`, + content: { + 'application/json': { + schema: { $ref: \`#/components/schemas/\${modelName}\` } + } + } + }, + '404': { + description: \`\${modelName} not found\` + } + }, + security: [{ BearerAuth: [] }] + }, + delete: { + summary: \`Delete \${modelName}\`, + tags: [modelName], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'string' }, + description: \`\${modelName} ID\` + } + ], + responses: { + '204': { + description: \`\${modelName} deleted successfully\` + }, + '404': { + description: \`\${modelName} not found\` + } + }, + security: [{ BearerAuth: [] }] + } + }; +}`; + +export default function SchemaProcessing() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('4. Schema Processing')}

    +

    + + Schema processing handles the transformation of + .idea + definitions into OpenAPI components and endpoints. This + includes generating security schemes, creating CRUD endpoints + for models, and handling complex schema relationships and + validations. + +

    + + {securitySchemesExample} + + + {crudEndpointsExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx new file mode 100644 index 0000000..af96c9e --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx @@ -0,0 +1,287 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const circularReferencesExample = `// Problem: Circular references in schemas +// Solution: Use allOf or oneOf patterns + +function handleCircularReferences(spec: any): void { + // Detect and resolve circular references + const visited = new Set(); + + function checkSchema(schema: any, path: string): void { + if (visited.has(path)) { + // Circular reference detected + console.warn(\`Circular reference detected: \${path}\`); + return; + } + + visited.add(path); + + if (schema.$ref) { + const refPath = schema.$ref.replace('#/components/schemas/', ''); + checkSchema(spec.components.schemas[refPath], refPath); + } + + if (schema.properties) { + for (const [propName, propSchema] of Object.entries(schema.properties)) { + checkSchema(propSchema, \`\${path}.\${propName}\`); + } + } + + visited.delete(path); + } + + for (const [name, schema] of Object.entries(spec.components.schemas)) { + checkSchema(schema, name); + } +}`; + +const validationErrorsExample = `// Problem: Generated spec doesn't validate +// Solution: Add comprehensive validation + +function validateOpenAPISpec(spec: any): void { + const errors: string[] = []; + + // Check required fields + if (!spec.openapi) errors.push('Missing openapi version'); + if (!spec.info) errors.push('Missing info object'); + if (!spec.paths) errors.push('Missing paths object'); + + // Validate info object + if (spec.info) { + if (!spec.info.title) errors.push('Missing info.title'); + if (!spec.info.version) errors.push('Missing info.version'); + } + + // Validate paths + if (spec.paths) { + for (const [path, pathObj] of Object.entries(spec.paths)) { + if (!path.startsWith('/')) { + errors.push(\`Path must start with '/': \${path}\`); + } + + for (const [method, operation] of Object.entries(pathObj)) { + if (!operation.responses) { + errors.push(\`Missing responses for \${method.toUpperCase()} \${path}\`); + } + } + } + } + + // Validate components + if (spec.components?.schemas) { + for (const [name, schema] of Object.entries(spec.components.schemas)) { + if (!schema.type && !schema.$ref && !schema.allOf && !schema.oneOf) { + errors.push(\`Schema \${name} missing type definition\`); + } + } + } + + if (errors.length > 0) { + throw new Error(\`OpenAPI validation failed:\\n\${errors.join('\\n')}\`); + } + + console.log('✅ OpenAPI specification validation passed'); +}`; + +const dependenciesExample = `# Install required dependencies +npm install --save-dev yaml swagger-ui-dist + +# For validation +npm install --save-dev swagger-parser + +# For code generation +npm install --save-dev @openapitools/openapi-generator-cli`; + +const performanceOptimizationExample = `// Problem: Large schemas cause performance issues +// Solution: Implement schema optimization + +function optimizeSchema(spec: any): any { + // Remove unused schemas + const usedSchemas = new Set(); + + // Find all schema references + function findReferences(obj: any): void { + if (typeof obj === 'object' && obj !== null) { + if (obj.$ref && obj.$ref.startsWith('#/components/schemas/')) { + const schemaName = obj.$ref.replace('#/components/schemas/', ''); + usedSchemas.add(schemaName); + } + + for (const value of Object.values(obj)) { + findReferences(value); + } + } + } + + findReferences(spec.paths); + + // Remove unused schemas + const optimizedSchemas: any = {}; + for (const schemaName of usedSchemas) { + if (spec.components.schemas[schemaName]) { + optimizedSchemas[schemaName] = spec.components.schemas[schemaName]; + } + } + + return { + ...spec, + components: { + ...spec.components, + schemas: optimizedSchemas + } + }; +}\n`; + +const debugModeExample = `interface DebugOpenAPIConfig extends AdvancedOpenAPIConfig { + debug?: boolean; + logLevel?: 'info' | 'warn' | 'error'; +} + +export default async function generateOpenAPISpecWithDebug( + props: PluginProps<{ config: DebugOpenAPIConfig }> +) { + const { config, schema, transformer } = props; + + if (config.debug) { + console.log('🔍 Debug mode enabled'); + console.log('Schema models:', Object.keys(schema.model || {})); + console.log('Schema types:', Object.keys(schema.type || {})); + console.log('Schema enums:', Object.keys(schema.enum || {})); + } + + try { + const spec = await generateOpenAPISpecification(schema, config); + + if (config.debug) { + console.log('Generated schemas:', Object.keys(spec.components.schemas)); + console.log('Generated paths:', Object.keys(spec.paths)); + } + + // Validate before writing + if (config.validation?.strict) { + await validateOpenAPISpecification(spec); + } + + // Optimize if needed + const optimizedSpec = config.debug ? + await optimizeOpenAPISchema(spec) : spec; + + // Generate outputs + const formats = config.formats || ['json']; + const outputBase = config.output.replace(/\\.[^.]+$/, ''); + + for (const format of formats) { + await generateOpenAPIFormat(optimizedSpec, format, outputBase, transformer); + } + + if (config.debug) { + console.log('✅ OpenAPI generation completed successfully'); + } + + } catch (error) { + console.error('❌ OpenAPI generation failed:', error.message); + if (config.debug) { + console.error('Stack trace:', error.stack); + } + throw error; + } +}\n`; + +export default function Troubleshooting() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('8. Troubleshooting')}

    +

    + + This section addresses common issues encountered when + generating OpenAPI specifications and provides solutions + for debugging and resolving problems. Understanding these + troubleshooting techniques helps ensure reliable + specification generation. + +

    + +

    {_('8.1. Common Issues')}

    +

    + + Common issues include schema reference errors, validation + failures, and performance problems with large specifications. + These problems typically arise from circular references, + invalid configurations, or missing dependencies. + +

    + +

    {_('8.1.1. Schema Reference Errors')}

    +

    + + Schema reference errors occur when the generator encounters + circular dependencies or invalid references between schema + components. These issues can break the specification + generation process and require careful handling of schema + relationships. + +

    + + {circularReferencesExample} + + +

    {_('8.1.2. Invalid OpenAPI Format')}

    +

    + + Invalid OpenAPI format errors occur when the generated + specification doesn't conform to OpenAPI standards. These + validation failures can prevent the specification from + working with OpenAPI tools and require comprehensive + validation during generation. + +

    + + {validationErrorsExample} + + +

    {_('8.1.3. Missing Dependencies')}

    +

    + + Missing dependencies can cause the plugin to fail during + execution or limit available features. Ensuring all required + packages are installed and properly configured is essential + for reliable operation. + +

    + + {dependenciesExample} + + +

    {_('8.1.4. Performance Issues')}

    +

    + + Performance issues can occur when generating specifications + for large schemas with many models and complex relationships. + Optimization techniques help maintain reasonable generation + times and manageable output file sizes. + +

    + + {performanceOptimizationExample} + + +

    {_('8.2. Debug Mode')}

    +

    + + Debug mode provides detailed logging and diagnostic + information during specification generation. This feature + helps identify issues, understand the generation process, + and optimize plugin configuration for better results. + +

    + + {debugModeExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx new file mode 100644 index 0000000..e400800 --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx @@ -0,0 +1,246 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C } from '../index.js'; +import Code from '../Code.js'; + +//code examples +const basicUsageExample = `// schema.idea +enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @unique @format("email") + name String @minLength(2) @maxLength(100) + role UserRole @default("USER") + active Boolean @default(true) + created Date @default("now()") + updated Date @default("updated()") +} + +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec.json" + info { + title "User API" + version "1.0.0" + description "User management API" + } + endpoints { + crud true + } + security { + bearer true + } +}`; + +const advancedUsageExample = `// schema.idea +plugin "./plugins/openapi-spec.js" { + output "./docs/api-spec" + formats ["json" "yaml" "html"] + info { + title "E-commerce API" + version "2.1.0" + description "Comprehensive e-commerce platform API" + contact { + name "API Team" + email "api@ecommerce.com" + url "https://ecommerce.com/api-support" + } + license { + name "Apache 2.0" + url "https://www.apache.org/licenses/LICENSE-2.0.html" + } + } + servers [ + { + url "https://api.ecommerce.com/v2" + description "Production server" + } + { + url "https://staging-api.ecommerce.com/v2" + description "Staging server" + } + ] + security { + apiKey true + bearer true + oauth2 true + } + endpoints { + crud true + custom { + "/auth/login" { + post { + summary "Authenticate user" + tags ["Authentication"] + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + email { type "string" format "email" } + password { type "string" minLength 8 } + remember { type "boolean" default false } + } + required ["email" "password"] + } + } + } + } + responses { + "200" { + description "Login successful" + content { + "application/json" { + schema { + type "object" + properties { + token { type "string" } + refreshToken { type "string" } + expiresIn { type "integer" } + user { "$ref" "#/components/schemas/User" } + } + } + } + } + } + "401" { + description "Invalid credentials" + content { + "application/json" { + schema { + type "object" + properties { + error { type "string" } + code { type "string" } + } + } + } + } + } + } + } + } + "/auth/refresh" { + post { + summary "Refresh access token" + tags ["Authentication"] + requestBody { + required true + content { + "application/json" { + schema { + type "object" + properties { + refreshToken { type "string" } + } + required ["refreshToken"] + } + } + } + } + responses { + "200" { + description "Token refreshed" + content { + "application/json" { + schema { + type "object" + properties { + token { type "string" } + expiresIn { type "integer" } + } + } + } + } + } + } + } + } + } + } + validation { + strict true + examples true + } +}`; + +const cliIntegrationExample = `# Generate OpenAPI specification +npm run transform + +# Serve documentation locally +npx swagger-ui-serve docs/api-spec.json + +# Validate specification +npx swagger-codegen validate -i docs/api-spec.json + +# Generate client SDKs +npx swagger-codegen generate -i docs/api-spec.json -l typescript-fetch -o ./sdk/typescript +npx swagger-codegen generate -i docs/api-spec.json -l python -o ./sdk/python`; + + +export default function UsageExamples() { + //hooks + const { _ } = useLanguage(); + + return ( +
    +

    {_('6. Usage Examples')}

    +

    + + Usage examples demonstrate practical applications of the + OpenAPI generator plugin with real-world scenarios. These + examples show how to configure the plugin for different + use cases and integrate the generated documentation into + your development workflow. + +

    + +

    {_('6.1. Basic Usage')}

    +

    + + Basic usage examples show the fundamental configuration + needed to generate OpenAPI specifications from simple + .idea + schemas. This includes model definitions, plugin + configuration, and the resulting API documentation structure. + +

    + + {basicUsageExample} + + +

    {_('6.2. Advanced Configuration')}

    +

    + + Advanced configuration demonstrates comprehensive plugin + setup with multiple output formats, detailed API metadata, + custom endpoints, and security schemes. This example shows + how to create production-ready API documentation with full + feature coverage. + +

    + + {advancedUsageExample} + + +

    {_('6.3. CLI Integration')}

    +

    + + CLI integration shows how to incorporate the OpenAPI + generator into your development workflow using command-line + tools. This includes generating specifications, serving + documentation locally, and integrating with API development + tools. + +

    + + {cliIntegrationExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx new file mode 100644 index 0000000..59b80c4 --- /dev/null +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx @@ -0,0 +1,10 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Overview } from './Overview.js'; +export { default as BasicImplementation } from './BasicImplementation.js'; +export { default as ConfigurationOptions } from './ConfigurationOptions.js'; +export { default as SchemaProcessing } from './SchemaProcessing.js'; +export { default as AdvancedFeatures } from './AdvancedFeatures.js'; +export { default as UsageExamples } from './UsageExamples.js'; +export { default as BestPractices } from './BestPractices.js'; +export { default as Troubleshooting } from './Troubleshooting.js'; +export { default as Conclusion } from './Conclusion.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/parser/api-references/ast.tsx b/packages/www/plugins/docs/components/parser/api-references/ast.tsx new file mode 100644 index 0000000..9f07ba2 --- /dev/null +++ b/packages/www/plugins/docs/components/parser/api-references/ast.tsx @@ -0,0 +1,1002 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, H3, C, SS, Nav } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +const examples = [ + `import { + SchemaTree, + EnumTree, + ModelTree, + TypeTree, + PropTree, + PluginTree, + UseTree +} from '@stackpress/idea-parser';`, + `import { SchemaTree, Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +SchemaTree.definitions(lexer); + +// Lexer now has definitions for all schema constructs: +// enum, prop, type, model, plugin, use keywords and structures`, + `import { SchemaTree } from '@stackpress/idea-parser'; + +const schemaCode = \` +plugin "./database" { + provider "postgresql" +} + +enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +} + +prop Text { type "text" } + +model User { + id String @id + name String @field.input(Text) + status Status +} +\`; + +const ast = SchemaTree.parse(schemaCode); +console.log(ast.type); // 'Program' +console.log(ast.kind); // 'schema' +console.log(ast.body.length); // 4 (plugin, enum, prop, model)`, + `import { SchemaTree } from '@stackpress/idea-parser'; + +const tree = new SchemaTree(); +const schemaCode = 'enum Status { ACTIVE "Active" }'; + +const result = tree.parse(schemaCode, 0); +console.log(result.body[0].kind); // 'enum'`, + `import { EnumTree, Lexer } from '@stackpress/idea-parser'; + +const lexer = new Lexer(); +EnumTree.definitions(lexer); + +// Adds 'EnumWord' token definition for 'enum' keyword`, + `import { EnumTree } from '@stackpress/idea-parser'; + +const enumCode = \`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`; + +const ast = EnumTree.parse(enumCode); +console.log(ast.kind); // 'enum' +console.log(ast.declarations[0].id.name); // 'Roles' +console.log(ast.declarations[0].init.properties.length); // 3 +console.log(ast.declarations[0].init.properties[0].key.name); // 'ADMIN' +console.log(ast.declarations[0].init.properties[0].value.value); // 'Admin'`, + `const tree = new EnumTree(); +tree._lexer.load('enum Status { ACTIVE "Active" INACTIVE "Inactive" }'); + +const enumToken = tree.enum(); +console.log(enumToken.declarations[0].id.name); // 'Status' +console.log(enumToken.declarations[0].init.properties[0].key.name); // 'ACTIVE' +console.log(enumToken.declarations[0].init.properties[0].value.value); // 'Active'`, + `// Inside enum parsing, after opening brace +const property = tree.property(); +console.log(property.key.name); // e.g., 'ADMIN' +console.log(property.value.value); // e.g., 'Admin'`, + `import { ModelTree } from '@stackpress/idea-parser'; + +const modelCode = \`model User @label("User" "Users") { + id String @label("ID") @id @default("nanoid(20)") + username String @label("Username") @searchable @field.input(Text) @is.required + password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide + role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) + address Address? @label("Address") @list.hide + age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) + active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno + created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) +}\`; + +const ast = ModelTree.parse(modelCode); +console.log(ast.kind); // 'model' +console.log(ast.mutable); // false (because of '!' modifier) +console.log(ast.declarations[0].id.name); // 'User'`, + `const tree = new ModelTree(); +tree._lexer.load('model User { id String @id }'); + +const modelToken = tree.model(); +console.log(modelToken.kind); // 'model' +console.log(modelToken.mutable); // false (immutable due to '!')`, + `import { TypeTree } from '@stackpress/idea-parser'; + +const typeCode = \`type Address @label("Address" "Addresses") { + street String @field.input @is.required + city String @field.input @is.required + country String @field.select + postal String @field.input +}\`; + +const ast = TypeTree.parse(typeCode); +console.log(ast.kind); // 'type' +console.log(ast.mutable); // true (mutable by default) +console.log(ast.declarations[0].id.name); // 'Address'`, + `const tree = new TypeTree(); +tree._lexer.load('type Address { street String city String }'); + +const typeToken = tree.type(); +console.log(typeToken.kind); // 'type' +console.log(typeToken.mutable); // true (default for types)`, + `// Inside type parsing +const property = tree.property(); +console.log(property.key.name); // e.g., 'street' +console.log(property.value); // Object containing type and attributes`, + `// For parsing generic type parameters +const parameter = tree.parameter(); +console.log(parameter.key.name); // Parameter name +console.log(parameter.value); // Parameter type/constraint`, + `import { PropTree } from '@stackpress/idea-parser'; + +const propCode = \`prop EmailInput { + type "email" + format "email" + placeholder "Enter your email" + required true +}\`; + +const ast = PropTree.parse(propCode); +console.log(ast.kind); // 'prop' +console.log(ast.declarations[0].id.name); // 'EmailInput'`, + `const tree = new PropTree(); +tree._lexer.load('prop Text { type "text" format "lowercase" }'); + +const propToken = tree.prop(); +console.log(propToken.kind); // 'prop' +console.log(propToken.declarations[0].id.name); // 'Text'`, + `import { PluginTree } from '@stackpress/idea-parser'; + +const pluginCode = \`plugin "./database-plugin" { + provider "postgresql" + url env("DATABASE_URL") + previewFeatures ["fullTextSearch"] +}\`; + +const ast = PluginTree.parse(pluginCode); +console.log(ast.kind); // 'plugin' +console.log(ast.declarations[0].id.name); // './database-plugin'`, + `const tree = new PluginTree(); +tree._lexer.load('plugin "./custom" { provider "custom-provider" }'); + +const pluginToken = tree.plugin(); +console.log(pluginToken.kind); // 'plugin' +console.log(pluginToken.declarations[0].id.name); // './custom'`, + `import { UseTree } from '@stackpress/idea-parser'; + +const useCode = 'use "./shared/types.idea"'; + +const ast = UseTree.parse(useCode); +console.log(ast.type); // 'ImportDeclaration' +console.log(ast.source.value); // './shared/types.idea'`, + `const tree = new UseTree(); +tree._lexer.load('use "./another.idea"'); + +const useToken = tree.use(); +console.log(useToken.type); // 'ImportDeclaration' +console.log(useToken.source.value); // './another.idea'`, + `import { EnumTree, ModelTree, TypeTree } from '@stackpress/idea-parser'; + +// Parse individual enum +const enumAST = EnumTree.parse(\`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`); + +// Parse individual model +const modelAST = ModelTree.parse(\`model User { + id String @id + username String @is.required +}\`); + +// Parse individual type +const typeAST = TypeTree.parse(\`type Address { + street String + city String +}\`);`, + `import { EnumTree, Compiler } from '@stackpress/idea-parser'; + +// Parse and compile in one step +const enumAST = EnumTree.parse(\`enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +}\`); +const [enumName, enumConfig] = Compiler.enum(enumAST); + +console.log(enumName); // 'Status' +console.log(enumConfig); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`, + `import { AbstractTree, Lexer } from '@stackpress/idea-parser'; +import type { DeclarationToken } from '@stackpress/idea-parser'; + +class CustomTree extends AbstractTree { + static definitions(lexer: Lexer) { + super.definitions(lexer); + // Add custom token definitions + lexer.define('CustomKeyword', (code, index) => { + // Custom token reader implementation + }); + return lexer; + } + + static parse(code: string, start = 0) { + return new this().parse(code, start); + } + + parse(code: string, start = 0): DeclarationToken { + this._lexer.load(code, start); + return this.customDeclaration(); + } + + customDeclaration(): DeclarationToken { + // Custom parsing logic + const keyword = this._lexer.expect('CustomKeyword'); + // ... more parsing logic + + return { + type: 'VariableDeclaration', + kind: 'custom', + start: keyword.start, + end: this._lexer.index, + declarations: [/* ... */] + }; + } +}`, + `import { SchemaTree, Exception } from '@stackpress/idea-parser'; + +try { + // Invalid syntax - missing closing brace + SchemaTree.parse('enum Status { ACTIVE "Active"'); +} catch (error) { + if (error instanceof Exception) { + console.log('Parse error:', error.message); + console.log('Position:', error.start, '-', error.end); + } +}`, + `try { + // Invalid - 'enum' keyword expected but found 'model' + EnumTree.parse('model User { id String }'); +} catch (error) { + console.log('Expected enum but found model'); +}`, + `import { EnumTree } from '@stackpress/idea-parser'; + +try { + // Empty string will throw an error + EnumTree.parse(''); +} catch (error) { + console.log('Error:', error.message); // 'Unexpected end of input' +}`, + `import { ModelTree } from '@stackpress/idea-parser'; + +try { + // Invalid - model names must be capitalized + ModelTree.parse('model user { id String }'); +} catch (error) { + console.log('Expected CapitalIdentifier but got something else'); +}`, + `// This is what happens internally: +import { SchemaTree, Compiler } from '@stackpress/idea-parser'; + +export function parse(code: string) { + const ast = SchemaTree.parse(code); // Parse to AST + return Compiler.schema(ast); // Compile to JSON +} + +export function final(code: string) { + const ast = SchemaTree.parse(code); // Parse to AST + return Compiler.final(ast); // Compile and clean up +}`, + `import { Lexer, SchemaTree } from '@stackpress/idea-parser'; + +// Create and configure lexer once +const lexer = new Lexer(); +SchemaTree.definitions(lexer); + +// Reuse for multiple parses +const tree = new SchemaTree(lexer); + +const result1 = tree.parse(code1); +const result2 = tree.parse(code2); +const result3 = tree.parse(code3);`, + `// Inside tree parsing methods +const checkpoint = this._lexer.clone(); + +try { + // Try to parse optional structure + return this.parseOptionalStructure(); +} catch (error) { + // Restore lexer state and continue + this._lexer = checkpoint; + return this.parseAlternativeStructure(); +}`, + `const enumCode = \`enum Roles { + ADMIN "Admin" + MANAGER "Manager" + USER "User" +}\`; + +const ast = EnumTree.parse(enumCode); +// Produces a complete AST with all three enum values`, + `const modelCode = \`model User @label("User" "Users") { + id String @label("ID") @id @default("nanoid(20)") + username String @label("Username") @searchable @field.input(Text) @is.required + password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide + role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) + address Address? @label("Address") @list.hide + age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) + balance Number[] @label("Balance") @filterable @sortable @field.number() @list.number() @view.number + active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno + created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) + updated Date @label("Updated") @default("updated()") @filterable @sortable @list.date(Pretty) + company Company? @label("My Company") +}\`; + +const ast = ModelTree.parse(modelCode); +// Produces a complete model AST with all columns and attributes` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Syntax Trees'); + const description = _( + 'The AST classes are responsible for parsing specific parts ' + + 'of schema code into Abstract Syntax Trees (ASTs). Each AST ' + + 'class handles a different type of declaration or construct ' + + 'in the schema language.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Syntax Trees')}

    + + The AST classes are responsible for parsing specific parts + of schema code into Abstract Syntax Trees (ASTs). Each AST + class handles a different type of declaration or construct + in the schema language. + + + {examples[0]} + +
    + +

    {_('SchemaTree')}

    + + Parses complete schema files containing multiple declarations. + + +

    {_('Static Methods')}

    + +

    {_('Setting Up Schema Definitions')}

    + + The following example shows how to configure a lexer for + schema parsing. + + + {examples[1]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + lexer + Lexer + {_('The lexer instance to configure')} + +
    + + {_('Returns')} +
  • + {_('The configured lexer instance.')} +
  • + +

    {_('Parsing Complete Schemas')}

    + + The following example shows how to parse a complete schema file. + + + {examples[2]} + + +

    {_('Parameters')}

    + + + {_('Parameter')} + + + {_('Type')} + + + {_('Description')} + + + code + string + {_('The complete schema code to parse')} + +
    + + {_('Returns')} +
  • + {_('A SchemaToken representing the entire parsed schema.')} +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Schema Content')}

    + + The following example shows how to parse schema content with + custom starting position. + + + {examples[3]} + + +

    {_('Parameters')}

    + + {_('Parameter')} + {_('Type')} + {_('Description')} + + code + string + {_('The schema code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + {_('A SchemaToken containing all parsed declarations.')} +
  • + +

    {_('EnumTree')}

    + + Parses enum declarations into AST tokens. + + +

    {_('Static Methods')}

    + +

    {_('Setting Up Enum Definitions')}

    + + The following example shows how to configure a lexer for + enum parsing. + + + {examples[4]} + + +

    {_('Parsing Enum Declarations')}

    + + The following example shows how to parse enum declarations + based on the test fixtures. + + + {examples[5]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The enum declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + + A DeclarationToken representing the parsed enum. + +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Enum Structure')}

    + + The following example shows how to parse the enum structure. + + + {examples[6]} + + + {_('Returns')} +
  • + + A DeclarationToken representing the enum structure. + +
  • + +

    {_('Parsing Enum Properties')}

    + + The following example shows how individual enum properties are parsed. + + + {examples[7]} + + + {_('Returns')} +
  • + + A PropertyToken representing a single enum key-value pair. + +
  • + +

    {_('ModelTree')}

    + + Parses model declarations (extends TypeTree for shared functionality). + + +

    {_('Static Methods')}

    + +

    {_('Parsing Model Declarations')}

    + + The following example shows how to parse model declarations + based on the test fixtures. + + + {examples[8]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The model declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + + A DeclarationToken representing the parsed model. + +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Model Structure')}

    + + The following example shows how to parse the model structure. + + + {examples[9]} + + + {_('Returns')} +
  • + + A DeclarationToken representing the model structure. + +
  • + +

    {_('TypeTree')}

    + + Parses type declarations. + + +

    {_('Static Methods')}

    + +

    {_('Parsing Type Declarations')}

    + + The following example shows how to parse type declarations. + + + {examples[10]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The type declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + + A DeclarationToken representing the parsed type. + +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Type Structure')}

    + + The following example shows how to parse the type structure. + + + {examples[11]} + + + {_('Returns')} +
  • + + A DeclarationToken representing the type structure. + +
  • + +

    {_('Parsing Type Properties')}

    + + The following example shows how type properties (columns) are parsed. + + + {examples[12]} + + + {_('Returns')} +
  • + + A PropertyToken representing a type column definition. + +
  • + +

    {_('Parsing Type Parameters')}

    + + The following example shows how type parameters are parsed. + + + {examples[13]} + + + {_('Returns')} +
  • + nslate + +
  • + +

    {_('PropTree')}

    + + Parses prop (property configuration) declarations. + + +

    {_('Static Methods')}

    + +

    {_('Parsing Prop Declarations')}

    + + The following example shows how to parse prop declarations. + + + {examples[14]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The prop declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + + A DeclarationToken representing the parsed prop. + +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Prop Structure')}

    + + The following example shows how to parse the prop structure. + + + {examples[15]} + + + {_('Returns')} +
  • + + A DeclarationToken representing the prop configuration. + +
  • + +

    {_('PluginTree')}

    + + Parses plugin declarations. + + +

    {_('Static Methods')}

    + +

    {_('Parsing Plugin Declarations')}

    + + The following example shows how to parse plugin declarations. + + + {examples[16]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The plugin declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + {_('A DeclarationToken representing the parsed plugin.')} +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Plugin Structure')}

    + + The following example shows how to parse the plugin structure. + + + {examples[17]} + + + {_('Returns')} +
  • A DeclarationToken representing the plugin configuration.
  • + +

    {_('UseTree')}

    + + Parses use (import) declarations. + + +

    {_('Static Methods')}

    + +

    {_('Parsing Use Declarations')}

    + + The following example shows how to parse use declarations. + + + {examples[18]} + + +

    {_('Parameters')}

    + + Parameter + Type + Description + + code + string + {_('The use declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
  • + {_('An ImportToken representing the parsed use statement.')} +
  • + +

    {_('Methods')}

    + +

    {_('Parsing Use Structure')}

    + + The following example shows how to parse the use structure. + + + {examples[19]} + + + {_('Returns')} +
  • {_('An ImportToken representing the import statement.')}
  • + +

    {_('Usage Patterns')}

    + +

    {_('Parsing Individual Components')}

    + + {examples[20]} + + +

    {_('Using with Compiler')}

    + + {examples[21]} + + +

    {_('Custom AST Classes')}

    + + You can extend AbstractTree to create custom parsers: + + + {examples[22]} + + +

    {_('Error Handling')}

    + + AST classes provide detailed error information when parsing fails: +

    Syntax Errors

    + + {examples[23]} + + +

    {_('Unexpected Tokens')}

    + + {examples[24]} + + +

    {_('Empty Input Handling')}

    + + {examples[25]} + + +

    {_('Invalid Identifiers')}

    + + {examples[26]} + + +

    {_('Integration with Main Functions')}

    + + AST classes are used internally by the main parse and final functions: + + + {examples[27]} + + +

    {_('Performance Considerations')}

    + +

    {_('Lexer Reuse')}

    + + AST classes can share lexer instances for better performance: + + + {examples[28]} + + +

    {_('Cloning for Backtracking')}

    + + AST classes use lexer cloning for safe parsing attempts: + + + {examples[29]} + + +

    {_('Test-Driven Examples')}

    + + Based on the test fixtures, here are real-world examples: + + +

    {_('Enum with Multiple Values')}

    + + {examples[30]} + + +

    {_('Complex Model with Attributes')}

    + + {examples[31]} + + + + This demonstrates the parser's ability to handle: + +
      +
    • Model mutability (! modifier)
    • +
    • Attributes (@label, @id, @default, etc.)
    • +
    • Optional types (Address?, Company?)
    • +
    • Array types (Number[])
    • +
    • Complex attribute parameters (@field.input(Text), @is.clt(80))
    • +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/views/parser/pages/compiler.tsx b/packages/www/plugins/docs/components/parser/api-references/compiler.tsx similarity index 50% rename from packages/www/plugins/docs/views/parser/pages/compiler.tsx rename to packages/www/plugins/docs/components/parser/api-references/compiler.tsx index 0d75bbe..9b73664 100644 --- a/packages/www/plugins/docs/views/parser/pages/compiler.tsx +++ b/packages/www/plugins/docs/components/parser/api-references/compiler.tsx @@ -3,47 +3,17 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav, SS } from '../../../components/index.js'; -import Code from '../../../components/Code.js'; -import Layout from '../../../components/Layout.js'; +import { H1, H2, H3, P, C, Nav } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Compiler'); - const description = _( - 'Compiler class for the parser library' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} +//example code constants +const basicImportExample = `import { Compiler } from '@stackpress/idea-parser';`; -const compilerParams = [ - `import { Compiler } from '@stackpress/idea-parser';`, - `import { Compiler } from '@stackpress/idea-parser'; +const arrayTokenExample = `import { Compiler } from '@stackpress/idea-parser'; // Example array token from parsing ["value1", "value2", "value3"] const arrayToken = { @@ -56,8 +26,9 @@ const arrayToken = { }; const result = Compiler.array(arrayToken); -console.log(result); // ['value1', 'value2', 'value3']`, -`import { Compiler } from '@stackpress/idea-parser'; +console.log(result); // ['value1', 'value2', 'value3']`; + +const dataTokenExample = `import { Compiler } from '@stackpress/idea-parser'; // Compile different types of data tokens const literalResult = Compiler.data({ type: 'Literal', value: 'hello' }); @@ -72,18 +43,26 @@ const objectResult = Compiler.data({ } ] }); -console.log(objectResult); // { name: 'John' }`, -`import { Compiler } from '@stackpress/idea-parser'; +console.log(objectResult); // { name: 'John' }`; -// Example enum token from parsing: enum Status { ACTIVE "Active" INACTIVE "Inactive" } +const enumTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example enum token from parsing: +// enum Status { ACTIVE "Active" INACTIVE "Inactive" } const enumToken = { kind: 'enum', declarations: [{ id: { name: 'Status' }, init: { properties: [ - { key: { name: 'ACTIVE' }, value: { type: 'Literal', value: 'Active' } }, - { key: { name: 'INACTIVE' }, value: { type: 'Literal', value: 'Inactive' } } + { + key: { name: 'ACTIVE' }, + value: { type: 'Literal', value: 'Active' } + }, + { + key: { name: 'INACTIVE' }, + value: { type: 'Literal', value: 'Inactive' } + } ] } }] @@ -91,41 +70,363 @@ const enumToken = { const [name, config] = Compiler.enum(enumToken); console.log(name); // 'Status' -console.log(config); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`, -`import { Compiler } from '@stackpress/idea-parser'; +console.log(config); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`; + +const finalSchemaExample = `import { Compiler } from '@stackpress/idea-parser'; // This method removes prop and use references for a clean final output const finalSchema = Compiler.final(schemaToken); console.log(finalSchema); -// Output will not contain 'prop' or 'use' sections`, +// Output will not contain 'prop' or 'use' sections`; -] +const identifierTokenExample = `import { Compiler } from '@stackpress/idea-parser'; -export function Body() { +// With references provided +const references = { MyProp: { type: 'text' } }; +const result1 = Compiler.identifier({ name: 'MyProp' }, references); +console.log(result1); // { type: 'text' } + +// Without references (returns template string) +const result2 = Compiler.identifier({ name: 'MyProp' }, false); +console.log(result2); // '\${MyProp}' + +// With empty references (throws error) +try { + Compiler.identifier({ name: 'UnknownProp' }, {}); +} catch (error) { + console.log(error.message); // 'Unknown reference UnknownProp' +}`; + +const literalTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +const stringLiteral = Compiler.literal({ type: 'Literal', value: 'hello' }); +console.log(stringLiteral); // 'hello' + +const numberLiteral = Compiler.literal({ type: 'Literal', value: 42 }); +console.log(numberLiteral); // 42 + +const booleanLiteral = Compiler.literal({ type: 'Literal', value: true }); +console.log(booleanLiteral); // true`; + +const modelTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example model token from parsing: +// model User { id String @id name String } +const modelToken = { + kind: 'model', + mutable: false, // model User! would be true + declarations: [{ + id: { name: 'User' }, + init: { + properties: [ + { + key: { name: 'columns' }, + value: { + type: 'ObjectExpression', + properties: [ + { + key: { name: 'id' }, + value: { + type: 'ObjectExpression', + properties: [ + { + key: { name: 'type' }, + value: { type: 'Literal', value: 'String' } + }, + { key: { name: 'attributes' }, value: { /* attributes */ } } + ] + } + } + ] + } + } + ] + } + }] +}; + +const [name, config] = Compiler.model(modelToken); +console.log(name); // 'User' +console.log(config.mutable); // false +console.log(config.columns); // Array of column configurations`; + +const objectTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example object token from parsing { name "John" age 30 } +const objectToken = { + type: 'ObjectExpression', + properties: [ + { key: { name: 'name' }, value: { type: 'Literal', value: 'John' } }, + { key: { name: 'age' }, value: { type: 'Literal', value: 30 } } + ] +}; + +const result = Compiler.object(objectToken); +console.log(result); // { name: 'John', age: 30 }`; + +const pluginTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example plugin token from parsing: +// plugin "./database" { provider "postgresql" } +const pluginToken = { + kind: 'plugin', + declarations: [{ + id: { name: './database' }, + init: { + properties: [ + { + key: { name: 'provider' }, + value: { type: 'Literal', value: 'postgresql' } + } + ] + } + }] +}; + +const [name, config] = Compiler.plugin(pluginToken); +console.log(name); // './database' +console.log(config); // { provider: 'postgresql' }`; + +const propTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example prop token from parsing: +// prop Text { type "text" format "lowercase" } +const propToken = { + kind: 'prop', + declarations: [{ + id: { name: 'Text' }, + init: { + properties: [ + { key: { name: 'type' }, value: { type: 'Literal', value: 'text' } }, + { + key: { name: 'format' }, + value: { type: 'Literal', value: 'lowercase' } + } + ] + } + }] +}; + +const [name, config] = Compiler.prop(propToken); +console.log(name); // 'Text' +console.log(config); // { type: 'text', format: 'lowercase' }`; + +const schemaDeclarationExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Compile a complete schema with all declaration types +const schemaConfig = Compiler.schema(schemaToken); +console.log(schemaConfig); +// Output contains: { enum: {...}, prop: {...}, type: {...}, model: {...}, plugin: {...}, use: [...] } + +// Compile with finalization (resolves references) +const finalizedConfig = Compiler.schema(schemaToken, true); +console.log(finalizedConfig); +// References are resolved in the output`; + +const typeTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example type token from parsing: +// type Address { street String city String } +const typeToken = { + kind: 'type', + mutable: true, // type Address (mutable) vs type Address! (immutable) + declarations: [{ + id: { name: 'Address' }, + init: { + properties: [ + { + key: { name: 'columns' }, + value: { + type: 'ObjectExpression', + properties: [ + { + key: { name: 'street' }, + value: { + type: 'ObjectExpression', + properties: [ + { key: { name: 'type' }, value: { type: 'Literal', value: 'String' } } + ] + } + } + ] + } + } + ] + } + }] +}; + +const [name, config] = Compiler.type(typeToken); +console.log(name); // 'Address' +console.log(config.mutable); // true +console.log(config.columns); // Array of column configurations`; + +const useTokenExample = `import { Compiler } from '@stackpress/idea-parser'; + +// Example use token from parsing: use "./another.idea" +const useToken = { + type: 'ImportDeclaration', + source: { type: 'Literal', value: './another.idea' } +}; + +const importPath = Compiler.use(useToken); +console.log(importPath); // './another.idea'`; + +const invalidTokenTypesExample = `// Throws: "Invalid data token type" +Compiler.data({ type: 'UnknownType' }); + +// Throws: "Invalid Enum" +Compiler.enum({ kind: 'notAnEnum' }); + +// Throws: "Invalid Plugin" +Compiler.plugin({ kind: 'notAPlugin' }); + +// Throws: "Invalid Prop" +Compiler.prop({ kind: 'notAProp' }); + +// Throws: "Invalid Schema" +Compiler.schema({ kind: 'notASchema' }); + +// Throws: "Invalid Type" +Compiler.type({ kind: 'notAType' }); + +// Throws: "Invalid Import" +Compiler.use({ type: 'NotAnImportDeclaration' });`; + +const missingPropertiesExample = `// Throws: "Expecting a columns property" +Compiler.model({ + kind: 'model', + declarations: [{ + id: { name: 'User' }, + init: { properties: [] } // Missing columns + }] +});`; + +const unknownReferencesExample = `// Throws: "Unknown reference MyProp" +Compiler.identifier({ name: 'MyProp' }, {});`; + +const duplicateDeclarationsExample = `// Throws: "Duplicate MyEnum" when compiling schema with duplicate names +Compiler.schema(schemaWithDuplicates);`; + +const typeModifiersExample = `Optional types: String? → { type: 'String', required: false } +Array types: String[] → { type: 'String', multiple: true } +Combined: String[]? → { type: 'String', required: false, multiple: true }`; + +const columnConfigurationExample = `// Input object format +{ + columns: { + id: { type: 'String', attributes: { id: true } }, + name: { type: 'String', attributes: { required: true } } + } +} + +// Output array format +{ + columns: [ + { name: 'id', type: 'String', required: true, multiple: false, + attributes: { id: true } }, + { name: 'name', type: 'String', required: true, multiple: false, + attributes: { required: true } } + ] +}`; + +const usageWithASTExample = `import { Compiler, EnumTree, ModelTree, SchemaTree } from '@stackpress/idea-parser'; + +// Parse and compile individual components +const enumAST = EnumTree.parse('enum Status { ACTIVE "Active" }'); +const [enumName, enumConfig] = Compiler.enum(enumAST); + +const modelAST = ModelTree.parse('model User { id String @id }'); +const [modelName, modelConfig] = Compiler.model(modelAST); + +// Parse and compile complete schema +const schemaAST = SchemaTree.parse(schemaCode); +const schemaConfig = Compiler.schema(schemaAST);`; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Compiler'); + const description = _( + 'Compiler class documentation for the Idea Parser library, ' + + 'including methods for compiling AST tokens into structured ' + + 'JSON configurations.' + ); return ( -
    -

    Compiler

    -

    - The Compiler class provides static methods for converting Abstract Syntax Tree (AST) tokens into structured JSON configurations. It serves as the bridge between parsed tokens and the final JSON output. -

    - - {compilerParams[0]} - + <> + {title} + + + + + + + + -

    Static Methods

    -

    - The following methods can be accessed directly from the Compiler class. -

    + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); -

    Converting Array Tokens

    + return ( +
    +
    +

    {_('Compiler')}

    +

    + + The Compiler class provides static methods for converting + Abstract Syntax Tree (AST) tokens into structured JSON + configurations. It serves as the bridge between parsed tokens + and the final JSON output. + +

    + + {basicImportExample} + +
    + +
    +

    {_('Static Methods')}

    +

    + + The following methods can be accessed directly from the + Compiler class. + +

    +
    + +

    {_('Converting Array Tokens')}

    - The following example shows how to compile array tokens into actual arrays. + + The following example shows how to compile array tokens into + actual arrays. +

    - {compilerParams[1]} + {arrayTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -133,27 +434,42 @@ export function Body() { token ArrayToken - The array token to compile + + + The array token to compile + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    -

    Returns

    -

    An array containing the compiled elements.

    +

    {_('Returns')}

    +

    + + An array containing the compiled elements. + +

    -

    Converting Data Tokens

    +

    {_('Converting Data Tokens')}

    - The following example shows how to compile various data tokens into their actual values. + + The following example shows how to compile various data tokens + into their actual values. +

    - {compilerParams[2]} + {dataTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -161,27 +477,43 @@ export function Body() { token DataToken - The data token to compile (can be object, array, literal, or identifier) + + + The data token to compile (can be object, array, literal, + or identifier) + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    - -

    Returns

    -

    The compiled data value based on the token type.

    -

    Converting Enum Declarations

    +

    {_('Returns')}

    +

    + + The compiled data value based on the token type. + +

    + +

    {_('Converting Enum Declarations')}

    - The following example shows how to compile enum declarations into JSON configurations. + + The following example shows how to compile enum declarations + into JSON configurations. +

    - {compilerParams[3]} + {enumTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -189,22 +521,33 @@ export function Body() { token DeclarationToken - The enum declaration token to compile + + + The enum declaration token to compile + +
    -

    Returns

    -

    A tuple containing the enum name and its configuration object.

    +

    {_('Returns')}

    +

    + + A tuple containing the enum name and its configuration object. + +

    -

    Converting Schema to Final JSON

    +

    {_('Converting Schema to Final JSON')}

    - The following example shows how to compile a schema token into a final JSON configuration. + + The following example shows how to compile a schema token + into a final JSON configuration. +

    - {compilerParams[4]} + {finalSchemaExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -212,38 +555,34 @@ export function Body() { token SchemaToken - The schema token to compile into final form + + + The schema token to compile into final form + +
    -

    Returns

    -

    A FinalSchemaConfig object with references resolved and removed.

    +

    {_('Returns')}

    +

    + + A FinalSchemaConfig object with references resolved + and removed. + +

    -

    Converting Identifier Tokens

    +

    {_('Converting Identifier Tokens')}

    - The following example shows how to resolve identifier tokens to their actual values. + + The following example shows how to resolve identifier tokens + to their actual values. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// With references provided -const references = { MyProp: { type: 'text' } }; -const result1 = Compiler.identifier({ name: 'MyProp' }, references); -console.log(result1); // { type: 'text' } - -// Without references (returns template string) -const result2 = Compiler.identifier({ name: 'MyProp' }, false); -console.log(result2); // '\${MyProp}' - -// With empty references (throws error) -try { - Compiler.identifier({ name: 'UnknownProp' }, {}); -} catch (error) { - console.log(error.message); // 'Unknown reference UnknownProp' -}`} + {identifierTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -251,36 +590,43 @@ try { token IdentifierToken - The identifier token to resolve + + + The identifier token to resolve + + references UseReferences - Reference map for resolving the identifier + + + Reference map for resolving the identifier + +
    -

    Returns

    -

    The resolved value from references, a template string, or throws an error.

    +

    {_('Returns')}

    +

    + + The resolved value from references, a template string, + or throws an error. + +

    -

    Converting Literal Tokens

    +

    {_('Converting Literal Tokens')}

    - The following example shows how to extract values from literal tokens. + + The following example shows how to extract values from + literal tokens. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -const stringLiteral = Compiler.literal({ type: 'Literal', value: 'hello' }); -console.log(stringLiteral); // 'hello' - -const numberLiteral = Compiler.literal({ type: 'Literal', value: 42 }); -console.log(numberLiteral); // 42 - -const booleanLiteral = Compiler.literal({ type: 'Literal', value: true }); -console.log(booleanLiteral); // true`} + {literalTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -288,58 +634,33 @@ console.log(booleanLiteral); // true`} token LiteralToken - The literal token to extract value from + + + The literal token to extract value from + +
    -

    Returns

    -

    The literal value (string, number, boolean, etc.).

    +

    {_('Returns')}

    +

    + + The literal value (string, number, boolean, etc.). + +

    -

    Converting Model Declarations

    +

    {_('Converting Model Declarations')}

    - The following example shows how to compile model declarations into JSON configurations. + + The following example shows how to compile model declarations + into JSON configurations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example model token from parsing: model User { id String @id name String } -const modelToken = { - kind: 'model', - mutable: false, // model User! would be true - declarations: [{ - id: { name: 'User' }, - init: { - properties: [ - { - key: { name: 'columns' }, - value: { - type: 'ObjectExpression', - properties: [ - { - key: { name: 'id' }, - value: { - type: 'ObjectExpression', - properties: [ - { key: { name: 'type' }, value: { type: 'Literal', value: 'String' } }, - { key: { name: 'attributes' }, value: { /* attributes */ } } - ] - } - } - ] - } - } - ] - } - }] -}; - -const [name, config] = Compiler.model(modelToken); -console.log(name); // 'User' -console.log(config.mutable); // false -console.log(config.columns); // Array of column configurations`} + {modelTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -347,39 +668,42 @@ console.log(config.columns); // Array of column configurations`} token DeclarationToken - The model declaration token to compile + + + The model declaration token to compile + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    -

    Returns

    -

    A tuple containing the model name and its configuration object.

    +

    {_('Returns')}

    +

    + + A tuple containing the model name and its configuration object. + +

    -

    Converting Object Tokens

    +

    {_('Converting Object Tokens')}

    - The following example shows how to compile object tokens into actual objects. + + The following example shows how to compile object tokens + into actual objects. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example object token from parsing { name "John" age 30 } -const objectToken = { - type: 'ObjectExpression', - properties: [ - { key: { name: 'name' }, value: { type: 'Literal', value: 'John' } }, - { key: { name: 'age' }, value: { type: 'Literal', value: 30 } } - ] -}; - -const result = Compiler.object(objectToken); -console.log(result); // { name: 'John', age: 30 }`} + {objectTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -387,44 +711,42 @@ console.log(result); // { name: 'John', age: 30 }`} token ObjectToken - The object token to compile + + + The object token to compile + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    -

    Returns

    -

    An object with compiled key-value pairs.

    +

    {_('Returns')}

    +

    + + An object with compiled key-value pairs. + +

    -

    Converting Plugin Declarations

    +

    {_('Converting Plugin Declarations')}

    - The following example shows how to compile plugin declarations into JSON configurations. + + The following example shows how to compile plugin declarations + into JSON configurations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example plugin token from parsing: plugin "./database" { provider "postgresql" } -const pluginToken = { - kind: 'plugin', - declarations: [{ - id: { name: './database' }, - init: { - properties: [ - { key: { name: 'provider' }, value: { type: 'Literal', value: 'postgresql' } } - ] - } - }] -}; - -const [name, config] = Compiler.plugin(pluginToken); -console.log(name); // './database' -console.log(config); // { provider: 'postgresql' }`} + {pluginTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -432,40 +754,33 @@ console.log(config); // { provider: 'postgresql' }`} token DeclarationToken - The plugin declaration token to compile + + + The plugin declaration token to compile + +
    -

    Returns

    -

    A tuple containing the plugin name and its configuration object.

    +

    {_('Returns')}

    +

    + + A tuple containing the plugin name and its configuration object. + +

    -

    Converting Prop Declarations

    +

    {_('Converting Prop Declarations')}

    - The following example shows how to compile prop declarations into JSON configurations. + + The following example shows how to compile prop declarations + into JSON configurations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example prop token from parsing: prop Text { type "text" format "lowercase" } -const propToken = { - kind: 'prop', - declarations: [{ - id: { name: 'Text' }, - init: { - properties: [ - { key: { name: 'type' }, value: { type: 'Literal', value: 'text' } }, - { key: { name: 'format' }, value: { type: 'Literal', value: 'lowercase' } } - ] - } - }] -}; - -const [name, config] = Compiler.prop(propToken); -console.log(name); // 'Text' -console.log(config); // { type: 'text', format: 'lowercase' }`} + {propTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -473,37 +788,42 @@ console.log(config); // { type: 'text', format: 'lowercase' }`} token DeclarationToken - The prop declaration token to compile + + + The prop declaration token to compile + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    -

    Returns

    -

    A tuple containing the prop name and its configuration object.

    +

    {_('Returns')}

    +

    + + A tuple containing the prop name and its configuration object. + +

    -

    Converting Schema Declarations

    +

    {_('Converting Schema Declarations')}

    - The following example shows how to compile complete schema tokens into JSON configurations. + + The following example shows how to compile complete schema + tokens into JSON configurations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Compile a complete schema with all declaration types -const schemaConfig = Compiler.schema(schemaToken); -console.log(schemaConfig); -// Output contains: { enum: {...}, prop: {...}, type: {...}, model: {...}, plugin: {...}, use: [...] } - -// Compile with finalization (resolves references) -const finalizedConfig = Compiler.schema(schemaToken, true); -console.log(finalizedConfig); -// References are resolved in the output`} + {schemaDeclarationExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -511,62 +831,42 @@ console.log(finalizedConfig); token SchemaToken - The schema token to compile + + + The schema token to compile + + finalize boolean - Whether to resolve references (default: false) + + + Whether to resolve references (default: false) + +
    -

    Returns

    -

    A SchemaConfig object containing all compiled declarations.

    +

    {_('Returns')}

    +

    + + A SchemaConfig object containing all compiled declarations. + +

    -

    Converting Type Declarations

    +

    {_('Converting Type Declarations')}

    - The following example shows how to compile type declarations into JSON configurations. + + The following example shows how to compile type declarations + into JSON configurations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example type token from parsing: type Address { street String city String } -const typeToken = { - kind: 'type', - mutable: true, // type Address (mutable) vs type Address! (immutable) - declarations: [{ - id: { name: 'Address' }, - init: { - properties: [ - { - key: { name: 'columns' }, - value: { - type: 'ObjectExpression', - properties: [ - { - key: { name: 'street' }, - value: { - type: 'ObjectExpression', - properties: [ - { key: { name: 'type' }, value: { type: 'Literal', value: 'String' } } - ] - } - } - ] - } - } - ] - } - }] -}; - -const [name, config] = Compiler.type(typeToken); -console.log(name); // 'Address' -console.log(config.mutable); // true -console.log(config.columns); // Array of column configurations`} + {typeTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -574,36 +874,42 @@ console.log(config.columns); // Array of column configurations`} token DeclarationToken - The type declaration token to compile + + + The type declaration token to compile + + references UseReferences - Reference map for resolving identifiers (default: false) + + + Reference map for resolving identifiers (default: false) + +
    -

    Returns

    -

    A tuple containing the type name and its configuration object.

    +

    {_('Returns')}

    +

    + + A tuple containing the type name and its configuration object. + +

    -

    Converting Use Declarations

    +

    {_('Converting Use Declarations')}

    - The following example shows how to compile use (import) declarations. + + The following example shows how to compile use (import) + declarations. +

    -{`import { Compiler } from '@stackpress/idea-parser'; - -// Example use token from parsing: use "./another.idea" -const useToken = { - type: 'ImportDeclaration', - source: { type: 'Literal', value: './another.idea' } -}; - -const importPath = Compiler.use(useToken); -console.log(importPath); // './another.idea'`} + {useTokenExample} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -611,126 +917,99 @@ console.log(importPath); // './another.idea'`} token ImportToken - The import declaration token to compile + + + The import declaration token to compile + +
    -

    Returns

    -

    The import path as a string.

    - -

    Error Handling

    +

    {_('Returns')}

    - The Compiler class throws Exception errors for various invalid conditions: + + The import path as a string. +

    -

    Invalid Token Types

    - -{`// Throws: "Invalid data token type" -Compiler.data({ type: 'UnknownType' }); - -// Throws: "Invalid Enum" -Compiler.enum({ kind: 'notAnEnum' }); - -// Throws: "Invalid Plugin" -Compiler.plugin({ kind: 'notAPlugin' }); - -// Throws: "Invalid Prop" -Compiler.prop({ kind: 'notAProp' }); - -// Throws: "Invalid Schema" -Compiler.schema({ kind: 'notASchema' }); +
    +

    {_('Error Handling')}

    +

    + + The Compiler class throws Exception errors for various + invalid conditions: + +

    -// Throws: "Invalid Type" -Compiler.type({ kind: 'notAType' }); - -// Throws: "Invalid Import" -Compiler.use({ type: 'NotAnImportDeclaration' });`} -
    - -

    Missing Required Properties

    +

    {_('Invalid Token Types')}

    -{`// Throws: "Expecting a columns property" -Compiler.model({ - kind: 'model', - declarations: [{ - id: { name: 'User' }, - init: { properties: [] } // Missing columns - }] -});`} + {invalidTokenTypesExample} -

    Unknown References

    +

    {_('Missing Required Properties')}

    -{`// Throws: "Unknown reference MyProp" -Compiler.identifier({ name: 'MyProp' }, {});`} + {missingPropertiesExample} -

    Duplicate Declarations

    +

    {_('Unknown References')}

    -{`// Throws: "Duplicate MyEnum" when compiling schema with duplicate names -Compiler.schema(schemaWithDuplicates);`} + {unknownReferencesExample} -

    Type Processing

    -

    - The Compiler automatically processes type information for models and types: -

    - -

    Type Modifiers

    +

    {_('Duplicate Declarations')}

    -{`Optional types: String? → { type: 'String', required: false } -Array types: String[] → { type: 'String', multiple: true } -Combined: String[]? → { type: 'String', required: false, multiple: true }`} + {duplicateDeclarationsExample} +
    -

    Column Configuration

    +
    +

    {_('Type Processing')}

    - Models and types are converted from object format to array format to preserve column order: + + The Compiler automatically processes type information for + models and types: +

    - -{`// Input object format -{ - columns: { - id: { type: 'String', attributes: { id: true } }, - name: { type: 'String', attributes: { required: true } } - } -} -// Output array format -{ - columns: [ - { name: 'id', type: 'String', required: true, multiple: false, attributes: { id: true } }, - { name: 'name', type: 'String', required: true, multiple: false, attributes: { required: true } } - ] -}`} +

    {_('Type Modifiers')}

    + + {typeModifiersExample} -

    Usage with AST

    +

    {_('Column Configuration')}

    - The Compiler is typically used in conjunction with AST classes: + + Models and types are converted from object format to array + format to preserve column order: +

    -{`import { Compiler, EnumTree, ModelTree, SchemaTree } from '@stackpress/idea-parser'; - -// Parse and compile individual components -const enumAST = EnumTree.parse('enum Status { ACTIVE "Active" }'); -const [enumName, enumConfig] = Compiler.enum(enumAST); - -const modelAST = ModelTree.parse('model User { id String @id }'); -const [modelName, modelConfig] = Compiler.model(modelAST); - -// Parse and compile complete schema -const schemaAST = SchemaTree.parse(schemaCode); -const schemaConfig = Compiler.schema(schemaAST);`} + {columnConfigurationExample} +
    + +
    +

    {_('Usage with AST')}

    +

    + + The Compiler is typically used in conjunction with AST classes: + +

    + + {usageWithASTExample} + +
    ); } diff --git a/packages/www/plugins/docs/views/parser/pages/exception-handling.tsx b/packages/www/plugins/docs/components/parser/api-references/exception-handling.tsx similarity index 53% rename from packages/www/plugins/docs/views/parser/pages/exception-handling.tsx rename to packages/www/plugins/docs/components/parser/api-references/exception-handling.tsx index f5b24be..1a55455 100644 --- a/packages/www/plugins/docs/views/parser/pages/exception-handling.tsx +++ b/packages/www/plugins/docs/components/parser/api-references/exception-handling.tsx @@ -1,46 +1,14 @@ //modules import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; - import Code from '../../../components/Code.js'; - import Layout from '../../../components/Layout.js'; - import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Exception'); - const description = _( - 'The Exception class extends the Exception class from @stackpress/lib to provide enhanced error handling specific to the idea parser library. It includes position information and better error reporting for parsing failures.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } - + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, H3, SS, Nav, P } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; + const examples = [ `import { Exception } from '@stackpress/idea-parser';`, `import { parse, Exception } from '@stackpress/idea-parser'; @@ -188,119 +156,207 @@ function validateSchema(code: string) { throw error; } }` -] - - export function Body() { - return ( -
    -

    Exception

    -

    The Exception class extends the Exception class from @stackpress/lib to provide enhanced error handling specific to the idea parser library. It includes position information and better error reporting for parsing failures.

    +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Exception'); + const description = _( + 'The Exception class extends the Exception class from ' + + '@stackpress/lib to provide enhanced error handling specific ' + + 'to the idea parser library. It includes position information ' + + 'and better error reporting for parsing failures.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Exception')}

    +

    + + The Exception class extends the Exception class from + @stackpress/lib to provide enhanced error handling specific + to the idea parser library. It includes position information + and better error reporting for parsing failures. + +

    {examples[0]} +
    -

    Overview

    -

    Exception is a specialized error class that extends the base Exception class with additional functionality for parser-specific error handling. It automatically includes position information when parsing fails, making it easier to identify and fix syntax errors in schema files.

    +
    +

    {_('Overview')}

    + + Exception is a specialized error class that extends the base + Exception class with additional functionality for parser-specific + error handling. It automatically includes position information + when parsing fails, making it easier to identify and fix syntax + errors in schema files. + +
    -

    Usage Examples

    +
    +

    {_('Usage Examples')}

    -

    Basic Error Handling

    +

    {_('Basic Error Handling')}

    {examples[1]} -

    Position Information

    -

    Exception includes position information to help locate errors in the source code:

    +

    {_('Position Information')}

    + + Exception includes position information to help locate errors in + the source code: + {examples[2]} -

    Common Error Scenarios

    +

    {_('Common Error Scenarios')}

    - Syntax Errors + {_('Syntax Errors')} {examples[3]} - Invalid Token Types + {_('Invalid Token Types')} {examples[4]} - Unknown References + {_('Unknown References')} {examples[5]} - Duplicate Declarations + {_('Duplicate Declarations')} {examples[6]} +
    -

    Integration with AST

    -

    All AST classes throw Exception when parsing fails:

    +
    +

    {_('Integration with AST')}

    + + All AST classes throw Exception when parsing fails: + {examples[7]} +
    -

    Error Recovery

    -

    While Exception indicates parsing failure, you can implement error recovery strategies:

    +
    +

    {_('Error Recovery')}

    + + While Exception indicates parsing failure, you can implement error + recovery strategies: + {examples[8]} +
    -

    Language Server Integration

    -

    Exception's position information makes it ideal for language server implementations:

    +
    +

    {_('Language Server Integration')}

    + + Exception's position information makes it ideal for language + server implementations: + {examples[9]} +
    -

    Inherited Features

    -

    Since Exception extends the base Exception class from @stackpress/lib, it inherits all the enhanced error handling features:

    +
    +

    {_('Inherited Features')}

    + + Since Exception extends the base Exception class from + @stackpress/lib, it inherits all the enhanced error handling + features: +
      -
    • Template-based error messages
    • -
    • Enhanced stack trace parsing
    • -
    • Position information support
    • -
    • HTTP status code integration
    • -
    • Validation error aggregation
    • +
    • {_('Template-based error messages')}
    • +
    • {_('Enhanced stack trace parsing')}
    • +
    • {_('Position information support')}
    • +
    • {_('HTTP status code integration')}
    • +
    • {_('Validation error aggregation')}
    -

    For more details on the base Exception functionality, refer to the @stackpress/lib Exception documentation.

    + + For more details on the base Exception functionality, refer to the + + @stackpress/lib Exception documentation + . + +
    -

    Best Practices

    +
    +

    {_('Best Practices')}

    -

    Always Check Error Type

    +

    {_('Always Check Error Type')}

    {examples[10]} -

    Use Position Information

    +

    {_('Use Position Information')}

    {examples[11]} -

    Provide Helpful Error Messages

    +

    {_('Provide Helpful Error Messages')}

    {examples[12]} +
    +
    -
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/parser/pages/lexer.tsx b/packages/www/plugins/docs/components/parser/api-references/lexer.tsx similarity index 51% rename from packages/www/plugins/docs/views/parser/pages/lexer.tsx rename to packages/www/plugins/docs/components/parser/api-references/lexer.tsx index db761e0..8e216bd 100644 --- a/packages/www/plugins/docs/views/parser/pages/lexer.tsx +++ b/packages/www/plugins/docs/components/parser/api-references/lexer.tsx @@ -3,44 +3,13 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav, SS } from '../../../components/index.js'; -import Code from '../../../components/Code.js'; -import Layout from '../../../components/Layout.js'; +import { H1, H2, H3, P, C, Nav, SS } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Lexer'); - const description = _( - 'The Lexer class implements the Parser interface and provides tokenization and parsing utilities for schema code. It manages a dictionary of token definitions and handles the parsing process by matching patterns against the input code.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const examples = [ `import { Lexer } from '@stackpress/idea-parser'; `, @@ -375,361 +344,605 @@ const customReader: Reader = (code, start, lexer) => { lexer.define('custom', customReader);` ] -export function Body() { +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Lexer'); + const description = _( + 'The Lexer class implements the Parser interface and provides ' + + 'tokenization and parsing utilities for schema code. It manages ' + + 'a dictionary of token definitions and handles the parsing ' + + 'process by matching patterns against the input code.' + ); return ( -
    -

    Lexer

    -

    The Lexer class implements the Parser interface and provides tokenization and parsing utilities for schema code. It manages a dictionary of token definitions and handles the parsing process by matching patterns against the input code.

    - - {examples[0]} - - -

    Properties

    -

    The following properties are available when instantiating a Lexer.

    - - - Property - Type - Description - - dictionary - Record‹string, Definition› Shallow copy of all token definitions - The current index position in the code - - - index - number - Current parsing position in the code - -
    - -

    Methods

    -

    The following methods are available when instantiating a Lexer.

    - -

    Cloning the Lexer

    -

    The following example shows how to create an exact copy of the lexer's current state.

    - - {examples[1]} - - - Returns -
  • A new Lexer instance with identical state to original
  • - -

    Defining Token Patterns

    -

    The following example shows how to register token definitions for parsing.

    - - {examples[2]} - - -

    Parameters

    - - Parameter - Type - Description - - key - string - Unique identifier for the token definition - - - reader - Reader - Function that attempts to match and parse the token - -
    + <> + {title} + + + + + + + + - Returns -
  • Void (modifies the lexer's internal dictionary).
  • + + + {styles.map((href, index) => ( + + ))} + + ) +} -

    Expecting Specific Tokens

    -

    The following example shows how to require specific tokens at the current position.

    - - {examples[3]} - +export function Body() { + const { _ } = useLanguage(); -

    Parameters

    + return ( +
    +
    +

    {_('Lexer')}

    + + The Lexer class implements the Parser interface and provides + tokenization and parsing utilities for schema code. It manages + a dictionary of token definitions and handles the parsing + process by matching patterns against the input code. + + + {examples[0]} + +
    + +
    +

    {_('Properties')}

    +

    + + The following properties are available when instantiating a Lexer. + +

    + + + {_('Property')} + {_('Type')} + {_('Description')} + + dictionary + Record‹string, Definition› {_( + 'Shallow copy of all token definitions' + )} + {_('The current index position in the code')} + + + index + number + {_('Current parsing position in the code')} + +
    +
    + +
    +

    {_('Methods')}

    +

    + + The following methods are available when instantiating a Lexer. + +

    + +

    {_('Cloning the Lexer')}

    +

    + + The following example shows how to create an exact copy of the + lexer's current state. + +

    + + {examples[1]} + + + {_('Returns')} +
  • + + A new Lexer instance with identical state to original + +
  • +
    + +
    +

    {_('Defining Token Patterns')}

    +

    + + The following example shows how to register token definitions + for parsing. + +

    + + {examples[2]} + +
    + +
    +

    {_('Parameters')}

    + + {_('Parameter')} + {_('Type')} + {_('Description')} + + key + string + {_('Unique identifier for the token definition')} + + + reader + Reader + + + Function that attempts to match and parse the token + + + +
    + + {_('Returns')} +
  • + + Void (modifies the lexer's internal dictionary). + +
  • +
    + +
    +

    {_('Expecting Specific Tokens')}

    +

    + + The following example shows how to require specific tokens at + the current position. + +

    + + {examples[3]} + +
    + +
    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} keys string | string[] - Token definition key(s) to expect + {_('Token definition key(s) to expect')}
    - Returns -
  • The matched token object, or throws an exception if no match is found.
  • - -

    Getting Token Definitions

    -

    The following example shows how to retrieve registered token definitions.

    + {_('Returns')} +
  • + + The matched token object, or throws an exception if no match + is found. + +
  • +
    + +

    {_('Getting Token Definitions')}

    +

    + + The following example shows how to retrieve registered token + definitions. + +

    {examples[4]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} key string - The token definition key to retrieve + {_('The token definition key to retrieve')}
    - Returns -
  • The Definition object if found, undefined otherwise.
  • - -

    Loading Code

    -

    The following example shows how to load code for parsing.

    + {_('Returns')} +
  • + + The Definition object if found, undefined otherwise. + +
  • + +

    {_('Loading Code')}

    +

    + + The following example shows how to load code for parsing. + +

    {examples[5]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} code string - The source code to parse + {_('The source code to parse')} index number - Starting position in the code (default: 0) + + + Starting position in the code (default: 0) + +
    - Returns -
  • The Lexer instance to allow method chaining.
  • - -

    Matching Tokens

    -

    The following example shows how to find the first matching token from available definitions.

    + {_('Returns')} +
  • + + The Lexer instance to allow method chaining. + +
  • + +

    {_('Matching Tokens')}

    +

    + + The following example shows how to find the first matching token + from available definitions. + +

    {examples[6]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} code string - The code to match against + {_('The code to match against')} start number - Starting position for matching + {_('Starting position for matching')} keys string[] - Optional array of definition keys to try (default: all definitions) + + + Optional array of definition keys to try (default: all + definitions) + +
    - Returns -
  • The first matching token object, or null if no match is found.
  • - -

    Testing for Next Tokens

    -

    The following example shows how to check if the next tokens match without consuming them.

    + {_('Returns')} +
  • + + The first matching token object, or null if no match is found. + +
  • + +

    {_('Testing for Next Tokens')}

    +

    + + The following example shows how to check if the next tokens + match without consuming them. + +

    {examples[7]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} names string | string[] - Token definition key(s) to test for + {_('Token definition key(s) to test for')}
    - Returns -
  • true if the next token(s) match, false otherwise. Does not advance the index.
  • - -

    Optional Token Parsing

    -

    The following example shows how to optionally parse tokens without throwing errors.

    + {_('Returns')} +
  • + + true if the next token(s) match, false otherwise. Does not + advance the index. + +
  • + +

    {_('Optional Token Parsing')}

    +

    + + The following example shows how to optionally parse tokens + without throwing errors. + +

    {examples[8]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} names string | string[] - Token definition key(s) to try parsing + {_('Token definition key(s) to try parsing')}
    - Returns -
  • The matched token object if found, undefined otherwise.
  • - -

    Reading Ahead

    -

    The following example shows how to read the next available token.

    + {_('Returns')} +
  • + + The matched token object if found, undefined otherwise. + +
  • + +

    {_('Reading Ahead')}

    +

    + + The following example shows how to read the next available token. + +

    {examples[9]} - Returns -
  • The next available token object, or undefined if no token can be parsed.
  • - -

    Getting Substrings

    -

    The following example shows how to extract portions of the source code.

    + {_('Returns')} +
  • + + The next available token object, or undefined if no token can + be parsed. + +
  • + +

    {_('Getting Substrings')}

    +

    + + The following example shows how to extract portions of the + source code. + +

    {examples[10]} -

    Parameters

    +

    {_('Parameters')}

    - Parameter - Type - Description + {_('Parameter')} + {_('Type')} + {_('Description')} start number - Starting position in the code + {_('Starting position in the code')} end number - Ending position in the code + {_('Ending position in the code')}
    - Returns -
  • The substring of code between start and end positions.
  • - -

    Finding Next Space

    -

    The following example shows how to find the next whitespace character (useful for error reporting).

    + {_('Returns')} +
  • + + The substring of code between start and end positions. + +
  • + +

    {_('Finding Next Space')}

    +

    + + The following example shows how to find the next whitespace + character (useful for error reporting). + +

    {examples[11]} - Returns -
  • The index of the next space character, or the code length if no space is found.
  • - -

    Parsing Complex Data Structures

    -

    The Lexer can parse complex nested data structures using the predefined token definitions:

    - -

    Parsing Objects

    + {_('Returns')} +
  • + + The index of the next space character, or the code length if + no space is found. + +
  • + +

    {_('Parsing Complex Data Structures')}

    +

    + + The Lexer can parse complex nested data structures using the + predefined token definitions: + +

    + +

    {_('Parsing Objects')}

    {examples[12]} -

    Parsing Arrays

    +

    {_('Parsing Arrays')}

    {examples[13]} -

    Parsing Comments

    +

    {_('Parsing Comments')}

    {examples[14]} -

    Error Handling

    -

    The Lexer provides detailed error information when parsing fails:

    +

    {_('Error Handling')}

    +

    + + The Lexer provides detailed error information when parsing fails: + +

    -

    Unknown Definitions

    +

    {_('Unknown Definitions')}

    {examples[15]} -

    Unexpected Tokens

    +

    {_('Unexpected Tokens')}

    {examples[16]} -

    Predefined Token Definitions

    -

    The library comes with comprehensive predefined token definitions:

    +

    {_('Predefined Token Definitions')}

    +

    + + The library comes with comprehensive predefined token definitions: + +

    -

    Literals

    +

    {_('Literals')}

      -
    • Null: Matches null keyword
    • -
    • Boolean: Matches true and false
    • -
    • String: Matches quoted strings "hello"
    • -
    • Float: Matches decimal numbers 4.4, -3.14
    • -
    • Integer: Matches whole numbers 42, -10
    • -
    • Environment: Matches environment variables env("VAR_NAME")
    • +
    • Null: {_('Matches null keyword')}
    • +
    • Boolean: {_('Matches true and false')}
    • +
    • String: {_( + 'Matches quoted strings "hello"' + )}
    • +
    • Float: {_( + 'Matches decimal numbers 4.4, -3.14' + )}
    • +
    • Integer: {_( + 'Matches whole numbers 42, -10' + )}
    • +
    • Environment: {_( + 'Matches environment variables env("VAR_NAME")' + )}
    -

    Identifiers

    +

    {_('Identifiers')}

      -
    • AnyIdentifier: Matches any valid identifier [a-z_][a-z0-9_]*
    • -
    • UpperIdentifier: Matches uppercase identifiers [A-Z_][A-Z0-9_]*
    • -
    • CapitalIdentifier: Matches capitalized identifiers [A-Z_][a-zA-Z0-9_]*
    • -
    • CamelIdentifier: Matches camelCase identifiers [a-z_][a-zA-Z0-9_]*
    • -
    • LowerIdentifier: Matches lowercase identifiers [a-z_][a-z0-9_]*
    • -
    • AttributeIdentifier: Matches attribute identifiers @field.input
    • +
    • AnyIdentifier: {_( + 'Matches any valid identifier [a-z_][a-z0-9_]*' + )}
    • +
    • UpperIdentifier: {_( + 'Matches uppercase identifiers [A-Z_][A-Z0-9_]*' + )}
    • +
    • CapitalIdentifier: {_( + 'Matches capitalized identifiers [A-Z_][a-zA-Z0-9_]*' + )}
    • +
    • CamelIdentifier: {_( + 'Matches camelCase identifiers [a-z_][a-zA-Z0-9_]*' + )}
    • +
    • LowerIdentifier: {_( + 'Matches lowercase identifiers [a-z_][a-z0-9_]*' + )}
    • +
    • AttributeIdentifier: {_( + 'Matches attribute identifiers @field.input' + )}
    -

    Structural

    +

    {_('Structural')}

      -
    • Array: Matches array expressions [ ... ]
    • -
    • Object: Matches object expressions { ... }
    • -
    • {, }, [, ], (, ): Bracket and brace tokens
    • -
    • !: Final modifier token
    • +
    • Array: {_( + 'Matches array expressions [ ... ]' + )}
    • +
    • Object: {_( + 'Matches object expressions { ... }' + )}
    • +
    • {, }, [, ], (, ): {_( + 'Bracket and brace tokens' + )}
    • +
    • !: {_('Final modifier token')}
    -

    Whitespace and Comments

    +

    {_('Whitespace and Comments')}

      -
    • whitespace: Matches any whitespace \s+
    • -
    • space: Matches spaces only
    • -
    • line: Matches line breaks
    • -
    • note: Matches block comments /* ... */
    • -
    • comment: Matches line comments // ...
    • +
    • whitespace: {_( + 'Matches any whitespace \\s+' + )}
    • +
    • space: {_('Matches spaces only')}
    • +
    • line: {_('Matches line breaks')}
    • +
    • note: {_( + 'Matches block comments /* ... */' + )}
    • +
    • comment: {_( + 'Matches line comments // ...' + )}
    -

    Data Groups

    +

    {_('Data Groups')}

      -
    • scalar: Array of scalar types ['Null', 'Boolean', 'String', 'Float', 'Integer', 'Environment']
    • -
    • data: Array of all data types [...scalar, 'Object', 'Array']
    • +
    • scalar: {_( + 'Array of scalar types [\'Null\', \'Boolean\', \'String\', ' + + '\'Float\', \'Integer\', \'Environment\']' + )}
    • +
    • data: {_( + 'Array of all data types [...scalar, \'Object\', \'Array\']' + )}
    -

    Usage with AST

    -

    The Lexer is typically used by AST classes for parsing specific language constructs:

    +

    {_('Usage with AST')}

    +

    + + The Lexer is typically used by AST classes for parsing specific + language constructs: + +

    {examples[17]} -

    Advanced Usage Patterns

    +

    {_('Advanced Usage Patterns')}

    -

    Backtracking with Clone

    +

    {_('Backtracking with Clone')}

    {examples[18]} -

    Conditional Parsing

    +

    {_('Conditional Parsing')}

    {examples[19]} -

    Custom Reader Functions

    -

    Reader functions should follow this pattern:

    +

    {_('Custom Reader Functions')}

    +

    + + Reader functions should follow this pattern: + +

    {examples[20]}
    diff --git a/packages/www/plugins/docs/views/parser/pages/tokens.tsx b/packages/www/plugins/docs/components/parser/api-references/tokens.tsx similarity index 52% rename from packages/www/plugins/docs/views/parser/pages/tokens.tsx rename to packages/www/plugins/docs/components/parser/api-references/tokens.tsx index f6b1544..78e171f 100644 --- a/packages/www/plugins/docs/views/parser/pages/tokens.tsx +++ b/packages/www/plugins/docs/components/parser/api-references/tokens.tsx @@ -1,46 +1,15 @@ //modules import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; - import Code from '../../../components/Code.js'; - import Layout from '../../../components/Layout.js'; - import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Tokens'); - const description = _( - 'Token types define the Abstract Syntax Tree (AST) structures used by the idea parser to represent parsed schema code. These types form the foundation of the parsing system, providing type-safe representations of schema elements.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } - + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, H3, C, SS, Nav } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + const examples = [ `import type { SchemaToken, @@ -117,7 +86,13 @@ const numberLiteral: LiteralToken = { shorthand: false, computed: false, key: { type: 'Identifier', name: 'ADMIN', start: 15, end: 20 }, - value: { type: 'Literal', value: 'Admin', start: 21, end: 28, raw: '"Admin"' } + value: { + type: 'Literal', + value: 'Admin', + start: 21, + end: 28, + raw: '"Admin"' + } } ] };`, @@ -317,26 +292,84 @@ const token: IdentifierToken = { // Can be used to highlight errors in editors const errorRange = { start: token.start, end: token.end };` ] - - export function Body() { - return ( -
    -

    Tokens

    -

    Token types define the Abstract Syntax Tree (AST) structures used by the idea parser to represent parsed schema code. These types form the foundation of the parsing system, providing type-safe representations of schema elements.

    + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Tokens'); + const description = _( + 'Token types define the Abstract Syntax Tree (AST) structures ' + + 'used by the idea parser to represent parsed schema code. These ' + + 'types form the foundation of the parsing system, providing ' + + 'type-safe representations of schema elements.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Tokens')}

    + + Token types define the Abstract Syntax Tree (AST) structures + used by the idea parser to represent parsed schema code. These + types form the foundation of the parsing system, providing type- + safe representations of schema elements. + {examples[0]} - -

    Core Token Types

    -

    The following types define the fundamental token structures used throughout the parsing system.

    - -

    UnknownToken

    -

    Base token structure for unrecognized or generic tokens during parsing.

    +
    + +
    +

    {_('Core Token Types')}

    + The following types define the fundamental token + structures used throughout the parsing system. + + +

    {_('UnknownToken')}

    + + Base token structure for unrecognized or generic tokens during + parsing. + {examples[1]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -344,40 +377,66 @@ const errorRange = { start: token.start, end: token.end };` type string - Token type identifier + + + Token type identifier + + start number - Starting character position in source code + + + Starting character position in source code + + end number - Ending character position in source code + + + Ending character position in source code + + value any - Parsed value of the token + + + Parsed value of the token + + raw string - Raw text from source code + + + Raw text from source code + +
    - Usage -

    Used as a fallback for tokens that don't match specific patterns and as a base structure for other token types.

    - -

    IdentifierToken

    -

    Represents identifiers such as variable names, type names, and property keys.

    + {_('Usage')} + + Used as a fallback for tokens that don't match specific patterns + and as a base structure for other token types. + + +

    {_('IdentifierToken')}

    + + Represents identifiers such as variable names, type names, + and property keys. + {examples[2]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -385,27 +444,43 @@ const errorRange = { start: token.start, end: token.end };` type 'Identifier' - Always 'Identifier' for identifier tokens + + + Always 'Identifier' for identifier tokens + + name string - The identifier name + + + The identifier name + + start number - Starting character position + + + Starting character position + + end number - Ending character position + + + Ending character position + +
    - Usage -

    Used throughout the parser for:

    + {_('Usage')} + Used throughout the parser for:
    • Enum names: enum UserRole
    • Model names: model User
    • @@ -413,18 +488,21 @@ const errorRange = { start: token.start, end: token.end };`
    • Type references: role UserRole
    - Examples from Tests + {_('Examples from Tests')} {examples[3]} -

    LiteralToken

    -

    Represents literal values such as strings, numbers, booleans, and null.

    +

    {_('LiteralToken')}

    + + Represents literal values such as strings, numbers, booleans, + and null. + {examples[4]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -456,8 +534,10 @@ const errorRange = { start: token.start, end: token.end };`
    - Usage -

    Used for all scalar values in schema definitions:

    + {_('Usage')} + + Used for all scalar values in schema definitions: +
    • String literals: "Admin", "localhost"
    • Number literals: 5432, 3.14
    • @@ -465,18 +545,22 @@ const errorRange = { start: token.start, end: token.end };`
    • Null literals: null
    - Examples from Tests + {_('Examples from Tests')} {examples[5]} +
    -

    ObjectToken

    -

    Represents object expressions containing key-value pairs.

    +
    +

    {_('ObjectToken')}

    + + Represents object expressions containing key-value pairs. + {examples[6]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -484,44 +568,79 @@ const errorRange = { start: token.start, end: token.end };` type 'ObjectExpression' - Always 'ObjectExpression' for object tokens + + + Always 'ObjectExpression' for object tokens + + start number - Starting character position + + + Starting character position + + end number - Ending character position + + + Ending character position + + properties PropertyToken[] - Array of property tokens + + + Array of property tokens + +
    - Usage -

    Used for:

    + {_('Usage')} + Used for:
      -
    • Enum definitions: { ADMIN "Admin", USER "User" }
    • -
    • Model column definitions: { id String @id, name String }
    • -
    • Plugin configurations: { provider "postgresql", url env("DATABASE_URL") }
    • -
    • Attribute parameters: @field.input({ type "text" })
    • +
    • + Enum definitions: + { ADMIN "Admin", USER "User" } +
    • +
    • + Model column definitions: + { id String @id, name String } +
    • +
    • + Plugin configurations: + { provider "postgresql", url env("DATABASE_URL") } +
    • +
    • + Attribute parameters: + @field.input({ type "text" }) +
    - Examples from Tests -

    The enum fixture shows an ObjectToken containing three PropertyTokens for ADMIN, MANAGER, and USER enum values.

    - -

    ArrayToken

    -

    Represents array expressions containing ordered elements.

    + {_('Examples from Tests')} + + The enum fixture shows an ObjectToken containing three PropertyTokens + for ADMIN, MANAGER, and USER enum values. + +
    + +
    +

    {_('ArrayToken')}

    + + Represents array expressions containing ordered elements. + {examples[7]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -529,40 +648,69 @@ const errorRange = { start: token.start, end: token.end };` type 'ArrayExpression' - Always 'ArrayExpression' for array tokens + + + Always 'ArrayExpression' for array tokens + + start number - Starting character position + + + Starting character position + + end number - Ending character position + + + Ending character position + + elements DataToken[] - Array of data tokens + + + Array of data tokens + +
    - Usage -

    Used for:

    + {_('Usage')} + Used for:
      -
    • Array type definitions: String[]
    • -
    • Plugin feature lists: previewFeatures ["fullTextSearch", "metrics"]
    • -
    • Attribute arrays: @is.oneOf(["admin", "user", "guest"])
    • +
    • + Array type definitions: + String[] +
    • +
    • + Plugin feature lists: + previewFeatures ["fullTextSearch", "metrics"] +
    • +
    • + Attribute arrays: + @is.oneOf(["admin", "user", "guest"]) +
    +
    -

    PropertyToken

    -

    Represents key-value pairs within object expressions.

    +
    +

    {_('PropertyToken')}

    + + Represents key-value pairs within object expressions. + {examples[8]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -570,72 +718,120 @@ const errorRange = { start: token.start, end: token.end };` type 'Property' - Always 'Property' for property tokens + + + Always 'Property' for property tokens + + kind 'init' - Always 'init' for initialization properties + + + Always 'init' for initialization properties + + start number - Starting character position + + + Starting character position + + end number - Ending character position + + + Ending character position + + method boolean - Always false (not used for method properties) + + + Always false (not used for method properties) + + shorthand boolean - Always false (not used for shorthand properties) + + + Always false (not used for shorthand properties) + + computed boolean - Always false (not used for computed properties) + + + Always false (not used for computed properties) + + key IdentifierToken - Property key identifier + + + Property key identifier + + value DataToken - Property value (literal, object, array, or identifier) + + + Property value (literal, object, array, or identifier) + +
    - Usage -

    Used within ObjectTokens for:

    + {_('Usage')} + Used within ObjectTokens for:
    • Enum key-value pairs: ADMIN "Admin"
    • Model column definitions: id String
    • -
    • Plugin configuration options: provider "postgresql"
    • +
    • + Plugin configuration options: provider "postgresql" +
    • Attribute parameters: type "text"
    - Examples from Tests -

    From the enum fixture, each enum value is represented as a PropertyToken with an IdentifierToken key and LiteralToken value.

    - -

    Declaration Tokens

    -

    The following types represent top-level declarations in schema files.

    - -

    DeclarationToken

    -

    Represents variable declarations for enums, props, types, models, and plugins.

    + {_('Examples from Tests')} + + From the enum fixture, each enum value is represented as a + PropertyToken with an IdentifierToken key and LiteralToken value. + +
    + +
    +

    {_('Declaration Tokens')}

    + + The following types represent top-level declarations in schema files. + + +

    {_('DeclarationToken')}

    + + Represents variable declarations for enums, props, types, models, + and plugins. + {examples[9]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -648,7 +844,9 @@ const errorRange = { start: token.start, end: token.end };` kind string - Declaration type: 'enum', 'prop', 'type', 'model', 'plugin' + + Declaration type: 'enum', 'prop', 'type', 'model', 'plugin' + mutable @@ -672,19 +870,30 @@ const errorRange = { start: token.start, end: token.end };`
    - Usage -

    Used by all tree parsers (EnumTree, PropTree, TypeTree, ModelTree, PluginTree) to represent their respective declarations. The kind property determines how the Compiler processes the declaration.

    - - Examples from Tests -

    The enum fixture shows a complete DeclarationToken with kind 'enum' containing the Roles enum definition.

    - -

    DeclaratorToken

    -

    Represents the declarator part of a variable declaration, containing the identifier and initialization.

    + {_('Usage')} + + Used by all tree parsers (EnumTree, PropTree, TypeTree, ModelTree, + PluginTree) to represent their respective declarations. The + kind property determines how the Compiler processes the + declaration. + + + {_('Examples from Tests')} + + The enum fixture shows a complete DeclarationToken with kind 'enum' + containing the Roles enum definition. + + +

    {_('DeclaratorToken')}

    + + Represents the declarator part of a variable declaration, + containing the identifier and initialization. + {examples[10]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -716,16 +925,22 @@ const errorRange = { start: token.start, end: token.end };`
    - Usage -

    Used within DeclarationTokens to separate the declaration name from its body. The id contains the name (e.g., "Roles", "User") and init contains the definition object.

    - -

    ImportToken

    -

    Represents use statements for importing other schema files.

    + {_('Usage')} + + Used within DeclarationTokens to separate the declaration name + from its body. The id contains the name (e.g., "Roles", "User") + and init contains the definition object. + + +

    {_('ImportToken')}

    + + Represents use statements for importing other schema files. + {examples[11]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -757,16 +972,23 @@ const errorRange = { start: token.start, end: token.end };`
    - Usage -

    Used by UseTree to represent use "./path/to/file.idea" statements. The Compiler extracts the source path for dependency resolution.

    - -

    SchemaToken

    -

    Represents the complete parsed schema file containing all declarations and imports.

    + {_('Usage')} + + Used by UseTree to represent use "./path/to/file.idea" + statements. The Compiler extracts the source path for dependency + resolution. + + +

    {_('SchemaToken')}

    + + Represents the complete parsed schema file containing all + declarations and imports. + {examples[12]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -774,64 +996,112 @@ const errorRange = { start: token.start, end: token.end };` type 'Program' - Always 'Program' for complete schemas + + + Always 'Program' for complete schemas + + kind 'schema' - Always 'schema' for schema files + + + Always 'schema' for schema files + + start number - Starting character position (usually 0) + + + Starting character position (usually 0) + + end number - Ending character position + + + Ending character position + + body (DeclarationToken|ImportToken)[] - Array of all declarations and imports + + + Array of all declarations and imports + +
    - Usage -

    Used by SchemaTree as the root token representing the entire parsed schema file. The Compiler processes the body array to generate the final schema configuration.

    - -

    U Types

    -

    The following types provide flexible token handling for different contexts.

    - -

    Token

    -

    Union type for all possible token types that can be returned by readers.

    + {_('Usage')} + + Used by SchemaTree as the root token representing the entire parsed + schema file. The Compiler processes the body array to generate the + final schema configuration. + +
    + +
    +

    {_('U Types')}

    + + The following types provide flexible token handling for different + contexts. + + +

    {_('Token')}

    + + Union type for all possible token types that can be returned by + readers. + {examples[13]} - Usage -

    Used as the return type for lexer operations and reader functions. Allows handling both recognized data tokens and unknown tokens.

    + {_('Usage')} + + Used as the return type for lexer operations and reader functions. + Allows handling both recognized data tokens and unknown tokens. + -

    DataToken

    -

    Union type for tokens representing data values.

    +

    {_('DataToken')}

    + + Union type for tokens representing data values. + {examples[14]} - Usage -

    Used throughout the Compiler for processing data values. These tokens can be converted to actual JavaScript values using Compiler.data().

    - -

    Parser Interface

    -

    The following types define the parser interface and reader functions.

    - -

    Reader

    -

    Function type for token readers that attempt to parse specific patterns.

    + {_('Usage')} + + Used throughout the Compiler for processing data values. These tokens + can be converted to actual JavaScript values using + Compiler.data(). + +
    + +
    +

    {_('Parser Interface')}

    + + The following types define the parser interface and reader functions. + + +

    {_('Reader')}

    + + Function type for token readers that attempt to parse specific + patterns. + {examples[15]} -

    Parameters

    +

    {_('Parameters')}

    ParameterType @@ -853,19 +1123,26 @@ const errorRange = { start: token.start, end: token.end };`
    - Returns -

    Token object if pattern matches, undefined otherwise.

    - - Usage -

    Used to define token recognition patterns in the definitions system. Each token type has a corresponding reader function.

    - -

    Definition

    -

    Pairs a token key with its reader function for lexer registration.

    + {_('Returns')} + + Token object if pattern matches, undefined otherwise. + + + {_('Usage')} + + Used to define token recognition patterns in the definitions system. + Each token type has a corresponding reader function. + + +

    {_('Definition')}

    + + Pairs a token key with its reader function for lexer registration. + {examples[16]} -

    Properties

    +

    {_('Properties')}

    PropertyType @@ -883,113 +1160,187 @@ const errorRange = { start: token.start, end: token.end };`
    Usage -

    Used by the Lexer to register and manage token definitions. The key identifies the token type, and the reader attempts to parse it.

    - -

    Parser

    -

    Interface defining the contract for parser implementations.

    + + Used by the Lexer to register and manage token definitions. The key + identifies the token type, and the reader attempts to parse it. + + +

    {_('Parser')}

    + + Interface defining the contract for parser implementations. + {examples[17]} Usage -

    Implemented by the Lexer class to provide consistent parsing operations across all tree parsers.

    - -

    Reference Types

    -

    The following types handle reference resolution and data processing.

    - -

    UseReferences

    -

    Type for managing prop and type references during compilation.

    + + Implemented by the Lexer class to provide consistent parsing + operations across all tree parsers. + +
    + +
    +

    {_('Reference Types')}

    + + The following types handle reference resolution and data processing. + + +

    {_('UseReferences')}

    + + Type for managing prop and type references during compilation. + {examples[18]} - Usage -

    Used by the Compiler to resolve identifier references:

    + {_('Usage')} + + Used by the Compiler to resolve identifier references: +
      -
    • false: Return template strings like ${PropName}
    • -
    • Record<string, any>: Resolve identifiers to actual values
    • +
    • + false: Return template strings like ${PropName} +
    • +
    • + Record<string, any>: Resolve identifiers to actual values +
    • Empty object {}: Throw error for unknown references
    -

    Scalar

    -

    Union type for primitive values that can be stored in schema configurations.

    +

    {_('Scalar')}

    + + Union type for primitive values that can be stored in schema + configurations. + {examples[19]} - Usage -

    Used in enum configurations and other places where only primitive values are allowed.

    + {_('Usage')} + + Used in enum configurations and other places where only primitive + values are allowed. + -

    Data

    -

    Recursive type for nested data structures in schema configurations.

    +

    {_('Data')}

    + + Recursive type for nested data structures in schema configurations. + {examples[20]} - Usage -

    Used throughout the system for representing complex nested data structures in plugin configurations, attributes, and other schema elements.

    + {_('Usage')} + + Used throughout the system for representing complex nested data + structures in plugin configurations, attributes, and other schema + elements. + +
    -

    Usage Examples

    +
    +

    {_('Usage Examples')}

    -

    Parsing and Token Generation

    +

    {_('Parsing and Token Generation')}

    {examples[21]} -

    Token Processing with Compiler

    +

    {_('Token Processing with Compiler')}

    {examples[22]} -

    Working with Complex Tokens

    +

    {_('Working with Complex Tokens')}

    {examples[23]} -

    Error Handling with Tokens

    +

    {_('Error Handling with Tokens')}

    {examples[24]} - -

    Token Validation

    -

    Tokens include position information for error reporting and validation:

    +
    + +
    +

    {_('Token Validation')}

    + + Tokens include position information for error reporting and + validation: + {examples[25]} +
    -

    Integration with AST

    -

    AST classes generate specific token types:

    +
    +

    {_('Integration with AST')}

    + + AST classes generate specific token types: +
      -
    • EnumTree: Generates DeclarationToken with kind: 'enum'
    • -
    • PropTree: Generates DeclarationToken with kind: 'prop'
    • -
    • TypeTree: Generates DeclarationToken with kind: 'type'
    • -
    • ModelTree: Generates DeclarationToken with kind: 'model'
    • -
    • PluginTree: Generates DeclarationToken with kind: 'plugin'
    • -
    • UseTree: Generates ImportToken
    • -
    • SchemaTree: Generates SchemaToken containing all other tokens
    • +
    • + EnumTree: + Generates DeclarationToken with kind: 'enum' +
    • +
    • + PropTree: + Generates DeclarationToken with kind: 'prop' +
    • +
    • + TypeTree: + Generates DeclarationToken with kind: 'type' +
    • +
    • + ModelTree: + Generates DeclarationToken with kind: 'model' +
    • +
    • + PluginTree: + Generates DeclarationToken with kind: 'plugin' +
    • +
    • + UseTree: + Generates ImportToken +
    • +
    • + SchemaTree: + Generates SchemaToken containing all other tokens +
    -

    Each AST class uses the Lexer to generate appropriate tokens, which are then processed by the Compiler to produce the final JSON configuration.

    - -
    + +
    + ); +} -
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx b/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx new file mode 100644 index 0000000..95cf467 --- /dev/null +++ b/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx @@ -0,0 +1,126 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, SS } from '../../index.js'; +import Code from '../../Code.js'; + +const enumsExamples = [ + `enum EnumName { + KEY1 "Display Value 1" + KEY2 "Display Value 2" + KEY3 "Display Value 3" +}`, + `enum UserRole { + ADMIN "Administrator" + MODERATOR "Moderator" + USER "Regular User" + GUEST "Guest User" +} + +enum OrderStatus { + PENDING "Pending Payment" + PAID "Payment Confirmed" + SHIPPED "Order Shipped" + DELIVERED "Order Delivered" + CANCELLED "Order Cancelled" +} + +enum Priority { + LOW "Low Priority" + MEDIUM "Medium Priority" + HIGH "High Priority" + URGENT "Urgent" +}`, + `export enum UserRole { + ADMIN = "Administrator", + MODERATOR = "Moderator", + USER = "Regular User", + GUEST = "Guest User" +}`, + `{ + "enum": { + "UserRole": { + "ADMIN": "Administrator", + "MODERATOR": "Moderator", + "USER": "Regular User", + "GUEST": "Guest User" + } + } +}` +] + +export default function Enums() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Enums')}

    + +

    + + Enums define a set of named constants with associated values, + perfect for representing fixed sets of options like user roles, + status values, or categories. + +

    + +

    {_('Syntax')}

    + + + {enumsExamples[0]} + + +

    {_('Structure')}

    +
      +
    • + {_('EnumName: ')} + The identifier used to reference this enum +
    • +
    • + {_('KEY: ')} + The constant name (typically uppercase) +
    • +
    • + {_('"Display Value": ')} + Human-readable label for the constant +
    • +
    + +

    {_('Example')}

    + + + {enumsExamples[1]} + + +

    {_('Generate Output')}

    + +

    + + When processed, enums generate language-specific constants: + +

    + +

    {_('TypeScript:')}

    + + + {enumsExamples[2]} + + +

    {_('JSON:')}

    + + + {enumsExamples[3]} + +
    + ) +} diff --git a/packages/www/plugins/docs/components/specifications/data-types/Models.tsx b/packages/www/plugins/docs/components/specifications/data-types/Models.tsx new file mode 100644 index 0000000..f0e94c6 --- /dev/null +++ b/packages/www/plugins/docs/components/specifications/data-types/Models.tsx @@ -0,0 +1,173 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, SS, C } from '../../index.js'; +import Code from '../../Code.js'; + +const modelsExamples = [ + `model ModelName { + columnName DataType @attribute1 @attribute2 + relationColumn RelatedModel @relation +} + +model ModelName! { // Mutable model + // columns... +}`, + `// base-schema.idea +model User { + id String @id + name String @required +} + +// extended-schema.idea +use "./base-schema.idea" + +// This will merge with the imported User model +model User { + email String @required + created Date @default("now()") +} + +// This will NOT merge - it completely replaces the imported User +model User! { + id String @id + username String @required + password String @required +}`, + `model User! { + id String @id @default("nanoid()") + email String @unique @required @field.input(Email) + username String @unique @required @field.input(Text) + password String @required @field.input(Password) + profile UserProfile? + role UserRole @default("USER") + active Boolean @default(true) + lastLogin Date? + created Date @default("now()") + updated Date @default("updated()") +} + +model UserProfile { + id String @id @default("nanoid()") + userId String @relation(User.id) + firstName String @required @field.input(Text) + lastName String @required @field.input(Text) + bio String @field.textarea + avatar String @field.upload + address Address + contact ContactInfo + preferences { + theme String @default("light") + language String @default("en") + notifications Boolean @default(true) + } +} + +model Post { + id String @id @default("nanoid()") + title String @required @field.input(Text) + slug String @unique @generated + content String @required @field.richtext + excerpt String @field.textarea + authorId String @relation(User.id) + author User @relation(User, authorId) + status PostStatus @default("DRAFT") + tags String[] @field.tags + publishedAt Date? + created Date @default("now()") + updated Date @default("updated()") +} + +enum PostStatus { + DRAFT "Draft" + PUBLISHED "Published" + ARCHIVED "Archived" +}` + +] + +export default function Models() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Models')}

    + +

    + + Models represent the core entities in your application, + typically corresponding to database tables or API resources. + They define the structure, relationships, and behavior of your + data. + +

    + +
    +

    {_('Syntax')}

    + + {modelsExamples[0]} + + +

    {_('Structure')}

    +
      +
    • + {_('ModelName: ')} + The identifier for this model +
    • +
    • + !: + + Optional non-mergeable indicator prevents automatic + merging when using use directives + +
    • +
    • + {_('columnName: ')} + The field name within the model +
    • +
    • + {_('DataType: ')} + + Built-in types (String, Number, Boolean, Date) or custom + types/enums + +
    • +
    • + {_('@attribute: ')} + + Attributes for validation, relationships, UI, etc. + +
    • +
    + +

    {_('Merging Behavior')}

    + +

    + + By default, when importing schemas with use directives, + models with the same name are automatically merged. The ! + suffix prevents this behavior: + +

    + + {modelsExamples[1]} + + +

    {_('Example')}

    + + {modelsExamples[2]} + +
    +
    + ) +} diff --git a/packages/www/plugins/docs/components/specifications/data-types/Props.tsx b/packages/www/plugins/docs/components/specifications/data-types/Props.tsx new file mode 100644 index 0000000..7245f06 --- /dev/null +++ b/packages/www/plugins/docs/components/specifications/data-types/Props.tsx @@ -0,0 +1,125 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, SS, C } from '../../index.js'; +import Code from '../../Code.js'; + +const propsExamples = [ + `prop PropName { + property "value" + nested { + property "value" + } +}`, + `prop Email { + type "email" + format "email" + validation { + required true + pattern "^[^\s@]+@[^\s@]+\.[^\s@]+$" + } + ui { + component "EmailInput" + placeholder "Enter your email address" + icon "envelope" + } +} + +prop Password { + type "password" + validation { + required true + minLength 8 + pattern "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]" + } + ui { + component "PasswordInput" + placeholder "Enter a secure password" + showStrength true + } +} + +prop Currency { + type "number" + format "currency" + validation { + min 0 + precision 2 + } + ui { + component "CurrencyInput" + symbol "$" + locale "en-US" + } +}`, + `model User { + email String @field.input(Email) + password String @field.input(Password) +}` +] + +export default function Props() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Props')}

    + +

    + + Props are reusable property configurations that define common + field behaviors, validation rules, and UI components. They + promote consistency and reduce duplication across your schema. + +

    + +

    {_('Syntax')}

    + + {propsExamples[0]} + + +

    {_('Structure')}

    + +
      +
    • + {_('PropName:')} + + The identifier used to reference this prop + +
    • +
    • + {_('property:')} + Configuration key-value pairs +
    • +
    • + {_('nested:')} + A nested prop +
    • +
    + +

    {_('Example')}

    + + {propsExamples[1]} + + + {_('Usage in Models')} +

    + Props are referenced using the + {_('@field')} {_('attribute:')} +

    + + {propsExamples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/components/specifications/data-types/Type.tsx b/packages/www/plugins/docs/components/specifications/data-types/Type.tsx new file mode 100644 index 0000000..c9c4e21 --- /dev/null +++ b/packages/www/plugins/docs/components/specifications/data-types/Type.tsx @@ -0,0 +1,119 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, SS } from '../../index.js'; +import Code from '../../Code.js'; + +const typeExamples = [ + `type TypeName { + columnName DataType @attribute1 @attribute2 + anotherColumn DataType @attribute +}`, + `type Address { + street String @required @field.input(Text) + city String @required @field.input(Text) + state String @field.select + postalCode String @field.input(Text) + country String @default("US") @field.select + coordinates { + latitude Number @field.input(Number) + longitude Number @field.input(Number) + } +} + +type ContactInfo { + email String @required @field.input(Email) + phone String @field.input(Phone) + website String @field.input(URL) + socialMedia { + twitter String @field.input(Text) + linkedin String @field.input(Text) + github String @field.input(Text) + } +} + +type Money { + amount Number @required @field.input(Currency) + currency String @default("USD") @field.select + exchangeRate Number @field.input(Number) +}`, + `model Company { + name String @required + address Address @required + contact ContactInfo + revenue Money +}` +] + +export default function Type() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Type')}

    + +

    + + Types define custom data structures with multiple columns, + similar to objects or structs in programming languages. They + are perfect for representing complex data that doesn't warrant + a full model. + +

    + +

    {_('Syntax')}

    + + {typeExamples[0]} + + +

    {_('Structure')}

    + +
      +
    • + {_('TypeName: ')} + + The identifier used to reference this type + +
    • +
    • + {_('columnName: ')} + The field name within the type +
    • +
    • + {_('DataType: ')} + + The data type (String, Number, Boolean, Date, etc.) + +
    • +
    • + {_('attribute: ')} + + Optional attributes for validation, UI, or behavior + +
    • +
    + +

    {_('Example')}

    + + + {typeExamples[1]} + + +

    {_('Usage in Models')}

    +

    + Types are used as column data types: +

    + + {typeExamples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx b/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx similarity index 54% rename from packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx rename to packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx index 0458494..adce31b 100644 --- a/packages/www/plugins/docs/views/specifications/components/schema-directives/Plugin.tsx +++ b/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx @@ -1,5 +1,6 @@ -import { H1, H2, P, SS, C } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; +import { H1, H2, P, SS, C } from '../../index.js'; +import Code from '../../Code.js'; +import { useLanguage, Translate } from 'r22n'; const pluginExamples = [ `plugin "path/to/plugin.js" { @@ -165,52 +166,117 @@ export default async function myPlugin( ] export default function Plugin() { + const { _ } = useLanguage(); + return (
    -

    Plugin

    -

    - The plugin directive configures code generation plugins that process your schema and generate various outputs like TypeScript interfaces, database schemas, API documentation, and more. -

    -

    Syntax

    - - {pluginExamples[0]} - - -

    Structure

    -
      -
    • Path: Relative or absolute path to the plugin file
    • -
    • Configuration Block: Key-value pairs that configure the plugin behavior
    • -
    • Nested Configuration: Support for complex configuration structures
    • -
    - -

    Example

    - - {pluginExamples[1]} - - -

    Plugin Configuration Options

    -

    - Common configuration patterns across different plugin types: -

    - - {pluginExamples[2]} - - -

    Multiple Plugins Execution

    -

    - You can configure multiple plugins to generate different outputs from the same schema: -

    - - {pluginExamples[3]} - - -

    Plugin Development

    -

    - Plugins are JavaScript/TypeScript modules that export a default function: -

    - - {pluginExamples[4]} - +
    +

    {_('Plugin')}

    +

    + + The plugin directive configures code generation + plugins that process your schema and generate various + outputs like TypeScript interfaces, database schemas, API + documentation, and more. + +

    +
    + +
    +

    {_('Syntax')}

    + + {pluginExamples[0]} + +
    + +
    +

    {_('Structure')}

    +
      +
    • + {_('Path:')}{' '} + + Relative or absolute path to the plugin file + +
    • +
    • + {_('Configuration Block:')}{' '} + + Key-value pairs that configure the plugin behavior + +
    • +
    • + {_('Nested Configuration:')}{' '} + + Support for complex configuration structures + +
    • +
    +
    + +
    +

    {_('Example')}

    + + {pluginExamples[1]} + +
    + +
    +

    {_('Plugin Configuration Options')}

    +

    + + Common configuration patterns across different plugin types: + +

    + + {pluginExamples[2]} + +
    + +
    +

    {_('Multiple Plugins Execution')}

    +

    + + You can configure multiple plugins to generate different + outputs from the same schema: + +

    + + {pluginExamples[3]} + +
    + +
    +

    {_('Plugin Development')}

    +

    + + Plugins are JavaScript/TypeScript modules that export a + default function: + +

    + + {pluginExamples[4]} + +
    - ) + ); } diff --git a/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx b/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx new file mode 100644 index 0000000..d45d35d --- /dev/null +++ b/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx @@ -0,0 +1,219 @@ +import { H1, H2, P, SS, C } from '../../index.js'; +import Code from '../../Code.js'; +import { useLanguage, Translate } from 'r22n'; + + +const useExamples = [ + `use "package/to/schema.idea" +use "./relative/path/schema.idea" +use "../parent/directory/schema.idea"`, + `// Common types used across multiple schemas +type Address { + street String @required + city String @required + country String @default("US") +} + +enum Status { + ACTIVE "Active" + INACTIVE "Inactive" +} + +prop Email { + type "email" + validation { + required true + format "email" + } +}`, + `// Import common definitions +use "../shared/common.idea" + +// Extend the Status enum (will merge with imported one) +enum Status { + PENDING "Pending Approval" + SUSPENDED "Temporarily Suspended" +} + +// Use imported types and props +model User { + id String @id @default("nanoid()") + email String @field.input(Email) + address Address + status Status @default("PENDING") +}`, + `// The Status enum now contains all values +enum Status { + ACTIVE "Active" // From common.idea + INACTIVE "Inactive" // From common.idea + PENDING "Pending Approval" // From user-schema.idea + SUSPENDED "Temporarily Suspended" // From user-schema.idea +}`, +`enum UserRole { + USER "Regular User" + ADMIN "Administrator" +}`, +`use "./base-schema.idea" + +// This will NOT merge with the imported UserRole +// Instead, it will override it completely +enum UserRole! { + GUEST "Guest User" + MEMBER "Member" + MODERATOR "Moderator" + ADMIN "Administrator" +}`, +`// ✅ Good - organize by domain +use "./shared/common-types.idea" +use "./auth/user-types.idea" +use "./commerce/product-types.idea" + +// ✅ Good - clear file naming +use "./enums/status-enums.idea" +use "./types/address-types.idea" +use "./props/form-props.idea" + +// ❌ Avoid - unclear imports +use "./stuff.idea" +use "./misc.idea"` +] + +export default function Use() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Use')}

    +

    + + The use directive imports definitions from other{' '} + .idea files, enabling modular schema organization and{' '} + reusability. When importing, data types with the same name are{' '} + automatically merged unless the ! (non-mergeable){' '} + indicator is used. + +

    +
    +
    +

    {_('Syntax')}

    + + {useExamples[0]} + +
    + +
    +

    {_('Structure')}

    +
      +
    • + {_('Path:')} {_('Relative or absolute path to the')}{' '} + .idea {_('file to import')} +
    • +
    • + {_('Automatic Merging:')}{' '} + {_('Data types with matching names are merged by default')} +
    • +
    • + {_('Merge Prevention:')} {_('Use')} !{' '} + {_('suffix to prevent merging')} +
    • +
    +
    + +
    +

    {_('Example')}

    +

    shared/common.idea

    + + {useExamples[1]} + + +

    user/user-schema.idea:

    + + {useExamples[2]} + + +

    {_('Result after merging:')}

    + + {useExamples[3]} + +
    + +
    + {_('Prevent merging with')} ! +

    + + When you want to prevent automatic merging and keep definitions{' '} + separate, use the ! suffix: + +

    + + {_('base-schema.idea:')} + + {useExamples[4]} + + + {_('extended-schema.idea:')} + + {useExamples[5]} + +
    + +
    +

    {_('Use Cases')}

    +
      +
    • + {_('Shared Types:')}{' '} + {_('Define common types once and reuse across multiple schemas')} +
    • +
    • + {_('Modular Organization:')}{' '} + {_('Split large schemas into manageable, focused files')} +
    • +
    • + {_('Team Collaboration:')}{' '} + {_('Different teams can work on separate schema files')} +
    • +
    • + {_('Environment-Specific:')}{' '} + {_('Override certain definitions for different environments')} +
    • +
    +
    + +
    +

    {_('Best Practices')}

    + + {useExamples[6]} + +
    +
    + ); +} diff --git a/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx new file mode 100644 index 0000000..ece6b34 --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx @@ -0,0 +1,20 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; + +export default function Conclusion() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Conclusion')}

    +

    + + This tutorial provides a comprehensive foundation for creating + test data generation plugins that can handle complex schemas and + generate realistic, useful test data for development and testing + workflows. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx b/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx new file mode 100644 index 0000000..a34c388 --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx @@ -0,0 +1,127 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const corePluginExample = `export default async function generateTestData( + props: PluginProps<{ config: TestDataConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate test data content + let content = ''; + + // Add file header and imports + content += generateFileHeader(config); + content += generateImports(config); + + // Generate data factories if requested + if (config.generateFactories) { + content += generateFactories(schema, config); + } + + // Generate mock data + if (schema.model) { + content += generateMockData(schema.model, config); + } + + // Generate fixtures if requested + if (config.generateFixtures) { + content += generateFixtures(schema, config); + } + + // Generate main export + content += generateMainExport(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ Test data generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ Test data generation failed:', error.message); + throw error; + } +}`; + +const headerAndImportsExample = `function generateFileHeader(config: TestDataConfig): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated Test Data and Fixtures + * Generated at: \${timestamp} + * Format: \${config.format} + * Count: \${config.count || 10} + * Seed: \${config.seed || 'random'} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateImports(config: TestDataConfig): string { + let imports = ''; + + if (config.format === 'typescript' || config.format === 'javascript') { + imports += \`import { faker } from '@faker-js/faker';\\n\\n\`; + + if (config.seed) { + imports += \`// Set seed for reproducible data\\nfaker.seed(\${config.seed});\\n\\n\`; + } + + if (config.locale && config.locale !== 'en') { + imports += \`// Set locale\\nfaker.setLocale('\${config.locale}');\\n\\n\`; + } + } + + return imports; +}`; + +export default function CorePluginFunction() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('4. Implementation')}

    +

    + + The implementation section covers the core plugin function and + supporting utilities that handle test data generation. This + includes the main plugin entry point, data generation functions, + and configuration validation. + +

    + +

    {_('4.1. Core Plugin Function')}

    +

    + + The core plugin function serves as the main entry point for test + data generation. It orchestrates the entire process from + configuration validation to file output, handling different + formats and generation options. + +

    + + {corePluginExample} + + +

    {_('4.2. Generation Functions')}

    +

    + + The generation functions provide the core logic for creating + different types of test data content. These utility functions + handle file headers, imports, data factories, and various data + generation patterns based on schema definitions. + +

    + + {headerAndImportsExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx b/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx new file mode 100644 index 0000000..5bd1d07 --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx @@ -0,0 +1,458 @@ +import Code from '../Code.js'; + +const factoriesExample = `function generateFactories(schema: any, config: TestDataConfig): string { + let content = '// Data Factories\\n'; + + // Generate enum factories + if (schema.enum) { + for (const [enumName, enumDef] of Object.entries(schema.enum)) { + content += generateEnumFactory(enumName, enumDef, config); + } + } + + // Generate model factories + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + content += generateModelFactory(modelName, model, config); + } + } + + return content + '\\n'; +} + +function generateEnumFactory(enumName: string, enumDef: any, config: TestDataConfig): string { + const values = Object.values(enumDef); + const valuesArray = values.map(v => \`"\${v}"\`).join(', '); + + return \`export function generate\${enumName}(): string { + return faker.helpers.arrayElement([\${valuesArray}]); +} + +\`; +} + +function generateModelFactory(modelName: string, model: any, config: TestDataConfig): string { + let content = \`export function generate\${modelName}(overrides: Partial<\${modelName}> = {}): \${modelName} { + return { +\`; + + for (const column of model.columns || []) { + const generator = generateFieldGenerator(column, config); + content += \` \${column.name}: \${generator},\\n\`; + } + + content += \` ...overrides, + }; +} + +export function generate\${modelName}Array(count: number = \${config.count || 10}): \${modelName}[] { + return Array.from({ length: count }, () => generate\${modelName}()); +} + +\`; + + return content; +}`; + +const fieldGeneratorExample = `function generateFieldGenerator(column: any, config: TestDataConfig): string { + // Check for custom generators first + if (config.customGenerators && config.customGenerators[column.type]) { + return config.customGenerators[column.type]; + } + + // Handle arrays + if (column.multiple) { + const baseGenerator = getBaseGenerator(column, config); + const arraySize = column.attributes?.minLength || 1; + const maxSize = column.attributes?.maxLength || 5; + return \`faker.helpers.multiple(() => \${baseGenerator}, { count: { min: \${arraySize}, max: \${maxSize} } })\`; + } + + return getBaseGenerator(column, config); +} + +function getBaseGenerator(column: any, config: TestDataConfig): string { + const { type, attributes = {} } = column; + + // Handle custom field types based on attributes + if (attributes.email) { + return 'faker.internet.email()'; + } + + if (attributes.url) { + return 'faker.internet.url()'; + } + + if (attributes.uuid) { + return 'faker.string.uuid()'; + } + + if (attributes.phone) { + return 'faker.phone.number()'; + } + + if (attributes.color) { + return 'faker.internet.color()'; + } + + // Handle based on field name patterns + const fieldName = column.name.toLowerCase(); + + if (fieldName.includes('email')) { + return 'faker.internet.email()'; + } + + if (fieldName.includes('name')) { + if (fieldName.includes('first')) return 'faker.person.firstName()'; + if (fieldName.includes('last')) return 'faker.person.lastName()'; + if (fieldName.includes('full')) return 'faker.person.fullName()'; + return 'faker.person.fullName()'; + } + + if (fieldName.includes('address')) { + return 'faker.location.streetAddress()'; + } + + if (fieldName.includes('city')) { + return 'faker.location.city()'; + } + + if (fieldName.includes('country')) { + return 'faker.location.country()'; + } + + if (fieldName.includes('phone')) { + return 'faker.phone.number()'; + } + + if (fieldName.includes('company')) { + return 'faker.company.name()'; + } + + if (fieldName.includes('title')) { + return 'faker.lorem.sentence()'; + } + + if (fieldName.includes('description') || fieldName.includes('content')) { + return 'faker.lorem.paragraphs()'; + } + + if (fieldName.includes('image') || fieldName.includes('avatar')) { + return 'faker.image.url()'; + } + + if (fieldName.includes('price') || fieldName.includes('amount')) { + return 'faker.commerce.price()'; + } + + // Handle based on schema type + switch (type) { + case 'String': + if (attributes.min && attributes.max) { + return \`faker.lorem.words({ min: \${attributes.min}, max: \${attributes.max} })\`; + } + return 'faker.lorem.words()'; + + case 'Number': + case 'Integer': + const min = attributes.min || 1; + const max = attributes.max || 1000; + return \`faker.number.int({ min: \${min}, max: \${max} })\`; + + case 'Boolean': + return 'faker.datatype.boolean()'; + + case 'Date': + if (fieldName.includes('birth')) { + return 'faker.date.birthdate()'; + } + if (fieldName.includes('future')) { + return 'faker.date.future()'; + } + if (fieldName.includes('past')) { + return 'faker.date.past()'; + } + return 'faker.date.recent()'; + + case 'JSON': + return 'faker.datatype.json()'; + + case 'ID': + return 'faker.string.uuid()'; + + default: + // Check if it's an enum or custom type + if (type.endsWith('Role') || type.endsWith('Status') || type.endsWith('Type')) { + return \`generate\${type}()\`; + } + return 'faker.lorem.word()'; + } +}`; + +const mockDataExample = `function generateMockData(models: Record, config: TestDataConfig): string { + if (config.format === 'json') { + return generateJSONMockData(models, config); + } + + let content = '// Mock Data\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`export const mock\${modelName}Data = generate\${modelName}Array(\${config.count || 10});\\n\`; + } + + return content + '\\n'; +} + +function generateJSONMockData(models: Record, config: TestDataConfig): string { + let content = ''; + const mockData: Record = {}; + + for (const [modelName, model] of Object.entries(models)) { + const data = []; + for (let i = 0; i < (config.count || 10); i++) { + const item: Record = {}; + + for (const column of model.columns || []) { + item[column.name] = generateMockValue(column, config); + } + + data.push(item); + } + + mockData[modelName.toLowerCase()] = data; + } + + return JSON.stringify(mockData, null, 2); +} + +function generateMockValue(column: any, config: TestDataConfig): any { + const { type, attributes = {} } = column; + + // Simple mock value generation for JSON format + switch (type) { + case 'String': + if (attributes.email) return 'user@example.com'; + if (attributes.url) return 'https://example.com'; + if (column.name.toLowerCase().includes('name')) return 'John Doe'; + return 'Sample Text'; + + case 'Number': + case 'Integer': + return Math.floor(Math.random() * 1000) + 1; + + case 'Boolean': + return Math.random() > 0.5; + + case 'Date': + return new Date().toISOString(); + + case 'ID': + return \`id_\${Math.random().toString(36).substr(2, 9)}\`; + + default: + return 'mock_value'; + } +}`; + +const fixturesExample = `function generateFixtures(schema: any, config: TestDataConfig): string { + let content = '// Test Fixtures\\n'; + + if (schema.model) { + for (const [modelName, model] of Object.entries(schema.model)) { + content += generateModelFixtures(modelName, model, config); + } + } + + return content; +} + +function generateModelFixtures(modelName: string, model: any, config: TestDataConfig): string { + const lowerName = modelName.toLowerCase(); + + return \`export const \${lowerName}Fixtures = { + valid: generate\${modelName}({ + // Override with specific test values + }), + + minimal: generate\${modelName}({ + // Minimal required fields only + \${generateMinimalFields(model)} + }), + + invalid: { + // Invalid data for negative testing + \${generateInvalidFields(model)} + }, + + edge: generate\${modelName}({ + // Edge case values + \${generateEdgeCaseFields(model)} + }), +}; + +\`; +}`; + +const fixtureUtilsExample = `function generateMinimalFields(model: any): string { + const requiredFields = model.columns?.filter((col: any) => + col.required && !col.attributes?.id && !col.attributes?.default + ) || []; + + return requiredFields.map((col: any) => { + const value = getMinimalValue(col); + return \`\${col.name}: \${value}\`; + }).join(',\\n '); +} + +function generateInvalidFields(model: any): string { + const fields = model.columns?.slice(0, 3) || []; // First 3 fields for example + + return fields.map((col: any) => { + const invalidValue = getInvalidValue(col); + return \`\${col.name}: \${invalidValue}\`; + }).join(',\\n '); +} + +function generateEdgeCaseFields(model: any): string { + const fields = model.columns?.slice(0, 3) || []; // First 3 fields for example + + return fields.map((col: any) => { + const edgeValue = getEdgeCaseValue(col); + return \`\${col.name}: \${edgeValue}\`; + }).join(',\\n '); +}`; + +const valueGeneratorsExample = `function getMinimalValue(column: any): string { + switch (column.type) { + case 'String': + return '"a"'; + case 'Number': + case 'Integer': + return column.attributes?.min || '1'; + case 'Boolean': + return 'true'; + case 'Date': + return 'new Date()'; + default: + return '""'; + } +} + +function getInvalidValue(column: any): string { + switch (column.type) { + case 'String': + if (column.attributes?.email) return '"invalid-email"'; + if (column.attributes?.min) return '""'; // Too short + return 'null'; + case 'Number': + case 'Integer': + return '"not-a-number"'; + case 'Boolean': + return '"not-boolean"'; + case 'Date': + return '"invalid-date"'; + default: + return 'null'; + } +} + +function getEdgeCaseValue(column: any): string { + switch (column.type) { + case 'String': + if (column.attributes?.max) { + return \`"\${'a'.repeat(column.attributes.max)}"\`; + } + return '"very long string that might cause issues with processing or display"'; + case 'Number': + case 'Integer': + return column.attributes?.max || '999999'; + case 'Boolean': + return 'false'; + case 'Date': + return 'new Date("1900-01-01")'; + default: + return '""'; + } +}`; + +const mainExportExample = `function generateMainExport(schema: any, config: TestDataConfig): string { + if (config.format === 'json') { + return ''; // JSON format doesn't need exports + } + + let content = '// Main Export\\nexport const testData = {\\n'; + + // Export factories + if (config.generateFactories && schema.model) { + content += ' factories: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName}: generate\${modelName},\\n\`; + content += \` \${modelName}Array: generate\${modelName}Array,\\n\`; + } + content += ' },\\n'; + } + + // Export mock data + if (schema.model) { + content += ' mockData: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName.toLowerCase()}: mock\${modelName}Data,\\n\`; + } + content += ' },\\n'; + } + + // Export fixtures + if (config.generateFixtures && schema.model) { + content += ' fixtures: {\\n'; + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName.toLowerCase()}: \${modelName.toLowerCase()}Fixtures,\\n\`; + } + content += ' },\\n'; + } + + content += '};\\n\\nexport default testData;\\n'; + + return content; +} + +function validateConfig(config: any): asserts config is TestDataConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('Test Data plugin requires "output" configuration as string'); + } + + if (!config.format || !['json', 'typescript', 'javascript'].includes(config.format)) { + throw new Error('format must be one of: json, typescript, javascript'); + } + + if (config.count && (typeof config.count !== 'number' || config.count < 1)) { + throw new Error('count must be a positive number'); + } +}`; + +export default function GenerationFunctions() { + return ( +
    + + {factoriesExample} + + + {fieldGeneratorExample} + + + {mockDataExample} + + + {fixturesExample} + + + {fixtureUtilsExample} + + + {valueGeneratorsExample} + + + {mainExportExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx b/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx new file mode 100644 index 0000000..4d9942d --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx @@ -0,0 +1,56 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, SS } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Test Data Generator Plugin Tutorial')}

    +

    + + This tutorial demonstrates how to create a plugin that + generates mock data and test fixtures from .idea schema + files. The plugin will transform your schema models into + realistic test data for development, testing, and prototyping. + +

    + +

    {_('1. Overview')}

    +

    + + Test data generation is crucial for development and testing + workflows. This plugin generates realistic mock data from your + .idea schema, including: + +

    +
      +
    • + Mock Data: + Realistic test data based on schema types + +
    • +
    • + Fixtures: + Predefined test datasets for consistent testing + +
    • +
    • + Factories: + Data generation functions for dynamic testing + +
    • +
    • + Relationships: + Proper handling of model relationships + +
    • +
    • + Customization: + Custom data generators and constraints + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx new file mode 100644 index 0000000..cfb3a6e --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx @@ -0,0 +1,46 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface TestDataConfig { + output: string; + format: 'json' | 'typescript' | 'javascript'; + count?: number; + seed?: number; + locale?: string; + generateFactories?: boolean; + generateFixtures?: boolean; + customGenerators?: Record; + relationships?: boolean; +} + +export default async function generateTestData( + props: PluginProps<{ config: TestDataConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`; + +export default function PluginStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('3. Plugin Structure')}

    +

    + + The following code shows how to generally layout the plugin so + you can focus on the implementation. + +

    + + {pluginStructureExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx new file mode 100644 index 0000000..486bb1d --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx @@ -0,0 +1,38 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C } from '../index.js'; + +export default function Prerequisites() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('2. Prerequisites')}

    +

    + + Before creating this plugin, you should have the following + knowledge and tools: + +

    +
      +
    • + Node.js 16+ and npm/yarn +
    • +
    • + TypeScript 4.0+ +
    • +
    • + Faker.js 8.0+ (for realistic data generation) +
    • +
    • + Basic understanding of testing concepts +
    • +
    • + Familiarity with the @stackpress/idea-transformer library +
    • +
    • + Understanding of .idea schema format +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx new file mode 100644 index 0000000..f60ee70 --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx @@ -0,0 +1,135 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C, SS } from '../index.js'; +import Code from '../Code.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +const schemaConfigExample = `plugin "./plugins/test-data.js" { + output "./generated/test-data.ts" + format "typescript" + count 20 + seed 12345 + locale "en" + generateFactories true + generateFixtures true + relationships true + customGenerators { + Email "faker.internet.email()" + Password "faker.internet.password()" + Slug "faker.lorem.slug()" + } +}`; + +export default function SchemaConfiguration() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('5. Schema Configuration')}

    +

    + + The schema configuration section demonstrates how to integrate + the test data plugin into your .idea schema files. This includes + plugin declaration syntax, configuration options, and examples + of how to customize the plugin behavior for different use cases. + +

    +

    + + Add the Test Data plugin to your .idea schema file: + +

    + + {schemaConfigExample} + + +

    {_('5.1. Configuration Options')}

    +

    + + The following options will be processed by the test data plugin + in this tutorial. + +

    + + + + Option + Type + Default + Description + + + output + string + Required + + Output file path for test data + + + + format + 'json'|'typescript'|'javascript' + Required + + Output format + + + + count + number + 10 + + Number of records to generate per model + + + + seed + number + undefined + + Seed for reproducible data generation + + + + locale + string + 'en' + + Locale for faker.js data generation + + + + generateFactories + boolean + true + + Generate data factory functions + + + + generateFixtures + boolean + true + + Generate test fixtures + + + + customGenerators + object + {`{}`} + + Custom data generators for specific types + + + + relationships + boolean + false + + Handle model relationships + + +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/index.tsx b/packages/www/plugins/docs/components/test-data-plugin/index.tsx new file mode 100644 index 0000000..d9611ee --- /dev/null +++ b/packages/www/plugins/docs/components/test-data-plugin/index.tsx @@ -0,0 +1,7 @@ +export { default as Overview } from './Overview.js'; +export { default as Prerequisites } from './Prerequisites.js'; +export { default as PluginStructure } from './PluginStructure.js'; +export { default as CorePluginFunction } from './CorePluginFunction.js'; +export { default as GenerationFunctions } from './GenerationFunctions.js'; +export { default as SchemaConfiguration } from './SchemaConfiguration.js'; +export { default as Conclusion } from './Conclusion.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/transformers/api-references/terminal.tsx b/packages/www/plugins/docs/components/transformers/api-references/terminal.tsx new file mode 100644 index 0000000..82cce3b --- /dev/null +++ b/packages/www/plugins/docs/components/transformers/api-references/terminal.tsx @@ -0,0 +1,1183 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, P, C, Nav } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +const basicExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +const terminal = await Terminal.load(['transform', '--input', './schema.idea']); +await terminal.run();` +]; + +const loadExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +// Load with command-line arguments +const args = ['transform', '--input', './schema.idea']; +const terminal = await Terminal.load(args); + +// Load with custom options +const terminal = await Terminal.load(args, { + cwd: '/custom/working/directory', + extname: '.schema', + brand: '[MY-TOOL]' +});` +]; + +const runExample = [ + `const terminal = await Terminal.load(['transform', '--input', './schema.idea']); +await terminal.run();` +]; + +const basicCommandExecutionExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +// Process a schema file +const args = ['transform', '--input', './schema.idea']; +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const shortFlagExample = [ + `// Using the short flag alias +const args = ['transform', '--i', './schema.idea']; +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const customWorkingDirectoryExample = [ + `// Set custom working directory +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: '/path/to/project' +}); +await terminal.run();` +]; + +const customFileExtensionExample = [ + `// Use custom file extension +const terminal = await Terminal.load(['transform', '--i', './schema.custom'], { + extname: '.custom' +}); +await terminal.run();` +]; + +const customBrandExample = [ + `// Use custom terminal brand +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + brand: '[MY-SCHEMA-TOOL]' +}); +await terminal.run();` +]; + +const directCommandLineExample = [ + `## Basic usage +node cli.js transform --input ./schema.idea + +## Using short flag +node cli.js transform --i ./schema.idea + +## With custom working directory +cd /path/to/project && node cli.js transform --i ./schema.idea` +]; + +const cliScriptExample = [ + `#!/usr/bin/env node +import Terminal from '@stackpress/idea-transformer/Terminal'; + +async function main() { + try { + const args = process.argv.slice(2); + const terminal = await Terminal.load(args, { + cwd: process.cwd(), + brand: '[SCHEMA-CLI]' + }); + await terminal.run(); + } catch (error) { + console.error('CLI Error:', error.message); + process.exit(1); + } +} + +main();` +]; + +const packageJsonIntegrationExample = [ + `{ + "name": "my-schema-tool", + "bin": { + "schema": "./cli.js" + }, + "scripts": { + "build": "schema transform --i ./schema.idea", + "dev": "schema transform --i ./dev-schema.idea" + } +}` +]; + +const defaultPathExample = [ + `// Default file path construction +const defaultPath = \`\${terminal.cwd}/schema\${terminal.extname}\`; +// Example: "/current/directory/schema.idea"` +]; + +const flagProcessingExample = [ + `// These are equivalent: +['transform', '--input', './schema.idea'] +['transform', '--i', './schema.idea'] + +// Uses default path: ./schema.idea +['transform']` +]; + +const missingSchemaFileExample = [ + `try { + const terminal = await Terminal.load(['transform', '--i', './nonexistent.idea']); + await terminal.run(); +} catch (error) { + console.error('File not found:', error.message); +}` +]; + +const invalidCommandExample = [ + `try { + const terminal = await Terminal.load(['invalid-command']); + await terminal.run(); +} catch (error) { + console.error('Unknown command:', error.message); +}` +]; + +const pluginErrorsExample = [ + `// If plugins fail during transformation +try { + const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + await terminal.run(); +} catch (error) { + console.error('Transformation failed:', error.message); +}` +]; + +const customEventHandlersExample = [ + `import Terminal from '@stackpress/idea-transformer/Terminal'; + +const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + +// Add custom event handler +terminal.on('custom-command', async (event) => { + console.log('Custom command executed'); + // Custom logic here +}); + +await terminal.run();` +]; + +const programmaticCLIExample = [ + `// Build CLI arguments programmatically +function buildCLIArgs(schemaFile: string, options: any = {}) { + const args = ['transform']; + + if (schemaFile) { + args.push('--input', schemaFile); + } + + return args; +} + +const args = buildCLIArgs('./my-schema.idea'); +const terminal = await Terminal.load(args); +await terminal.run();` +]; + +const batchProcessingExample = [ + `import { glob } from 'glob'; + +async function processAllSchemas(pattern: string) { + const schemaFiles = await glob(pattern); + + for (const schemaFile of schemaFiles) { + console.log(\`Processing \${schemaFile}...\`); + + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + + console.log(\`Completed \${schemaFile}\`); + } +} + +// Process all .idea files in a directory +await processAllSchemas('./schemas/**/*.idea');` +]; + +const environmentBasedConfigExample = [ + `const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: process.env.SCHEMA_CWD || process.cwd(), + extname: process.env.SCHEMA_EXT || '.idea', + brand: process.env.CLI_BRAND || '[IDEA]' +}); + +await terminal.run();` +]; + +const webpackPluginExample = [ + `class SchemaTransformPlugin { + constructor(options = {}) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.beforeCompile.tapAsync('SchemaTransformPlugin', async (params, callback) => { + try { + const terminal = await Terminal.load(['transform', '--i', this.options.schemaFile]); + await terminal.run(); + callback(); + } catch (error) { + callback(error); + } + }); + } +}` +]; + +const gulpTaskExample = [ + `import gulp from 'gulp'; +import Terminal from '@stackpress/idea-transformer/Terminal'; + +gulp.task('transform-schema', async () => { + const terminal = await Terminal.load(['transform', '--i', './schema.idea']); + await terminal.run(); +});` +]; + +const npmScriptsExample = [ + `{ + "scripts": { + "schema:build": "node -e \"import('./cli.js').then(m => m.default(['transform', '--i', './schema.idea']))\"", + "schema:dev": "node -e \"import('./cli.js').then(m => m.default(['transform', '--i', './dev-schema.idea']))\"", + "schema:watch": "nodemon --watch schema.idea --exec \"npm run schema:build\"" + } +}` +]; + +const unitTestingExample = [ + `import { expect } from 'chai'; +import Terminal from '@stackpress/idea-transformer/Terminal'; + +describe('Terminal Tests', () => { + it('should process schema file', async () => { + const terminal = await Terminal.load(['transform', '--i', './test-schema.idea'], { + cwd: './test-fixtures' + }); + + expect(terminal.cwd).to.include('test-fixtures'); + + // Run the terminal command + await terminal.run(); + + // Verify output files were created + // ... assertions here + }); + + it('should use default options', async () => { + const terminal = await Terminal.load(['transform']); + + expect(terminal.extname).to.equal('.idea'); + expect(terminal.cwd).to.be.a('string'); + }); +});` +]; + +const integrationTestingExample = [ + `import fs from 'fs'; +import path from 'path'; + +describe('Terminal Integration', () => { + it('should generate expected output files', async () => { + const outputDir = './test-output'; + const schemaFile = './test-schema.idea'; + + // Clean output directory + if (fs.existsSync(outputDir)) { + fs.rmSync(outputDir, { recursive: true }); + } + + // Run transformation + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + + // Verify expected files were created + const expectedFiles = ['types.ts', 'enums.ts', 'models.ts']; + for (const file of expectedFiles) { + const filePath = path.join(outputDir, file); + expect(fs.existsSync(filePath)).to.be.true; + } + }); +});` +]; + +const errorHandlingBestPracticeExample = [ + `// Always wrap terminal execution in try-catch +async function safeTransform(schemaFile: string) { + try { + const terminal = await Terminal.load(['transform', '--i', schemaFile]); + await terminal.run(); + console.log(\`✅ Successfully processed \${schemaFile}\`); + } catch (error) { + console.error(\`❌ Failed to process \${schemaFile}:\`, error.message); + throw error; + } +}` +]; + +const configurationManagementExample = [ + `// Use configuration objects for reusable settings +const defaultConfig = { + cwd: process.cwd(), + extname: '.idea', + brand: '[SCHEMA-TOOL]' +}; + +async function createTerminal(args: string[], config = defaultConfig) { + return await Terminal.load(args, config); +}` +]; + +const loggingAndDebuggingExample = [ + `// Add logging for better debugging +const terminal = await Terminal.load(['transform', '--i', './schema.idea'], { + cwd: process.cwd() +}); + +console.log(\`Working directory: \${terminal.cwd}\`); +console.log(\`File extension: \${terminal.extname}\`); + +await terminal.run();` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Terminal'); + const description = _( + 'A command-line interface for processing schema files and executing ' + + 'transformations through terminal commands' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Terminal')} +
    + +
    + ); +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Terminal')}

    +

    + + A command-line interface for processing schema files and + executing transformations through terminal commands. The Terminal + class provides a comprehensive CLI interface for the idea-transformer + library, enabling developers to process schema files and execute + transformations from the command line. + +

    + + + {basicExample[0]} + +
    + +
    +

    {_('Overview')}

    +

    + + The Terminal class provides a command-line interface for + processing schema files and executing transformations. This + section outlines the core capabilities and features of the + Terminal class, which extends the base Terminal functionality + to provide schema-specific command-line operations. + +

    + +

    + + The Terminal class (exported as Terminal) extends the base + Terminal class from stackpress to provide command-line + functionality for the idea-transformer library. It handles: + +

    + +
      +
    • {_('Command-line argument parsing')}
    • +
    • {_('Schema file resolution')}
    • +
    • {_('Transformation execution')}
    • +
    • {_('Error reporting and logging')}
    • +
    +
    + +
    +

    {_('Loading a Terminal Instance')}

    +

    + + The load method creates a new Terminal instance from + command-line arguments and optional configuration. This is + the primary way to create a terminal instance for processing + schema files from the command line. + +

    + +

    + + The following example shows how to create a new Terminal + instance from command-line arguments. + +

    + + + {loadExample[0]} + + +

    {_('Parameters')}

    + + + + Parameter + Type + Description + + + args + string[] + + + Command-line arguments array + + + + + options + TerminalOptions + + + Optional configuration for terminal behavior + + + +
    + +

    {_('Returns')}

    +

    + + A promise that resolves to a new Terminal instance + configured with the specified arguments and options. + +

    +
    + +
    +

    {_('Properties')}

    +

    + + The properties section describes the instance variables + available on Terminal objects. These properties provide + access to configuration details and runtime information + needed for command-line operations. + +

    + +

    + + The following properties are available when instantiating + a Terminal. + +

    + + + + Property + Type + Description + + + cwd + string + + + Current working directory for file operations + + + + + extname + string + + + Default file extension for schema files ' + + '(default: \'.idea\') + + + +
    +
    + +
    +

    {_('Running Terminal Commands')}

    +

    + + The run method executes the configured terminal command and + processes the specified schema file. This method handles the + complete workflow from command parsing to schema + transformation execution. + +

    + +

    + + The Terminal automatically sets up event handlers for + processing commands. The main command supported is transform. + +

    + + + {runExample[0]} + + +

    {_('Command Structure')}

    +

    + + The terminal expects commands in the following format: + +

    + + transform --input <schema-file> [--i <schema-file>] + + +

    {_('Flags')}

    + + + + Flag + Alias + Description + + + --input + --i + + + Path to the schema file to process + + + +
    +
    + +
    +

    {_('Usage Examples')}

    +

    + + This section provides practical examples of how to use the + Terminal class in various scenarios. These examples demonstrate + common patterns and use cases for command-line schema processing. + +

    + +

    {_('Basic Command Execution')}

    +

    + + Basic command execution demonstrates the fundamental workflow + for processing schema files through the Terminal interface. + This example shows the simplest way to transform a schema file + using command-line arguments. + +

    + + + {basicCommandExecutionExample[0]} + + +

    {_('Using Short Flag Syntax')}

    +

    + + Short flag syntax provides convenient aliases for common + command-line options. This example shows how to use abbreviated + flags to make command-line usage more efficient. + +

    + + + {shortFlagExample[0]} + + +

    {_('Custom Working Directory')}

    +

    + + Custom working directory configuration allows you to specify + where the Terminal should operate. This is useful when + processing schema files from different locations or when + integrating with build systems. + +

    + + + {customWorkingDirectoryExample[0]} + + +

    {_('Custom File Extension')}

    +

    + + Custom file extension support enables the Terminal to work + with schema files that use non-standard extensions. This + flexibility allows integration with different naming + conventions and file organization strategies. + +

    + + + {customFileExtensionExample[0]} + + +

    {_('Custom Brand/Label')}

    +

    + + Custom brand configuration allows you to customize the + Terminal's display name and branding. This is useful when + building custom CLI tools based on the idea-transformer + library. + +

    + + + {customBrandExample[0]} + +
    + +
    +

    {_('Command-Line Integration')}

    +

    + + This section demonstrates how to integrate the Terminal class + with actual command-line environments and build systems. + These examples show practical applications for creating CLI + tools and automating schema processing. + +

    + +

    {_('Direct Command-Line Usage')}

    +

    + + Direct command-line usage shows how to invoke the Terminal + functionality from shell commands. This section provides + examples of the actual command syntax and available options. + +

    + + + {directCommandLineExample[0]} + + +

    {_('CLI Script Example')}

    +

    + + CLI script examples demonstrate how to create executable + scripts that use the Terminal class. This pattern is useful + for creating standalone CLI tools and integrating with package + managers. + +

    + + + {cliScriptExample[0]} + + +

    {_('Package.json Integration')}

    +

    + + Package.json integration shows how to configure npm scripts + and binary commands using the Terminal class. This enables + seamless integration with Node.js project workflows and package + distribution. + +

    + + + {packageJsonIntegrationExample[0]} + +
    + +
    +

    {_('Default Behavior')}

    +

    + + This section explains the default behavior and conventions + used by the Terminal class. Understanding these defaults helps + developers predict how the Terminal will behave in different + scenarios and configure it appropriately. + +

    + +

    {_('File Path Resolution')}

    +

    + + File path resolution describes how the Terminal determines + which schema file to process when no explicit path is provided. + This automatic resolution simplifies common use cases while + maintaining flexibility. + +

    + +

    + + When no input file is specified, the terminal uses a default + path: + +

    + + + {defaultPathExample[0]} + + +

    {_('Flag Processing')}

    +

    + + Flag processing explains how the Terminal parses and + prioritizes command-line flags. Understanding this order + of precedence helps developers use the most appropriate + flag syntax for their needs. + +

    + +

    + + The terminal processes the following flags in order of + preference: + +

    + +
      +
    1. + --input (full flag name) +
    2. +
    3. + --i (short alias) +
    4. +
    5. + Default file path if no flags provided +
    6. +
    + + + {flagProcessingExample[0]} + +
    + +
    +

    {_('Error Handling')}

    +

    + + This section covers common error conditions that can occur + when using the Terminal class. Understanding these error + scenarios helps developers implement proper error handling + and provide better user experiences. + +

    + +

    {_('Missing Schema File')}

    +

    + + Missing schema file errors occur when the specified schema + file doesn't exist or isn't accessible. This section shows + how these errors are reported and how to handle them + appropriately in CLI applications. + +

    + + + {missingSchemaFileExample[0]} + + +

    {_('Invalid Command')}

    +

    + + Invalid command errors occur when unsupported commands are + passed to the Terminal. This section explains how the + Terminal handles unknown commands and provides guidance + for error recovery. + +

    + + + {invalidCommandExample[0]} + + +

    {_('Plugin Errors')}

    +

    + + Plugin errors can occur during the transformation process + when plugins fail to execute properly. This section covers + how to handle and debug plugin-related issues in CLI + environments. + +

    + + + {pluginErrorsExample[0]} + +
    + +
    +

    {_('Advanced Usage')}

    +

    + + This section covers advanced patterns and techniques for + using the Terminal class in complex scenarios. These + examples demonstrate sophisticated use cases and integration + patterns for power users. + +

    + +

    {_('Custom Event Handlers')}

    +

    + + Custom event handlers allow you to extend the Terminal's + functionality with additional commands and behaviors. This + pattern enables building specialized CLI tools with custom + functionality. + +

    + + + {customEventHandlersExample[0]} + + +

    {_('Programmatic CLI Building')}

    +

    + + Programmatic CLI building demonstrates how to construct + command-line arguments dynamically in code. This approach is + useful for building tools that generate CLI commands based on + configuration or user input. + +

    + + + {programmaticCLIExample[0]} + + +

    {_('Batch Processing')}

    +

    + + Batch processing shows how to use the Terminal class to + process multiple schema files in sequence. This pattern is + essential for build systems and automation tools that need to + handle multiple schemas. + +

    + + + {batchProcessingExample[0]} + + +

    {_('Environment-Based Configuration')}

    +

    + + Environment-based configuration demonstrates how to use + environment variables to configure Terminal behavior. This + approach enables flexible deployment and configuration management + across different environments. + +

    + + + {environmentBasedConfigExample[0]} + +
    + +
    +

    {_('Integration with Build Tools')}

    +

    + + This section demonstrates how to integrate the Terminal class + with popular build tools and development workflows. These + examples show practical applications for automating schema + processing in development and deployment pipelines. + +

    + +

    {_('Webpack Plugin')}

    +

    + + Webpack plugin integration shows how to incorporate schema + transformation into Webpack build processes. This enables + automatic schema processing as part of the application build + pipeline. + +

    + + + {webpackPluginExample[0]} + + +

    {_('Gulp Task')}

    +

    + + Gulp task integration demonstrates how to create Gulp tasks + that use the Terminal class for schema processing. This pattern + is useful for projects that use Gulp as their primary build tool. + +

    + + + {gulpTaskExample[0]} + + +

    {_('NPM Scripts')}

    +

    + + NPM scripts integration shows how to configure package.json + scripts that use the Terminal class. This approach enables + easy schema processing through standard npm commands and + supports development workflows. + +

    + + + {npmScriptsExample[0]} + +
    + +
    +

    {_('Testing')}

    +

    + + This section covers testing strategies and patterns for + applications that use the Terminal class. These examples + demonstrate how to write effective tests for CLI functionality + and ensure reliable schema processing. + +

    + +

    {_('Unit Testing')}

    +

    + + Unit testing examples show how to test Terminal functionality + in isolation. These tests verify that the Terminal class behaves + correctly with different command-line arguments and configuration + options. + +

    + + + {unitTestingExample[0]} + + +

    {_('Integration Testing')}

    +

    + + Integration testing demonstrates how to test the complete + workflow from command-line input to generated output files. + These tests ensure that the entire transformation pipeline + works correctly in realistic scenarios. + +

    + + + {integrationTestingExample[0]} + +
    + +
    +

    {_('Best Practices')}

    +

    + + This section outlines recommended approaches for using the + Terminal class effectively. Following these practices helps + ensure reliable, maintainable, and user-friendly CLI + applications. + +

    + +

    {_('Error Handling')}

    +

    + + Error handling best practices ensure that CLI applications + provide clear feedback when issues occur. This section + demonstrates patterns for implementing robust error handling + and user-friendly error messages. + +

    + + + {errorHandlingBestPracticeExample[0]} + + +

    {_('Configuration Management')}

    +

    + + Configuration management best practices help maintain clean, + reusable configuration patterns. This section provides + guidance on organizing configuration options and providing + sensible defaults. + +

    + + + {configurationManagementExample[0]} + + +

    {_('Logging and Debugging')}

    +

    + + Logging and debugging practices help developers troubleshoot + issues and understand Terminal behavior. This section + demonstrates effective logging strategies and debugging + techniques for CLI applications. + +

    + + + {loggingAndDebuggingExample[0]} + +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/components/transformers/api-references/transformer.tsx b/packages/www/plugins/docs/components/transformers/api-references/transformer.tsx new file mode 100644 index 0000000..7ee1506 --- /dev/null +++ b/packages/www/plugins/docs/components/transformers/api-references/transformer.tsx @@ -0,0 +1,988 @@ +//modules +import type { + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, P, C, Nav, SS } from '../../index.js'; +import Code from '../../Code.js'; +import Layout from '../../Layout.js'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; + +const basicExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); +await transformer.transform();` +]; + +const loadExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +// Load with default options +const transformer = await Transformer.load('./schema.idea'); + +// Load with custom options +const transformer = await Transformer.load('./schema.idea', { + cwd: '/custom/working/directory', + fs: customFileSystem +});` +]; + +const schemaExample = [ + `const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); + +console.log(schema.model); // Access model definitions +console.log(schema.enum); // Access enum definitions +console.log(schema.type); // Access type definitions +console.log(schema.prop); // Access prop definitions +console.log(schema.plugin); // Access plugin configurations` +]; + +const transformExample = [ + `const transformer = await Transformer.load('./schema.idea'); + +// Transform with no additional context +await transformer.transform(); + +// Transform with additional context +await transformer.transform({ + outputDir: './generated', + debug: true +});` +]; + +const pluginContextExample = [ + `{ + transformer: Transformer, // The transformer instance + config: PluginConfig, // Plugin-specific configuration + schema: SchemaConfig, // Complete processed schema + cwd: string, // Current working directory + ...extras // Any additional context passed to transform() +}` +]; + +const basicSchemaLoadingExample = [ + `import Transformer from '@stackpress/idea-transformer'; + +const transformer = await Transformer.load('./schema.idea'); +const schema = await transformer.schema(); + +// Access different parts of the schema +console.log('Models:', Object.keys(schema.model || {})); +console.log('Enums:', Object.keys(schema.enum || {})); +console.log('Types:', Object.keys(schema.type || {}));` +]; + +const multipleSchemaFilesExample = [ + `// main.idea +/* +use "./shared/types.idea" +use "./shared/enums.idea" + +model User { + id String @id + profile Profile // From shared/types.idea + role UserRole // From shared/enums.idea +} +*/ + +const transformer = await Transformer.load('./main.idea'); +const schema = await transformer.schema(); + +// The schema now includes definitions from all imported files +console.log(schema.type?.Profile); // Available from shared/types.idea +console.log(schema.enum?.UserRole); // Available from shared/enums.idea` +]; + +const pluginDevelopmentExample = [ + `// schema.idea +/* +plugin "./plugins/generate-types.js" { + output "./generated/types.ts" + format "typescript" +} +*/ + +// plugins/generate-types.js +export default function generateTypes({ transformer, config, schema, cwd }) { + const outputPath = config.output; + const format = config.format; + + // Generate TypeScript types based on schema + let content = ''; + + if (schema.model) { + for (const [name, model] of Object.entries(schema.model)) { + content += \`export interface \${name} {\n\`; + for (const column of model.columns) { + const optional = column.required ? '' : '?'; + content += \` \${column.name}\${optional}: \${column.type};\n\`; + } + content += '}\n\n'; + } + } + + // Write generated content to file + await writeFile(path.resolve(cwd, outputPath), content); +} + +// Execute the transformation +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform({ + timestamp: new Date().toISOString() +});` +]; + +const errorHandlingExample = [ + `import { Exception } from '@stackpress/idea-parser'; + +try { + const transformer = await Transformer.load('./schema.idea'); + const schema = await transformer.schema(); + await transformer.transform(); +} catch (error) { + if (error instanceof Exception) { + console.error('Schema processing error:', error.message); + console.error('Error code:', error.code); + } else { + console.error('Unexpected error:', error); + } +}` +]; + +const customFileSystemExample = [ + `import { NodeFS } from '@stackpress/lib'; + +// Using custom file system +const customFS = new NodeFS(); +const transformer = await Transformer.load('./schema.idea', { + fs: customFS, + cwd: '/custom/working/directory' +});` +]; + +const fileNotFoundExample = [ + `// Throws: "Input file /path/to/nonexistent.idea does not exist" +const transformer = await Transformer.load('./nonexistent.idea'); +await transformer.schema(); // Error thrown here` +]; + +const noPluginsExample = [ + `// If schema has no plugins defined +const transformer = await Transformer.load('./schema-without-plugins.idea'); +await transformer.transform(); // Throws: "No plugins defined in schema file"` +]; + +const invalidPluginExample = [ + `// If plugin file doesn't export a function +const transformer = await Transformer.load('./schema.idea'); +await transformer.transform(); // Plugin is silently skipped if not a function` +]; + +const schemaOrganizationExample = [ + `// Organize schemas hierarchically +// shared/base.idea - Common types and enums +// modules/user.idea - User-specific models +// main.idea - Main schema that imports others + +use "./shared/base.idea" +use "./modules/user.idea" + +// Additional models specific to this schema +model Application { + id String @id + users User[] +}` +]; + +const pluginDevelopmentBestPracticeExample = [ + `// Always validate plugin configuration +export default async function myPlugin({ config, schema, transformer, cwd }) { + // Validate required configuration + if (!config.output) { + throw new Error('Plugin requires output configuration'); + } + + // Use transformer's file loader for consistent path resolution + const outputPath = await transformer.loader.absolute(config.output); + + // Process schema safely + const models = schema.model || {}; + const enums = schema.enum || {}; + + // Generate output... +}` +]; + +const errorRecoveryExample = [ + `// Implement graceful error handling +async function processSchema(schemaPath) { + try { + const transformer = await Transformer.load(schemaPath); + const schema = await transformer.schema(); + await transformer.transform(); + return { success: true, schema }; + } catch (error) { + console.error(\`Failed to process \${schemaPath}:\`, error.message); + return { success: false, error: error.message }; + } +}` +]; + +const buildSystemIntegrationExample = [ + `// Integration with build tools +import Transformer from '@stackpress/idea-transformer'; + +export async function buildSchemas(inputDir, outputDir) { + const schemaFiles = await glob(\`\${inputDir}/**/*.idea\`); + + for (const schemaFile of schemaFiles) { + const transformer = await Transformer.load(schemaFile); + await transformer.transform({ outputDir }); + } +}` +]; + +const testingExample = [ + `// Testing schema transformations +import { expect } from 'chai'; + +describe('Schema Transformation', () => { + it('should process schema correctly', async () => { + const transformer = await Transformer.load('./test-schema.idea'); + const schema = await transformer.schema(); + + expect(schema.model).to.have.property('User'); + expect(schema.model.User.columns).to.have.length.greaterThan(0); + }); +});` +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Transformer'); + const description = _( + 'A class for loading, processing, and transforming schema files ' + + 'with plugin support and schema merging capabilities' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Right() { + const { _ } = useLanguage(); + return ( + +
    + {_('Transformer')} +
    + +
    + ); +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Transformer')}

    +

    + + A class for loading, processing, and transforming schema files + with plugin support and schema merging capabilities. The + Transformer class serves as the core component of the + idea-transformer library, providing comprehensive functionality + for schema processing, plugin execution, and file management. + +

    + + + {basicExample[0]} + +
    + +
    +

    {_('Overview')}

    +

    + + The Transformer class provides a comprehensive solution for + processing schema files and executing transformations. This + section outlines the core capabilities and responsibilities of + the Transformer class within the idea-transformer ecosystem. + +

    + +

    + + The Transformer class is the core component of the + idea-transformer library. It handles: + +

    + +
      +
    • + + Loading schema files (both .idea and .json formats) + +
    • +
    • + + Processing and merging schema configurations from + multiple files + +
    • +
    • + + Executing plugins defined in the schema + +
    • +
    • + + Managing file dependencies and imports + +
    • +
    +
    + +
    +

    {_('Loading a Transformer')}

    +

    + + The load method creates a new Transformer instance configured + with the specified input file and options. This is the primary + way to create a transformer and begin working with schema files. + +

    + +

    + + The following example shows how to create a new Transformer + instance. + +

    + + + {loadExample[0]} + + +

    {_('Parameters')}

    + + + + Parameter + Type + Description + + + input + string + + + Path to the schema file to load + + + + + options + LoaderOptions + + + Optional configuration for the file loader + + + +
    + +

    {_('Returns')}

    +

    + + A promise that resolves to a new Transformer instance configured + with the specified input file and options. + +

    +
    + +
    +

    {_('Properties')}

    +

    + + The properties section describes the instance variables + available on Transformer objects. These properties provide + access to the underlying file system operations and + configuration details needed for schema processing. + +

    + +

    + + The following properties are available when instantiating + a Transformer. + +

    + + + + Property + Type + Description + + + loader + FileLoader + + + File system loader for handling file operations + + + + + input + string + + + Absolute path to the input schema file + + + +
    +
    + +
    +

    {_('Methods')}

    +

    + + The methods section covers the instance methods available + on Transformer objects. These methods provide the core + functionality for loading schema configurations, processing + dependencies, and executing plugin transformations. + +

    + +

    {_('Loading Schema Configuration')}

    +

    + + The schema method loads and processes the complete schema + configuration, including all dependencies and imports. This + method handles the complex process of merging multiple + schema files and resolving all references. + +

    + +

    + + The following example shows how to load and process the + schema configuration. + +

    + + + {schemaExample[0]} + + +

    {_('Returns')}

    +

    + + A promise that resolves to a SchemaConfig object containing + all processed schema definitions. + +

    + +

    {_('Features')}

    +
      +
    • + + File Format Support: Automatically detects and + handles both .idea and .json schema files + +
    • +
    • + + Dependency Resolution: Processes use directives + to import and merge external schema files + +
    • +
    • + + Schema Merging: Intelligently merges child schemas + into parent schemas based on mutability rules + +
    • +
    • + + Caching: Caches the processed schema to avoid + redundant processing + +
    • +
    + +

    {_('Schema Merging Rules')}

    +

    + + When processing use directives, the transformer applies + these merging rules: + +

    + +
      +
    1. + Props and Enums: + + Simple merge where parent takes precedence + +
    2. +
    3. + Types and Models: +
        +
      • + + If parent doesn't exist or is immutable: child is added + +
      • +
      • + + If parent is mutable: attributes and columns are merged + +
      • +
      • + + Child columns are prepended to parent columns + +
      • +
      • + + Parent attributes take precedence over child attributes + +
      • +
      +
    4. +
    + +

    {_('Transforming with Plugins')}

    +

    + + The transform method executes all plugins defined in the + schema configuration. This method coordinates the plugin + execution process, providing each plugin with the necessary + context and handling any errors that occur during + transformation. + +

    + +

    + + The following example shows how to execute all plugins + defined in the schema. + +

    + + + {transformExample[0]} + + +

    {_('Parameters')}

    + + + + Parameter + Type + Description + + + extras + T + + + Optional additional context to pass to plugins + + + +
    + +

    {_('Returns')}

    +

    + + A promise that resolves when all plugins have been executed. + +

    + +

    {_('Plugin Execution Process')}

    +
      +
    1. + + Validation: Ensures plugins are defined in the + schema + +
    2. +
    3. + + Module Resolution: Resolves plugin file paths + relative to the schema file + +
    4. +
    5. + + Dynamic Import: Loads plugin modules dynamically + +
    6. +
    7. + + Context Injection: Passes context including + transformer, schema, config, and extras + +
    8. +
    9. + + Execution: Calls each plugin function with the + injected context + +
    10. +
    + +

    {_('Plugin Context')}

    +

    + + Each plugin receives a context object with the following + properties: + +

    + + + {pluginContextExample[0]} + +
    + +
    +

    {_('Usage Examples')}

    +

    + + This section provides practical examples of how to use the + Transformer class in various scenarios. These examples + demonstrate common patterns and best practices for working + with schema files, plugins, and transformations. + +

    + +

    {_('Basic Schema Loading')}

    +

    + + Basic schema loading demonstrates the fundamental workflow + for loading and accessing schema configurations. This + example shows how to create a transformer instance and + retrieve different parts of the processed schema. + +

    + + + {basicSchemaLoadingExample[0]} + + +

    {_('Working with Multiple Schema Files')}

    +

    + + Working with multiple schema files shows how the Transformer + handles complex schema hierarchies with imports and + dependencies. This example demonstrates how the use + directive enables modular schema organization. + +

    + + + {multipleSchemaFilesExample[0]} + + +

    {_('Plugin Development and Execution')}

    +

    + + Plugin development and execution demonstrates how to create + and use plugins with the Transformer. This example shows + both the schema configuration and plugin implementation, + illustrating the complete plugin workflow. + +

    + + + {pluginDevelopmentExample[0]} + + +

    {_('Error Handling')}

    +

    + + Error handling examples show how to properly catch and + handle different types of errors that can occur during + schema processing and transformation. This includes both + expected errors from the idea-parser and unexpected + runtime errors. + +

    + + + {errorHandlingExample[0]} + + +

    {_('Custom File System')}

    +

    + + Custom file system usage demonstrates how to configure the + Transformer to work with different file system + implementations. This is useful for testing, custom + storage backends, or specialized deployment scenarios. + +

    + + + {customFileSystemExample[0]} + +
    + +
    +

    {_('Error Scenarios')}

    +

    + + This section covers common error conditions that can occur + when using the Transformer class. Understanding these + scenarios helps developers implement proper error handling + and debugging strategies. + +

    + +

    {_('File Not Found')}

    +

    + + File not found errors occur when the specified schema file + doesn't exist or isn't accessible. This section shows how + these errors are reported and how to handle them + appropriately. + +

    + + + {fileNotFoundExample[0]} + + +

    {_('No Plugins Defined')}

    +

    + + No plugins defined errors occur when attempting to execute + transformations on schemas that don't have any plugin + configurations. This section explains when this error + occurs and how to handle it. + +

    + + + {noPluginsExample[0]} + + +

    {_('Invalid Plugin Module')}

    +

    + + Invalid plugin module scenarios occur when plugin files + exist but don't export the expected function interface. + This section covers how the Transformer handles these + situations and what developers should expect. + +

    + + + {invalidPluginExample[0]} + +
    + +
    +

    {_('Best Practices')}

    +

    + + This section outlines recommended approaches for using the + Transformer class effectively. Following these practices + helps ensure reliable, maintainable, and efficient schema + processing workflows. + +

    + +

    {_('Schema Organization')}

    +

    + + Schema organization best practices help maintain clean, + modular, and reusable schema files. This section provides + guidance on structuring schema hierarchies and managing + dependencies effectively. + +

    + + + {schemaOrganizationExample[0]} + + +

    {_('Plugin Development')}

    +

    + + Plugin development best practices ensure that plugins are + robust, reliable, and integrate well with the Transformer + ecosystem. This section covers validation, error handling, + and proper use of the plugin context. + +

    + + + {pluginDevelopmentBestPracticeExample[0]} + + +

    {_('Error Recovery')}

    +

    + + Error recovery strategies help build resilient applications + that can handle schema processing failures gracefully. + This section demonstrates patterns for implementing robust + error handling and recovery mechanisms. + +

    + + + {errorRecoveryExample[0]} + +
    + +
    +

    {_('Integration with Other Tools')}

    +

    + + This section demonstrates how to integrate the Transformer + class with other development tools and workflows. These + examples show practical applications in build systems, + testing frameworks, and development environments. + +

    + +

    {_('Build Systems')}

    +

    + + Build system integration shows how to incorporate schema + transformation into automated build processes. This + enables continuous generation of code, documentation, + and other artifacts from schema definitions. + +

    + + + {buildSystemIntegrationExample[0]} + + +

    {_('Testing')}

    +

    + + Testing integration demonstrates how to write tests for + schema transformations and validate that schemas are + processed correctly. This is essential for maintaining + schema quality and catching regressions. + +

    + + + {testingExample[0]} + +
    + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + } + > + + + ); +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx new file mode 100644 index 0000000..0fd16a1 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx @@ -0,0 +1,193 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +const examples = [ +`// Add a class with decorators +sourceFile.addClass({ + name: "UserController", + isExported: true, + decorators: [ + { + name: "Controller", + arguments: ["'users'"], + }, + ], + methods: [ + { + name: "getUser", + decorators: [ + { + name: "Get", + arguments: ["':id'"], + }, + ], + parameters: [ + { + name: "id", + type: "string", + decorators: [ + { + name: "Param", + arguments: ["'id'"], + }, + ], + }, + ], + returnType: "Promise", + statements: "return this.userService.findById(id);", + }, + ], +});`, +`// Generate mapped types +sourceFile.addTypeAlias({ + name: "PartialUser", + type: "{ [K in keyof User]?: User[K] }", +}); + +// Generate conditional types +sourceFile.addTypeAlias({ + name: "NonNullable", + typeParameters: [{ name: "T" }], + type: "T extends null | undefined ? never : T", +}); + +// Generate template literal types +sourceFile.addTypeAlias({ + name: "EventName", + typeParameters: [{ name: "T", constraint: "string" }], + type: \`on\${Capitalize}\`, +});`, +`// Add module declaration +sourceFile.addModule({ + name: "Express", + declarationKind: ModuleDeclarationKind.Module, + statements: [ + { + kind: StructureKind.Interface, + name: "Request", + properties: [ + { name: "user", type: "User", hasQuestionToken: true }, + ], + }, + ], +}); + +// Add ambient module +sourceFile.addModule({ + name: '"my-library"', + declarationKind: ModuleDeclarationKind.Module, + hasDeclareKeyword: true, + statements: [ + "export function myFunction(): void;", + ], +});`, +`// Find and modify existing interfaces +const existingInterface = sourceFile.getInterface("User"); +if (existingInterface) { + // Add new properties + existingInterface.addProperty({ + name: "lastLoginAt", + type: "Date", + hasQuestionToken: true, + }); + + // Modify existing properties + const emailProp = existingInterface.getProperty("email"); + if (emailProp) { + emailProp.setType("string & { readonly brand: 'Email' }"); + } + + // Add extends clause + existingInterface.addExtends("BaseEntity"); +} + +// Remove nodes +const deprecatedMethod = sourceFile.getFunction("oldFunction"); +deprecatedMethod?.remove();` +]; + +export default function AdvanceTsMorphPlugin() { + const { _ } = useLanguage(); + return ( +
    +

    {_('6. Advanced ts-morph Features')}

    +

    + + Advanced ts-morph features enable sophisticated code generation + scenarios including decorators, complex type systems, module + declarations, and code manipulation. These features are essential + for building production-ready plugins that handle enterprise-level + requirements. + +

    + +

    {_('6.1. Working with Decorators')}

    +

    + + Decorators are essential for modern TypeScript applications, + especially when working with frameworks like Angular, NestJS, or + TypeORM. ts-morph provides comprehensive support for generating + classes and methods with decorators. + +

    + + {examples[0]} + + +

    {_('6.2. Generating Complex Types')}

    +

    + + Complex type generation includes mapped types, conditional types, + and template literal types that leverage TypeScript's advanced + type system. These features enable the creation of sophisticated + type-safe APIs and utility types. + +

    + + {examples[1]} + + +

    {_('6.3. Working with Modules')}

    +

    + + Module declarations and ambient modules are crucial for creating + type definitions and extending existing libraries. This section + covers both namespace-style modules and modern ES module patterns. + +

    + + {examples[2]} + + +

    {_('6.4. Manipulating Existing Code')}

    +

    + + Code manipulation capabilities allow plugins to modify existing + TypeScript files, add new functionality, and refactor code + structures. This is particularly useful for migration tools and + code modernization plugins. + +

    + + {examples[3]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx similarity index 53% rename from packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx rename to packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx index 86a16db..314e832 100644 --- a/packages/www/plugins/docs/views/tutorials/components/ts-morph/best-practices.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx @@ -1,5 +1,6 @@ -import { H1, H2, P } from '../../../../components/index.js' -import Code from '../../../../components/Code.js' +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P } from '../index.js' +import Code from '../Code.js' const examples = [ `interface PluginOptions { @@ -147,57 +148,129 @@ export class MainPlugin { ]; export default function BestPractices() { + const { _ } = useLanguage(); return ( -
    -

    8. Best Practices

    +
    +

    {_('8. Best Practices')}

    - Following best practices ensures your plugins are maintainable, performant, and reliable in production environments. These guidelines cover type safety, error handling, performance optimization, and code organization strategies. + + Following best practices ensures your plugins are maintainable, + performant, and reliable in production environments. These + guidelines cover type safety, error handling, performance + optimization, and code organization strategies. +

    -

    8.1. Type Safety

    +

    {_('8.1. Type Safety')}

    - Type safety is fundamental to building reliable plugins that catch errors at compile time rather than runtime. Always use TypeScript interfaces and proper type validation throughout your plugin implementation. + + Type safety is fundamental to building reliable plugins that catch + errors at compile time rather than runtime. Always use TypeScript + interfaces and proper type validation throughout your plugin + implementation. +

    - Always use TypeScript interfaces for your plugin configuration and data structures: + + Always use TypeScript interfaces for your plugin configuration + and data structures: +

    - {examples[0]} + + {examples[0]} + -

    8.2. Error Handling

    +

    {_('8.2. Error Handling')}

    - Comprehensive error handling provides clear feedback to users and helps with debugging when things go wrong. Implement custom error types and meaningful error messages to improve the developer experience. + + Comprehensive error handling provides clear feedback to users and + helps with debugging when things go wrong. Implement custom error + types and meaningful error messages to improve the developer + experience. +

    - Implement comprehensive error handling: + + Implement comprehensive error handling: +

    - {examples[1]} + + {examples[1]} + -

    8.3. Performance Optimization

    +

    {_('8.3. Performance Optimization')}

    - Performance optimization becomes crucial when dealing with large schemas or generating substantial amounts of code. Implement caching strategies and batch processing to maintain reasonable execution times. + + Performance optimization becomes crucial when dealing with large + schemas or generating substantial amounts of code. Implement + caching strategies and batch processing to maintain reasonable + execution times. +

    - For large schemas, optimize performance: + + For large schemas, optimize performance: +

    - {examples[2]} + + {examples[2]} + -

    8.4. Code Organization

    +

    {_('8.4. Code Organization')}

    - Proper code organization makes your plugin easier to maintain, test, and extend. Separate concerns into focused classes and modules that each handle specific aspects of the generation process. + + Proper code organization makes your plugin easier to maintain, + test, and extend. Separate concerns into focused classes and + modules that each handle specific aspects of the generation + process. +

    - Structure your plugin code for maintainability: + + Structure your plugin code for maintainability: +

    - {examples[3]} + + {examples[3]} + -

    8.5. Documentation Generation

    +

    {_('8.5. Documentation Generation')}

    - Documentation generation ensures your generated code is self-documenting and provides valuable context for developers. Implement comprehensive JSDoc comment generation with examples and type information. + + Documentation generation ensures your generated code is + self-documenting and provides valuable context for developers. + Implement comprehensive JSDoc comment generation with examples + and type information. +

    - Add comprehensive JSDoc comments: + + Add comprehensive JSDoc comments: +

    - {examples[4]} + + {examples[4]} +
    ) } diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx similarity index 76% rename from packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx rename to packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx index cdaa8c4..9c5c7c8 100644 --- a/packages/www/plugins/docs/views/tutorials/components/ts-morph/create-first-plugin.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx @@ -1,5 +1,6 @@ -import { H1, H2, P, C } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, C } from '../index.js'; +import Code from '../Code.js'; const examples = [ `// src/types.ts @@ -477,45 +478,128 @@ export type AnyModel = User | Post;` ]; export default function CreateFirstPlugin() { + const { _ } = useLanguage(); return ( -
    -

    5. Creating Your First Plugin

    +
    +

    {_('5. Creating Your First Plugin')}

    - Creating your first plugin with ts-morph involves understanding the complete workflow from schema processing to code generation. This comprehensive example demonstrates building a TypeScript interface generator that transforms JSON schemas into properly typed interfaces with full feature support. + + Creating your first plugin with ts-morph involves + understanding the complete workflow from schema processing to code + generation. This comprehensive example demonstrates building a + TypeScript interface generator that transforms JSON schemas into + properly typed interfaces with full feature support. +

    - Let's create a plugin that generates TypeScript interfaces from JSON schema definitions. This will demonstrate the core concepts of using ts-morph for code generation. + + Let's create a plugin that generates TypeScript interfaces from + JSON schema definitions. This will demonstrate the core concepts + of using ts-morph for code generation. +

    -

    5.1. Define the Plugin Interface

    +

    {_('5.1. Define the Plugin Interface')}

    - Defining clear interfaces for your plugin ensures type safety and provides a solid foundation for implementation. This section establishes the data structures and configuration options that will guide the entire plugin development process. + + Defining clear interfaces for your plugin ensures type safety and + provides a solid foundation for implementation. This section + establishes the data structures and configuration options that + will guide the entire plugin development process. +

    -

    First, let's define the types for our plugin:

    - {examples[0]} - -

    5.2. Core Plugin Implementation

    - The core plugin implementation orchestrates the entire code generation process, from loading input schemas to generating and saving TypeScript files. This comprehensive class demonstrates best practices for plugin architecture and error handling. + + First, let's define the types for our plugin: +

    - {examples[1]} - -

    5.3. Plugin Entry Point

    + + {examples[0]} + + +

    {_('5.2. Core Plugin Implementation')}

    - The plugin entry point provides a clean API for consumers and handles CLI integration. This section shows how to create both programmatic and command-line interfaces for your plugin, making it accessible in different usage scenarios. + + The core plugin implementation orchestrates the entire code + generation process, from loading input schemas to generating and + saving TypeScript files. This comprehensive class demonstrates + best practices for plugin architecture and error handling. +

    - {examples[2]} - -

    5.4. Example Usage

    + + {examples[1]} + + +

    {_('5.3. Plugin Entry Point')}

    +

    + + The plugin entry point provides a clean API for consumers and + handles CLI integration. This section shows how to create both + programmatic and command-line interfaces for your plugin, making + it accessible in different usage scenarios. + +

    + + {examples[2]} + + +

    {_('5.4. Example Usage')}

    +

    + + Example usage demonstrates the plugin in action with realistic + data structures. This comprehensive example shows how the plugin + processes complex schemas with various property types, + relationships, and validation rules. + +

    +

    + + Create an example schema file: + +

    + + {examples[3]} + +

    + + Run the plugin: + +

    + + {examples[4]} +

    - Example usage demonstrates the plugin in action with realistic data structures. This comprehensive example shows how the plugin processes complex schemas with various property types, relationships, and validation rules. + + Generated output: +

    -

    Create an example schema file:

    - {examples[3]} -

    Run the plugin:

    - {examples[4]} -

    Generated output:

    - {examples[5]} + + {examples[5]} +
    ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx new file mode 100644 index 0000000..e95c965 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx @@ -0,0 +1,85 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C, SS } from '../index.js'; +import Code from '../Code.js'; + +const examples = [ + `# Using npm +npm install --save-dev ts-morph + +# Using yarn +yarn add --dev ts-morph + +# Using Deno +deno add ts-morph@jsr:@ts-morph/ts-morph` +] + +export default function installation() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('2. Installation')}

    +

    + + Before starting with ts-morph plugin development, ensure + you have the necessary tools and knowledge. This section outlines + the essential requirements for successful plugin creation and + provides installation guidance. + +

    + +

    + + Before starting, ensure you have: + +

    + +
      +
    • + {_('Node.js 16+')} + + and npm/yarn installed + +
    • +
    • + {_('TypeScript 4.0+')} + + knowledge + +
    • +
    • + + Basic understanding of Abstract Syntax Trees (AST) + +
    • +
    • + + Familiarity with TypeScript interfaces, classes, and modules + +
    • +
    + +

    + + Installing ts-morph is straightforward and can be done + using your preferred package manager. The library is available + through npm, yarn, and even Deno for different development + environments. + +

    + +

    + + Install ts-morph in your project: + +

    + + {examples[0]} + +
    + ) +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx new file mode 100644 index 0000000..d6c5843 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx @@ -0,0 +1,135 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, C, SS } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + return ( +
    +

    {_('Creating Plugins with ts-morph: A Comprehensive Guide')}

    +

    + + This guide demonstrates how to create powerful code generation + plugins using ts-morph, a TypeScript library that provides an + easier way to programmatically navigate and manipulate TypeScript + and JavaScript code. We'll walk through creating a complete plugin + that generates TypeScript interfaces from schema definitions. + +

    + +

    {_('1. Introduction')}

    +

    + + ts-morph is a powerful TypeScript library that wraps the + TypeScript Compiler API, making it much easier to work with + TypeScript Abstract Syntax Trees (AST). This introduction covers + the fundamental concepts and advantages of using ts-morph + for plugin development. + +

    +

    + + Unlike string-based code generation, ts-morph provides: + +

    +
      +
    • + {_('Type-safe code manipulation:')} + + Work with actual TypeScript nodes instead of strings + +
    • +
    • + {_('Automatic formatting:')} + + Generated code is properly formatted and follows TypeScript + conventions + +
    • +
    • + {_('IntelliSense support:')} + + Full IDE support when writing your plugins + +
    • +
    • + {_('AST navigation:')} + + Easy traversal and modification of code structures + +
    • +
    • + {_('Validation:')} + + Automatic syntax validation of generated code + +
    • +
    + +

    {_('Why Use ts-morph for Plugins?')}

    +

    + + Understanding the advantages of ts-morph over traditional + code generation approaches helps you make informed decisions about + plugin architecture. This comparison highlights the key benefits + that make ts-morph an excellent choice for TypeScript code + generation. + +

    +

    + + Traditional code generation often involves: + +

    +
      +
    • + + Concatenating strings to build code + +
    • +
    • + + Manual indentation and formatting + +
    • +
    • + + Error-prone syntax construction + +
    • +
    • + + Difficulty maintaining complex code structures + +
    • +
    + +

    + + With ts-morph, you can: + +

    +
      +
    • + + Create TypeScript constructs programmatically + +
    • +
    • + + Leverage the compiler's knowledge for validation + +
    • +
    • + + Generate properly formatted, syntactically correct code + +
    • +
    • + + Easily modify existing code structures + +
    • +
    +
    + ) +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx new file mode 100644 index 0000000..b6a7997 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx @@ -0,0 +1,185 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, H3, P } from '../index.js' + +export default function References() { + const { _ } = useLanguage(); + return ( + <> +
    +

    {_('10. References')}

    +

    + + This section provides comprehensive resources for continued + learning and development with ts-morph. These references + include official documentation, community resources, and + related tools that enhance the plugin development experience. + +

    +
    + +
    +

    {_('10.1. Official Documentation')}

    +

    + + Official documentation provides authoritative information + about ts-morph APIs, TypeScript compiler internals, and AST + manipulation techniques. + +

    +

    + + ts-morph Documentation + : + https://ts-morph.com/ +

    +

    + + TypeScript Compiler API + : + https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API +

    +

    + + TypeScript AST Viewer + : + https://ts-ast-viewer.com/ +

    +
    + +
    +

    {_('10.2. Useful Resources')}

    +

    + + Additional resources provide practical examples, community + insights, and tools that complement the official documentation + for comprehensive plugin development. + +

    +

    + + ts-morph GitHub Repository + : + https://github.com/dsherret/ts-morph +

    +

    + + TypeScript Handbook + : + https://www.typescriptlang.org/docs/ +

    +

    + AST Explorer: + https://astexplorer.net/ +

    +
    + +
    +

    {_('10.3. Community Examples')}

    +

    + + Community examples showcase real-world usage patterns and + provide inspiration for advanced plugin development techniques. + +

    +

    + + ts-morph Examples + : + https://github.com/dsherret/ts-morph/tree/latest/packages/ts-morph/scripts +

    +

    + + Code Generation Patterns + : + https://github.com/topics/code-generation +

    + +

    {_('Related Tools')}

    +

    + + TypeScript ESLint + : + + For linting generated code + +

    +

    + Prettier: + + For formatting generated code + +

    +

    + ts-node: + + For running TypeScript directly + +

    +

    + Jest: + + For testing your plugins + +

    + +

    + + This comprehensive guide provides everything you need to create + powerful code generation plugins using ts-morph. The library's + type-safe approach to code manipulation makes it an excellent + choice for building robust, maintainable code generators that + produce high-quality TypeScript output. + +

    +
    + + ) +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx new file mode 100644 index 0000000..57e7ad0 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx @@ -0,0 +1,95 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C } from '../index.js'; +import Code from '../Code.js'; + +const examples = [ + `mkdir ts-morph-plugin-tutorial +cd ts-morph-plugin-tutorial +npm init -y +npm install --save-dev typescript ts-morph @types/node`, + `{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}`, + `ts-morph-plugin-tutorial/ +├── src/ +│ ├── index.ts +│ ├── plugin.ts +│ └── types.ts +├── examples/ +│ ├── input.json +│ └── output.ts +├── tests/ +│ └── plugin.test.ts +├── package.json +└── tsconfig.json` +] + +export default function SettingUpProject() { + const { _ } = useLanguage(); + return ( +
    +

    {_('3. Setting Up the Project')}

    +

    + + Setting up a proper project structure is crucial for maintainable + plugin development. This section guides you through creating a + well-organized TypeScript project with all necessary configurations + and dependencies + +

    +

    + + Let's create a new TypeScript project for our plugin: + +

    + + {examples[0]} + + +

    + + Create a basic tsconfig.json: + +

    + + {examples[1]} + + +

    + + Create the project structure: + +

    + + {examples[2]} + +
    + ) +} diff --git a/packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx similarity index 79% rename from packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx rename to packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx index e54e9c1..fe0fe8a 100644 --- a/packages/www/plugins/docs/views/tutorials/components/ts-morph/testing-your-plugin.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx @@ -1,6 +1,6 @@ - -import { H1, P, C, B } from '../../../../components/index.js' -import Code from '../../../../components/Code.js' +import { useLanguage, Translate } from 'r22n'; +import { H1, P } from '../index.js' +import Code from '../Code.js' const examples = [ `// tests/plugin.test.ts @@ -126,22 +126,44 @@ describe("TypeScriptInterfaceGenerator", () => { ]; export default function TestingYourPlugin() { + const { _ } = useLanguage(); return ( -
    -

    7. Testing Your Plugin

    +
    +

    {_('7. Testing Your Plugin')}

    - Comprehensive testing ensures your plugin works correctly across different scenarios and maintains reliability as it evolves. This section covers unit testing, integration testing, and validation strategies for ts-morph plugins. + + Comprehensive testing ensures your plugin works correctly across + different scenarios and maintains reliability as it evolves. This + section covers unit testing, integration testing, and validation + strategies for ts-morph plugins. +

    - Create comprehensive tests for your plugin: + + Create comprehensive tests for your plugin: +

    - {examples[0]} + + {examples[0]} +

    - Run tests: + + Run tests: +

    - {examples[1]} + + {examples[1]} +
    ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx new file mode 100644 index 0000000..0b858d1 --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx @@ -0,0 +1,244 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, H3, P } from '../index.js' +import Code from '../Code.js' + +const examples = [ +`function validateGeneratedCode(sourceFile: SourceFile): void { + const diagnostics = sourceFile.getPreEmitDiagnostics(); + + if (diagnostics.length > 0) { + const errors = diagnostics.map(d => ({ + message: d.getMessageText(), + line: d.getLineNumber(), + file: d.getSourceFile()?.getFilePath() + })); + + throw new Error(\`Generated TypeScript has errors: \${JSON.stringify(errors, null, 2)}\`); + } +}`, +`function detectCircularReferences(schemas: Schema[]): string[] { + const graph = new Map>(); + const cycles: string[] = []; + + // Build dependency graph + for (const schema of schemas) { + const deps = new Set(); + + for (const prop of Object.values(schema.properties)) { + if (prop.type && schemas.some(s => s.name === prop.type)) { + deps.add(prop.type); + } + } + + graph.set(schema.name, deps); + } + + // Detect cycles using DFS + const visited = new Set(); + const recursionStack = new Set(); + + function hasCycle(node: string): boolean { + if (recursionStack.has(node)) { + cycles.push(node); + return true; + } + + if (visited.has(node)) { + return false; + } + + visited.add(node); + recursionStack.add(node); + + const deps = graph.get(node) || new Set(); + for (const dep of deps) { + if (hasCycle(dep)) { + return true; + } + } + + recursionStack.delete(node); + return false; + } + + for (const schema of schemas) { + hasCycle(schema.name); + } + + return cycles; +}`, +`class StreamingGenerator { + async generateLargeSchema(schemas: Schema[]): Promise { + const batchSize = 10; + + for (let i = 0; i < schemas.length; i += batchSize) { + const batch = schemas.slice(i, i + batchSize); + + // Process batch + await this.processBatch(batch); + + // Clear memory + if (global.gc) { + global.gc(); + } + } + } + + private async processBatch(schemas: Schema[]): Promise { + // Process smaller batches to avoid memory issues + } +}`, +`const DEBUG = process.env.DEBUG === 'true'; + +function debugLog(message: string, data?: any): void { + if (DEBUG) { + console.log(\`[DEBUG] \${message}\`, data ? JSON.stringify(data, null, 2) : ''); + } +} + +// Usage +debugLog('Processing schema', schema); +debugLog('Generated interface', interfaceDeclaration.getText());`, +`async function saveIntermediateResults( + sourceFile: SourceFile, + step: string +): Promise { + if (process.env.SAVE_INTERMEDIATE === 'true') { + const outputPath = \`debug-\${step}-\${Date.now()}.ts\`; + await fs.writeFile(outputPath, sourceFile.getFullText()); + console.log(\`Saved intermediate result: \${outputPath}\`); + } +}`, +`function validateStep( + sourceFile: SourceFile, + stepName: string +): void { + try { + const diagnostics = sourceFile.getPreEmitDiagnostics(); + if (diagnostics.length > 0) { + throw new Error(\`Step \${stepName} produced invalid TypeScript\`); + } + console.log(\`✅ Step \${stepName} completed successfully\`); + } catch (error) { + console.error(\`❌ Step \${stepName} failed:\`, error.message); + throw error; + } +}` +]; + +export default function Troubleshooting() { + const { _ } = useLanguage(); + return ( + <> +
    +

    {_('9. Troubleshooting')}

    +

    + + Troubleshooting guides help developers quickly identify and + resolve common issues encountered during plugin development. + This section covers validation, debugging techniques, and + solutions for typical problems. + +

    +
    + +
    +

    {_('9.1. Common Issues')}

    +

    + + Common issues in ts-morph plugin development typically involve + syntax validation, circular references, and memory management. + Understanding these patterns helps prevent and resolve problems + efficiently. + +

    + +

    {_('9.1.1. Invalid TypeScript Syntax')}

    +

    + + Invalid TypeScript syntax can break the compilation process and + prevent your plugin from generating usable code. Implement + validation checks to catch syntax errors early in the generation + process. + +

    + + {examples[0]} + + +

    {_('9.1.2. Circular Type References')}

    +

    + + Circular type references can cause infinite loops and compilation + errors. Detecting and handling these scenarios is crucial for + plugins that work with complex, interconnected data structures. + +

    + + {examples[1]} + + +

    {_('9.1.3. Memory Issues with Large Schemas')}

    +

    + + Memory management becomes important when processing large schemas + or generating substantial amounts of code. Implement streaming + and batching strategies to handle large-scale generation + efficiently. + +

    + + {examples[2]} + +
    + +
    +

    {_('9.2. Debugging Tips')}

    +

    + + Effective debugging techniques help identify issues quickly and + understand the plugin's behavior during development. These tools + and strategies provide visibility into the generation process. + +

    + +

    {_('9.2.1. Enable Verbose Logging')}

    +

    + + Verbose logging provides detailed information about the plugin's + execution flow, helping identify where issues occur and what data + is being processed at each step. + +

    + + {examples[3]} + + +

    {_('9.2.2. Save Intermediate Results')}

    +

    + + Saving intermediate results allows you to inspect the code + generation process at different stages, making it easier to + identify where problems occur and verify that each step produces + the expected output. + +

    + + {examples[4]} + + +

    {_('9.2.3. Validate Each Step')}

    +

    + + Step-by-step validation ensures that each phase of the generation + process produces valid TypeScript code, helping catch issues early + before they compound into larger problems. + +

    + + {examples[5]} + +
    + + ) +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx new file mode 100644 index 0000000..a9766bc --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx @@ -0,0 +1,646 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, H2, P, C } from '../index.js'; +import Code from '../Code.js'; + +const examples = [ + `import { Project } from "ts-morph"; + +// Create a new project +const project = new Project({ + compilerOptions: { + target: ScriptTarget.ES2020, + module: ModuleKind.CommonJS, + }, +}); + +// Create a source file +const sourceFile = project.createSourceFile("example.ts", ""); + +// Add content to the file +sourceFile.addInterface({ + name: "User", + properties: [ + { name: "id", type: "string" }, + { name: "name", type: "string" }, + ], +}); + +// Get the generated code +console.log(sourceFile.getFullText()); +// Output: +// interface User { +// id: string; +// name: string; +// }`, + `// Add imports +sourceFile.addImportDeclaration({ + moduleSpecifier: "react", + namedImports: ["useState", "useEffect"], +}); + +// Add a class +sourceFile.addClass({ + name: "UserService", + isExported: true, + methods: [ + { + name: "getUser", + parameters: [{ name: "id", type: "string" }], + returnType: "Promise", + statements: "return fetch('/api/users/' + id).then(r => r.json());", + }, + ], +}); + +// Add a function +sourceFile.addFunction({ + name: "createUser", + isExported: true, + isAsync: true, + parameters: [{ name: "userData", type: "Partial" }], + returnType: "Promise", + statements: [ + "const response = await fetch('/api/users', {", + " method: 'POST',", + " headers: { 'Content-Type': 'application/json' },", + " body: JSON.stringify(userData)", + "});", + "return response.json();", + ], +}); + +// Add type aliases +sourceFile.addTypeAlias({ + name: "UserId", + isExported: true, + type: "string", +}); + +// Add enums +sourceFile.addEnum({ + name: "UserRole", + isExported: true, + members: [ + { name: "ADMIN", value: "admin" }, + { name: "USER", value: "user" }, + { name: "GUEST", value: "guest" }, + ], +});`, + `import { Project } from "ts-morph"; + +const project = new Project(); + +const source = project.createSourceFile("newFile.ts", null, { overwrite: true }); + +const myClass = source.addClass({ + name: "MyClass", +}); + +myClass.addMethod({ + name: "myMethod", + isDefaultExport: true + parameters: [{ name: "param1", type: "string" }], + returnType: "void", + statements: "console.log(param1);" +}); + +project.saveSync();`, + `export default class MyClass { + myMethod(param1: string): void { + console.log(param1); + } +}`, + `import { Project } from "ts-morph"; + +const project = new Project(); + +const source = project.createSourceFile("newFile.ts", null, { overwrite: true }); + +source.addFunction({ + name: "myFunction", + isExported: true, + isAsync: true, + parameters: [ + { name: "param1", type: "string" }, + { name: "param2", type: "number" } + ], + returnType: "void", + statements: [ + "console.log(param1);", + "console.log(param2);" + ] +}); + +project.saveSync();`, + `export async function myFunction(param1: string, param2: number): void { + console.log(param1); + console.log(param2); +}`, + `import { VariableDeclarationKind } from 'ts-morph'; + +source.addVariableStatement({ + isExported: true, + declarationKind: VariableDeclarationKind.Const, + declarations: [{ + name: "foo", + initializer: '\'bar\'' + }] +});`, + `export const foo = 'bar';`, + `source.addExportDeclaration({ + namedExports: ['ComponentA', 'ComponentB', 'ComponentC'] +});`, + `source.addTypeAlias({ + name: "ExampleType", + isExported: true, + type: "string | number" +});`, + `export type ExampleType = string | number;`, + `source.addTypeAlias({ + name: "AnotherType", + isExported: true, + type: "boolean" +}); + +source.addInterface({ + name: "ExampleInterface", + isExported: true, + properties: [ + { name: "id", type: "number" }, + { name: "name", type: "string" } + ] +}); + +// Optionally, use addExportDeclaration to export all at once +source.addExportDeclaration({ + namedExports: ["ExampleType", "AnotherType", "ExampleInterface"] +});`, + `export type ExampleType = string | number; +export type AnotherType = boolean; +export interface ExampleInterface { + id: number; + name: string; +}`, + `source.addImportDeclaration({ + moduleSpecifier: 'react', + namedImports: [ 'useState', 'useEffect' ] +});`, + `import { useState, useEffect } from 'react';`, + `source.addImportDeclaration({ + moduleSpecifier: 'next', + namedImports: [ + 'NextApiRequest as Request', + 'NextApiResponse as as Response' + ] +});`, + `import type { + NextApiRequest as Request, + NextApiResponse as Response +} from 'next';`, + `source.addImportDeclaration({ + moduleSpecifier: 'react', + defaultImport: 'React' +});`, + `import React from 'react';`, + `// Load existing files +project.addSourceFilesAtPaths("src/**/*.ts"); + +// Get a specific file +const existingFile = project.getSourceFile("src/models/User.ts"); + +// Find and modify existing constructs +const userInterface = existingFile?.getInterface("User"); +if (userInterface) { + // Add a new property + userInterface.addProperty({ + name: "email", + type: "string", + hasQuestionToken: true, // Makes it optional + }); + + // Add JSDoc comments + userInterface.addJsDoc({ + description: "Represents a user in the system", + tags: [ + { tagName: "example", text: "const user: User = { id: '1', name: 'John' };" }, + ], + }); +}` +]; + +export default function UnderstandingTsMorphBasics() { + const { _ } = useLanguage(); + return ( + <> +
    +

    {_('4. Understanding ts-morph Basics')}

    +

    + + Understanding the fundamental concepts of ts-morph is + essential for effective plugin development. This section covers + the core APIs, project management, source file manipulation, + and code generation patterns that form the foundation of all + ts-morph operations. + +

    +
    + +
    +

    {_('4.1. Project and Source Files')}

    +

    + + The Project class is the entry point for all ts-morph + operations, providing methods to create, load, and manage + TypeScript source files. Understanding how to work with projects + and source files is fundamental to building effective code + generation plugins. + +

    + + {examples[0]} + +
    + +
    +

    {_('4.2. Adding Different Constructs')}

    +

    + + ts-morph provides comprehensive APIs for adding various + TypeScript constructs including imports, classes, functions, + types, and enums. This section demonstrates the most commonly + used patterns for generating different types of TypeScript code. + +

    + + {examples[1]} + +
    + +
    +

    {_('4.3. Exporting a Class')}

    +

    + + Creating and exporting classes is a common requirement in + TypeScript code generation. This example demonstrates the basic + pattern for generating classes with methods, including proper + export declarations and method implementations. + +

    +

    + + A simple example of how to create a new TypeScript file with a + class and a method using ts-morph looks like the + following: + +

    + + {examples[2]} + + +

    + + This code will create a new TypeScript file newFile.ts + with the following content: + +

    + + {examples[3]} + +

    + + You can use isExported or isDefaultExport to + export or export default respectively. Also + statements can be a string or an array of strings + (string[]). + +

    +
    + +
    +

    {_('4.4. Exporting a Function')}

    +

    + + Function generation at the source file level provides flexibility + for creating utility functions, API endpoints, and standalone + operations. This section shows how to create functions with + various configurations including async operations, parameters, + and return types. + +

    +

    + + Similar to adding a method to a class, you can use + addFunction to add a function at the source file level. + An example of how to use addFunction to add a function + with arguments and a body looks like the following: + +

    + + {examples[4]} + +

    + + In the above example, myFunction takes two parameters, + param1 of type string and param2 of type number. + The function body contains two console.log statements. + +

    +

    + + After running the above code, the content of newFile.ts + would look like the following: + +

    + + {examples[5]} + +
    + +
    +

    {_('4.5. Exporting a Const')}

    +

    + + Constant declarations are essential for defining configuration + values, default settings, and immutable data structures. The + addVariableStatement method provides flexible options for + creating various types of variable declarations with proper export + handling. + +

    +

    + + To export a constant in ts-morph, you can utilize the + addVariableStatement method on a SourceFile object. + This method allows you to add a variable declaration to the file, + including the capability to export the declaration. + +

    + + {examples[6]} + +

    + + The provided ts-morph script will generate the following + code in the source file. + +

    + + {examples[7]} + +
    + +
    +

    {_('4.6. Exporting an Object')}

    +

    + + Export declarations provide a clean way to re-export multiple + entities from other modules or to export collections of related + functionality. This pattern is commonly used in index files and + module aggregation scenarios. + +

    +

    + + To generate an export statement that directly exports multiple + imported entities in a single line using ts-morph, you + don't need to declare them as variables first. Instead, you can + use the addExportDeclaration method directly after your + imports. This approach is more straightforward and aligns with + typical TypeScript import-export patterns. + +

    + + {examples[8]} + +
    + +
    +

    {_('4.7. Exporting Types')}

    +

    + + Type exports are crucial for creating reusable type definitions + that can be consumed by other modules. ts-morph provides + dedicated methods for creating both type aliases and interfaces + with proper export configurations. + +

    +

    + + To export a single type, you can use the addTypeAlias or + addInterface method (depending on whether you are defining + an alias or an interface), and set the isExported property + to true. An example of exporting a type alias looks like the + following: + +

    + + {examples[9]} + +

    + + This will generate a file with the following content: + +

    + + {examples[10]} + +

    + + To export multiple types at the same time, you can add multiple + type declarations (either type aliases or interfaces) with the + isExported property set to true for each. Alternatively, + you can use the addExportDeclaration method to export + previously declared types. An example of declaring and exporting + multiple types looks like the following: + +

    + + {examples[11]} + +

    + + This will generate a file with the following content: + +

    + + {examples[12]} + +
    + +
    +

    {_('4.8. Importing Values')}

    +

    + + Import declarations are essential for bringing external + dependencies and modules into your generated code. The + addImportDeclaration method provides comprehensive options + for creating various types of import statements including named + imports, default imports, and type imports. + +

    +

    + + To import a set of values from a module in ts-morph, you + can use the addImportDeclaration method on a + SourceFile object. This method allows you to add an import + declaration to the code file you are working with. Here's how to + use this method to import specific values from the react + module: + +

    + + {examples[13]} + +

    + + The provided ts-morph script will generate the following + code in the source file: + +

    + + {examples[14]} + +

    + + You can also import types like the following: + +

    + + {examples[15]} + +

    + + The above code renders the following: + +

    + + {examples[16]} + +
    + +
    +

    {_('4.9. Importing Defaults')}

    +

    + + Default imports are commonly used for importing the main export + from a module, such as React components or utility libraries. The + same addImportDeclaration method handles default imports + with a slightly different configuration. + +

    +

    + + To import a default from a module in ts-morph, you can + also use the addImportDeclaration method: + +

    + + {examples[17]} + +

    + + This would create the following code: + +

    + + {examples[18]} + +
    + +
    +

    {_('4.10. Working with Existing Code')}

    +

    + + Working with existing code is a powerful feature of + ts-morph that allows you to modify, extend, and refactor + existing TypeScript files. This capability is essential for + plugins that need to augment or update existing codebases rather + than generating new files from scratch. + +

    + + {examples[19]} + +
    + + ) +} diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx new file mode 100644 index 0000000..433648d --- /dev/null +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx @@ -0,0 +1,10 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Installation } from './Installation.js'; +export { default as SettingUpProject } from './SettingUpProject.js'; +export { default as UnderstandingTsMorphBasics } from './UnderstandingTsMorphBasics.js'; +export { default as CreateFirstPlugin } from './CreateFirstPlugin.js'; +export { default as AdvanceTsMorphPlugin } from './AdvanceTsMorphPlugin.js'; +export { default as TestingYourPlugin } from './TestingYourPlugin.js'; +export { default as BestPractices } from './BestPractices.js'; +export { default as Troubleshooting } from './Troubleshooting.js'; +export { default as References } from './References.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx new file mode 100644 index 0000000..830b6b9 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx @@ -0,0 +1,184 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, Code } from '../index.js'; + +const namespaceConfigurationExample = +`// With namespace configuration +namespace: "MyApp" +exportType: "namespace"`; + +const namespaceOutputExample = +`// Generated output: +export namespace MyApp { + export enum UserRole { + ADMIN = "admin", + USER = "user", + } + + export interface User { + id: string; + name: string; + role: UserRole; + } +}`; + +const standardEnumExample = +`// Standard enum (default) +enumType: "enum" +export enum UserRole { + ADMIN = "admin", + USER = "user", +}`; + +const unionTypeExample = +`// Union type +enumType: "union" +export type UserRole = "admin" | "user";`; + +const constAssertionExample = +`// Const assertion +enumType: "const" +export const UserRole = { + ADMIN: "admin", + USER: "user", +} as const; +export type UserRole = typeof UserRole[keyof typeof UserRole];`; + +const relationshipHandlingExample = +`function handleRelationships( + column: any, + config: TypeScriptConfig, + availableTypes: Set +): string { + // Check if the column type is another model/type + if (availableTypes.has(column.type)) { + let type = column.type; + + if (column.multiple) { + type = \`\${type}[]\`; + } + + if (!column.required && config.strictNullChecks) { + type = \`\${type} | null\`; + } + + return type; + } + + return formatPropertyType(column, config, availableTypes); +}`; + +const genericTypeSupportExample = +`function generateGenericTypes( + models: Record, + config: TypeScriptConfig +): string { + let content = '// Generic Types\\n'; + + // Generate paginated response type + content += \`export interface PaginatedResponse { + data: T[]; + total: number; + page: number; + limit: number; +}\\n\\n\`; + + // Generate API response type + content += \`export interface ApiResponse { + success: boolean; + data?: T; + error?: string; + errors?: Record; +}\\n\\n\`; + + return content; +}`; + +export default function AdvancedFeatures() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Advanced Features')}

    +

    + + Advanced features extend the basic TypeScript interface + generation with sophisticated organization, multiple enum types, + relationship handling, and generic type support. These features + enable production-ready TypeScript definitions that handle + complex scenarios. + +

    +
    + +
    +

    {_('Namespace Support')}

    +

    + + Namespace support allows you to organize generated types within + TypeScript namespaces, preventing naming conflicts and providing + better code organization. This feature is particularly useful + for large projects with multiple schema files. + +

    + + {namespaceConfigurationExample} + + + {namespaceOutputExample} + +
    + +
    +

    {_('Different Enum Types')}

    +

    + + Different enum types provide flexibility in how enumerations are + represented in TypeScript. The plugin supports standard enums, + union types, and const assertions, each with different runtime + characteristics and use cases. + +

    + + {standardEnumExample} + + + {unionTypeExample} + + + {constAssertionExample} + +
    + +
    +

    {_('Relationship Handling')}

    +

    + + Relationship handling manages references between different types + and models in your schema. This ensures that type relationships + are properly represented in the generated TypeScript code with + correct type references and nullability handling. + +

    + + {relationshipHandlingExample} + +
    + +
    +

    {_('Generic Type Support')}

    +

    + + Generic type support enables the generation of reusable type + definitions that work with multiple data types. This includes + common patterns like paginated responses and API response + wrappers that enhance type safety across your application. + +

    + + {genericTypeSupportExample} + +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx new file mode 100644 index 0000000..d18ce98 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx @@ -0,0 +1,179 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, Code } from '../index.js'; + +const typeSafetyInterface = +`interface TypeScriptColumn { + name: string; + type: string; + required: boolean; + multiple: boolean; + description?: string; + attributes?: Record; +}`; + +const columnValidation = +`function validateColumn(column: any): column is TypeScriptColumn { + return ( + typeof column.name === 'string' && + typeof column.type === 'string' && + typeof column.required === 'boolean' + ); +}`; + +const typeNameSanitization = +`function sanitizeTypeName(name: string): string { + // Ensure TypeScript-valid names + return name + .replace(/[^a-zA-Z0-9_]/g, '_') + .replace(/^[0-9]/, '_$&') + .replace(/^_+|_+$/g, ''); +}`; + +const pascalCaseConversion = +`function toPascalCase(str: string): string { + return str + .split(/[-_\\s]+/) + .map(word => + word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() + ) + .join(''); +}`; + +const jsDocGeneration = +`function generateJSDocComment( + column: any, + includeAttributes: boolean = true +): string { + const lines: string[] = []; + + if (column.description) { + lines.push(column.description); + } + + if (includeAttributes && column.attributes) { + if (column.attributes.default) { + lines.push(\`@default \${column.attributes.default}\`); + } + if (column.attributes.example) { + lines.push(\`@example \${column.attributes.example}\`); + } + } + + if (lines.length === 0) return ''; + + if (lines.length === 1) { + return \` /** \${lines[0]} */\\n\`; + } + + return \` /**\\n\${lines.map(line => + \` * \${line}\`).join('\\n')}\\n */\\n\`; +}`; + +const typeCacheOptimization = +`// Cache type mappings +const typeCache = new Map(); + +function getCachedTypeMapping( + schemaType: string, + strictNullChecks: boolean +): string { + const cacheKey = \`\${schemaType}:\${strictNullChecks}\`; + + if (typeCache.has(cacheKey)) { + return typeCache.get(cacheKey)!; + } + + const mappedType = mapSchemaTypeToTypeScript( + schemaType, + strictNullChecks + ); + typeCache.set(cacheKey, mappedType); + + return mappedType; +}`; + +export default function BestPractices() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Best Practices')}

    +

    + + Best practices ensure your generated TypeScript interfaces are + maintainable, reliable, and follow industry standards. These + guidelines cover type safety, naming conventions, documentation + generation, and performance optimization. + +

    +
    + +
    +

    {_('Type Safety')}

    +

    + + Type safety is crucial for preventing runtime errors and + improving developer experience. Always validate input data and + use proper TypeScript types throughout the plugin implementation + to ensure reliable code generation. + +

    + + {typeSafetyInterface} + + + {columnValidation} + +
    + +
    +

    {_('Naming Conventions')}

    +

    + + Naming conventions ensure that generated TypeScript identifiers + are valid and follow established patterns. Proper naming improves + code readability and prevents conflicts with reserved keywords + or invalid characters. + +

    + + {typeNameSanitization} + + + {pascalCaseConversion} + +
    + +
    +

    {_('Documentation Generation')}

    +

    + + Documentation generation creates comprehensive JSDoc comments that + provide context and examples for the generated types. This + improves the developer experience by providing inline + documentation in IDEs and code editors. + +

    + + {jsDocGeneration} + +
    + +
    +

    {_('Performance Optimization')}

    +

    + + Performance optimization techniques help maintain reasonable + generation times when working with large schemas. Caching + strategies and efficient algorithms ensure the plugin scales + well with complex type hierarchies. + +

    + + {typeCacheOptimization} + +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx new file mode 100644 index 0000000..779c284 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx @@ -0,0 +1,305 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C, Code } from '../index.js'; + +const corePluginFunctionExample = + `export default async function generateTypeScriptInterfaces( + props: PluginProps<{ config: TypeScriptConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate TypeScript content + let content = ''; + + // Add file header + content += generateFileHeader(); + + // Generate enums + if (config.generateEnums !== false && schema.enum) { + content += generateEnums(schema.enum, config); + } + + // Generate custom types + if (schema.type) { + content += generateCustomTypes(schema.type, config); + } + + // Generate interfaces from models + if (schema.model) { + content += generateInterfaces(schema.model, config); + } + + // Generate utility types + if (config.generateUtilityTypes) { + content += generateUtilityTypes(schema, config); + } + + // Wrap in namespace if specified + if (config.namespace) { + content = wrapInNamespace(content, config.namespace, + config.exportType); + } + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ TypeScript interfaces generated: \${outputPath}\`); + + } catch (error) { + console.error( + '❌ TypeScript interface generation failed:', + error.message + ); + throw error; + } +}`; + +const typeMappingFunctionsExample = + `function mapSchemaTypeToTypeScript( + schemaType: string, + strictNullChecks: boolean = true +): string { + const typeMap: Record = { + 'String': 'string', + 'Number': 'number', + 'Integer': 'number', + 'Boolean': 'boolean', + 'Date': 'Date', + 'JSON': 'any', + 'ID': 'string' + }; + + const baseType = typeMap[schemaType] || schemaType; + + // Handle strict null checks + if (!strictNullChecks && baseType !== 'any') { + return \`\${baseType} | null | undefined\`; + } + + return baseType; +} + +function formatPropertyType( + column: any, + config: TypeScriptConfig, + availableTypes: Set = new Set() +): string { + let type = column.type; + + // Check if it's a reference to another type + if (availableTypes.has(column.type)) { + type = column.type; + } else { + type = mapSchemaTypeToTypeScript(column.type, config.strictNullChecks); + } + + // Handle arrays + if (column.multiple) { + type = \`\${type}[]\`; + } + + // Handle optional properties + if (!column.required && config.strictNullChecks) { + type = \`\${type} | null\`; + } + + return type; +}`; + +const generationFunctionsExample = + `function generateFileHeader(): string { + const timestamp = new Date().toISOString(); + return \`/** + * Generated TypeScript interfaces + * Generated at: \${timestamp} + * + * This file is auto-generated. Do not edit manually. + */ + +\`; +} + +function generateEnums( + enums: Record, + config: TypeScriptConfig +): string { + let content = '// Enums\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + if (config.includeComments) { + content += \`/**\\n * \${enumName} enumeration\\n */\\n\`; + } + + switch (config.enumType) { + case 'union': + content += generateUnionEnum(enumName, enumDef); + break; + case 'const': + content += generateConstEnum(enumName, enumDef); + break; + default: + content += generateStandardEnum(enumName, enumDef); + } + + content += '\\n'; + } + + return content + '\\n'; +} + +function generateStandardEnum(enumName: string, enumDef: any): string { + let content = \`export enum \${enumName} {\\n\`; + + for (const [key, value] of Object.entries(enumDef)) { + content += \` \${key} = "\${value}",\\n\`; + } + + content += '}'; + return content; +} + +function generateInterfaces( + models: Record, + config: TypeScriptConfig +): string { + let content = '// Model Interfaces\\n'; + const availableTypes = new Set([ + ...Object.keys(models), + ...(config.namespace ? [] : Object.keys(models)) + ]); + + for (const [modelName, model] of Object.entries(models)) { + if (config.includeComments) { + content += \`/**\\n * \${modelName} model interface\\n\`; + if (model.description) { + content += \` * \${model.description}\\n\`; + } + content += \` */\\n\`; + } + + content += \`export interface \${modelName} {\\n\`; + + for (const column of model.columns || []) { + const propertyType = formatPropertyType(column, config, + availableTypes); + const optional = !column.required ? '?' : ''; + + if (config.includeComments) { + let comment = ''; + if (column.description) { + comment += column.description; + } + if (column.attributes?.default) { + comment += comment ? + \` (default: \${column.attributes.default})\` : + \`Default: \${column.attributes.default}\`; + } + if (comment) { + content += \` /** \${comment} */\\n\`; + } + } + + content += \` \${column.name}\${optional}: \${propertyType};\\n\`; + } + + content += '}\\n\\n'; + } + + return content; +}`; + +const validationFunctionsExample = + `function validateConfig(config: any): asserts config is TypeScriptConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error( + 'TypeScript plugin requires "output" configuration as string' + ); + } + + if (config.exportType && + !['named', 'default', 'namespace'].includes(config.exportType)) { + throw new Error( + 'exportType must be one of: named, default, namespace' + ); + } + + if (config.enumType && + !['enum', 'union', 'const'].includes(config.enumType)) { + throw new Error('enumType must be one of: enum, union, const'); + } +}`; + +export default function Implementation() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Implementation')}

    +

    + + The implementation section covers the core plugin function and + supporting utilities that handle TypeScript interface generation. + This includes configuration validation, content generation, file + writing, and error handling throughout the generation process. + +

    + +

    {_('Core Plugin Function')}

    +

    + + The core plugin function serves as the main entry point for + TypeScript interface generation. It orchestrates the entire process + from configuration validation through content generation to file + output, ensuring proper error handling and logging throughout. + +

    + + {corePluginFunctionExample} + + +

    {_('Type Mapping Functions')}

    +

    + + Type mapping functions handle the conversion of .idea schema + types to their TypeScript equivalents. These functions ensure proper + type safety and handle complex scenarios like nullable types, arrays, + and custom type references. + +

    + + {typeMappingFunctionsExample} + + +

    {_('Generation Functions')}

    +

    + + Generation functions create specific parts of the TypeScript output + including enums, interfaces, and utility types. These functions + handle formatting, documentation generation, and proper TypeScript + syntax construction. + +

    + + {generationFunctionsExample} + + +

    {_('Validation Functions')}

    +

    + + Validation functions ensure that the plugin configuration is correct + and that the generated TypeScript code meets quality standards. + These functions catch configuration errors early and prevent invalid + output generation. + +

    + + {validationFunctionsExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx new file mode 100644 index 0000000..2991162 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx @@ -0,0 +1,20 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + + return ( + <> +

    {_('TypeScript Interface Generator Plugin Tutorial')}

    +

    + + This tutorial demonstrates how to create a plugin that generates + TypeScript interfaces and types from .idea schema files. The + plugin will transform your schema models, types, and enums into + proper TypeScript definitions with full type safety. + +

    + + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx new file mode 100644 index 0000000..98e1629 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx @@ -0,0 +1,54 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C, SS } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Overview')}

    +

    + + TypeScript interfaces provide compile-time type checking and + excellent IDE support. This plugin transforms your .idea + schema definitions into comprehensive TypeScript type definitions + that integrate seamlessly with your development workflow and + provide robust type safety throughout your application. + +

    +

    + + This plugin generates TypeScript definitions from your + .idea schema, including: + +

    +
      +
    • + + Interfaces: TypeScript interfaces from schema models + +
    • +
    • + + Types: Custom types and type aliases + +
    • +
    • + + Enums: TypeScript enums with multiple output formats + +
    • +
    • + + Utility Types: Helper types for CRUD operations + +
    • +
    • + + Namespaces: Organized code with namespace support + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx new file mode 100644 index 0000000..ee275db --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx @@ -0,0 +1,50 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface TypeScriptConfig { + output: string; + namespace?: string; + exportType?: 'named' | 'default' | 'namespace'; + generateUtilityTypes?: boolean; + includeComments?: boolean; + strictNullChecks?: boolean; + generateEnums?: boolean; + enumType?: 'enum' | 'union' | 'const'; +} + +export default async function generateTypeScriptInterfaces( + props: PluginProps<{ config: TypeScriptConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`; + +export default function PluginStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Plugin Structure')}

    +

    + + The plugin structure defines the core architecture and + configuration interface for the TypeScript interface generator. + This includes the main plugin function, configuration types, and + the overall organization of the generated TypeScript code. + +

    + + {pluginStructureExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx new file mode 100644 index 0000000..ee519a7 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx @@ -0,0 +1,42 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C } from '../index.js'; + +export default function Prerequisites() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Prerequisites')}

    +

    + + Before implementing the TypeScript interface generator plugin, + ensure you have the necessary development environment and + knowledge. This section covers the essential requirements for + successful plugin creation and TypeScript integration. + +

    +
      +
    • + + Node.js 16+ and npm/yarn + +
    • +
    • + + TypeScript 4.0+ development experience + +
    • +
    • + + Familiarity with the @stackpress/idea-transformer library + +
    • +
    • + + Understanding of .idea schema format + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx new file mode 100644 index 0000000..067a290 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx @@ -0,0 +1,131 @@ +import { useLanguage, Translate } from 'r22n'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; +import { H2, H3, P, C } from '../index.js'; +import Code from '../Code.js'; + + +const basicConfigurationExample = `plugin "./plugins/typescript-interfaces.js" { + output "./generated/types.ts" + namespace "MyApp" + exportType "named" + generateUtilityTypes true + includeComments true + strictNullChecks true + generateEnums true + enumType "enum" +}`; + +const configurationTableData = [ + { + option: 'output', + type: 'string', + defaultValue: 'Required', + description: 'Output file path for TypeScript definitions' + }, + { + option: 'namespace', + type: 'string', + defaultValue: 'undefined', + description: 'Wrap types in a namespace' + }, + { + option: 'exportType', + type: "'named'|'default'|'namespace'", + defaultValue: "'named'", + description: 'Export style for types' + }, + { + option: 'generateUtilityTypes', + type: 'boolean', + defaultValue: 'false', + description: 'Generate helper utility types' + }, + { + option: 'includeComments', + type: 'boolean', + defaultValue: 'false', + description: 'Include JSDoc comments' + }, + { + option: 'strictNullChecks', + type: 'boolean', + defaultValue: 'true', + description: 'Handle null/undefined types' + }, + { + option: 'generateEnums', + type: 'boolean', + defaultValue: 'true', + description: 'Generate enum definitions' + }, + { + option: 'enumType', + type: "'enum'|'union'|'const'", + defaultValue: "'enum'", + description: 'Enum generation style' + } +]; + +export default function SchemaConfiguration() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Schema Configuration')}

    +

    + + Schema configuration demonstrates how to integrate the TypeScript + interface generator into your .idea schema files. This + section covers plugin configuration options and their effects on + the generated TypeScript output. + +

    +

    + + Add the TypeScript plugin to your .idea schema file: + +

    + + {basicConfigurationExample} + + +

    {_('Configuration Options')}

    +

    + + Configuration options control how TypeScript interfaces are + generated, including output formatting, type handling, and feature + enablement. Understanding these options helps you customize the + plugin to meet your specific project requirements. + +

    + + + + Option + Type + Default + Description + + {configurationTableData.map((row, index) => ( + + + {row.option} + + + {row.type} + + + {row.defaultValue} + + + {row.description} + + + ))} +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx new file mode 100644 index 0000000..f0842a0 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx @@ -0,0 +1,207 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P, C, Code } from '../index.js'; + +const typeNameValidation = +`function validateTypeName(name: string): void { + if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) { + throw new Error(\`Invalid TypeScript identifier: \${name}\`); + } +}`; + +const circularReferenceDetection = +`function detectCircularReferences( + types: Record +): string[] { + const visited = new Set(); + const recursionStack = new Set(); + const cycles: string[] = []; + + function visit(typeName: string): void { + if (recursionStack.has(typeName)) { + cycles.push(typeName); + return; + } + + if (visited.has(typeName)) return; + + visited.add(typeName); + recursionStack.add(typeName); + + // Check type dependencies... + + recursionStack.delete(typeName); + } + + for (const typeName of Object.keys(types)) { + visit(typeName); + } + + return cycles; +}`; + +const dependencyValidation = +`function validateTypeDependencies( + schema: any +): void { + const availableTypes = new Set([ + ...Object.keys(schema.model || {}), + ...Object.keys(schema.type || {}), + ...Object.keys(schema.enum || {}) + ]); + + // Validate all type references... +}`; + +const verboseLogging = +`const VERBOSE = process.env.TS_PLUGIN_VERBOSE === 'true'; + +function verboseLog(message: string, data?: any) { + if (VERBOSE) { + console.log(\`[TypeScript Plugin] \${message}\`, data || ''); + } +}`; + +const typeScriptValidation = +`import { transpile, ScriptTarget } from 'typescript'; + +function validateGeneratedTypeScript(content: string): void { + try { + transpile(content, { + target: ScriptTarget.ES2020, + strict: true + }); + console.log('✅ Generated TypeScript is valid'); + } catch (error) { + throw new Error(\`Invalid TypeScript: \${error.message}\`); + } +}`; + +export default function Troubleshooting() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Troubleshooting')}

    +

    + + This section addresses common issues encountered when generating + TypeScript interfaces and provides solutions for debugging and + resolving problems. Understanding these troubleshooting techniques + helps ensure reliable interface generation. + +

    +
    + +
    +

    {_('Common Issues')}

    +

    + + Common issues include invalid TypeScript identifiers, circular + type references, and missing dependencies. These problems + typically arise from schema complexity or configuration + mismatches that can be resolved with proper validation and + error handling. + +

    + +
    +

    {_('Invalid TypeScript Names')}

    +

    + + Invalid TypeScript names occur when schema identifiers contain + characters that are not valid in TypeScript. The plugin should + validate and sanitize names to ensure they conform to + TypeScript identifier rules. + +

    + + {typeNameValidation} + +
    + +
    +

    {_('Circular Type References')}

    +

    + + Circular type references can cause infinite loops during + generation or compilation errors in the generated TypeScript + code. Detecting and handling these scenarios is essential for + robust type generation. + +

    + + {circularReferenceDetection} + +
    + +
    +

    {_('Missing Type Dependencies')}

    +

    + + Missing type dependencies occur when a type references another + type that doesn't exist in the schema. Validating type + dependencies ensures all references are resolvable and prevents + compilation errors. + +

    + + {dependencyValidation} + +
    +
    + +
    +

    {_('Debugging Tips')}

    +

    + + Debugging tips help identify and resolve issues during TypeScript + interface generation. These techniques provide visibility into + the generation process and help diagnose problems with schema + processing or output generation. + +

    + +
    +

    {_('Enable Verbose Output')}

    +

    + + Verbose output provides detailed logging during the generation + process, helping identify where issues occur and what data is + being processed at each step. + +

    + + {verboseLogging} + +
    + +
    +

    {_('Validate Generated TypeScript')}

    +

    + + Validating generated TypeScript ensures that the output is + syntactically correct and will compile successfully. This + validation step catches generation errors before the code is + used in development. + +

    + + {typeScriptValidation} + +
    +
    + +
    +

    + + This tutorial provides a comprehensive foundation for creating + TypeScript interface generators from .idea files. The + generated types can be used throughout your TypeScript projects + for compile-time type checking and enhanced IDE support. + +

    +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx new file mode 100644 index 0000000..d20ddd0 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx @@ -0,0 +1,138 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const basicSchemaExample = `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +type Address { + street String @required + city String @required + country String @required + postal String +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("USER") + address Address? + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/typescript-interfaces.js" { + output "./types.ts" + generateUtilityTypes true + includeComments true +}`; + +const generatedOutputExample = `/** + * Generated TypeScript interfaces + * Generated at: 2024-01-15T10:30:00.000Z + * + * This file is auto-generated. Do not edit manually. + */ + +// Enums +/** + * UserRole enumeration + */ +export enum UserRole { + ADMIN = "admin", + USER = "user", + GUEST = "guest", +} + +// Custom Types +/** + * Address type definition + */ +export interface Address { + street: string; + city: string; + country: string; + postal?: string | null; +} + +// Model Interfaces +/** + * User model interface + */ +export interface User { + /** Default: nanoid() */ + id: string; + email: string; + name: string; + /** Default: USER */ + role: UserRole; + address?: Address | null; + /** Default: true */ + active: boolean; + /** Default: now() */ + createdAt: Date; +} + +// Utility Types +export type CreateUserInput = Omit; + +export type UpdateUserInput = Partial; + +export type AnyModel = User; + +export type UserKeys = keyof User;`; + +export default function UsageExamples() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Usage Examples')}

    +

    + + Usage examples demonstrate practical applications of the TypeScript + interface generator with real-world scenarios. These examples show + how to configure the plugin for different use cases and how the + generated TypeScript code integrates into development workflows. + +

    + +

    {_('Basic Schema')}

    +

    + + A basic schema example shows the fundamental structure needed to + generate TypeScript interfaces. This includes model definitions with + proper attributes, enum declarations, and plugin configuration that + produces clean, type-safe TypeScript code. + +

    + + {basicSchemaExample} + + +

    {_('Generated Output')}

    +

    + + The generated output demonstrates the TypeScript code produced by + the plugin from the basic schema example. This shows how schema + definitions are transformed into proper TypeScript interfaces with + full type safety and documentation. + +

    + + {generatedOutputExample} + + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx new file mode 100644 index 0000000..890be10 --- /dev/null +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx @@ -0,0 +1,10 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Overview } from './Overview.js'; +export { default as Prerequisites } from './Prerequisites.js'; +export { default as PluginStructure } from './PluginStructure.js'; +export { default as Implementation } from './Implementation.js'; +export { default as SchemaConfiguration } from './SchemaConfiguration.js'; +export { default as UsageExamples } from './UsageExamples.js'; +export { default as AdvancedFeatures } from './AdvancedFeatures.js'; +export { default as BestPractices } from './BestPractices.js'; +export { default as Troubleshooting } from './Troubleshooting.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx new file mode 100644 index 0000000..a8f9b76 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx @@ -0,0 +1,137 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const customValidatorsExample = `// In plugin configuration +customValidators: { + Email: "z.string().email().transform(val => val.toLowerCase())", + Password: "z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/)", + Slug: "z.string().regex(/^[a-z0-9-]+$/)", + Color: "z.string().regex(/^#[0-9A-F]{6}$/i)", + JSON: "z.string().transform(val => JSON.parse(val))" +}`; + +const conditionalValidationExample = `// Generated schema with conditional validation +export const UserSchema = z.object({ + id: z.string(), + email: z.string().email(), + role: UserRoleSchema, + adminCode: z.string().optional(), +}).refine((data) => { + // Admin users must have admin code + if (data.role === 'admin' && !data.adminCode) { + return false; + } + return true; +}, { + message: "Admin users must provide an admin code", + path: ["adminCode"], +});`; + +const transformPreprocessExample = `// Add transforms to generated schemas +function addTransforms(schema: string, column: any): string { + if (column.attributes?.transform) { + switch (column.attributes.transform) { + case 'lowercase': + return schema + '.transform(val => val.toLowerCase())'; + case 'uppercase': + return schema + '.transform(val => val.toUpperCase())'; + case 'trim': + return schema + '.transform(val => val.trim())'; + case 'slug': + return schema + '.transform(val => val.toLowerCase().replace(/\\s+/g, "-"))'; + } + } + + return schema; +}`; + +const asyncValidationExample = `// Generate async validation schemas +export const UserSchemaAsync = UserSchema.extend({ + email: z.string().email().refine(async (email) => { + // Check if email is unique + const exists = await checkEmailExists(email); + return !exists; + }, { + message: "Email already exists", + }), +}); + +// Usage +const validateUserAsync = async (data: unknown) => { + try { + const user = await UserSchemaAsync.parseAsync(data); + return { success: true, data: user }; + } catch (error) { + return { success: false, errors: error.errors }; + } +};`; + +export default function AdvancedFeatures() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('7. Advanced Features')}

    +

    + + Advanced features extend the basic Zod schema generation with sophisticated + validation patterns, conditional logic, data transformation, and asynchronous + validation. These features enable production-ready validation that handles + complex business requirements. + +

    + +

    {_('7.1. Custom Validators')}

    +

    + + Custom validators allow you to define specialized validation logic for + specific data types or business rules. This feature enables the creation + of reusable validation patterns that can be applied across multiple + schema definitions. + +

    + + {customValidatorsExample} + + +

    {_('7.2. Conditional Validation')}

    +

    + + Conditional validation enables complex validation logic that depends on + the values of other fields. This feature is essential for implementing + business rules that require cross-field validation and context-dependent + constraints. + +

    + + {conditionalValidationExample} + + +

    {_('7.3. Transform and Preprocess')}

    +

    + + Transform and preprocess capabilities allow you to modify data during + validation, enabling data normalization, formatting, and cleanup. This + feature ensures data consistency and proper formatting before validation. + +

    + + {transformPreprocessExample} + + +

    {_('7.4. Async Validation')}

    +

    + + Async validation enables validation rules that require external data + sources or API calls, such as checking for unique values or validating + against external services. This feature is crucial for comprehensive + data validation in real applications. + +

    + + {asyncValidationExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx new file mode 100644 index 0000000..138e4fd --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx @@ -0,0 +1,164 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const errorHandlingExample = `// Centralized validation error handling +class ValidationError extends Error { + constructor(public errors: z.ZodError) { + super('Validation failed'); + this.name = 'ValidationError'; + } + + getFieldErrors(): Record { + const fieldErrors: Record = {}; + + this.errors.errors.forEach((error) => { + const field = error.path.join('.'); + fieldErrors[field] = error.message; + }); + + return fieldErrors; + } +} + +// Usage +function validateWithErrorHandling(schema: z.ZodSchema, data: unknown): T { + const result = schema.safeParse(data); + + if (!result.success) { + throw new ValidationError(result.error); + } + + return result.data; +}`; + +const schemaCompositionExample = `// Compose schemas for reusability +const BaseEntitySchema = z.object({ + id: z.string(), + createdAt: z.date(), + updatedAt: z.date(), +}); + +const UserSchema = BaseEntitySchema.extend({ + email: z.string().email(), + name: z.string().min(1), +}); + +const PostSchema = BaseEntitySchema.extend({ + title: z.string().min(1), + content: z.string(), + authorId: z.string(), +});`; + +const typeGuardsExample = `// Generate type guards from schemas +export const isUser = (data: unknown): data is User => { + return UserSchema.safeParse(data).success; +}; + +export const isCreateUserInput = (data: unknown): data is CreateUserInput => { + return CreateUserSchema.safeParse(data).success; +}; + +// Usage +function processUserData(data: unknown) { + if (isUser(data)) { + // TypeScript knows data is User + console.log(data.email); + } +}`; + +const apiIntegrationExample = `// Middleware for API validation +function validateBody(schema: z.ZodSchema) { + return (req: Request, res: Response, next: NextFunction) => { + const result = schema.safeParse(req.body); + + if (!result.success) { + return res.status(400).json({ + success: false, + error: 'Validation failed', + errors: result.error.errors.reduce((acc, err) => { + const field = err.path.join('.'); + acc[field] = err.message; + return acc; + }, {} as Record) + }); + } + + req.body = result.data; + next(); + }; +} + +// Usage +app.post('/users', validateBody(CreateUserSchema), (req, res) => { + // req.body is now typed and validated + const user = req.body; // Type: CreateUserInput +});`; + +export default function BestPractices() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('8. Best Practices')}

    +

    + + Best practices ensure your generated Zod validation schemas are + maintainable, performant, and provide excellent developer experience. + These guidelines cover error handling, schema composition, type safety, + and API integration patterns. + +

    + +

    {_('8.1. Error Handling')}

    +

    + + Proper error handling ensures that validation failures provide clear, + actionable feedback to users and developers. Implement centralized error + handling patterns and meaningful error messages to improve the overall + user experience. + +

    + + {errorHandlingExample} + + +

    {_('8.2. Schema Composition')}

    +

    + + Schema composition enables the creation of reusable validation components + that can be combined to build complex validation schemas. This approach + promotes code reuse and maintains consistency across your validation logic. + +

    + + {schemaCompositionExample} + + +

    {_('8.3. Type Guards')}

    +

    + + Type guards provide runtime type checking that integrates seamlessly + with TypeScript's type system. Generated type guards enable safe type + narrowing and improve code reliability by ensuring data conforms to + expected types. + +

    + + {typeGuardsExample} + + +

    {_('8.4. API Integration')}

    +

    + + API integration patterns show how to use generated Zod schemas for + request validation in web applications. This includes middleware creation, + error response formatting, and type-safe request handling. + +

    + + {apiIntegrationExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx b/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx new file mode 100644 index 0000000..b9616f1 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx @@ -0,0 +1,503 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const corePluginFunction = +`export default async function generateZodSchemas( + props: PluginProps<{ config: ZodConfig }> +) { + const { config, schema, transformer } = props; + + try { + // Validate configuration + validateConfig(config); + + // Generate Zod content + let content = ''; + + // Add file header and imports + content += generateFileHeader(); + content += generateImports(config); + + // Generate enums if requested + if (config.includeEnums && schema.enum) { + content += generateEnumSchemas(schema.enum, config); + } + + // Generate custom type schemas + if (schema.type) { + content += generateTypeSchemas(schema.type, config); + } + + // Generate model schemas + if (schema.model) { + content += generateModelSchemas(schema.model, config); + } + + // Generate utility schemas + content += generateUtilitySchemas(schema, config); + + // Generate main export + content += generateMainExport(schema, config); + + // Write to output file + const outputPath = await transformer.loader.absolute(config.output); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, content, 'utf8'); + + console.log(\`✅ Zod validation schemas generated: \${outputPath}\`); + + } catch (error) { + console.error('❌ Zod schema generation failed:', error.message); + throw error; + } +}`; + +const enumGeneration = `function generateEnumSchemas(enums: Record, config: ZodConfig): string { + let content = '// Enum Schemas\\n'; + + for (const [enumName, enumDef] of Object.entries(enums)) { + const values = Object.values(enumDef); + const zodValues = values.map(v => \`"\${v}"\`).join(', '); + + content += \`export const \${enumName}Schema = z.enum([\${zodValues}]);\\n\`; + + if (config.generateTypes) { + content += \`export type \${enumName} = z.infer;\\n\`; + } + + content += '\\n'; + } + + return content + '\\n'; +}`; + +const typeGeneration = `function generateTypeSchemas(types: Record, config: ZodConfig): string { + let content = '// Type Schemas\\n'; + + for (const [typeName, typeDef] of Object.entries(types)) { + content += \`export const \${typeName}Schema = z.object({\\n\`; + + for (const column of typeDef.columns || []) { + const fieldSchema = generateFieldSchema(column, config); + content += \` \${column.name}: \${fieldSchema},\\n\`; + } + + content += '})'; + + // Add strict mode if enabled + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type \${typeName} = z.infer;\\n\`; + } + + content += '\\n'; + } + + return content; +}`; + +const modelGeneration = `function generateModelSchemas(models: Record, config: ZodConfig): string { + let content = '// Model Schemas\\n'; + + for (const [modelName, model] of Object.entries(models)) { + content += \`export const \${modelName}Schema = z.object({\\n\`; + + for (const column of model.columns || []) { + const fieldSchema = generateFieldSchema(column, config); + content += \` \${column.name}: \${fieldSchema},\\n\`; + } + + content += '})'; + + // Add strict mode if enabled + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type \${modelName} = z.infer;\\n\`; + } + + // Generate input schemas + content += generateInputSchemas(modelName, model, config); + + content += '\\n'; + } + + return content; +}`; + +const fieldMapping = `function generateFieldSchema(column: any, config: ZodConfig): string { + let schema = mapTypeToZod(column.type, config); + + // Handle arrays + if (column.multiple) { + schema = \`z.array(\${schema})\`; + } + + // Handle optional fields + if (!column.required) { + schema += '.optional()'; + } + + // Add custom validations based on attributes + if (column.attributes) { + schema = addAttributeValidations(schema, column.attributes, config); + } + + return schema; +} + +function mapTypeToZod(schemaType: string, config: ZodConfig): string { + // Check for custom validators first + if (config.customValidators && config.customValidators[schemaType]) { + return config.customValidators[schemaType]; + } + + const typeMap: Record = { + 'String': 'z.string()', + 'Number': 'z.number()', + 'Integer': 'z.number().int()', + 'Boolean': 'z.boolean()', + 'Date': 'z.date()', + 'JSON': 'z.any()', + 'ID': 'z.string()' + }; + + return typeMap[schemaType] || \`\${schemaType}Schema\`; +}`; + +const attributeValidations = `function addAttributeValidations(schema: string, attributes: any, config: ZodConfig): string { + let validatedSchema = schema; + + // String validations + if (attributes.min && schema.includes('z.string()')) { + validatedSchema += \`.min(\${attributes.min})\`; + } + + if (attributes.max && schema.includes('z.string()')) { + validatedSchema += \`.max(\${attributes.max})\`; + } + + if (attributes.email && schema.includes('z.string()')) { + validatedSchema += '.email()'; + } + + if (attributes.url && schema.includes('z.string()')) { + validatedSchema += '.url()'; + } + + if (attributes.uuid && schema.includes('z.string()')) { + validatedSchema += '.uuid()'; + } + + if (attributes.regex && schema.includes('z.string()')) { + validatedSchema += \`.regex(/\${attributes.regex}/)\`; + } + + // Number validations + if (attributes.min && schema.includes('z.number()')) { + validatedSchema += \`.min(\${attributes.min})\`; + } + + if (attributes.max && schema.includes('z.number()')) { + validatedSchema += \`.max(\${attributes.max})\`; + } + + if (attributes.positive && schema.includes('z.number()')) { + validatedSchema += '.positive()'; + } + + if (attributes.negative && schema.includes('z.number()')) { + validatedSchema += '.negative()'; + } + + if (attributes.nonnegative && schema.includes('z.number()')) { + validatedSchema += '.nonnegative()'; + } + + // Array validations + if (attributes.minLength && schema.includes('z.array(')) { + validatedSchema += \`.min(\${attributes.minLength})\`; + } + + if (attributes.maxLength && schema.includes('z.array(')) { + validatedSchema += \`.max(\${attributes.maxLength})\`; + } + + if (attributes.nonempty && schema.includes('z.array(')) { + validatedSchema += '.nonempty()'; + } + + // Custom error messages + if (config.errorMessages) { + const fieldName = extractFieldName(schema); + if (fieldName && config.errorMessages[fieldName]) { + validatedSchema += \`.describe("\${config.errorMessages[fieldName]}")\`; + } + } + + return validatedSchema; +} + +function extractFieldName(schema: string): string | null { + // Extract field name from schema for error message lookup + const match = schema.match(/(\\w+)Schema/); + return match ? match[1] : null; +}`; + +const inputSchemas = `function generateInputSchemas(modelName: string, model: any, config: ZodConfig): string { + let content = ''; + + // Generate create input schema (omit auto-generated fields) + const createFields = model.columns?.filter((col: any) => + !col.attributes?.id && !col.attributes?.default + ) || []; + + if (createFields.length > 0) { + content += \`export const Create\${modelName}Schema = z.object({\\n\`; + + for (const column of createFields) { + const fieldSchema = generateFieldSchema(column, config); + content += \` \${column.name}: \${fieldSchema},\\n\`; + } + + content += '})'; + + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type Create\${modelName}Input = z.infer;\\n\`; + } + } + + // Generate update input schema (all fields optional) + content += \`export const Update\${modelName}Schema = \${modelName}Schema.partial()\`; + + if (config.strictMode) { + content += '.strict()'; + } + + content += ';\\n'; + + if (config.generateTypes) { + content += \`export type Update\${modelName}Input = z.infer;\\n\`; + } + + return content; +}`; + +const utilitySchemas = `function generateUtilitySchemas(schema: any, config: ZodConfig): string { + let content = '// Utility Schemas\\n'; + + // Generate pagination schema + content += \`export const PaginationSchema = z.object({ + page: z.number().int().positive().default(1), + limit: z.number().int().positive().max(100).default(10), + search: z.string().optional(), + sort: z.string().optional(), +}); + +\`; + + if (config.generateTypes) { + content += \`export type PaginationParams = z.infer;\\n\\n\`; + } + + // Generate API response schemas + content += \`export const APIResponseSchema = (dataSchema: T) => + z.object({ + success: z.boolean(), + data: dataSchema.optional(), + error: z.string().optional(), + errors: z.record(z.array(z.string())).optional(), + }); + +export const PaginatedResponseSchema = (dataSchema: T) => + z.object({ + success: z.boolean(), + data: z.array(dataSchema).optional(), + total: z.number().int().nonnegative(), + page: z.number().int().positive(), + limit: z.number().int().positive(), + error: z.string().optional(), + errors: z.record(z.array(z.string())).optional(), + }); + +\`; + + return content; +}`; + +const exportFunctions = `function generateMainExport(schema: any, config: ZodConfig): string { + if (config.exportStyle === 'namespace') { + return generateNamespaceExport(schema, config); + } + + if (config.exportStyle === 'default') { + return generateDefaultExport(schema, config); + } + + // Named exports (default) + return '// All schemas are exported as named exports above\\n'; +} + +function generateNamespaceExport(schema: any, config: ZodConfig): string { + let content = 'export namespace Schemas {\\n'; + + // Export enums + if (config.includeEnums && schema.enum) { + for (const enumName of Object.keys(schema.enum)) { + content += \` export const \${enumName} = \${enumName}Schema;\\n\`; + } + } + + // Export types + if (schema.type) { + for (const typeName of Object.keys(schema.type)) { + content += \` export const \${typeName} = \${typeName}Schema;\\n\`; + } + } + + // Export models + if (schema.model) { + for (const modelName of Object.keys(schema.model)) { + content += \` export const \${modelName} = \${modelName}Schema;\\n\`; + content += \` export const Create\${modelName} = Create\${modelName}Schema;\\n\`; + content += \` export const Update\${modelName} = Update\${modelName}Schema;\\n\`; + } + } + + content += '}\\n\\n'; + return content; +} + +function generateDefaultExport(schema: any, config: ZodConfig): string { + let content = 'const schemas = {\\n'; + + // Add enums + if (config.includeEnums && schema.enum) { + for (const enumName of Object.keys(schema.enum)) { + content += \` \${enumName}: \${enumName}Schema,\\n\`; + } + } + + // Add types + if (schema.type) { + for (const typeName of Object.keys(schema.type)) { + content += \` \${typeName}: \${typeName}Schema,\\n\`; + } + } + + // Add models + if (schema.model) { + for (const modelName of Object.keys(schema.model)) { + content += \` \${modelName}: \${modelName}Schema,\\n\`; + content += \` Create\${modelName}: Create\${modelName}Schema,\\n\`; + content += \` Update\${modelName}: Update\${modelName}Schema,\\n\`; + } + } + + content += \` Pagination: PaginationSchema, + APIResponse: APIResponseSchema, + PaginatedResponse: PaginatedResponseSchema, +}; + +export default schemas; +\`; + + return content; +}`; + +const configValidation = `function validateConfig(config: any): asserts config is ZodConfig { + if (!config.output || typeof config.output !== 'string') { + throw new Error('Zod plugin requires "output" configuration as string'); + } + + if (config.exportStyle && !['named', 'default', 'namespace'].includes(config.exportStyle)) { + throw new Error('exportStyle must be one of: named, default, namespace'); + } +}`; + +export default function Implementation() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('4. Implementation')}

    +

    + + The implementation section covers the core plugin function and + supporting utilities that handle Zod schema generation. This + includes configuration validation, content generation, file writing, + and error handling throughout the generation process. + +

    + +

    {_('4.1. Core Plugin Function')}

    +

    + + The core plugin function serves as the main entry point for Zod + schema generation. It orchestrates the entire process from + configuration validation through content generation to file output, + ensuring proper error handling and logging throughout. + +

    + + {corePluginFunction} + + +

    {_('4.2. Generation Functions')}

    +

    + + Generation functions create specific parts of the Zod validation + output including enum schemas, type schemas, model schemas, and + utility schemas. These functions handle proper Zod syntax + construction and validation rule application. + +

    + + {corePluginFunction} + + + {enumGeneration} + + + {typeGeneration} + + + {modelGeneration} + + + {fieldMapping} + + + {attributeValidations} + + + {inputSchemas} + + + {utilitySchemas} + + + {exportFunctions} + + + {configValidation} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx b/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx new file mode 100644 index 0000000..ad4629f --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx @@ -0,0 +1,20 @@ +import { useLanguage, Translate } from 'r22n'; +import { H1, P, C } from '../index.js'; + +export default function Introduction() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Validation Schema Generator Plugin Tutorial')}

    +

    + + This tutorial demonstrates how to create a plugin that generates + Zod validation schemas from .idea schema files. The plugin + will transform your schema models into type-safe validation + schemas with comprehensive validation rules. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Overview.tsx b/packages/www/plugins/docs/components/validation-plugin/Overview.tsx new file mode 100644 index 0000000..2b45c50 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/Overview.tsx @@ -0,0 +1,54 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C, SS } from '../index.js'; + +export default function Overview() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('1. Overview')}

    +

    + + Zod is a TypeScript-first schema validation library that provides + runtime type checking and validation. This plugin transforms your + .idea schema definitions into comprehensive Zod validation + schemas that provide robust runtime validation with excellent + TypeScript integration. + +

    +

    + + This plugin generates Zod schemas from your .idea schema, + including: + +

    +
      +
    • + + Schema Validation: Zod schemas for all models and types + +
    • +
    • + + Type Inference: TypeScript types inferred from Zod schemas + +
    • +
    • + + Custom Validators: Support for custom validation rules + +
    • +
    • + + Error Messages: Customizable validation error messages + +
    • +
    • + + Nested Validation: Support for nested objects and arrays + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx new file mode 100644 index 0000000..527106c --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx @@ -0,0 +1,46 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P } from '../index.js'; +import Code from '../Code.js'; + +const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +import fs from 'fs/promises'; +import path from 'path'; + +interface ZodConfig { + output: string; + generateTypes?: boolean; + includeEnums?: boolean; + customValidators?: Record; + errorMessages?: Record; + strictMode?: boolean; + exportStyle?: 'named' | 'default' | 'namespace'; +} + +export default async function generateZodSchemas( + props: PluginProps<{ config: ZodConfig }> +) { + const { config, schema, transformer } = props; + + // Implementation here... +}`; + +export default function PluginStructure() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('3. Plugin Structure')}

    +

    + + The plugin structure defines the core architecture and configuration + interface for the Zod validation schema generator. This includes + the main plugin function, configuration types, and the overall + organization of the generated validation code. + +

    + + {pluginStructureExample} + +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx new file mode 100644 index 0000000..35e7673 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx @@ -0,0 +1,44 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, P, C } from '../index.js'; + +export default function Prerequisites() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('2. Prerequisites')}

    +

    + + Before implementing the Zod validation schema generator plugin, + ensure you have the necessary development environment and knowledge. + This section covers the essential requirements for successful plugin + creation and Zod integration. + +

    +
      +
    • + Node.js 16+ and npm/yarn +
    • +
    • + TypeScript 4.0+ +
    • +
    • + Zod 3.0+ +
    • +
    • + Basic understanding of validation concepts +
    • +
    • + + Familiarity with the @stackpress/idea-transformer library + +
    • +
    • + + Understanding of .idea schema format + +
    • +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx new file mode 100644 index 0000000..ab5ae47 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx @@ -0,0 +1,121 @@ +import { useLanguage, Translate } from 'r22n'; +import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; +import { H2, H3, P, C } from '../index.js'; +import Code from '../Code.js'; + +const basicConfiguration = `plugin "./plugins/zod-validation.js" { + output "./generated/validation.ts" + generateTypes true + includeEnums true + strictMode true + exportStyle "named" + customValidators { + Email "z.string().email()" + Password "z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/)" + PhoneNumber "z.string().regex(/^\\+?[1-9]\\d{1,14}$/)" + } + errorMessages { + email "Please enter a valid email address" + password "Password must be at least 8 characters with uppercase, lowercase, and number" + required "This field is required" + } +}`; + + + +const configurationOptions = [ + { + option: 'output', + type: 'string', + description: 'Output file path for validation schemas', + default: 'Required' + }, + { + option: 'generateTypes', + type: 'boolean', + description: 'Generate TypeScript types from schemas', + default: 'true' + }, + { + option: 'includeEnums', + type: 'boolean', + description: 'Generate enum validation schemas', + default: 'true' + }, + { + option: 'customValidators', + type: 'object', + description: 'Custom Zod validators for specific types', + default: '{}' + }, + { + option: 'errorMessages', + type: 'object', + description: 'Custom error messages for validation', + default: '{}' + }, + { + option: 'strictMode', + type: 'boolean', + description: 'Use strict object validation', + default: 'false' + }, + { + option: 'exportStyle', + type: '\'named\'|\'default\'|\'namespace\'', + description: 'Export style for schemas', + default: '\'named\'' + } +]; + +export default function SchemaConfiguration() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('5. Schema Configuration')}

    +

    + + Schema configuration demonstrates how to integrate the Zod validation + generator into your .idea schema files. This section covers plugin + configuration options and their effects on the generated validation schemas. + +

    + +

    + + Add the Zod validation plugin to your .idea schema file: + +

    + + {basicConfiguration} + + +

    {_('Configuration Options')}

    +

    + + Configuration options control how Zod validation schemas are generated, + including output formatting, validation strictness, and feature enablement. + Understanding these options helps you customize the plugin to meet your + specific validation requirements. + +

    + + + Option + Type + Description + Default + + {configurationOptions.map(config => ( + + {config.option} + {config.type} + {_(config.description)} + {config.default} + + ))} +
    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx new file mode 100644 index 0000000..65ccb6d --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx @@ -0,0 +1,175 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const circularDependenciesExample = `// Handle circular references with lazy evaluation +const UserSchema: z.ZodSchema = z.lazy(() => z.object({ + id: z.string(), + posts: z.array(PostSchema), +})); + +const PostSchema: z.ZodSchema = z.lazy(() => z.object({ + id: z.string(), + author: UserSchema, +}));`; + +const complexValidationExample = `// Use refinements for complex validation +const PasswordSchema = z.string() + .min(8, "Password must be at least 8 characters") + .refine((password) => /[A-Z]/.test(password), { + message: "Password must contain at least one uppercase letter", + }) + .refine((password) => /[a-z]/.test(password), { + message: "Password must contain at least one lowercase letter", + }) + .refine((password) => /\\d/.test(password), { + message: "Password must contain at least one number", + });`; + +const performanceOptimizationExample = `// Use preprocess for expensive operations +const OptimizedSchema = z.preprocess( + (data) => { + // Expensive preprocessing + return normalizeData(data); + }, + z.object({ + // Schema definition + }) +);`; + +const schemaTestingExample = `// Test schemas with various inputs +describe('UserSchema', () => { + it('should validate valid user data', () => { + const validData = { + email: 'test@example.com', + name: 'Test User', + age: 25 + }; + + expect(() => UserSchema.parse(validData)).not.toThrow(); + }); + + it('should reject invalid email', () => { + const invalidData = { + email: 'invalid-email', + name: 'Test User', + age: 25 + }; + + expect(() => UserSchema.parse(invalidData)).toThrow(); + }); +});`; + +const errorCustomizationExample = `// Customize error messages for better UX +const UserSchema = z.object({ + email: z.string().email("Please enter a valid email address"), + age: z.number().min(18, "You must be at least 18 years old"), +});`; + +export default function Troubleshooting() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('9. Troubleshooting')}

    +

    + + This section addresses common issues encountered when generating Zod + validation schemas and provides solutions for debugging and resolving + problems. Understanding these troubleshooting techniques helps ensure + reliable validation schema generation. + +

    + +

    {_('9.1. Common Issues')}

    +

    + + Common issues include circular dependencies, complex validation rules, + and performance problems with large schemas. These problems typically + arise from schema complexity or validation requirements that need + specialized handling. + +

    + +

    {_('9.1.1. Circular Dependencies')}

    +

    + + Circular dependencies occur when schemas reference each other in a way + that creates infinite loops. Zod provides lazy evaluation to handle + these scenarios while maintaining type safety and validation integrity. + +

    + + {circularDependenciesExample} + + +

    {_('9.1.2. Complex Validation Rules')}

    +

    + + Complex validation rules require sophisticated logic that goes beyond + simple type checking. Use Zod's refinement capabilities to implement + business rules and cross-field validation while maintaining clear + error messages. + +

    + + {complexValidationExample} + + +

    {_('9.1.3. Performance Issues')}

    +

    + + Performance issues can arise when validation schemas are complex or + when processing large amounts of data. Optimize validation performance + using preprocessing, caching, and efficient schema design patterns. + +

    + + {performanceOptimizationExample} + + +

    {_('9.2. Debugging Tips')}

    +

    + + Debugging tips help identify and resolve issues during Zod schema + generation and usage. These techniques provide visibility into + validation behavior and help diagnose problems with schema logic + or performance. + +

    + +

    {_('9.2.1. Schema Testing')}

    +

    + + Schema testing ensures that your validation logic works correctly + across different input scenarios. Comprehensive testing helps catch + edge cases and ensures validation behaves as expected in production. + +

    + + {schemaTestingExample} + + +

    {_('9.2.2. Error Message Customization')}

    +

    + + Error message customization improves user experience by providing + clear, actionable feedback when validation fails. Well-crafted error + messages help users understand what went wrong and how to fix it. + +

    + + {errorCustomizationExample} + + +

    + + This tutorial provides a comprehensive foundation for creating + Zod validation schemas from .idea files. The generated schemas + provide runtime type checking and validation with excellent + TypeScript integration. + +

    +
    + ); +} \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx new file mode 100644 index 0000000..e6c5902 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx @@ -0,0 +1,173 @@ +import { useLanguage, Translate } from 'r22n'; +import { H2, H3, P } from '../index.js'; +import Code from '../Code.js'; + +const basicSchemaExample = `enum UserRole { + ADMIN "admin" + USER "user" + GUEST "guest" +} + +model User { + id String @id @default("nanoid()") + email String @email @required + name String @min(2) @max(50) @required + age Number @min(18) @max(120) + role UserRole @default("USER") + active Boolean @default(true) + createdAt Date @default("now()") +} + +plugin "./plugins/zod-validation.js" { + output "./validation.ts" + generateTypes true + strictMode true +}`; + +const generatedValidationUsage = `import { + UserSchema, + CreateUserSchema, + UpdateUserSchema, + UserRole +} from './validation'; + +// Validate complete user object +const validateUser = (data: unknown) => { + try { + const user = UserSchema.parse(data); + console.log('Valid user:', user); + return { success: true, data: user }; + } catch (error) { + console.error('Validation failed:', error.errors); + return { success: false, errors: error.errors }; + } +}; + +// Validate user creation data +const validateCreateUser = (data: unknown) => { + const result = CreateUserSchema.safeParse(data); + + if (result.success) { + console.log('Valid create data:', result.data); + return result.data; + } else { + console.error('Validation errors:', result.error.errors); + throw new Error('Invalid user data'); + } +}; + +// Validate user update data +const validateUpdateUser = (data: unknown) => { + return UpdateUserSchema.parse(data); +}; + +// Example usage +const userData = { + email: 'john@example.com', + name: 'John Doe', + age: 30, + role: 'user' as UserRole +}; + +const validUser = validateCreateUser(userData);`; + +const formValidationExample = `import { CreateUserSchema } from './validation'; + +// React form validation +function UserForm() { + const [errors, setErrors] = useState>({}); + + const handleSubmit = (formData: FormData) => { + const data = Object.fromEntries(formData); + + const result = CreateUserSchema.safeParse(data); + + if (!result.success) { + const fieldErrors: Record = {}; + + result.error.errors.forEach((error) => { + const field = error.path[0] as string; + fieldErrors[field] = error.message; + }); + + setErrors(fieldErrors); + return; + } + + // Submit valid data + submitUser(result.data); + }; + + return ( +
    + + {errors.email && {errors.email}} + + + {errors.name && {errors.name}} + + + {errors.age && {errors.age}} + + +
    + ); +}`; + +export default function UsageExamples() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('6. Usage Examples')}

    +

    + + Usage examples demonstrate practical applications of the Zod + validation generator with real-world scenarios. These examples + show how to configure the plugin for different use cases and + how the generated validation schemas integrate into development + workflows. + +

    + +

    {_('6.1. Basic Schema')}

    +

    + + A basic schema example shows the fundamental structure needed + to generate Zod validation schemas. This includes model + definitions with proper validation attributes and plugin + configuration that produces comprehensive validation rules. + +

    + + {basicSchemaExample} + + +

    {_('6.2. Generated Validation Usage')}

    +

    + + The generated validation usage demonstrates how to use the Zod + schemas produced by the plugin in real applications. This shows + practical patterns for data validation, error handling, and + type safety in TypeScript applications. + +

    + + {generatedValidationUsage} + + +

    {_('6.3. Form Validation Example')}

    +

    + + Zod schemas with frontend frameworks for user input validation. + This demonstrates real-world usage patterns for form handling + and user feedback. + +

    + + {formValidationExample} + +
    + ); +}; + diff --git a/packages/www/plugins/docs/components/validation-plugin/index.tsx b/packages/www/plugins/docs/components/validation-plugin/index.tsx new file mode 100644 index 0000000..890be10 --- /dev/null +++ b/packages/www/plugins/docs/components/validation-plugin/index.tsx @@ -0,0 +1,10 @@ +export { default as Introduction } from './Introduction.js'; +export { default as Overview } from './Overview.js'; +export { default as Prerequisites } from './Prerequisites.js'; +export { default as PluginStructure } from './PluginStructure.js'; +export { default as Implementation } from './Implementation.js'; +export { default as SchemaConfiguration } from './SchemaConfiguration.js'; +export { default as UsageExamples } from './UsageExamples.js'; +export { default as AdvancedFeatures } from './AdvancedFeatures.js'; +export { default as BestPractices } from './BestPractices.js'; +export { default as Troubleshooting } from './Troubleshooting.js'; \ No newline at end of file diff --git a/packages/www/plugins/docs/plugin.ts b/packages/www/plugins/docs/plugin.ts index 06d1ba8..79f6614 100644 --- a/packages/www/plugins/docs/plugin.ts +++ b/packages/www/plugins/docs/plugin.ts @@ -59,11 +59,11 @@ export default function plugin(server: Server) { 'parser/api-reference', 'parser/examples', 'parser/best-practices', - 'parser/pages/compiler', - 'parser/pages/lexer', - 'parser/pages/ast', - 'parser/pages/tokens', - 'parser/pages/exception-handling', + 'parser/api-references/compiler', + 'parser/api-references/lexer', + 'parser/api-references/ast', + 'parser/api-references/tokens', + 'parser/api-references/exception-handling', //transformers 'transformers/introduction', 'transformers/api-reference', @@ -73,8 +73,8 @@ export default function plugin(server: Server) { 'transformers/examples', 'transformers/error-handling', 'transformers/best-practices', - 'transformers/pages/transformer', - 'transformers/pages/terminal', + 'transformers/api-references/transformer', + 'transformers/api-references/terminal', //plugins 'plugin-development/plugin-development-guide', 'plugin-development/plugin-examples', diff --git a/packages/www/plugins/docs/styles/styles.css b/packages/www/plugins/docs/styles/styles.css new file mode 100644 index 0000000..84da1e6 --- /dev/null +++ b/packages/www/plugins/docs/styles/styles.css @@ -0,0 +1,3 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); + +* { font-family: 'Poppins', sans-serif; } \ No newline at end of file diff --git a/packages/www/plugins/docs/views/getting-started.tsx b/packages/www/plugins/docs/views/getting-started.tsx index c94243a..0293518 100644 --- a/packages/www/plugins/docs/views/getting-started.tsx +++ b/packages/www/plugins/docs/views/getting-started.tsx @@ -4,12 +4,29 @@ import type { ServerPageProps } from 'stackpress/view/client'; import { useState } from 'react'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, H2, P, C, Nav } from '../components/index.js'; import Code from '../components/Code.js'; import Layout from '../components/Layout.js'; +const npmInstallCommand = 'npm i -D @stackpress/idea'; + +const yarnInstallCommand = 'yarn add --dev @stackpress/idea'; + +const schemaExample = `model User { + id String @id @default("nanoid()") + name String @required + email String @unique @required + created Date @default("now()") +} + +plugin "./plugins/typescript-generator.js" { + output "./generated/types.ts" +}`; + +const generateCommand = 'npx idea transform --input schema.idea'; + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -17,9 +34,7 @@ export function Head(props: ServerPageProps) { const { _ } = useLanguage(); //variables const title = _('Getting Started'); - const description = _( - 'describe' - ); + const description = _('describe'); return ( <> {title} @@ -39,74 +54,110 @@ export function Head(props: ServerPageProps) { ))} - ) + ); } export function Body() { const [install, setInstall] = useState('npm'); + const { _ } = useLanguage(); + return (
    -

    Getting Started

    -

    - The following is a guide to get you started with Idea. -

    +
    +

    {_('Getting Started')}

    +

    + + The following is a guide to get you started with Idea. + +

    +
    -

    Installation

    - -
    -
    -
    setInstall('npm')} - > - +
    +

    {_('Installation')}

    +
    +
    +
    setInstall('npm')} + > + +
    +
    setInstall('yarn')} + > + +
    -
    setInstall('yarn')} + - -
    + {npmInstallCommand} + + + {yarnInstallCommand} +
    - { - ' npm i -D @stackpress/idea' - } - { - 'yarn add --dev @stackpress/idea' - } -
    - -

    Create your first schema

    -

    Create a new file called schema.idea

    - - - {`model User { - id String @id @default("nanoid()") - name String @required - email String @unique @required - created Date @default("now()") -} - -plugin "./plugins/typescript-generator.js" { - output "./generated/types.ts" -} +
    -`} - +
    +

    {_('Create your first schema')}

    +

    + + Create a new file called schema.idea + +

    + + {schemaExample} + +
    -

    Generate Code

    - - {`npx idea transform --input schema.idea - `} - +
    +

    {_('Generate Code')}

    + + {generateCommand} + +
    -

    Explore the Results

    -

    Check the generated files in your output directories!

    +
    +

    {_('Explore the Results')}

    +

    + + Check the generated files in your output directories! + +

    +
    -
    ); } @@ -123,4 +174,4 @@ export default function Page(props: ServerPageProps) { ); -} +} \ No newline at end of file diff --git a/packages/www/plugins/docs/views/index.tsx b/packages/www/plugins/docs/views/index.tsx index a336236..873fc3c 100644 --- a/packages/www/plugins/docs/views/index.tsx +++ b/packages/www/plugins/docs/views/index.tsx @@ -3,12 +3,63 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'r22n'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, P, Nav, SS } from '../components/index.js'; +import { H1, H2, P, Nav } from '../components/index.js'; import Layout from '../components/Layout.js'; import Code from '../components/Code.js'; +const schemaExample = ` +// schema.idea +enum UserRole { + ADMIN "Administrator" + CUSTOMER "Customer" +} + +model User { + id String @id @default("nanoid()") + email String @unique @required + name String @required + role UserRole @default("CUSTOMER") + orders Order[] @relation(Order.userId) +} + +model Product { + id String @id @default("nanoid()") + name String @required + price Number @required + inStock Boolean @default(true) +} + +model Order { + id String @id @default("nanoid()") + userId String @relation(User.id) + total Number @required + status String @default("PENDING") +} + +// Generate everything with plugins +plugin "./plugins/typescript-generator.js" { + output "./src/types/schema.ts" +} + +plugin "./plugins/database-generator.js" { + output "./database/schema.sql" + dialect "postgresql" +} + +plugin "./plugins/react-forms.js" { + output "./src/components/forms/" + framework "react" + styling "tailwind" +} + +plugin "./plugins/api-generator.js" { + output "./src/api/" + framework "express" + includeValidation true +}` + export function DocumentationHead(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -18,7 +69,9 @@ export function DocumentationHead(props: ServerPageProps) { const url = request.url?.pathname || '/docs'; const title = _('What is .idea?'); const description = _( - 'The .idea file format is a declarative schema definition language designed to simplify application development by providing a single source of truth for data structures, relationships, and code generation.' + 'The .idea file format is a declarative schema definition language' + + 'designed to simplify application development by providing a single' + + 'source of truth for data structures, relationships, and code generation.' ); return ( <> @@ -43,167 +96,170 @@ export function DocumentationHead(props: ServerPageProps) { } export function DocumentationBody() { + const { _ } = useLanguage(); + return (
    -

    What is .idea?

    +

    {_('What is .idea?')}

    - The .idea file format is a declarative schema definition language designed to simplify application development by providing a single source of truth for data structures, relationships, and code generation. It enables developers to define their application's data model once and generate multiple outputs including database schemas, TypeScript interfaces, API documentation, forms, and more. + + The .idea file format is a declarative schema definition + language designed to simplify application development by + providing a single source of truth for data structures, + relationships, and code generation. It enables developers + to define their application's data model once and generate + multiple outputs including database schemas, TypeScript + interfaces, API documentation, forms, and more. +

    - Think of it as the bridge between AI prompting and full-stack code generation - where a simple schema definition can automatically generate everything from database tables to React components, API endpoints to documentation sites. + + Think of it as the bridge between AI prompting and full- + stack code generation - where a simple schema definition can + automatically generate everything from database tables to + React components, API endpoints to documentation sites. +

    -

    Why Use .idea?

    -
      -
    • Single Source of Truth
    • -
    • Type Safety Everywhere
    • -
    • Rapid Development
    • -
    • Perfect Consistency
    • -
    • Infinite Extensibility
    • -
    • AI-to-Code Bridge
    • +

      {_('Why Use .idea?')}

      + +
        +
      • +

        {_('Single Source of Truth')}

        + + Define your data model once, use it everywhere. No more + maintaining separate schemas for database, frontend, and + API. + +
      • +
      • +

        Type Safety Everywhere

        + + Generate type-safe code across languages - TypeScript, + Python, Rust, Go, and more. Catch errors at compile time. + +
      • +
      • +

        Rapid Development

        + + Generate boilerplate code, forms, and documentation in + seconds. What used to take hours now happens instantly. + +
      -

      - Single Source of Truth
      - Define your data model once, use it everywhere. No more maintaining separate schemas for database, frontend, and API. -

      - -

      - Type Safety Everywhere
      - Generate type-safe code across languages - TypeScript, Python, Rust, Go, and more. Catch errors at compile time. -

      - -

      - Rapid Development
      - Generate boilerplate code, forms, and documentation in seconds. What used to take hours now happens instantly. -

      - -

      Who Should Use This?

      - -

      - Junior Developers
      - Easy syntax, rapid prototyping, learn best practices through generated code. -

      -

      - Senior Developers
      - Powerful features, extensible plugins, maintain consistency across large codebases. -

      - -

      - CTOs & Technical Leaders
      - Reduce development time by 60-80%, improve consistency, accelerate time-to-market. -

      - -

      The Plugin Ecosystem

      -

      - The power of .idea comes from its plugin system. Generate code for any technology: -

      +

      {_('Who Should Use This?')}

      + +
        +
      • +

        {_('Junior Developers')}

        + + Easy syntax, rapid prototyping, learn best practices through + generated code. + +
      • +
      • +

        {_('Senior Developers')}

        + + Powerful features, extensible plugins, maintain consistency + across large codebases. + +
      • +
      • +

        {_('CTOs & Technical Leaders')}

        + + Reduce development time by 60-80%, improve consistency, + accelerate time-to-market. + +
      • +
      -

      - Languages
      - TypeScript, Python, Rust, Go, Java, C#, PHP, and more. -

      +

      {_('The Plugin Ecosystem')}

      - Frameworks
      - React, Vue, Angular, Next.js, Express, FastAPI, Django, and more. + + The power of .idea comes from its plugin system. Generate code + for any technology: +

      -

      - Databases
      - PostgreSQL, MySQL, MongoDB, Neo4j, and more. -

      +
        +
      • +

        {_('Languages')}

        + + TypeScript, Python, Rust, Go, Java, C#, PHP, and more. + +
      • +
      • +

        {_('Frameworks')}

        + + React, Vue, Angular, Next.js, Express, FastAPI, Django, and + more. + +
      • +
      • +

        {_('Databases')}

        + + PostgreSQL, MySQL, MongoDB, Neo4j, and more. + +
      • +
      -

      Real-World Example

      +

      {_('Real-World Example')}

      - Here's how a simple e-commerce schema becomes a full application: + + Here's how a simple e-commerce schema becomes a full + application: +

      - - {`// schema.idea -enum UserRole { - ADMIN "Administrator" - CUSTOMER "Customer" -} - -model User { - id String @id @default("nanoid()") - email String @unique @required - name String @required - role UserRole @default("CUSTOMER") - orders Order[] @relation(Order.userId) -} - -model Product { - id String @id @default("nanoid()") - name String @required - price Number @required - inStock Boolean @default(true) -} - -model Order { - id String @id @default("nanoid()") - userId String @relation(User.id) - total Number @required - status String @default("PENDING") -} - -// Generate everything with plugins -plugin "./plugins/typescript-generator.js" { - output "./src/types/schema.ts" -} - -plugin "./plugins/database-generator.js" { - output "./database/schema.sql" - dialect "postgresql" -} - -plugin "./plugins/react-forms.js" { - output "./src/components/forms/" - framework "react" - styling "tailwind" -} - -plugin "./plugins/api-generator.js" { - output "./src/api/" - framework "express" - includeValidation true -}`} + + {schemaExample}

      - From this single schema, generate: + + From this single schema, generate: +

      +
        -
      • ✅ TypeScript interfaces
      • -
      • ✅ PostgreSQL schema
      • -
      • ✅ React components
      • -
      • ✅ API documentation
      • -
      • ✅ Validation schemas
      • -
      • ✅ Test data
      • +
      • ✅ {_('TypeScript interfaces')}
      • +
      • ✅ {_('PostgreSQL schema')}
      • +
      • ✅ {_('React components')}
      • +
      • ✅ {_('API documentation')}
      • +
      • ✅ {_('Validation schemas')}
      • +
      • ✅ {_('Test data')}
      -

      AI-Powered Workflow

      +

      {_('AI-Powered Workflow')}

      - The perfect workflow for AI-driven development: + + The perfect workflow for AI-driven development: +

      -
        -
      1. 1. Describe your app to an AI
      2. -
      3. 2. Get a .idea schema
      4. -
      5. 3. Configure plugins
      6. -
      7. 4. Generate full-stack code
      8. -
      9. 5. Iterate and improve
      10. +
          +
        1. {_('Describe your app to an AI')}
        2. +
        3. {_('Get a .idea schema')}
        4. +
        5. {_('Configure plugins')}
        6. +
        7. {_('Generate full-stack code')}
        8. +
        9. {_('Iterate and improve')}

        - Go from idea to working application in minutes, not days. + + Go from idea to working application in minutes, not days. +

        -
    ); } diff --git a/packages/www/plugins/docs/views/parser/api-reference.tsx b/packages/www/plugins/docs/views/parser/api-reference.tsx index 80d1c01..886e843 100644 --- a/packages/www/plugins/docs/views/parser/api-reference.tsx +++ b/packages/www/plugins/docs/views/parser/api-reference.tsx @@ -3,13 +3,47 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useState } from 'react'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, P, C, Nav, SS, A } from '../../components/index.js'; +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; +const parseExample = `import { parse } from '@stackpress/idea-parser'; + +const result = parse(\` +prop Text { type "text" } +model User { + name String @field.input(Text) +} +\`); + +console.log(result); +// Output includes prop references: { prop: { Text: { type: "text" } }, ... }`; + +const finalExample = `import { final } from '@stackpress/idea-parser'; + +const result = final(\` +prop Text { type "text" } +model User { + name String @field.input(Text) +} +\`); + +console.log(result); +// Output has resolved references: { model: { User: { ... } } } +// No 'prop' section in output`; + +const exceptionExample = `import { Exception } from '@stackpress/idea-parser'; + +try { + const result = parse(invalidCode); +} catch (error) { + if (error instanceof Exception) { + console.log('Parsing error:', error.message); + } +}`; + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -18,7 +52,9 @@ export function Head(props: ServerPageProps) { //variables const title = _('API Reference'); const description = _( - 'API Reference for the parser library' + 'Complete API reference for the Idea Parser library, ' + + 'including detailed documentation for all classes, ' + + 'methods, and interfaces.' ); return ( <> @@ -33,9 +69,18 @@ export function Head(props: ServerPageProps) { - + {styles.map((href, index) => ( - + ))} ) @@ -43,121 +88,179 @@ export function Head(props: ServerPageProps) { export function Right() { const { _ } = useLanguage(); + return ( - + + ); } -const exampleCode = [ - `import { parse } from '@stackpress/idea-parser'; +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('API Reference')}

    + +
    +

    {_('Main Functions')}

    +

    parse(code: string)

    + + Converts schema code into a JSON representation with + references preserved. + + {_('Parameters:')}: +
  • + code (string): {_('The schema code to parse')} +
  • -const result = parse(\` -prop Text { type "text" } -model User { - name String @field.input(Text) -} -\`); + {_('Returns:')}: +
  • + SchemaConfig: {_('JSON object representing the ' + + 'parse schema')} +
  • -console.log(result); -// Output includes prop references: { prop: { Text: { type: "text" } }, ... }`, - `import { final } from '@stackpress/idea-parser'; +

    {_('Example:')}

    + + {parseExample} + -const result = final(\` -prop Text { type "text" } -model User { - name String @field.input(Text) -} -\`); +

    final(code: string)

    + + Converts schema code into a clean JSON representation with + references resolved and removed. + -console.log(result); -// Output has resolved references: { model: { User: { ... } } } -// No 'prop' section in output`, -`import { Exception } from '@stackpress/idea-parser'; + {_('Parameters')} +
  • + code (string): {_('The schema code to parse')} +
  • -try { - const result = parse(invalidCode); -} catch (error) { - if (error instanceof Exception) { - console.log('Parsing error:', error.message); - } -}` -] + {_('Returns:')}: +
  • + FinalSchemaConfig: {_('Clean JSON object without ' + + 'prop/use references')} +
  • -export function Body() { - return ( -
    -

    API Reference

    -

    Main Functions

    -

    parse(code: string)

    -

    Converts schema code into a JSON representation with references preserved.

    - Parameters: -
  • code (string): The schema code to parse
  • - - Returns: -
  • SchemaConfig: JSON object representing the parse schema
  • - -

    Example:

    - - {exampleCode[0]} - - -

    final(code: string)

    -

    - Converts schema code into a clean JSON representation with references resolved and removed. -

    - - Parameters -
  • code (string): The schema code to parse
  • - - Returns: -
  • FinalSchemaConfig: Clean JSON object without prop/use references
  • - - Example: - - {exampleCode[1]} - - -

    Core Classes

    -
      -
    • Compiler: Static methods for converting AST tokens to JSON
    • -
    • Lexer: Tokenization and parsing utilities
    • -
    • SchemaTree: Main parser for complete schema files
    • -
    • Syntax Trees: Individual parsers for different schema elements
    • -
    • Tokens: AST token structures and type definitions
    • -
    - -

    Exception Handling

    -

    The library uses a custom Exception class that extends the standard Exception class for better error reporting.

    - - {exampleCode[2]} - - -
    + +
    +

    {_('Core Classes')}

    +
      +
    • + + Compiler: + {_('Static methods for converting AST tokens to JSON')} +
    • +
    • + + Lexer: + {_('Tokenization and parsing utilities')} +
    • +
    • + SchemaTree: + {_('Main parser for complete schema files')} +
    • +
    • + + Syntax Trees: + {_('Individual parsers for different schema elements')} +
    • +
    • + + Tokens: + {_('AST token structures and type definitions')} +
    • +
    +
    + +
    +

    {_('Exception Handling')}

    + + The library uses a custom Exception class that extends the + standard Exception class for better error reporting. + + + {exceptionExample} + +
    + +
    +
    ); } diff --git a/packages/www/plugins/docs/views/parser/best-practices.tsx b/packages/www/plugins/docs/views/parser/best-practices.tsx index d6c4b71..ee6b080 100644 --- a/packages/www/plugins/docs/views/parser/best-practices.tsx +++ b/packages/www/plugins/docs/views/parser/best-practices.tsx @@ -3,52 +3,18 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Best Practices'); - const description = _( - 'Best practices for using the parser library effectively' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - -const typeSafetyExamples = [ - `import type { SchemaConfig, ModelConfig } from '@stackpress/idea-parser'; +const typeSafetyExample = `import type { SchemaConfig, ModelConfig } from '@stackpress/idea-parser'; const schema: SchemaConfig = parse(code); -` -]; +`; -const errorHandlingExamples = [ - `import { parse, Exception } from '@stackpress/idea-parser'; +const errorHandlingExample = `import { parse, Exception } from '@stackpress/idea-parser'; try { const result = parse(schemaCode); @@ -61,11 +27,9 @@ try { console.error('Unexpected error:', error); // Handle other errors } -}` -]; +}`; -const schemaStructureExamples = [ - `// Good: Proper model structure +const schemaStructureExample = `// Good: Proper model structure model User { id String @id name String @@ -74,104 +38,228 @@ model User { // Bad: Missing required properties model User { // Missing columns - will throw error -}` -]; +}`; -const namingExamples = [ - `// Good +const namingExample = `// Good enum UserStatus { ACTIVE "Active" SUSPENDED "Suspended" } prop EmailInput { type "email" format "email" } // Less clear enum Status { A "Active" S "Suspended" } -prop Input { type "email" }` -]; +prop Input { type "email" }`; -const errorSolutionsExamples = [ - `Error: "Invalid Schema"`, - `Error: "Expecting a columns property"`, - `Error: "Duplicate [name]"`, - `Error: "Unknown reference [name]"` -]; +const errorExamples = { + invalidSchema: 'Error: "Invalid Schema"', + missingColumns: 'Error: "Expecting a columns property"', + duplicateName: 'Error: "Duplicate [name]"', + unknownReference: 'Error: "Unknown reference [name]"' +}; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Best practices and guidelines for using the Idea Parser ' + + 'library effectively, including error handling, type safety, ' + + 'and common pitfalls to avoid.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} export function Body() { + const { _ } = useLanguage(); + return (
    -

    Best Practices

    +

    {_('Best Practices')}

    - Follow these best practices to use the parser library effectively and avoid common pitfalls. + + Follow these best practices to use the parser library + effectively and avoid common pitfalls. +

    -

    1. Use Type Safety

    -

    - The library is built with TypeScript and provides comprehensive type definitions: -

    - - {typeSafetyExamples[0]} - -

    2. Handle Errors Gracefully

    -

    - Always wrap parsing operations in try-catch blocks: -

    - - {errorHandlingExamples[0]} - +
    +

    {_('1. Use Type Safety')}

    +

    + + The library is built with TypeScript and provides + comprehensive type definitions + +

    + + {typeSafetyExample} + +
    -

    3. Choose the Right Function

    -
  • Use parse() when you need to preserve references for further processing
  • -
  • Use final() when you want a clean output for final consumption
  • +
    +

    {_('2. Handle Errors Gracefully')}

    +

    + + Always wrap parsing operations in try-catch blocks + +

    + + {errorHandlingExample} + +
    -

    4. Validate Schema Structure

    -

    - Ensure your schema follows the expected structure: -

    - - {schemaStructureExamples[0]} - +
    +

    {_('3. Choose the Right Function')}

    +
  • + Use parse() + + when you need to preserve references for further processing + +
  • +
  • + Use final() + + when you want a clean output for final consumption + +
  • +
    -

    5. Use Meaningful Names

    -

    - Choose descriptive names for your schema elements: -

    - - {namingExamples[0]} - +
    +

    {_('4. Validate Schema Structure')}

    +

    + + Ensure your schema follows the expected structure: + +

    + + {schemaStructureExample} + +
    -

    Error Handling

    -

    - Common errors and their solutions: -

    +
    +

    {_('5. Use Meaningful Names')}

    +

    + + Choose descriptive names for your schema elements: + +

    + + {namingExample} + +
    -

    Invalid Schema Structure

    - - {errorSolutionsExamples[0]} - -
  • Solution: Ensure your schema follows the correct syntax and structure.
  • - -

    Missing Required Properties

    - - {errorSolutionsExamples[1]} - -
  • Solution: Models and types must have a columns definition.
  • - -

    Duplicate Declarations

    - - {errorSolutionsExamples[2]} - -
  • Solution: Each declaration name must be unique within the schema.
  • - -

    Unknown References

    - - {errorSolutionsExamples[3]} - -
  • Solution: Ensure all referenced props and types are defined before use.
  • - -
    ); } diff --git a/packages/www/plugins/docs/views/parser/core-concepts.tsx b/packages/www/plugins/docs/views/parser/core-concepts.tsx index 2d60112..0371d4a 100644 --- a/packages/www/plugins/docs/views/parser/core-concepts.tsx +++ b/packages/www/plugins/docs/views/parser/core-concepts.tsx @@ -3,22 +3,25 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useState } from 'react'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; +const processingFlow = `Raw Schema Code → SchemaTree → Compiler → JSON Output +`; + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; //hooks const { _ } = useLanguage(); //variables - const title = _('Getting Started'); + const title = _('Core Concepts'); const description = _( - 'describe' + 'Learn the core concepts of the Idea Parser library including ' + + 'schema structure, processing flow, and key components.' ); return ( <> @@ -33,51 +36,135 @@ export function Head(props: ServerPageProps) { - + {styles.map((href, index) => ( - + ))} ) } export function Body() { + const { _ } = useLanguage(); + return (
    -

    Core Concepts

    -

    Schema Structure

    -

    An .idea schema file can contain several types of declarations:

    +

    {_('Core Concepts')}

    -
      -
    1. Plugins: External integrations and configurations -
    2. -
    3. Use statements: Import other schema files
    4. -
    5. Props: Reusable property configurations
    6. -
    7. Enums: Enumerated value definitions
    8. -
    9. Types: Custom type definitions with columns
    10. -
    11. Models: Database model definitions
    12. -
    +
    +

    {_('Schema Structure')}

    +

    + + A complete .idea schema file can contain multiple + elements organized in a specific structure: + +

    -

    Processing FLow

    -

    The library follows this processing flow:

    +
      +
    1. + Plugins:{' '} + + External integrations and configurations + +
    2. +
    3. + Use statements:{' '} + + Import other schema files + +
    4. +
    5. + Props:{' '} + + Reusable property configurations + +
    6. +
    7. + Enums:{' '} + + Enumerated value definitions + +
    8. +
    9. + Types:{' '} + + Custom type definitions with columns + +
    10. +
    11. + Models:{' '} + + Database model definitions + +
    12. +
    +
    - - {`Raw Schema Code → SchemaTree → Compiler → JSON Output - `} - +
    +

    {_('Processing Flow')}

    +

    + + The library follows this processing flow: + +

    -
      -
    1. Raw Code: Your .idea schema file content
    2. -
    3. SchemaTree: Parses the entire file into an Abstract Syntax Tree
    4. -
    5. Compiler: Converts AST tokens into structured JSON
    6. -
    7. JSON Output: Final configuration object
    8. -
    + + {processingFlow} + -
    +
    +
    ); } diff --git a/packages/www/plugins/docs/views/parser/examples.tsx b/packages/www/plugins/docs/views/parser/examples.tsx index 023865d..d91cf95 100644 --- a/packages/www/plugins/docs/views/parser/examples.tsx +++ b/packages/www/plugins/docs/views/parser/examples.tsx @@ -3,46 +3,13 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useState } from 'react'; import { useLanguage } from 'stackpress/view/client'; //docs -import { H1, H2, P, C, Nav } from '../../components/index.js'; +import { H1, H2, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Examples'); - const description = _( - 'Examples of how to use the parser library' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - -const completeSchemaExample = [ - `import { final } from '@stackpress/idea-parser'; +const completeSchemaExamples = `import { final } from '@stackpress/idea-parser'; const schemaCode = \` plugin "./database-plugin" { @@ -79,8 +46,9 @@ model User! { \`; const result = final(schemaCode); -console.log(JSON.stringify(result, null, 2));`, -`import { Compiler, EnumTree, ModelTree } from '@stackpress/idea-parser'; +console.log(JSON.stringify(result, null, 2));`; + +const individualComponentsExample = `import { Compiler, EnumTree, ModelTree } from '@stackpress/idea-parser'; // Parse individual enum const enumCode = \`enum Status { ACTIVE "Active" INACTIVE "Inactive" }\`; @@ -90,27 +58,91 @@ const [enumName, enumConfig] = Compiler.enum(enumAST); // Parse individual model const modelCode = \`model User { id String @id name String }\`; const modelAST = ModelTree.parse(modelCode); -const [modelName, modelConfig] = Compiler.model(modelAST);` -] +const [modelName, modelConfig] = Compiler.model(modelAST);`; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Examples'); + const description = _( + 'Practical examples showing how to use the Idea Parser ' + + 'library for parsing schema files and working with ' + + 'individual components.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} export function Body() { + const { _ } = useLanguage(); + return (
    -

    Examples

    -

    Complete Schema Example

    - - {completeSchemaExample[0]} - - -

    Working with Individual Components

    - - {completeSchemaExample[1]} - - -
    ); } diff --git a/packages/www/plugins/docs/views/parser/installation.tsx b/packages/www/plugins/docs/views/parser/installation.tsx index 3c884e9..ba8933e 100644 --- a/packages/www/plugins/docs/views/parser/installation.tsx +++ b/packages/www/plugins/docs/views/parser/installation.tsx @@ -3,13 +3,39 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useState } from 'react'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'stackpress/view/client'; //docs -import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; +import { H1, H2, P, C, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; +const installCommand = `npm install @stackpress/idea-parser +`; + +const usageExample = ` +import { parse, final } from '@stackpress/idea-parser'; + +// Parse a schema file into JSON (includes references) +const schemaCode = \` +prop Text { type "text" } +enum Roles { + ADMIN "Admin" + USER "User" +} +model User { + id String @id + name String @field.input(Text) + role Roles +} +\`; + +// Parse with references intact +const parsedSchema = parse(schemaCode); + +// Parse and clean up references (final version) +const finalSchema = final(schemaCode); +`; + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -18,7 +44,11 @@ export function Head(props: ServerPageProps) { //variables const title = _('Installation'); const description = _( - 'A TypeScript library for parsing .idea schema files into Abstract Syntax Trees (AST) and converting them to readable JSON configurations. This library is designed to help developers work with schema definitions in a structured and type-safe manner.' + 'A TypeScript library for parsing .idea schema files into ' + + 'Abstract Syntax Trees (AST) and converting them to readable ' + + 'JSON configurations. This library is designed to help ' + + 'developers work with schema definitions in a structured and ' + + 'type-safe manner.' ); return ( <> @@ -33,70 +63,99 @@ export function Head(props: ServerPageProps) { - + {styles.map((href, index) => ( - + ))} ) } -const examples = [ - `npm install @stackpress/idea-parser - `, - `import { parse, final } from '@stackpress/idea-parser'; +export function Body() { + const { _ } = useLanguage(); -// Parse a schema file into JSON (includes references) -const schemaCode = \` -prop Text { type "text" } -enum Roles { - ADMIN "Admin" - USER "User" -} -model User { - id String @id - name String @field.input(Text) - role Roles -} -\`; + return ( +
    +
    +

    {_('Idea Parser')}

    + + A TypeScript library for parsing .idea schema files into + Abstract Syntax Trees (AST) and converting them to readable + JSON configurations. This library is designed to help + developers work with schema definitions in a structured and + type-safe manner. + -// Parse with references intact -const parsedSchema = parse(schemaCode); +
    -// Parse and clean up references (final version) -const finalSchema = final(schemaCode);` -] +
    +

    {_('Installation')}

    +

    Install the package using npm:

    + + {installCommand} + +
    -export function Body() { - return ( -
    -

    Idea Parser

    -

    - A TypeScript library for parsing .idea schema files into Abstract Syntax Trees (AST) and converting them to readable JSON configurations. This library is designed to help developers work with schema definitions in a structured and type-safe manner. -

    - -

    Installation

    -

    Install the package using npm:

    - - {examples[0]} - - -

    Quick Start

    -

    The library provides two main functions for parsing schema files:

    - -

    Basic Usage

    - - {examples[1]} - - -
  • Difference between parse and final
  • -
  • parse(code: string): Converts schema code to JSON while preserving prop and use references
  • -
  • final(code: string): Like parse but removes prop and use references for a clean final output
  • - -
    ); } diff --git a/packages/www/plugins/docs/views/parser/pages/ast.tsx b/packages/www/plugins/docs/views/parser/pages/ast.tsx deleted file mode 100644 index 02f6d18..0000000 --- a/packages/www/plugins/docs/views/parser/pages/ast.tsx +++ /dev/null @@ -1,856 +0,0 @@ -//modules -import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, H3, P, C, SS, Nav } from '../../../components/index.js'; - import Code from '../../../components/Code.js'; - import Layout from '../../../components/Layout.js'; - import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Syntax Trees'); - const description = _( - 'The AST classes are responsible for parsing specific parts of schema code into Abstract Syntax Trees (ASTs). Each AST class handles a different type of declaration or construct in the schema language.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } - -const examples = [ - `import { - SchemaTree, - EnumTree, - ModelTree, - TypeTree, - PropTree, - PluginTree, - UseTree -} from '@stackpress/idea-parser';`, - `import { SchemaTree, Lexer } from '@stackpress/idea-parser'; - -const lexer = new Lexer(); -SchemaTree.definitions(lexer); - -// Lexer now has definitions for all schema constructs: -// enum, prop, type, model, plugin, use keywords and structures`, - `import { SchemaTree } from '@stackpress/idea-parser'; - -const schemaCode = \` -plugin "./database" { - provider "postgresql" -} - -enum Status { - ACTIVE "Active" - INACTIVE "Inactive" -} - -prop Text { type "text" } - -model User { - id String @id - name String @field.input(Text) - status Status -} -\`; - -const ast = SchemaTree.parse(schemaCode); -console.log(ast.type); // 'Program' -console.log(ast.kind); // 'schema' -console.log(ast.body.length); // 4 (plugin, enum, prop, model)`, - `import { SchemaTree } from '@stackpress/idea-parser'; - -const tree = new SchemaTree(); -const schemaCode = 'enum Status { ACTIVE "Active" }'; - -const result = tree.parse(schemaCode, 0); -console.log(result.body[0].kind); // 'enum'`, - `import { EnumTree, Lexer } from '@stackpress/idea-parser'; - -const lexer = new Lexer(); -EnumTree.definitions(lexer); - -// Adds 'EnumWord' token definition for 'enum' keyword`, - `import { EnumTree } from '@stackpress/idea-parser'; - -const enumCode = \`enum Roles { - ADMIN "Admin" - MANAGER "Manager" - USER "User" -}\`; - -const ast = EnumTree.parse(enumCode); -console.log(ast.kind); // 'enum' -console.log(ast.declarations[0].id.name); // 'Roles' -console.log(ast.declarations[0].init.properties.length); // 3 -console.log(ast.declarations[0].init.properties[0].key.name); // 'ADMIN' -console.log(ast.declarations[0].init.properties[0].value.value); // 'Admin'`, - `const tree = new EnumTree(); -tree._lexer.load('enum Status { ACTIVE "Active" INACTIVE "Inactive" }'); - -const enumToken = tree.enum(); -console.log(enumToken.declarations[0].id.name); // 'Status' -console.log(enumToken.declarations[0].init.properties[0].key.name); // 'ACTIVE' -console.log(enumToken.declarations[0].init.properties[0].value.value); // 'Active'`, - `// Inside enum parsing, after opening brace -const property = tree.property(); -console.log(property.key.name); // e.g., 'ADMIN' -console.log(property.value.value); // e.g., 'Admin'`, - `import { ModelTree } from '@stackpress/idea-parser'; - -const modelCode = \`model User @label("User" "Users") { - id String @label("ID") @id @default("nanoid(20)") - username String @label("Username") @searchable @field.input(Text) @is.required - password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide - role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) - address Address? @label("Address") @list.hide - age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) - active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno - created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) -}\`; - -const ast = ModelTree.parse(modelCode); -console.log(ast.kind); // 'model' -console.log(ast.mutable); // false (because of '!' modifier) -console.log(ast.declarations[0].id.name); // 'User'`, - `const tree = new ModelTree(); -tree._lexer.load('model User { id String @id }'); - -const modelToken = tree.model(); -console.log(modelToken.kind); // 'model' -console.log(modelToken.mutable); // false (immutable due to '!')`, - `import { TypeTree } from '@stackpress/idea-parser'; - -const typeCode = \`type Address @label("Address" "Addresses") { - street String @field.input @is.required - city String @field.input @is.required - country String @field.select - postal String @field.input -}\`; - -const ast = TypeTree.parse(typeCode); -console.log(ast.kind); // 'type' -console.log(ast.mutable); // true (mutable by default) -console.log(ast.declarations[0].id.name); // 'Address'`, - `const tree = new TypeTree(); -tree._lexer.load('type Address { street String city String }'); - -const typeToken = tree.type(); -console.log(typeToken.kind); // 'type' -console.log(typeToken.mutable); // true (default for types)`, - `// Inside type parsing -const property = tree.property(); -console.log(property.key.name); // e.g., 'street' -console.log(property.value); // Object containing type and attributes`, - `// For parsing generic type parameters -const parameter = tree.parameter(); -console.log(parameter.key.name); // Parameter name -console.log(parameter.value); // Parameter type/constraint`, - `import { PropTree } from '@stackpress/idea-parser'; - -const propCode = \`prop EmailInput { - type "email" - format "email" - placeholder "Enter your email" - required true -}\`; - -const ast = PropTree.parse(propCode); -console.log(ast.kind); // 'prop' -console.log(ast.declarations[0].id.name); // 'EmailInput'`, - `const tree = new PropTree(); -tree._lexer.load('prop Text { type "text" format "lowercase" }'); - -const propToken = tree.prop(); -console.log(propToken.kind); // 'prop' -console.log(propToken.declarations[0].id.name); // 'Text'`, - `import { PluginTree } from '@stackpress/idea-parser'; - -const pluginCode = \`plugin "./database-plugin" { - provider "postgresql" - url env("DATABASE_URL") - previewFeatures ["fullTextSearch"] -}\`; - -const ast = PluginTree.parse(pluginCode); -console.log(ast.kind); // 'plugin' -console.log(ast.declarations[0].id.name); // './database-plugin'`, - `const tree = new PluginTree(); -tree._lexer.load('plugin "./custom" { provider "custom-provider" }'); - -const pluginToken = tree.plugin(); -console.log(pluginToken.kind); // 'plugin' -console.log(pluginToken.declarations[0].id.name); // './custom'`, - `import { UseTree } from '@stackpress/idea-parser'; - -const useCode = 'use "./shared/types.idea"'; - -const ast = UseTree.parse(useCode); -console.log(ast.type); // 'ImportDeclaration' -console.log(ast.source.value); // './shared/types.idea'`, - `const tree = new UseTree(); -tree._lexer.load('use "./another.idea"'); - -const useToken = tree.use(); -console.log(useToken.type); // 'ImportDeclaration' -console.log(useToken.source.value); // './another.idea'`, - `import { EnumTree, ModelTree, TypeTree } from '@stackpress/idea-parser'; - -// Parse individual enum -const enumAST = EnumTree.parse(\`enum Roles { - ADMIN "Admin" - MANAGER "Manager" - USER "User" -}\`); - -// Parse individual model -const modelAST = ModelTree.parse(\`model User { - id String @id - username String @is.required -}\`); - -// Parse individual type -const typeAST = TypeTree.parse(\`type Address { - street String - city String -}\`);`, - `import { EnumTree, Compiler } from '@stackpress/idea-parser'; - -// Parse and compile in one step -const enumAST = EnumTree.parse(\`enum Status { - ACTIVE "Active" - INACTIVE "Inactive" -}\`); -const [enumName, enumConfig] = Compiler.enum(enumAST); - -console.log(enumName); // 'Status' -console.log(enumConfig); // { ACTIVE: 'Active', INACTIVE: 'Inactive' }`, - `import { AbstractTree, Lexer } from '@stackpress/idea-parser'; -import type { DeclarationToken } from '@stackpress/idea-parser'; - -class CustomTree extends AbstractTree { - static definitions(lexer: Lexer) { - super.definitions(lexer); - // Add custom token definitions - lexer.define('CustomKeyword', (code, index) => { - // Custom token reader implementation - }); - return lexer; - } - - static parse(code: string, start = 0) { - return new this().parse(code, start); - } - - parse(code: string, start = 0): DeclarationToken { - this._lexer.load(code, start); - return this.customDeclaration(); - } - - customDeclaration(): DeclarationToken { - // Custom parsing logic - const keyword = this._lexer.expect('CustomKeyword'); - // ... more parsing logic - - return { - type: 'VariableDeclaration', - kind: 'custom', - start: keyword.start, - end: this._lexer.index, - declarations: [/* ... */] - }; - } -}`, - `import { SchemaTree, Exception } from '@stackpress/idea-parser'; - -try { - // Invalid syntax - missing closing brace - SchemaTree.parse('enum Status { ACTIVE "Active"'); -} catch (error) { - if (error instanceof Exception) { - console.log('Parse error:', error.message); - console.log('Position:', error.start, '-', error.end); - } -}`, - `try { - // Invalid - 'enum' keyword expected but found 'model' - EnumTree.parse('model User { id String }'); -} catch (error) { - console.log('Expected enum but found model'); -}`, - `import { EnumTree } from '@stackpress/idea-parser'; - -try { - // Empty string will throw an error - EnumTree.parse(''); -} catch (error) { - console.log('Error:', error.message); // 'Unexpected end of input' -}`, - `import { ModelTree } from '@stackpress/idea-parser'; - -try { - // Invalid - model names must be capitalized - ModelTree.parse('model user { id String }'); -} catch (error) { - console.log('Expected CapitalIdentifier but got something else'); -}`, - `// This is what happens internally: -import { SchemaTree, Compiler } from '@stackpress/idea-parser'; - -export function parse(code: string) { - const ast = SchemaTree.parse(code); // Parse to AST - return Compiler.schema(ast); // Compile to JSON -} - -export function final(code: string) { - const ast = SchemaTree.parse(code); // Parse to AST - return Compiler.final(ast); // Compile and clean up -}`, - `import { Lexer, SchemaTree } from '@stackpress/idea-parser'; - -// Create and configure lexer once -const lexer = new Lexer(); -SchemaTree.definitions(lexer); - -// Reuse for multiple parses -const tree = new SchemaTree(lexer); - -const result1 = tree.parse(code1); -const result2 = tree.parse(code2); -const result3 = tree.parse(code3);`, - `// Inside tree parsing methods -const checkpoint = this._lexer.clone(); - -try { - // Try to parse optional structure - return this.parseOptionalStructure(); -} catch (error) { - // Restore lexer state and continue - this._lexer = checkpoint; - return this.parseAlternativeStructure(); -}`, - `const enumCode = \`enum Roles { - ADMIN "Admin" - MANAGER "Manager" - USER "User" -}\`; - -const ast = EnumTree.parse(enumCode); -// Produces a complete AST with all three enum values`, - `const modelCode = \`model User @label("User" "Users") { - id String @label("ID") @id @default("nanoid(20)") - username String @label("Username") @searchable @field.input(Text) @is.required - password String @label("Password") @field.password @is.clt(80) @is.cgt(8) @is.required @list.hide @view.hide - role Roles @label("Role") @filterable @field.select @list.text(Uppercase) @view.text(Uppercase) - address Address? @label("Address") @list.hide - age Number @label("Age") @unsigned @filterable @sortable @field.number(Age) @is.gt(0) @is.lt(150) - balance Number[] @label("Balance") @filterable @sortable @field.number() @list.number() @view.number - active Boolean @label("Active") @default(true) @filterable @field.switch @list.yesno @view.yesno - created Date @label("Created") @default("now()") @filterable @sortable @list.date(Pretty) - updated Date @label("Updated") @default("updated()") @filterable @sortable @list.date(Pretty) - company Company? @label("My Company") -}\`; - -const ast = ModelTree.parse(modelCode); -// Produces a complete model AST with all columns and attributes` -] - - export function Body() { - return ( -
    -

    Syntax Trees

    -

    The AST classes are responsible for parsing specific parts of schema code into Abstract Syntax Trees (ASTs). Each AST class handles a different type of declaration or construct in the schema language.

    - - {examples[0]} - - -

    SchemaTree

    -

    Parses complete schema files containing multiple declarations.

    - -

    Static Methods

    - -

    Setting Up Schema Definitions

    -

    The following example shows how to configure a lexer for schema parsing.

    - - {examples[1]} - - -

    Parameters

    - - Parameter - Type - Description - - lexer - Lexer - The lexer instance to configure - -
    - - Returns -
  • The configured lexer instance.
  • - -

    Parsing Complete Schemas

    -

    The following example shows how to parse a complete schema file.

    - - {examples[2]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The complete schema code to parse - -
    - - Returns -
  • A SchemaToken representing the entire parsed schema.
  • - -

    Methods

    - -

    Parsing Schema Content

    -

    The following example shows how to parse schema content with custom starting position.

    - - {examples[3]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The schema code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A SchemaToken containing all parsed declarations.
  • - -

    EnumTree

    -

    Parses enum declarations into AST tokens.

    - -

    Static Methods

    - -

    Setting Up Enum Definitions

    -

    The following example shows how to configure a lexer for enum parsing.

    - - {examples[4]} - - -

    Parsing Enum Declarations

    -

    The following example shows how to parse enum declarations based on the test fixtures.

    - - {examples[5]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The enum declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A DeclarationToken representing the parsed enum.
  • - -

    Methods

    - -

    Parsing Enum Structure

    -

    The following example shows how to parse the enum structure.

    - - {examples[6]} - - - Returns -
  • A DeclarationToken representing the enum structure.
  • - -

    Parsing Enum Properties

    -

    The following example shows how individual enum properties are parsed.

    - - {examples[7]} - - - Returns -
  • A PropertyToken representing a single enum key-value pair.
  • - -

    ModelTree

    -

    Parses model declarations (extends TypeTree for shared functionality).

    - -

    Static Methods

    - -

    Parsing Model Declarations

    -

    The following example shows how to parse model declarations based on the test fixtures.

    - - {examples[8]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The model declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A DeclarationToken representing the parsed model.
  • - -

    Methods

    - -

    Parsing Model Structure

    -

    The following example shows how to parse the model structure.

    - - {examples[9]} - - - Returns -
  • A DeclarationToken representing the model structure.
  • - -

    TypeTree

    -

    Parses type declarations.

    - -

    Static Methods

    - -

    Parsing Type Declarations

    -

    The following example shows how to parse type declarations.

    - - {examples[10]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The type declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A DeclarationToken representing the parsed type.
  • - -

    Methods

    - -

    Parsing Type Structure

    -

    The following example shows how to parse the type structure.

    - - {examples[11]} - - - Returns -
  • A DeclarationToken representing the type structure.
  • - -

    Parsing Type Properties

    -

    The following example shows how type properties (columns) are parsed.

    - - {examples[12]} - - - Returns -
  • A PropertyToken representing a type column definition.
  • - -

    Parsing Type Parameters

    -

    The following example shows how type parameters are parsed.

    - - {examples[13]} - - - Returns -
  • A PropertyToken representing a type parameter.
  • - -

    PropTree

    -

    Parses prop (property configuration) declarations.

    - -

    Static Methods

    - -

    Parsing Prop Declarations

    -

    The following example shows how to parse prop declarations.

    - - {examples[14]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The prop declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A DeclarationToken representing the parsed prop.
  • - -

    Methods

    - -

    Parsing Prop Structure

    -

    The following example shows how to parse the prop structure.

    - - {examples[15]} - - - Returns -
  • A DeclarationToken representing the prop configuration.
  • - -

    PluginTree

    -

    Parses plugin declarations.

    - -

    Static Methods

    - -

    Parsing Plugin Declarations

    -

    The following example shows how to parse plugin declarations.

    - - {examples[16]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The plugin declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • A DeclarationToken representing the parsed plugin.
  • - -

    Methods

    - -

    Parsing Plugin Structure

    -

    The following example shows how to parse the plugin structure.

    - - {examples[17]} - - - Returns -
  • A DeclarationToken representing the plugin configuration.
  • - -

    UseTree

    -

    Parses use (import) declarations.

    - -

    Static Methods

    - -

    Parsing Use Declarations

    -

    The following example shows how to parse use declarations.

    - - {examples[18]} - - -

    Parameters

    - - Parameter - Type - Description - - code - string - The use declaration code to parse - - - start - number - Starting position in the code (default: 0) - -
    - - Returns -
  • An ImportToken representing the parsed use statement.
  • - -

    Methods

    - -

    Parsing Use Structure

    -

    The following example shows how to parse the use structure.

    - - {examples[19]} - - - Returns -
  • An ImportToken representing the import statement.
  • - -

    Usage Patterns

    - -

    Parsing Individual Components

    - - {examples[20]} - - -

    Using with Compiler

    - - {examples[21]} - - -

    Custom AST Classes

    -

    You can extend AbstractTree to create custom parsers:

    - - {examples[22]} - - -

    Error Handling

    -

    AST classes provide detailed error information when parsing fails:

    - -

    Syntax Errors

    - - {examples[23]} - - -

    Unexpected Tokens

    - - {examples[24]} - - -

    Empty Input Handling

    - - {examples[25]} - - -

    Invalid Identifiers

    - - {examples[26]} - - -

    Integration with Main Functions

    -

    AST classes are used internally by the main parse and final functions:

    - - {examples[27]} - - -

    Performance Considerations

    - -

    Lexer Reuse

    -

    AST classes can share lexer instances for better performance:

    - - {examples[28]} - - -

    Cloning for Backtracking

    -

    AST classes use lexer cloning for safe parsing attempts:

    - - {examples[29]} - - -

    Test-Driven Examples

    -

    Based on the test fixtures, here are real-world examples:

    - -

    Enum with Multiple Values

    - - {examples[30]} - - -

    Complex Model with Attributes

    - - {examples[31]} - - -

    This demonstrates the parser's ability to handle:

    -
      -
    • Model mutability (! modifier)
    • -
    • Attributes (@label, @id, @default, etc.)
    • -
    • Optional types (Address?, Company?)
    • -
    • Array types (Number[])
    • -
    • Complex attribute parameters (@field.input(Text), @is.clt(80))
    • -
    - -
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } \ No newline at end of file diff --git a/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx b/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx index 0b1a0d8..b5dacab 100644 --- a/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx +++ b/packages/www/plugins/docs/views/plugin-development/advanced-tutorials.tsx @@ -3,9 +3,9 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, H3, P, SS, Nav } from '../../components/index.js'; import Layout from '../../components/Layout.js'; export function Head(props: ServerPageProps) { @@ -16,7 +16,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('Advanced Tutorials'); const description = _( - 'Advanced plugin development topics for developers who need to create sophisticated code generation tools' + 'Advanced plugin development topics for developers who need to ' + + 'create sophisticated code generation tools' ); return ( <> @@ -41,29 +42,48 @@ export function Head(props: ServerPageProps) { export function Right() { const { _ } = useLanguage(); + return (
    {_('Advanced Tutorials')}
    -
    @@ -71,131 +91,346 @@ export function Right() { } export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Advanced Tutorials

    -

    - This section covers advanced plugin development topics for developers who need to create sophisticated code generation tools. These tutorials demonstrate complex patterns and integration techniques for building enterprise-grade plugins. -

    - -

    7.1. API Development Plugins

    - -

    7.1.1. GraphQL Schema Plugin

    -

    - The GraphQL Schema Plugin tutorial teaches you how to create a plugin that generates GraphQL type definitions and schemas from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate GraphQL type definitions from models and types
    • -
    • Create queries, mutations, and subscriptions
    • -
    • Support for custom scalars and directives
    • -
    • Handle relationships and nested types
    • -
    • Generate complete GraphQL schema files
    • -
    - -

    - Generated Output: GraphQL schema files with type definitions, queries, and mutations -

    - -

    7.1.2. TypeScript Interface Plugin

    -

    - The TypeScript Interface Plugin tutorial demonstrates how to create a plugin that generates TypeScript interfaces and types from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate TypeScript interfaces from models and types
    • -
    • Create enums and utility types
    • -
    • Support for namespaces and modules
    • -
    • Handle optional and array types
    • -
    • Generate comprehensive type definitions
    • -
    - -

    - Generated Output: TypeScript definition files with interfaces, types, and enums -

    - -

    7.1.3. API Client Plugin

    -

    - The API Client Plugin tutorial shows how to create a plugin that generates API client libraries from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate REST and GraphQL API clients
    • -
    • Support multiple authentication strategies
    • -
    • Create type-safe client methods
    • -
    • Handle request/response transformations
    • -
    • Generate both JavaScript and TypeScript clients
    • -
    - -

    - Generated Output: Complete API client libraries with methods and types -

    - -

    7.2. Validation and Testing Plugins

    -

    - Validation and testing plugins help ensure data quality and application reliability by generating validation schemas and test data. These plugins are essential for building robust applications that can handle edge cases and maintain data integrity across different environments. -

    - -

    7.2.1. Validation Plugin

    -

    - The Validation Plugin tutorial teaches you how to create a plugin that generates Zod validation schemas from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate Zod schemas from models and types
    • -
    • Create custom validators and transformations
    • -
    • Handle complex validation rules
    • -
    • Support for nested object validation
    • -
    • Generate comprehensive validation suites
    • -
    - -

    - Generated Output: Zod validation schemas with custom validators -

    - -

    7.2.2. Test Data Plugin

    -

    - The Test Data Plugin tutorial demonstrates how to create a plugin that generates realistic test data and fixtures from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate realistic mock data using Faker.js
    • -
    • Create factory functions for dynamic data generation
    • -
    • Support for relationships and constraints
    • -
    • Generate test fixtures and seed data
    • -
    • Handle localization and custom generators
    • -
    - -

    - Generated Output: Test data files, factories, and fixtures in multiple formats -

    - -

    7.3. Documentation and Specification Plugins

    -

    - The OpenAPI Specification Plugin tutorial shows how to create a plugin that generates OpenAPI 3.0 specifications from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate OpenAPI 3.0 compliant specifications
    • -
    • Create schemas and CRUD endpoints automatically
    • -
    • Support multiple authentication schemes
    • -
    • Generate multiple output formats (JSON, YAML, HTML)
    • -
    • Include validation rules and examples
    • -
    - -

    - Generated Output: Complete OpenAPI specifications with interactive documentation -

    +
    +

    {_('Advanced Tutorials')}

    +

    + + This section covers advanced plugin development topics for + developers who need to create sophisticated code generation + tools. These tutorials demonstrate complex patterns and + integration techniques for building enterprise-grade plugins. + +

    +
    + +
    +

    {_('7.1. API Development Plugins')}

    + +

    {_('7.1.1. GraphQL Schema Plugin')}

    +

    + + The + GraphQL Schema Plugin + tutorial teaches you how to create a plugin that + generates GraphQL type definitions and schemas from your + schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate GraphQL type definitions from models and types + +
    • +
    • + + Create queries, mutations, and subscriptions + +
    • +
    • + + Support for custom scalars and directives + +
    • +
    • + + Handle relationships and nested types + +
    • +
    • + + Generate complete GraphQL schema files + +
    • +
    + +

    + + Generated Output: GraphQL schema files with + type definitions, queries, and mutations + +

    + +

    {_('7.1.2. TypeScript Interface Plugin')}

    +

    + + The + TypeScript Interface Plugin + tutorial demonstrates how to create a plugin that + generates TypeScript interfaces and types from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate TypeScript interfaces from models and types + +
    • +
    • + + Create enums and utility types + +
    • +
    • + + Support for namespaces and modules + +
    • +
    • + + Handle optional and array types + +
    • +
    • + + Generate comprehensive type definitions + +
    • +
    + +

    + + Generated Output: TypeScript definition files + with interfaces, types, and enums + +

    + +

    {_('7.1.3. API Client Plugin')}

    +

    + + The + API Client Plugin + tutorial shows how to create a plugin that generates + API client libraries from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate REST and GraphQL API clients + +
    • +
    • + + Support multiple authentication strategies + +
    • +
    • + + Create type-safe client methods + +
    • +
    • + + Handle request/response transformations + +
    • +
    • + + Generate both JavaScript and TypeScript clients + +
    • +
    + +

    + + Generated Output: Complete API client + libraries with methods and types + +

    +
    + +
    +

    {_('7.2. Validation and Testing Plugins')}

    +

    + + Validation and testing plugins help ensure data quality and + application reliability by generating validation schemas and + test data. These plugins are essential for building robust + applications that can handle edge cases and maintain data + integrity across different environments. + +

    + +

    {_('7.2.1. Validation Plugin')}

    +

    + + The + Validation Plugin + tutorial teaches you how to create a plugin that + generates Zod validation schemas from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate Zod schemas from models and types + +
    • +
    • + + Create custom validators and transformations + +
    • +
    • + + Handle complex validation rules + +
    • +
    • + + Support for nested object validation + +
    • +
    • + + Generate comprehensive validation suites + +
    • +
    + +

    + + Generated Output: Zod validation schemas with + custom validators + +

    + +

    {_('7.2.2. Test Data Plugin')}

    +

    + + The + Test Data Plugin + tutorial demonstrates how to create a plugin that + generates realistic test data and fixtures from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate realistic mock data using Faker.js + +
    • +
    • + + Create factory functions for dynamic data generation + +
    • +
    • + + Support for relationships and constraints + +
    • +
    • + + Generate test fixtures and seed data + +
    • +
    • + + Handle localization and custom generators + +
    • +
    + +

    + + Generated Output: Test data files, factories, + and fixtures in multiple formats + +

    +
    + +
    +

    {_('7.3. Documentation and Specification Plugins')}

    +

    + + The + OpenAPI Specification Plugin + tutorial shows how to create a plugin that generates + OpenAPI 3.0 specifications from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate OpenAPI 3.0 compliant specifications + +
    • +
    • + + Create schemas and CRUD endpoints automatically + +
    • +
    • + + Support multiple authentication schemes + +
    • +
    • + + Generate multiple output formats (JSON, YAML, HTML) + +
    • +
    • + + Include validation rules and examples + +
    • +
    + +

    + + Generated Output: Complete OpenAPI + specifications with interactive documentation + +

    +
    ); @@ -215,4 +450,3 @@ export default function Page(props: ServerPageProps) { ); } - \ No newline at end of file diff --git a/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx b/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx index f742f10..44b98e5 100644 --- a/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx +++ b/packages/www/plugins/docs/views/plugin-development/available-tutorials.tsx @@ -3,9 +3,9 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; import Layout from '../../components/Layout.js'; export function Head(props: ServerPageProps) { @@ -16,7 +16,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('Available Tutorials'); const description = _( - 'Comprehensive tutorials for creating specific types of plugins with step-by-step instructions and complete code examples' + 'Comprehensive tutorials for creating specific types of plugins ' + + 'with step-by-step instructions and complete code examples' ); return ( <> @@ -40,112 +41,244 @@ export function Head(props: ServerPageProps) { } export function Right() { - const { _ } = useLanguage(); - return ( - -
    - {_('Available Tutorials')} -
    - -
    - ); - } + const { _ } = useLanguage(); + return ( + +
    + {_('Available Tutorials')} +
    + +
    + ); +} export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Available Tutorials

    -

    - This section provides links to comprehensive tutorials for creating specific types of plugins. Each tutorial includes step-by-step instructions, complete code examples, and explanations of key concepts for building production-ready plugins. -

    - -

    6.1. Meta Coding With TSMorph

    -

    - The TSMorph Plugin Guide demonstrates how to create powerful code generation plugins using ts-morph, a TypeScript library that provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code. This guide is essential for developers who need to generate complex TypeScript code with proper syntax and formatting. -

    - -

    6.2. Database Integration Plugins

    -

    - The MySQL Tables Plugin tutorial teaches you how to create a plugin that generates MySQL CREATE TABLE statements from your schema. -

    - -

    - Learn how to create a plugin that generates MySQL CREATE TABLE statements from your schema. -

    - -

    What you'll learn:

    -
      -
    • Parse schema models and their columns
    • -
    • Map schema types to MySQL data types
    • -
    • Generate SQL DDL statements with constraints
    • -
    • Handle primary keys, foreign keys, and indexes
    • -
    • Implement proper error handling and validation
    • -
    - -

    - Generated Output: SQL files that can be executed to create database tables -

    - -

    6.3. Frontend Development Plugins

    -

    - The HTML Form Plugin tutorial demonstrates how to create a plugin that generates responsive HTML forms from your schema. -

    - -

    - Learn how to create a plugin that generates responsive HTML forms from your schema. -

    - -

    What you'll learn:

    -
      -
    • Generate HTML form elements based on field types
    • -
    • Support multiple CSS frameworks (Bootstrap, Tailwind, Custom)
    • -
    • Include client-side validation and constraints
    • -
    • Handle different form layouts and themes
    • -
    • Create accessible, responsive forms
    • -
    - -

    - Generated Output: Complete HTML files with forms, styling, and JavaScript validation -

    - -

    6.4. Documentation Generation Plugins

    -

    - The Markdown Documentation Plugin tutorial shows how to create a plugin that generates comprehensive markdown documentation from your schema. -

    - -

    - Learn how to create a plugin that generates comprehensive markdown documentation from your schema. -

    - -

    What you'll learn:

    -
      -
    • Parse all schema elements (models, types, enums, props)
    • -
    • Generate structured documentation with navigation
    • -
    • Include examples and cross-references
    • -
    • Support multiple documentation formats and templates
    • -
    • Create both single-file and multi-file documentation
    • -
    - -

    - Generated Output: Markdown documentation files with complete schema reference -

    +
    +

    {_('Available Tutorials')}

    +

    + + This section provides links to comprehensive tutorials for + creating specific types of plugins. Each tutorial includes + step-by-step instructions, complete code examples, and + explanations of key concepts for building production-ready + plugins. + +

    +
    + +
    +

    {_('6.1. Meta Coding With TSMorph')}

    +

    + + The + TSMorph Plugin Guide + demonstrates how to create powerful code generation + plugins using ts-morph, a TypeScript library that + provides an easier way to programmatically navigate and + manipulate TypeScript and JavaScript code. This guide is + essential for developers who need to generate complex + TypeScript code with proper syntax and formatting. + +

    +
    + +
    +

    {_('6.2. Database Integration Plugins')}

    +

    + + The + MySQL Tables Plugin + tutorial teaches you how to create a plugin that + generates MySQL CREATE TABLE statements from your + schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Parse schema models and their columns + +
    • +
    • + + Map schema types to MySQL data types + +
    • +
    • + + Generate SQL DDL statements with constraints + +
    • +
    • + + Handle primary keys, foreign keys, and indexes + +
    • +
    • + + Implement proper error handling and validation + +
    • +
    + +

    + + Generated Output: SQL files that can be + executed to create database tables + +

    +
    + +
    +

    {_('6.3. Frontend Development Plugins')}

    +

    + + The + HTML Form Plugin + tutorial demonstrates how to create a plugin that + generates responsive HTML forms from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Generate HTML form elements based on field types + +
    • +
    • + + Support multiple CSS frameworks (Bootstrap, Tailwind, + Custom) + +
    • +
    • + + Include client-side validation and constraints + +
    • +
    • + + Handle different form layouts and themes + +
    • +
    • + + Create accessible, responsive forms + +
    • +
    + +

    + + Generated Output: Complete HTML files with + forms, styling, and JavaScript validation + +

    +
    + +
    +

    {_('6.4. Documentation Generation Plugins')}

    +

    + + The + Markdown Documentation Plugin + tutorial shows how to create a plugin that generates + comprehensive markdown documentation from your schema. + +

    + +

    {_("What you'll learn:")}

    +
      +
    • + + Parse all schema elements (models, types, enums, props) + +
    • +
    • + + Generate structured documentation with navigation + +
    • +
    • + + Include examples and cross-references + +
    • +
    • + + Support multiple documentation formats and templates + +
    • +
    • + + Create both single-file and multi-file documentation + +
    • +
    + +

    + + Generated Output: Markdown documentation + files with complete schema reference + +

    +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/best-practices.tsx b/packages/www/plugins/docs/views/plugin-development/best-practices.tsx index 7fa7cee..52ce2d7 100644 --- a/packages/www/plugins/docs/views/plugin-development/best-practices.tsx +++ b/packages/www/plugins/docs/views/plugin-development/best-practices.tsx @@ -3,46 +3,18 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, H3, P, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Best Practices'); - const description = _( - 'Essential best practices for plugin development covering type safety, configuration validation, file operations, and CLI integration' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const typeSafetyExample = [ `// Always use proper typing for plugin props -import type { PluginProps, PluginWithCLIProps } from '@stackpress/idea-transformer/types'; +import type { + PluginProps, + PluginWithCLIProps +} from '@stackpress/idea-transformer/types'; // Define custom config types interface MyPluginConfig { @@ -59,23 +31,37 @@ export default async function typedPlugin( // TypeScript will enforce config structure const output: string = config.output; // ✅ Type-safe - const format: 'typescript' | 'javascript' = config.format; // ✅ Type-safe - const strict: boolean = config.strict ?? false; // ✅ Type-safe with default + const format: 'typescript' | 'javascript' = config.format; + // ✅ Type-safe + const strict: boolean = config.strict ?? false; + // ✅ Type-safe with default }` ]; const configurationValidationExample = [ - `function validateConfig(config: any): asserts config is MyPluginConfig { + `function validateConfig( + config: any +): asserts config is MyPluginConfig { if (!config.output || typeof config.output !== 'string') { - throw new Error('Plugin requires "output" configuration as string'); + throw new Error( + 'Plugin requires "output" configuration as string' + ); } - if (!config.format || !['typescript', 'javascript'].includes(config.format)) { - throw new Error('Plugin requires "format" to be "typescript" or "javascript"'); + if ( + !config.format || + !['typescript', 'javascript'].includes(config.format) + ) { + throw new Error( + 'Plugin requires "format" to be "typescript" or ' + + '"javascript"' + ); } } -export default async function validatedPlugin(props: PluginProps<{}>) { +export default async function validatedPlugin( + props: PluginProps<{}> +) { validateConfig(props.config); // Now config is properly typed @@ -89,7 +75,9 @@ export default async function filePlugin(props: PluginProps<{}>) { const { config, transformer } = props; // ✅ Use transformer.loader for path resolution - const outputPath = await transformer.loader.absolute(config.output); + const outputPath = await transformer.loader.absolute( + config.output + ); // ✅ Create directories if needed await fs.mkdir(path.dirname(outputPath), { recursive: true }); @@ -98,18 +86,23 @@ export default async function filePlugin(props: PluginProps<{}>) { try { await fs.writeFile(outputPath, content, 'utf8'); } catch (error) { - throw new Error(\`Failed to write output file: \${error.message}\`); + throw new Error( + \`Failed to write output file: \${error.message}\` + ); } }` ]; const cliIntegrationExample = [ `// Use CLI props when available -export default async function adaptivePlugin(props: PluginWithCLIProps) { +export default async function adaptivePlugin( + props: PluginWithCLIProps +) { const { cli, config } = props; // Adapt behavior based on CLI context - const outputDir = config.outputDir || path.join(cli.cwd, 'generated'); + const outputDir = config.outputDir || + path.join(cli.cwd, 'generated'); const verbose = config.verbose || false; if (verbose) { @@ -125,53 +118,135 @@ export default async function adaptivePlugin(props: PluginWithCLIProps) { }` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Essential best practices for plugin development covering type ' + + 'safety, configuration validation, file operations, and CLI ' + + 'integration' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Best Practices

    -

    - This section outlines essential best practices for plugin development, covering type safety, configuration validation, file operations, and CLI integration. Following these practices ensures that plugins are reliable, maintainable, and provide excellent developer experiences. -

    - -

    5.1. Type Safety

    -

    - Type safety is crucial for creating reliable plugins that catch errors at compile time rather than runtime. This section demonstrates how to use TypeScript effectively in plugin development, including proper typing for configuration objects and plugin properties. -

    - - - {typeSafetyExample[0]} - - -

    5.2. Configuration Validation

    -

    - Configuration validation ensures that plugins receive valid configuration options and fail early with clear error messages when configuration is invalid. This approach prevents runtime errors and provides better debugging experiences for plugin users. -

    - - - {configurationValidationExample[0]} - - -

    5.3. File Operations

    -

    - File operations in plugins should follow consistent patterns for path resolution, directory creation, and error handling. This section demonstrates best practices for working with files and directories in a way that's compatible with the idea transformer system. -

    - - - {fileOperationsExample[0]} - - -

    5.4. CLI Integration

    -

    - CLI integration enables plugins to provide rich command-line experiences by adapting behavior based on the execution context. This section shows how to use CLI properties effectively and create plugins that work well in both programmatic and interactive environments. -

    - - - {cliIntegrationExample[0]} - +
    +

    {_('Best Practices')}

    +

    + + This section outlines essential best practices for plugin + development, covering type safety, configuration validation, + file operations, and CLI integration. Following these practices + ensures that plugins are reliable, maintainable, and provide + excellent developer experiences. + +

    +
    + +
    +

    {_('5.1. Type Safety')}

    +

    + + Type safety is crucial for creating reliable plugins that catch + errors at compile time rather than runtime. This section + demonstrates how to use TypeScript effectively in plugin + development, including proper typing for configuration objects + and plugin properties. + +

    + + + {typeSafetyExample[0]} + +
    + +
    +

    {_('5.2. Configuration Validation')}

    +

    + + Configuration validation ensures that plugins receive valid + configuration options and fail early with clear error messages + when configuration is invalid. This approach prevents runtime + errors and provides better debugging experiences for plugin + users. + +

    + + + {configurationValidationExample[0]} + +
    + +
    +

    {_('5.3. File Operations')}

    +

    + + File operations in plugins should follow consistent patterns + for path resolution, directory creation, and error handling. + This section demonstrates best practices for working with files + and directories in a way that's compatible with the idea + transformer system. + +

    + + + {fileOperationsExample[0]} + +
    + +
    +

    {_('5.4. CLI Integration')}

    +

    + + CLI integration enables plugins to provide rich command-line + experiences by adapting behavior based on the execution context. + This section shows how to use CLI properties effectively and + create plugins that work well in both programmatic and + interactive environments. + +

    + + + {cliIntegrationExample[0]} + +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/error-handling.tsx b/packages/www/plugins/docs/views/plugin-development/error-handling.tsx index 3f13558..5c32a05 100644 --- a/packages/www/plugins/docs/views/plugin-development/error-handling.tsx +++ b/packages/www/plugins/docs/views/plugin-development/error-handling.tsx @@ -3,43 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, H3, P, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Error Handling'); - const description = _( - 'Proper error handling is essential for creating robust plugins that provide clear feedback when issues occur' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const pluginErrorHandlingExample = [ `import type { PluginProps } from '@stackpress/idea-transformer/types'; @@ -49,22 +18,33 @@ export default async function safePlugin(props: PluginProps<{}>) { try { // Validate required configuration if (!config.output) { - throw new Error('Missing required "output" configuration'); + throw new Error( + 'Missing required "output" configuration' + ); } // Validate schema has required elements - if (!schema.model || Object.keys(schema.model).length === 0) { - throw new Error('Schema must contain at least one model'); + if ( + !schema.model || + Object.keys(schema.model).length === 0 + ) { + throw new Error( + 'Schema must contain at least one model' + ); } // Process schema const content = await processSchema(schema); // Write output - const outputPath = await transformer.loader.absolute(config.output); + const outputPath = await transformer.loader.absolute( + config.output + ); await writeOutput(outputPath, content); - console.log(\`✅ Plugin completed successfully: \${outputPath}\`); + console.log( + \`✅ Plugin completed successfully: \${outputPath}\` + ); } catch (error) { console.error(\`❌ Plugin failed:\`, error.message); @@ -74,7 +54,9 @@ export default async function safePlugin(props: PluginProps<{}>) { ]; const gracefulErrorRecoveryExample = [ - `export default async function resilientPlugin(props: PluginProps<{}>) { + `export default async function resilientPlugin( + props: PluginProps<{}> +) { const { config, schema, transformer } = props; const warnings: string[] = []; @@ -83,54 +65,125 @@ const gracefulErrorRecoveryExample = [ // Attempt primary functionality await primaryGeneration(schema, config); } catch (error) { - warnings.push(\`Primary generation failed: \${error.message}\`); + warnings.push( + \`Primary generation failed: \${error.message}\` + ); // Fallback to basic generation try { await fallbackGeneration(schema, config); warnings.push('Used fallback generation'); } catch (fallbackError) { - throw new Error(\`Both primary and fallback generation failed: \${fallbackError.message}\`); + throw new Error( + \`Both primary and fallback generation failed: \` + + \`\${fallbackError.message}\` + ); } } // Report warnings if (warnings.length > 0) { console.warn('Plugin completed with warnings:'); - warnings.forEach(warning => console.warn(\` ⚠️ \${warning}\`)); + warnings.forEach(warning => + console.warn(\` ⚠️ \${warning}\`) + ); } }` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Error Handling'); + const description = _( + 'Proper error handling is essential for creating robust plugins ' + + 'that provide clear feedback when issues occur' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Error Handling

    -

    - Proper error handling is essential for creating robust plugins that provide clear feedback when issues occur. This section covers error handling strategies, validation patterns, and techniques for graceful failure recovery in plugin development. -

    +
    +

    {_('Error Handling')}

    +

    + + Proper error handling is essential for creating robust plugins + that provide clear feedback when issues occur. This section + covers error handling strategies, validation patterns, and + techniques for graceful failure recovery in plugin development. + +

    +
    -

    4.1. Plugin Error Handling

    -

    - Plugin error handling demonstrates how to implement comprehensive error checking and reporting in plugins. This approach ensures that plugins fail gracefully with meaningful error messages, helping users quickly identify and resolve configuration or schema issues. -

    +
    +

    {_('4.1. Plugin Error Handling')}

    +

    + + Plugin error handling demonstrates how to implement + comprehensive error checking and reporting in plugins. This + approach ensures that plugins fail gracefully with meaningful + error messages, helping users quickly identify and resolve + configuration or schema issues. + +

    - - {pluginErrorHandlingExample[0]} - + + {pluginErrorHandlingExample[0]} + +
    -

    4.2. Graceful Error Recovery

    -

    - Graceful error recovery shows how plugins can implement fallback mechanisms and continue operation even when primary functionality fails. This approach improves plugin reliability and provides better user experiences by attempting alternative approaches when errors occur. -

    +
    +

    {_('4.2. Graceful Error Recovery')}

    +

    + + Graceful error recovery shows how plugins can implement + fallback mechanisms and continue operation even when primary + functionality fails. This approach improves plugin reliability + and provides better user experiences by attempting alternative + approaches when errors occur. + +

    - - {gracefulErrorRecoveryExample[0]} - + + {gracefulErrorRecoveryExample[0]} + +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/getting-started.tsx b/packages/www/plugins/docs/views/plugin-development/getting-started.tsx index 6ff4898..9df2eb3 100644 --- a/packages/www/plugins/docs/views/plugin-development/getting-started.tsx +++ b/packages/www/plugins/docs/views/plugin-development/getting-started.tsx @@ -3,44 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, H3, C, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Getting Started'); - const description = _( - 'Essential information for developers who are new to plugin development with prerequisites, basic concepts, and step-by-step guidance' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - - const commonPluginStructureExample = [ `import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; @@ -65,7 +33,9 @@ export default async function myPlugin( const content = processSchema(schema); // 3. Write output - const outputPath = await transformer.loader.absolute(config.output); + const outputPath = await transformer.loader.absolute( + config.output + ); await fs.mkdir(path.dirname(outputPath), { recursive: true }); await fs.writeFile(outputPath, content, 'utf8'); @@ -130,14 +100,18 @@ const configurationValidationExample = [ } if (config.format && !['json', 'yaml'].includes(config.format)) { - throw new Error(\`Unsupported format: \${config.format}\`); + throw new Error( + \`Unsupported format: \${config.format}\` + ); } }` ]; const fileOperationsExample = [ `// ✅ Good - uses transformer's file loader -const outputPath = await transformer.loader.absolute(config.output); +const outputPath = await transformer.loader.absolute( + config.output +); // ✅ Good - creates directories if needed await fs.mkdir(path.dirname(outputPath), { recursive: true }); @@ -146,7 +120,9 @@ await fs.mkdir(path.dirname(outputPath), { recursive: true }); try { await fs.writeFile(outputPath, content, 'utf8'); } catch (error) { - throw new Error(\`Failed to write file: \${error.message}\`); + throw new Error( + \`Failed to write file: \${error.message}\` + ); }` ]; @@ -157,8 +133,13 @@ const errorHandlingExample = [ validateConfig(props.config); // Check for required schema elements - if (!props.schema.model || Object.keys(props.schema.model).length === 0) { - console.warn('⚠️ No models found in schema. Skipping generation.'); + if ( + !props.schema.model || + Object.keys(props.schema.model).length === 0 + ) { + console.warn( + '⚠️ No models found in schema. Skipping generation.' + ); return; } @@ -177,7 +158,9 @@ const errorHandlingExample = [ const schemaProcessingExample = [ `// ✅ Good - checks for existence before processing if (schema.model) { - for (const [modelName, model] of Object.entries(schema.model)) { + for (const [modelName, model] of Object.entries( + schema.model + )) { // Process model } } @@ -224,186 +207,391 @@ enum UserRole { }` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Getting Started'); + const description = _( + 'Essential information for developers who are new to plugin ' + + 'development with prerequisites, basic concepts, and step-by-step ' + + 'guidance' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Getting Started

    -

    - This section provides essential information for developers who are new to plugin development. It covers prerequisites, basic concepts, and step-by-step guidance for creating your first plugin. -

    - -

    8.1. Prerequisites

    -

    - Before starting plugin development, ensure you have the necessary knowledge and tools. These prerequisites will help you understand the examples and successfully implement your own plugins. -

    - -

    - Before starting these tutorials, make sure you have: -

    - -
      -
    • Basic understanding of TypeScript/JavaScript
    • -
    • Familiarity with the idea-transformer plugin system
    • -
    • Understanding of the target technology (MySQL, HTML/CSS, Markdown)
    • -
    - -

    8.2. Plugin Development Basics

    -

    - Plugin development follows consistent patterns that make it easy to create new plugins once you understand the core concepts. This section outlines the fundamental steps and patterns used across all plugin types. -

    - -

    - All plugins in the idea-transformer system follow a similar pattern: -

    - -
      -
    1. Import Types: Use the provided TypeScript types for type safety
    2. -
    3. Define Configuration: Specify what configuration options your plugin accepts
    4. -
    5. Validate Input: Check that required configuration is provided
    6. -
    7. Process Schema: Parse the schema and extract relevant information
    8. -
    9. Generate Output: Create the target files or content
    10. -
    11. Handle Errors: Provide meaningful error messages and graceful failure
    12. -
    - -

    8.3. Common Plugin Structure

    -

    - The common plugin structure provides a template that can be adapted for any type of code generation. This structure ensures consistency across plugins and includes all essential components for robust plugin development. -

    - - - {commonPluginStructureExample[0]} - - -

    8.4. Schema Structure

    -

    - Understanding the schema structure is crucial for plugin development. The processed schema provides a standardized format that plugins can rely on, regardless of the original .idea file structure. -

    - -

    - All plugins receive a processed schema with this structure: -

    - - - {schemaStructureExample[0]} - - -

    8.5. Implementation Guidelines

    -

    - These implementation guidelines help ensure that your plugins are reliable, maintainable, and follow established patterns. Following these guidelines will make your plugins easier to debug and extend. -

    - -

    8.5.1. Type Safety

    -

    - Type safety prevents runtime errors and provides better development experiences through IDE support and compile-time error checking. -

    - -

    - Always use the provided TypeScript types: -

    - - - {typeSafetyExample[0]} - - -

    8.5.2. Configuration Validation

    -

    - Configuration validation ensures that plugins receive valid input and fail early with clear error messages when configuration is incorrect. -

    - -

    - Validate all required configuration upfront: -

    - - - {configurationValidationExample[0]} - - -

    8.5.3. File Operations

    -

    - File operations should follow consistent patterns for path resolution, directory creation, and error handling to ensure compatibility with the idea transformer system. -

    - -

    - Use the transformer's file loader for consistent path resolution: -

    - - - {fileOperationsExample[0]} - - -

    8.5.4. Error Handling

    -

    - Comprehensive error handling provides better user experiences and makes plugins more reliable in production environments. -

    - -

    - Provide meaningful error messages and handle edge cases: -

    - - - {errorHandlingExample[0]} - - -

    8.5.5. Schema Processing

    -

    - Schema processing should handle optional elements gracefully and provide meaningful defaults to ensure plugins work with various schema configurations. -

    - -

    - Handle optional schema elements gracefully: -

    - - - {schemaProcessingExample[0]} - - -

    8.6. Usage in Schema Files

    -

    - This section demonstrates how to use plugins within .idea schema files, showing the declarative syntax for plugin configuration and how multiple plugins can work together to generate comprehensive outputs. -

    - -

    - To use any of these plugins in your schema file: -

    - - - {usageInSchemaFilesExample[0]} - - -

    8.7. Next Steps

    -

    - After completing the getting started section, you'll be ready to dive into specific tutorials and start building your own plugins. These next steps will guide you toward becoming proficient in plugin development. -

    - -
      -
    1. Choose a Tutorial: Start with the tutorial that matches your immediate needs
    2. -
    3. Follow Along: Each tutorial provides step-by-step instructions with complete code examples
    4. -
    5. Customize: Adapt the examples to your specific requirements
    6. -
    7. Extend: Use the patterns learned to create your own custom plugins
    8. -
    - -

    8.8. Additional Plugin Ideas

    -

    - Beyond the provided tutorials, there are many other types of plugins you can create using the patterns and techniques covered in this documentation: -

    - -
      -
    • Database Migration Generator: Create migration files for various databases
    • -
    • Form Validation Generator: Generate client-side validation rules
    • -
    • Mock Server Generator: Create mock API servers for testing
    • -
    • Documentation Site Generator: Build complete documentation websites
    • -
    • Configuration File Generator: Generate app configuration files
    • -
    • Seed Data Generator: Create database seed scripts
    • -
    • API Test Generator: Generate automated API test suites
    • -
    - -

    - Happy coding! 🚀 -

    +
    +

    {_('Getting Started')}

    + + This section provides essential information for developers who + are new to plugin development. It covers prerequisites, basic + concepts, and step-by-step guidance for creating your first + plugin. + +
    + +
    +

    {_('8.1. Prerequisites')}

    + + Before starting plugin development, ensure you have the + necessary knowledge and tools. These prerequisites will help + you understand the examples and successfully implement your + own plugins. + + + + Before starting these tutorials, make sure you have: + + +
      +
    • + + Basic understanding of TypeScript/JavaScript + +
    • +
    • + + Familiarity with the idea-transformer plugin system + +
    • +
    • + + Understanding of the target technology + (MySQL, HTML/CSS, Markdown) + +
    • +
    +
    + +
    +

    {_('8.2. Plugin Development Basics')}

    + + Plugin development follows consistent patterns that make it + easy to create new plugins once you understand the core + concepts. This section outlines the fundamental steps and + patterns used across all plugin types. + + + + All plugins in the idea-transformer system follow a + similar pattern: + + +
      +
    1. + + Import Types: Use the provided TypeScript + types for type safety + +
    2. +
    3. + + Define Configuration: Specify what + configuration options your plugin accepts + +
    4. +
    5. + + Validate Input: Check that required + configuration is provided + +
    6. +
    7. + + Process Schema: Parse the schema and + extract relevant information + +
    8. +
    9. + + Generate Output: Create the target files + or content + +
    10. +
    11. + + Handle Errors: Provide meaningful error + messages and graceful failure + +
    12. +
    +
    + +
    +

    {_('8.3. Common Plugin Structure')}

    + + The common plugin structure provides a template that can be + adapted for any type of code generation. This structure + ensures consistency across plugins and includes all essential + components for robust plugin development. + + + + {commonPluginStructureExample[0]} + +
    + +
    +

    {_('8.4. Schema Structure')}

    + + Understanding the schema structure is crucial for plugin + development. The processed schema provides a standardized + format that plugins can rely on, regardless of the original + .idea file structure. + + + + All plugins receive a processed schema with this structure: + + + + {schemaStructureExample[0]} + +
    + +
    +

    {_('8.5. Implementation Guidelines')}

    + + These implementation guidelines help ensure that your plugins + are reliable, maintainable, and follow established patterns. + Following these guidelines will make your plugins easier to + debug and extend. + + +
    +

    {_('8.5.1. Type Safety')}

    + + Type safety prevents runtime errors and provides better + development experiences through IDE support and compile-time + error checking. + + + + Always use the provided TypeScript types: + + + + {typeSafetyExample[0]} + +
    + +
    +

    {_('8.5.2. Configuration Validation')}

    + + Configuration validation ensures that plugins receive valid + input and fail early with clear error messages when + configuration is incorrect. + + + + Validate all required configuration upfront: + + + + {configurationValidationExample[0]} + +
    + +
    +

    {_('8.5.3. File Operations')}

    + + File operations should follow consistent patterns for path + resolution, directory creation, and error handling to ensure + compatibility with the idea transformer system. + + + + Use the transformer's file loader for consistent path + resolution: + + + + {fileOperationsExample[0]} + +
    + +
    +

    {_('8.5.4. Error Handling')}

    + + Comprehensive error handling provides better user experiences + and makes plugins more reliable in production environments. + + + + Provide meaningful error messages and handle edge cases: + + + + {errorHandlingExample[0]} + +
    + +
    +

    {_('8.5.5. Schema Processing')}

    + + Schema processing should handle optional elements gracefully + and provide meaningful defaults to ensure plugins work with + various schema configurations. + + + + Handle optional schema elements gracefully: + + + + {schemaProcessingExample[0]} + +
    +
    + +
    +

    {_('8.6. Usage in Schema Files')}

    + + This section demonstrates how to use plugins within + .idea schema files, showing the declarative syntax + for plugin configuration and how multiple plugins can work + together to generate comprehensive outputs. + + + + To use any of these plugins in your schema file: + + + + {usageInSchemaFilesExample[0]} + +
    + +
    +

    {_('8.7. Next Steps')}

    + + After completing the getting started section, you'll be ready + to dive into specific tutorials and start building your own + plugins. These next steps will guide you toward becoming + proficient in plugin development. + + +
      +
    1. + + Choose a Tutorial: Start with the tutorial + that matches your immediate needs + +
    2. +
    3. + + Follow Along: Each tutorial provides + step-by-step instructions with complete code examples + +
    4. +
    5. + + Customize: Adapt the examples to your + specific requirements + +
    6. +
    7. + + Extend: Use the patterns learned to + create your own custom plugins + +
    8. +
    +
    + +
    +

    {_('8.8. Additional Plugin Ideas')}

    + + Beyond the provided tutorials, there are many other types of + plugins you can create using the patterns and techniques + covered in this documentation: + + +
      +
    • + + Database Migration Generator: Create + migration files for various databases + +
    • +
    • + + Form Validation Generator: Generate + client-side validation rules + +
    • +
    • + + Mock Server Generator: Create mock API + servers for testing + +
    • +
    • + + Documentation Site Generator: Build + complete documentation websites + +
    • +
    • + + Configuration File Generator: Generate + app configuration files + +
    • +
    • + + Seed Data Generator: Create database + seed scripts + +
    • +
    • + + API Test Generator: Generate automated + API test suites + +
    • +
    + + + Happy coding! 🚀 + +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx index c9717c5..f54d637 100644 --- a/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx +++ b/packages/www/plugins/docs/views/plugin-development/plugin-configuration.tsx @@ -3,43 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, P, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Plugin Configuration'); - const description = _( - 'Plugin configuration enables developers to customize plugin behavior through schema declarations' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const schemaPluginDefinitionExample = [ `// schema.idea plugin "./plugins/my-plugin.js" { @@ -76,35 +45,100 @@ const pluginConfigurationAccessExample = [ }` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Configuration'); + const description = _( + 'Plugin configuration enables developers to customize plugin ' + + 'behavior through schema declarations' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Plugin Configuration

    -

    - Plugin configuration enables developers to customize plugin behavior through schema declarations. This section covers how to define configuration options in schema files, access configuration within plugins, and implement flexible plugin behavior based on user preferences. -

    +
    +

    {_('Plugin Configuration')}

    +

    + + Plugin configuration enables developers to customize plugin + behavior through schema declarations. This section covers + how to define configuration options in schema files, access + configuration within plugins, and implement flexible plugin + behavior based on user preferences. + +

    +
    -

    3.1. Schema Plugin Definition

    -

    - Schema plugin definitions specify how plugins are declared and configured within .idea schema files. This declarative approach allows users to configure multiple plugins with different settings while maintaining clean, readable schema files. -

    +
    +

    {_('3.1. Schema Plugin Definition')}

    +

    + + Schema plugin definitions specify how plugins are declared + and configured within .idea schema files. This declarative + approach allows users to configure multiple plugins with + different settings while maintaining clean, readable schema + files. + +

    - - {schemaPluginDefinitionExample[0]} - + + {schemaPluginDefinitionExample[0]} + +
    -

    3.2. Plugin Configuration Access

    -

    - Plugin configuration access demonstrates how plugins can read and utilize configuration options provided in schema files. This section shows how to access both simple and nested configuration values, provide defaults, and implement conditional behavior based on configuration settings. -

    +
    +

    {_('3.2. Plugin Configuration Access')}

    +

    + + Plugin configuration access demonstrates how plugins can + read and utilize configuration options provided in schema + files. This section shows how to access both simple and + nested configuration values, provide defaults, and implement + conditional behavior based on configuration settings. + +

    - - {pluginConfigurationAccessExample[0]} - + + {pluginConfigurationAccessExample[0]} + +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx index 390a315..6ae899a 100644 --- a/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx +++ b/packages/www/plugins/docs/views/plugin-development/plugin-development-guide.tsx @@ -3,44 +3,13 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Plugin Development Guide'); - const description = _( - 'Comprehensive guide covering everything from basic plugin structure to advanced development patterns for the idea ecosystem' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const basicPluginExample = [ `import type { PluginWithCLIProps } from '@stackpress/idea'; @@ -137,128 +106,258 @@ await transformer.transform({ });` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Development Guide'); + const description = _( + 'Comprehensive guide covering everything from basic plugin' + + ' structure to advanced development patterns for the idea ecosystem' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Idea Plugins

    -

    - The following documentation explains how to develop plugins for .idea files. This comprehensive guide covers everything from basic plugin structure to advanced development patterns, providing developers with the knowledge needed to create powerful code generation plugins for the idea ecosystem. -

    +
    +

    {_('Idea Plugins')}

    +

    + + The following documentation explains how to develop plugins + for .idea files. This comprehensive guide covers everything + from basic plugin structure to advanced development patterns, + providing developers with the knowledge needed to create + powerful code generation plugins for the idea ecosystem. + +

    +
    -

    1. Plugin Development Guide

    -

    - This section covers the fundamental concepts and structures needed to create effective plugins for the idea ecosystem. Plugins are JavaScript or TypeScript modules that process schema definitions and generate various outputs like code, documentation, or configuration files. -

    +
    +

    {_('1. Plugin Development Guide')}

    +

    + + This section covers the fundamental concepts and structures + needed to create effective plugins for the idea ecosystem. + Plugins are JavaScript or TypeScript modules that process + schema definitions and generate various outputs like code, + documentation, or configuration files. + +

    -

    - Creating a plugin involves just exporting a function like the example below: -

    +

    + + Creating a plugin involves just exporting a function like the + example below: + +

    - - {basicPluginExample[0]} - + + {basicPluginExample[0]} + +
    -

    1.1. Basic Plugin Structure

    -

    - The basic plugin structure provides the foundation for all idea plugins. This structure ensures consistency across plugins and provides access to essential functionality like schema processing, file operations, and configuration management. -

    +
    +

    {_('1.1. Basic Plugin Structure')}

    +

    + + The basic plugin structure provides the foundation for all + idea plugins. This structure ensures consistency across + plugins and provides access to essential functionality like + schema processing, file operations, and configuration + management. + +

    - - {basicPluginStructureExample[0]} - + + {basicPluginStructureExample[0]} + -

    Properties

    -

    - The PluginProps contains the following properties. -

    +

    {_('Properties')}

    +

    + + The PluginProps contains the following properties. + +

    - - Property - Type - Description - - config - PluginConfig - Plugin-specific configuration from the schema - - - schema - SchemaConfig - Complete processed schema configuration - - - transformer - Transformer<{}> - The transformer instance executing the plugin - - - cwd - string - Current working directory for file operations - -
    + + + Property + Type + Description + + + config + PluginConfig + + + Plugin-specific configuration from the schema + + + + + schema + SchemaConfig + + + Complete processed schema configuration + + + + + transformer + Transformer<{}> + + + The transformer instance executing the plugin + + + + + cwd + string + + + Current working directory for file operations + + + +
    +
    -

    1.2. CLI-Aware Plugin Structure

    -

    - CLI-aware plugins extend the basic plugin structure to include command-line interface capabilities. These plugins can interact with the terminal, access CLI-specific properties, and provide enhanced user experiences through interactive features and detailed logging. -

    +
    +

    {_('1.2. CLI-Aware Plugin Structure')}

    +

    + + CLI-aware plugins extend the basic plugin structure to + include command-line interface capabilities. These plugins + can interact with the terminal, access CLI-specific + properties, and provide enhanced user experiences through + interactive features and detailed logging. + +

    - - {cliPluginExample[0]} - + + {cliPluginExample[0]} + -

    Properties

    -

    - The PluginWithCLIProps contains the following properties. -

    +

    {_('Properties')}

    +

    + + The PluginWithCLIProps contains the following properties. + +

    - - Property - Type - Description - - config - PluginConfig - Plugin-specific configuration from the schema - - - schema - SchemaConfig - Complete processed schema configuration - - - transformer - Transformer<{}> - The transformer instance executing the plugin - - - cwd - string - Current working directory for file operations - - - cli - Terminal - Terminal instance for CLI interactions - -
    + + + Property + Type + Description + + + config + PluginConfig + + + Plugin-specific configuration from the schema + + + + + schema + SchemaConfig + + + Complete processed schema configuration + + + + + transformer + Transformer<{}> + + + The transformer instance executing the plugin + + + + + cwd + string + + + Current working directory for file operations + + + + + cli + Terminal + + + Terminal instance for CLI interactions + + + +
    +
    -

    1.3. Custom Plugin Props

    -

    - Custom plugin props allow developers to extend the base plugin functionality with additional properties and configuration options. This feature enables plugins to receive custom data, maintain state, and implement specialized behaviors beyond the standard plugin interface. -

    +
    +

    {_('1.3. Custom Plugin Props')}

    +

    + + Custom plugin props allow developers to extend the base + plugin functionality with additional properties and + configuration options. This feature enables plugins to + receive custom data, maintain state, and implement + specialized behaviors beyond the standard plugin interface. + +

    -

    - You can extend the base plugin props with custom properties: -

    +

    + + You can extend the base plugin props with custom properties: + +

    - - {customPluginPropsExample[0]} - + + {customPluginPropsExample[0]} + +
    ); diff --git a/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx b/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx index 4604410..c2e8566 100644 --- a/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx +++ b/packages/www/plugins/docs/views/plugin-development/plugin-examples.tsx @@ -3,43 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav } from '../../components/index.js'; +import { H1, H2, P, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Plugin Examples'); - const description = _( - 'Practical examples of common plugin implementations demonstrating real-world patterns and best practices' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const typescriptInterfaceGeneratorExample = [ `import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; @@ -207,44 +176,117 @@ function generateEnums(enums: Record): string { }` ]; +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Plugin Examples'); + const description = _( + 'Practical examples of common plugin implementations ' + + 'demonstrating real-world patterns and best practices' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + export function Body() { + //hooks + const { _ } = useLanguage(); + return (
    -

    Plugin Examples

    -

    - This section provides practical examples of common plugin implementations. These examples demonstrate real-world patterns and best practices for creating plugins that generate TypeScript interfaces, enums, and interactive CLI tools. -

    +
    +

    {_('Plugin Examples')}

    +

    + + This section provides practical examples of common plugin + implementations. These examples demonstrate real-world + patterns and best practices for creating plugins that + generate TypeScript interfaces, enums, and interactive + CLI tools. + +

    +
    -

    2.1. TypeScript Interface Generator

    -

    - The TypeScript interface generator demonstrates how to create a plugin that processes schema models and types to generate TypeScript interface definitions. This example shows how to handle type mapping, optional properties, and namespace organization. -

    +
    +

    {_('2.1. TypeScript Interface Generator')}

    +

    + + The TypeScript interface generator demonstrates how to + create a plugin that processes schema models and types to + generate TypeScript interface definitions. This example + shows how to handle type mapping, optional properties, and + namespace organization. + +

    - - {typescriptInterfaceGeneratorExample[0]} - + + {typescriptInterfaceGeneratorExample[0]} + +
    -

    2.2. Enum Generator

    -

    - The enum generator plugin shows how to process schema enum definitions and convert them into TypeScript enum declarations. This example demonstrates simple schema processing and file generation patterns that can be adapted for other output formats. -

    +
    +

    {_('2.2. Enum Generator')}

    +

    + + The enum generator plugin shows how to process schema enum + definitions and convert them into TypeScript enum + declarations. This example demonstrates simple schema + processing and file generation patterns that can be adapted + for other output formats. + +

    - - {enumGeneratorExample[0]} - + + {enumGeneratorExample[0]} + +
    -

    2.3. CLI-Interactive Plugin

    -

    - The CLI-interactive plugin demonstrates how to create plugins that provide rich command-line experiences. This example shows how to use the CLI properties for user interaction, progress reporting, and adaptive behavior based on the execution context. -

    +
    +

    {_('2.3. CLI-Interactive Plugin')}

    +

    + + The CLI-interactive plugin demonstrates how to create + plugins that provide rich command-line experiences. This + example shows how to use the CLI properties for user + interaction, progress reporting, and adaptive behavior + based on the execution context. + +

    - - {cliInteractivePluginExample[0]} - + + {cliInteractivePluginExample[0]} + +
    ); diff --git a/packages/www/plugins/docs/views/specifications/best-practices.tsx b/packages/www/plugins/docs/views/specifications/best-practices.tsx index db9bd54..0fa1021 100644 --- a/packages/www/plugins/docs/views/specifications/best-practices.tsx +++ b/packages/www/plugins/docs/views/specifications/best-practices.tsx @@ -3,44 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import { H1, H2, P, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Best Practices'); - const description = _( - 'Best practices for using the .idea file format to generate various outputs like TypeScript interfaces, database schemas, API documentation, and more.' - ); - return ( - <> - {title} - - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - const bestPractices = [ `// ✅ Good enum UserAccountStatus { @@ -181,66 +149,162 @@ plugin "./plugins/form-generator.js" { framework "react" styling "tailwind" }` -] +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Best Practices'); + const description = _( + 'Best practices for using the .idea file format to generate ' + + 'various outputs like TypeScript interfaces, database schemas, ' + + 'API documentation, and more.' + ); + return ( + <> + {title} + + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} export function Body() { + const { _ } = useLanguage(); + return (
    -

    Best Practices

    -

    1. Schema Organization

    -

    Use Descriptive Names

    - - {bestPractices[0]} - - -

    Group Related Elements

    - - {bestPractices[1]} - - -

    Use Consistent Naming Conventions

    - - {bestPractices[2]} - - -

    2. Type Safety

    -

    Define Custom Types for Complex Data

    - - {bestPractices[3]} - - -

    Use Enums for Fixed Sets of Values

    - - {bestPractices[4]} - - -

    3. Validation and Constraints

    -

    Use Appropriate Validation Attributes

    - - {bestPractices[5]} - - -

    Provide Meaningful Defaults

    - - {bestPractices[6]} - - -

    4. Relationships

    -

    Use Clear Relationship Patterns

    - - {bestPractices[7]} - - -

    5. Plugin Configuration

    -

    Organize Plugins by Purpose

    - - {bestPractices[8]} - - -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/complete-examples.tsx b/packages/www/plugins/docs/views/specifications/complete-examples.tsx index 2cc69f3..c58c930 100644 --- a/packages/www/plugins/docs/views/specifications/complete-examples.tsx +++ b/packages/www/plugins/docs/views/specifications/complete-examples.tsx @@ -1,47 +1,15 @@ //modules import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useState } from 'react'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; - import Code from '../../components/Code.js'; - import Layout from '../../components/Layout.js'; - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Complete Examples'); - const description = _( - 'Complete examples of how to use the .idea file format to generate various outputs like TypeScript interfaces, database schemas, API documentation, and more.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage } from 'r22n'; +//docs +import { H1, H2, Nav } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; - const ecommerceSchema = `// E-commerce application schema +const ecommerceSchema = `// E-commerce application schema plugin "./plugins/generate-types.js" { output "./src/types/schema.ts" } @@ -211,7 +179,7 @@ model OrderItem { quantity Number @required @min(1) price Money @required total Money @required -}` +}`; const blogSchema = `// Blog application schema plugin "./plugins/generate-types.js" { @@ -335,41 +303,99 @@ model Comment { parent Comment? @relation(Comment, parentId) replies Comment[] @relation(Comment.parentId) created Date @default("now()") -}` - - export function Body() { - return ( -
    -

    Complete Examples

    -

    E-commerce Application Schema

    - +}`; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Complete Examples'); + const description = _( + 'Complete examples of how to use the .idea file format to ' + + 'generate various outputs like TypeScript interfaces, database ' + + 'schemas, API documentation, and more.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +

    {_('Complete Examples')}

    + +
    +

    {_('E-commerce Application Schema')}

    + {ecommerceSchema} +
    -

    Blog Application Schema

    - +
    +

    {_('Blog Application Schema')}

    + {blogSchema} +
    +
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } - \ No newline at end of file + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx deleted file mode 100644 index aede100..0000000 --- a/packages/www/plugins/docs/views/specifications/components/data-types/Enums.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { H1, H2, P, SS } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; - -const enumsExamples = [ - `enum EnumName { - KEY1 "Display Value 1" - KEY2 "Display Value 2" - KEY3 "Display Value 3" -}`, - `enum UserRole { - ADMIN "Administrator" - MODERATOR "Moderator" - USER "Regular User" - GUEST "Guest User" -} - -enum OrderStatus { - PENDING "Pending Payment" - PAID "Payment Confirmed" - SHIPPED "Order Shipped" - DELIVERED "Order Delivered" - CANCELLED "Order Cancelled" -} - -enum Priority { - LOW "Low Priority" - MEDIUM "Medium Priority" - HIGH "High Priority" - URGENT "Urgent" -}`, - `export enum UserRole { - ADMIN = "Administrator", - MODERATOR = "Moderator", - USER = "Regular User", - GUEST = "Guest User" -}`, - `{ - "enum": { - "UserRole": { - "ADMIN": "Administrator", - "MODERATOR": "Moderator", - "USER": "Regular User", - "GUEST": "Guest User" - } - } -}` -] - -export default function Enums() { - return ( -
    -

    Enums

    -

    Enums define a set of named constants with associated values, perfect for representing fixed sets of options like user roles, status values, or categories.

    -

    Syntax

    - - {enumsExamples[0]} - - -

    Structure

    -
      -
    • EnumName: The identifier used to reference this enum
    • -
    • KEY: The constant name (typically uppercase)
    • -
    • "Display Value": Human-readable label for the constant
    • -
    - -

    Example

    - - {enumsExamples[1]} - - -

    Generate Output

    -

    When processed, enums generate language-specific constants:

    - TypeScript: - - {enumsExamples[2]} - - - JSON: - - {enumsExamples[3]} - -
    - ) -} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx deleted file mode 100644 index f4ad4e0..0000000 --- a/packages/www/plugins/docs/views/specifications/components/data-types/Models.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { H1, H2, P, SS, C } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; - -const modelsExamples = [ - `model ModelName { - columnName DataType @attribute1 @attribute2 - relationColumn RelatedModel @relation -} - -model ModelName! { // Mutable model - // columns... -}`, -`// base-schema.idea -model User { - id String @id - name String @required -} - -// extended-schema.idea -use "./base-schema.idea" - -// This will merge with the imported User model -model User { - email String @required - created Date @default("now()") -} - -// This will NOT merge - it completely replaces the imported User -model User! { - id String @id - username String @required - password String @required -}`, -`model User! { - id String @id @default("nanoid()") - email String @unique @required @field.input(Email) - username String @unique @required @field.input(Text) - password String @required @field.input(Password) - profile UserProfile? - role UserRole @default("USER") - active Boolean @default(true) - lastLogin Date? - created Date @default("now()") - updated Date @default("updated()") -} - -model UserProfile { - id String @id @default("nanoid()") - userId String @relation(User.id) - firstName String @required @field.input(Text) - lastName String @required @field.input(Text) - bio String @field.textarea - avatar String @field.upload - address Address - contact ContactInfo - preferences { - theme String @default("light") - language String @default("en") - notifications Boolean @default(true) - } -} - -model Post { - id String @id @default("nanoid()") - title String @required @field.input(Text) - slug String @unique @generated - content String @required @field.richtext - excerpt String @field.textarea - authorId String @relation(User.id) - author User @relation(User, authorId) - status PostStatus @default("DRAFT") - tags String[] @field.tags - publishedAt Date? - created Date @default("now()") - updated Date @default("updated()") -} - -enum PostStatus { - DRAFT "Draft" - PUBLISHED "Published" - ARCHIVED "Archived" -}` - -] - -export default function Models() { - return ( -
    -

    Models

    -

    Models represent the core entities in your application, typically corresponding to database tables or API resources. They define the structure, relationships, and behavior of your data.

    -

    Syntax

    - - {modelsExamples[0]} - - -

    Structure

    -
      -
    • ModelName: The identifier for this model
    • -
    • !: Optional non-mergeable indicator (prevents automatic merging when using use directives)
    • -
    • columnName: The field name within the model
    • -
    • DataType: Built-in types (String, Number, Boolean, Date) or custom types/enums
    • -
    • @attribute: Attributes for validation, relationships, UI, etc.
    • -
    - -

    Merging Behavior

    -

    By default, when importing schemas with use directives, models with the same name are automatically merged. The ! suffix prevents this behavior:

    - - {modelsExamples[1]} - - -

    Example

    - - {modelsExamples[2]} - -
    - ) -} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx deleted file mode 100644 index 05fd4f7..0000000 --- a/packages/www/plugins/docs/views/specifications/components/data-types/Props.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { H1, H2, P, SS, C } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; - -const propsExamples = [ - `prop PropName { - property "value" - nested { - property "value" - } -}`, -`prop Email { - type "email" - format "email" - validation { - required true - pattern "^[^\s@]+@[^\s@]+\.[^\s@]+$" - } - ui { - component "EmailInput" - placeholder "Enter your email address" - icon "envelope" - } -} - -prop Password { - type "password" - validation { - required true - minLength 8 - pattern "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]" - } - ui { - component "PasswordInput" - placeholder "Enter a secure password" - showStrength true - } -} - -prop Currency { - type "number" - format "currency" - validation { - min 0 - precision 2 - } - ui { - component "CurrencyInput" - symbol "$" - locale "en-US" - } -}`, -`model User { - email String @field.input(Email) - password String @field.input(Password) -}` -] - -export default function Props() { - return ( -
    -

    Props

    -

    Props are reusable property configurations that define common field behaviors, validation rules, and UI components. They promote consistency and reduce duplication across your schema.

    -

    Syntax

    - - {propsExamples[0]} - - -

    Structure

    -
      -
    • PropName: The identifier used to reference this prop
    • -
    • property: Configuration key-value pairs
    • -
    • nested: A nested prop
    • -
    - -

    Example

    - - {propsExamples[1]} - - - Usage in Models -

    Props are referenced using the @field attribute:

    - - {propsExamples[2]} - -
    - ) -} diff --git a/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx b/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx deleted file mode 100644 index 41579ed..0000000 --- a/packages/www/plugins/docs/views/specifications/components/data-types/Type.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { H1, H2, P, SS} from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; - -const typeExamples = [ - `type TypeName { - columnName DataType @attribute1 @attribute2 - anotherColumn DataType @attribute -}`, -`type Address { - street String @required @field.input(Text) - city String @required @field.input(Text) - state String @field.select - postalCode String @field.input(Text) - country String @default("US") @field.select - coordinates { - latitude Number @field.input(Number) - longitude Number @field.input(Number) - } -} - -type ContactInfo { - email String @required @field.input(Email) - phone String @field.input(Phone) - website String @field.input(URL) - socialMedia { - twitter String @field.input(Text) - linkedin String @field.input(Text) - github String @field.input(Text) - } -} - -type Money { - amount Number @required @field.input(Currency) - currency String @default("USD") @field.select - exchangeRate Number @field.input(Number) -}`, -`model Company { - name String @required - address Address @required - contact ContactInfo - revenue Money -}` -] - -export default function Type() { - return ( -
    -

    Type

    -

    Types define custom data structures with multiple columns, similar to objects or structs in programming languages. They're perfect for representing complex data that doesn't warrant a full model.

    -

    Syntax

    - - {typeExamples[0]} - - -

    Structure

    -
      -
    • TypeName: The identifier used to reference this type
    • -
    • columnName: The field name within the type
    • -
    • DataType: The data type (String, Number, Boolean, Date, etc.)
    • -
    • attribute1: Optional attributes for validation, UI, or behavior
    • -
    - -

    Example

    - - {typeExamples[1]} - - - Usage in Models -

    Types are used as column data types:

    - - {typeExamples[2]} - -
    - ) -} diff --git a/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx b/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx deleted file mode 100644 index f2f2805..0000000 --- a/packages/www/plugins/docs/views/specifications/components/schema-directives/Use.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { H1, H2, P, SS, C } from '../../../../components/index.js'; -import Code from '../../../../components/Code.js'; - -const useExamples = [ - `use "package/to/schema.idea" -use "./relative/path/schema.idea" -use "../parent/directory/schema.idea"`, - `// Common types used across multiple schemas -type Address { - street String @required - city String @required - country String @default("US") -} - -enum Status { - ACTIVE "Active" - INACTIVE "Inactive" -} - -prop Email { - type "email" - validation { - required true - format "email" - } -}`, - `// Import common definitions -use "../shared/common.idea" - -// Extend the Status enum (will merge with imported one) -enum Status { - PENDING "Pending Approval" - SUSPENDED "Temporarily Suspended" -} - -// Use imported types and props -model User { - id String @id @default("nanoid()") - email String @field.input(Email) - address Address - status Status @default("PENDING") -}`, - `// The Status enum now contains all values -enum Status { - ACTIVE "Active" // From common.idea - INACTIVE "Inactive" // From common.idea - PENDING "Pending Approval" // From user-schema.idea - SUSPENDED "Temporarily Suspended" // From user-schema.idea -}`, -`enum UserRole { - USER "Regular User" - ADMIN "Administrator" -}`, -`use "./base-schema.idea" - -// This will NOT merge with the imported UserRole -// Instead, it will override it completely -enum UserRole! { - GUEST "Guest User" - MEMBER "Member" - MODERATOR "Moderator" - ADMIN "Administrator" -}`, -`// ✅ Good - organize by domain -use "./shared/common-types.idea" -use "./auth/user-types.idea" -use "./commerce/product-types.idea" - -// ✅ Good - clear file naming -use "./enums/status-enums.idea" -use "./types/address-types.idea" -use "./props/form-props.idea" - -// ❌ Avoid - unclear imports -use "./stuff.idea" -use "./misc.idea"` -] - -export default function Use() { - return ( -
    -

    Use

    -

    - The use directive imports definitions from other .idea files, enabling modular schema organization and reusability. When importing, data types with the same name are automatically merged unless the ! (non-mergeable) indicator is used. -

    -

    Syntax

    - - {useExamples[0]} - - -

    Structure

    -
      -
    • Path: Relative or absolute path to the .idea file to import
    • -
    • Automatic Merging: Data types with matching names are merged by default
    • -
    • Merge Prevention: Use ! suffix to prevent merging
    • -
    - -

    Example

    -

    shared/common.idea

    - - {useExamples[1]} - - -

    user/user-schema.idea:

    - - {useExamples[2]} - - -

    Result after merging:

    - - {useExamples[3]} - - - Prevent merging with ! -

    - When you want to prevent automatic merging and keep definitions separate, use the ! suffix: -

    - - base-schema.idea: - - {useExamples[4]} - - - extended-schema.idea: - - {useExamples[5]} - - -

    Use Cases

    -
      -
    • Shared Types: Define common types once and reuse across multiple schemas
    • -
    • Modular Organization: Split large schemas into manageable, focused files
    • -
    • Team Collaboration: Different teams can work on separate schema files
    • -
    • Environment-Specific: Override certain definitions for different environments
    • -
    - -

    Best Practices

    - - {useExamples[6]} - -
    - ) -} diff --git a/packages/www/plugins/docs/views/specifications/data-types.tsx b/packages/www/plugins/docs/views/specifications/data-types.tsx index 77aab05..9a8bdc2 100644 --- a/packages/www/plugins/docs/views/specifications/data-types.tsx +++ b/packages/www/plugins/docs/views/specifications/data-types.tsx @@ -3,14 +3,14 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, P, Nav } from '../../components/index.js'; import Layout from '../../components/Layout.js'; -import Models from './components/data-types/Models.js'; -import Type from './components/data-types/Type.js'; -import Props from './components/data-types/Props.js'; -import Enums from './components/data-types/Enums.js'; +import Models from '../../components/specifications/data-types/Models.js'; +import Type from '../../components/specifications/data-types/Type.js'; +import Props from '../../components/specifications/data-types/Props.js'; +import Enums from '../../components/specifications/data-types/Enums.js'; export function Head(props: ServerPageProps) { //props @@ -20,7 +20,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('Data Types'); const description = _( - 'The .idea format supports four primary data types that form the building blocks of your application schema.' + 'The .idea format supports four primary data types that form ' + + 'the building blocks of your application schema.' ); return ( <> @@ -38,7 +39,12 @@ export function Head(props: ServerPageProps) { {styles.map((href, index) => ( - + ))} ) @@ -47,47 +53,74 @@ export function Head(props: ServerPageProps) { export function Right() { const { _ } = useLanguage(); return ( - + + ); } export function Body() { + const { _ } = useLanguage(); + return (
    -

    Data Types

    -

    The .idea format supports four primary data types that form the building blocks of your application schema.

    - - -
    - -
    - -
    - +
    +

    {_('Data Types')}

    +

    + + The .idea format supports four primary data types that form + the building blocks of your application schema. + +

    +
    -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/error-handling.tsx b/packages/www/plugins/docs/views/specifications/error-handling.tsx index d28088c..a9410e7 100644 --- a/packages/www/plugins/docs/views/specifications/error-handling.tsx +++ b/packages/www/plugins/docs/views/specifications/error-handling.tsx @@ -3,45 +3,13 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useState } from 'react'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, H, Nav, SS } from '../../components/index.js'; +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Error Handling'); - const description = _( - 'Error handling is a crucial aspect of any application. The .idea file format provides a way to handle errors in a structured way.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - -const errors = [ +const errorsExamples = [ `// ❌ Invalid - missing quotes around enum values enum Status { ACTIVE Active @@ -103,8 +71,7 @@ model User { active Boolean @default(true) name String @minLength(2) @maxLength(50) }` - -] +]; const errorPrevention = [ `import type { PluginProps, SchemaConfig } from '@stackpress/idea-transformer/types'; @@ -125,7 +92,7 @@ export default async function myPlugin(props: PluginProps<{}>) { } } }`, -`// Always validate required fields + `// Always validate required fields model User { id String @id @required email String @required @unique @@ -138,7 +105,7 @@ model Product { active Boolean // Not Number created Date @default("now()") // Not String }`, -`// Consistent ID patterns + `// Consistent ID patterns model User { id String @id @default("nanoid()") } @@ -152,7 +119,7 @@ model User { created Date @default("now()") updated Date @default("updated()") }`, -`# Parse schema to check for errors + `# Parse schema to check for errors npm run idea:parse schema.idea # Transform schema to validate plugins @@ -160,81 +127,214 @@ npm run idea:transform schema.idea # Generate output to verify results npm run idea:generate` -] +]; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Error Handling'); + const description = _( + 'Error handling is a crucial aspect of any application. The ' + + '.idea file format provides a way to handle errors in a ' + + 'structured way.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} export function Body() { + const { _ } = useLanguage(); + return (
    -

    Error Handling

    -

    Common Errors and Solutions

    -

    1. Invalid Schema Structure

    -

    Error: Invalid Schema

    -

    Cause: Syntax errors or malformed declarations

    -

    Solution:

    - - {errors[0]} - - -

    2. Missing Required Properties

    -

    Error: Expecting a columns property

    -

    Cause: Models and types must have column definitions

    -

    Solution:

    - - {errors[1]} - - -

    3. Duplicate Declarations

    -

    Error: Duplicate [name]

    -

    Cause: Models and types must have column definitions

    -

    Solution: Multiple declarations with the same name

    - - {errors[2]} - - - -

    4. Unknown References

    -

    Error: Unknown reference [name]

    -

    Cause: Referencing undefined props, types, or enums

    -

    Solution:

    - - {errors[3]} - - -

    5. Type Mismatches

    -

    Error: Type mismatch

    -

    Cause: Using incompatible types or attributes

    -

    Solution:

    - - {errors[4]} - - -

    Error Prevention

    -

    1. Use TypeScript for Plugin Development

    - - {errorPrevention[0]} - - -

    2. Validate Schema Before Processing

    - - {errorPrevention[1]} - - -

    3. Use Consistent Patterns

    - - {errorPrevention[2]} - - -

    4. Test Schema Changes

    - - {errorPrevention[3]} - - -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/plugin-system.tsx b/packages/www/plugins/docs/views/specifications/plugin-system.tsx index 04074a1..ebe143b 100644 --- a/packages/www/plugins/docs/views/specifications/plugin-system.tsx +++ b/packages/www/plugins/docs/views/specifications/plugin-system.tsx @@ -3,13 +3,36 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import { H1, H2, P, C, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; +const pluginDeclaration = [ + `plugin "./path/to/plugin.js" { + output "./generated/output.ts" + format "typescript" + options { + strict true + comments true + } +}`, + `import type { PluginProps } from '@stackpress/idea-transformer/types'; + +export default async function myPlugin(props: PluginProps<{}>) { + const { config, schema, transformer } = props; + + // Process schema and generate output + const content = generateFromSchema(schema); + + // Write to configured output path + const outputPath = await transformer.loader.absolute(config.output); + await writeFile(outputPath, content); +}` +]; + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -18,7 +41,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('Plugin System'); const description = _( - 'The plugin system enables extensible code generation from your schema definitions.' + 'The plugin system enables extensible code generation from ' + + 'your schema definitions.' ); return ( <> @@ -35,93 +59,103 @@ export function Head(props: ServerPageProps) { {styles.map((href, index) => ( - + ))} ) } -const pluginDeclaration = [ - `plugin "./path/to/plugin.js" { - output "./generated/output.ts" - format "typescript" - options { - strict true - comments true - } -}`, - `import type { PluginProps } from '@stackpress/idea-transformer/types'; - -export default async function myPlugin(props: PluginProps<{}>) { - const { config, schema, transformer } = props; - - // Process schema and generate output - const content = generateFromSchema(schema); - - // Write to configured output path - const outputPath = await transformer.loader.absolute(config.output); - await writeFile(outputPath, content); -}` -] - export function Body() { + const { _ } = useLanguage(); + return (
    -

    Plugin System

    -

    The plugin system enables extensible code generation from your schema definitions.

    - -

    Plugin Declaration

    - - {pluginDeclaration[0]} - +
    +

    {_('Plugin System')}

    +

    + + The plugin system enables extensible code generation from + your schema definitions. + +

    +
    -

    Common Plugin Types

    - - Plugin Type - Purpose - Output - - TypeScript Generator - Generate interfaces and types - .ts files - - - Database Schema - Generate SQL DDL - .sql files - - - API Documentation - Generate OpenAPI Specs - .json/.yaml files - - - Form Generator - Generate HTML Forms - .html files - - - Validation Schema - Generate Zod/Joi schemas - .ts files - - - Mock Data - Generate test fixtures - .json files - -
    +
    +

    {_('Plugin Declaration')}

    + + {pluginDeclaration[0]} + -

    Plugin Development

    +

    {_('Common Plugin Types')}

    + + + Plugin Type + Purpose + Output + + + TypeScript Generator + Generate interfaces and types + .ts files + + + Database Schema + Generate SQL DDL + .sql files + + + API Documentation + Generate OpenAPI Specs + .json/.yaml files + + + Form Generator + Generate HTML Forms + .html files + + + Validation Schema + Generate Zod/Joi schemas + .ts files + + + Mock Data + Generate test fixtures + .json files + +
    - - {pluginDeclaration[1]} - +

    {_('Plugin Development')}

    + + {pluginDeclaration[1]} + +
    -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/processing-flow.tsx b/packages/www/plugins/docs/views/specifications/processing-flow.tsx index 32b2a76..45fcee8 100644 --- a/packages/www/plugins/docs/views/specifications/processing-flow.tsx +++ b/packages/www/plugins/docs/views/specifications/processing-flow.tsx @@ -1,54 +1,17 @@ //modules import type { - ServerConfigProps, - ServerPageProps - } from 'stackpress/view/client'; - import { useState } from 'react'; - import { useLanguage } from 'stackpress/view/client'; - //docs - import { H1, H2, P, C, H, Nav, SS } from '../../components/index.js'; - import Code from '../../components/Code.js'; - import Layout from '../../components/Layout.js'; - - - export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Processing Flow'); - const description = _( - 'The .idea file format follows a structured processing flow:' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) - } - - export function Body() { - return ( -
    -

    Processing Flow

    -

    The .idea file format follows a structured processing flow:

    - - {`┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ + ServerConfigProps, + ServerPageProps +} from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; +//docs +import { H1, H2, P, C, Nav, SS } from '../../components/index.js'; +import Code from '../../components/Code.js'; +import Layout from '../../components/Layout.js'; + + +const processingFlowDiagram = ` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ .idea File │───▶│ Parser │───▶│ AST (JSON) │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ @@ -69,37 +32,132 @@ import type { ┌─────────────────┐ │ Generated Code │ │ │ - └─────────────────┘`} + └─────────────────┘ +` + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Processing Flow'); + const description = _( + 'The .idea file format follows a structured processing ' + + 'flow:' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Processing Flow')}

    +

    + + The .idea file format follows a structured + processing flow: + +

    +
    + +
    + + {processingFlowDiagram} -

    Processing Steps

    +

    {_('Processing Steps')}

      -
    1. Parsing: Convert .idea syntax into Abstract Syntax Tree (AST)
    2. -
    3. Validation: Check for syntax errors, type consistency, and constraint violations
    4. -
    5. Transformation: Convert AST into structured JSON configuration
    6. -
    7. Plugin Execution: Run configured plugins to generate output files
    8. -
    9. Code Generation: Create TypeScript, SQL, documentation, forms, etc.
    10. +
    11. + {_('Parsing:')} + + Convert .idea syntax into Abstract Syntax Tree (AST) + +
    12. +
    13. + {_('Validation:')} + + Check for syntax errors, type consistency, and constraint + violations + +
    14. +
    15. + {_('Transformation:')} + + Convert AST into structured JSON configuration + +
    16. +
    17. + {_('Plugin Execution:')} + + Run configured plugins to generate output files + +
    18. +
    19. + {_('Code Generation:')} + + Create TypeScript, SQL, documentation, forms, etc. + +
    +
    +
    - ); - } - - export default function Page(props: ServerPageProps) { - const { data, session, request, response } = props; - return ( - - - - ); - } - \ No newline at end of file + +
    + ); +} + +export default function Page(props: ServerPageProps) { + const { data, session, request, response } = props; + return ( + + + + ); +} diff --git a/packages/www/plugins/docs/views/specifications/schema-directives.tsx b/packages/www/plugins/docs/views/specifications/schema-directives.tsx index c6978e8..197b4bc 100644 --- a/packages/www/plugins/docs/views/specifications/schema-directives.tsx +++ b/packages/www/plugins/docs/views/specifications/schema-directives.tsx @@ -3,12 +3,12 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, H, Nav } from '../../components/index.js'; +import { H1, P, Nav } from '../../components/index.js'; import Layout from '../../components/Layout.js'; -import Use from './components/schema-directives/Use.js'; -import Plugin from './components/schema-directives/Plugin.js'; +import Use from '../../components/specifications/schema-directives/Use.js'; +import Plugin from '../../components/specifications/schema-directives/Plugin.js'; export function Head(props: ServerPageProps) { //props @@ -18,7 +18,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('Schema Directives'); const description = _( - 'Schema directives are special declarations that control how the schema is processed and what outputs are generated.' + 'Schema directives are special declarations that control how ' + + 'the schema is processed and what outputs are generated.' ); return ( <> @@ -35,7 +36,12 @@ export function Head(props: ServerPageProps) { {styles.map((href, index) => ( - + ))} ) @@ -44,37 +50,60 @@ export function Head(props: ServerPageProps) { export function Right() { const { _ } = useLanguage(); return ( - + + ); } export function Body() { + const { _ } = useLanguage(); + return (
    -

    Schema Directives

    -

    - Schema directives are special declarations that control how the schema is processed and what outputs are generated. -

    +
    +

    {_('Schema Directives')}

    +

    + + Schema directives are special declarations that control how + the schema is processed and what outputs are generated. + +

    +
    - - +
    + + +
    -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/schema-elements.tsx b/packages/www/plugins/docs/views/specifications/schema-elements.tsx index 6f5b4d9..ce53cd8 100644 --- a/packages/www/plugins/docs/views/specifications/schema-elements.tsx +++ b/packages/www/plugins/docs/views/specifications/schema-elements.tsx @@ -3,9 +3,9 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, H, Nav, SS } from '../../components/index.js'; +import { H1, H2, P, C, H, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; @@ -36,7 +36,12 @@ export function Head(props: ServerPageProps) { {styles.map((href, index) => ( - + ))} ) @@ -123,99 +128,150 @@ type Address @serializable @cacheable(3600) { ] export function Body() { + const { _ } = useLanguage(); + return (
    -

    Schema Elements

    -

    Attributes (@)

    -

    - Attributes provide metadata and configuration for columns, types, and models. They define validation rules, UI components, relationships, and behavior. Attributes can be attached to any schema element and are processed by plugins according to their specific needs. -

    - - - Note: - There are no reserved or pre-defined attributes in idea. You can define any arbitrary attributes in your schema. It's up to the plugins to recognize and process them. - - -

    Attribute Syntax

    -

    - Attributes always start with the at symbol (@) followed by letters, numbers, and periods. They can be expressed in several forms: -

    - - {examples[0]} - - -

    Attribute Value Types

    -

    Attributes can hold different types of values:

    - - {examples[1]} - - -

    Attribute Scope

    -

    Attributes can be applied to different schema elements:

    - - {examples[2]} - - -

    Columns

    -

    - Columns define the individual fields within models and types, specifying their data type, constraints, and behavior. -

    - - - Types - Description - Example - - String - Text data - name String - - - Number - Numeric data - age Number - - - Boolean - True or false values - active Boolean - - - Date - Date/time values - created Date - - - JSON - JSON Objects - metadata JSON - - - CustomType - User-defined types - address Address - - - EnumType - Enum values - role UserRole - -
    - -

    Optional and Array Types

    - - {examples[3]} - - -

    Nested Types

    - - {examples[4]} - - -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/schema-structure.tsx b/packages/www/plugins/docs/views/specifications/schema-structure.tsx index 41a0d9c..47e71d9 100644 --- a/packages/www/plugins/docs/views/specifications/schema-structure.tsx +++ b/packages/www/plugins/docs/views/specifications/schema-structure.tsx @@ -3,50 +3,13 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs import { H1, P, C, Nav } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; -export function Head(props: ServerPageProps) { - //props - const { request, styles = [] } = props; - //hooks - const { _ } = useLanguage(); - //variables - const title = _('Schema Structure'); - const description = _( - 'A complete .idea schema file can contain multiple elements organized in a specific structure.' - ); - return ( - <> - {title} - - - - - - - - - - - - {styles.map((href, index) => ( - - ))} - - ) -} - -export function Body() { - return ( -
    -

    Schema Structure

    -

    A complete .idea schema file can contain multiple elements organized in a specific structure:

    - - {`// 1. Plugin declarations +const schemaExample = `// 1. Plugin declarations plugin "./plugins/generate-types.js" { output "./generated/types.ts" } @@ -93,13 +56,82 @@ model User! { address Address? active Boolean @default(true) created Date @default("now()") -}`} - +}`; + +export function Head(props: ServerPageProps) { + //props + const { request, styles = [] } = props; + //hooks + const { _ } = useLanguage(); + //variables + const title = _('Schema Structure'); + const description = _( + 'A complete .idea schema file can contain multiple elements ' + + 'organized in a specific structure.' + ); + return ( + <> + {title} + + + + + + + + + + + + {styles.map((href, index) => ( + + ))} + + ) +} + +export function Body() { + const { _ } = useLanguage(); + + return ( +
    +
    +

    {_('Schema Structure')}

    +

    + + A complete .idea schema file can contain multiple + elements organized in a specific structure: + +

    +
    + +
    + + {schemaExample} + +
    -
    ); } diff --git a/packages/www/plugins/docs/views/specifications/syntax-overview.tsx b/packages/www/plugins/docs/views/specifications/syntax-overview.tsx index 21b6355..879a1b0 100644 --- a/packages/www/plugins/docs/views/specifications/syntax-overview.tsx +++ b/packages/www/plugins/docs/views/specifications/syntax-overview.tsx @@ -3,9 +3,9 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, P, C, H, Nav, SS } from '../../components/index.js'; +import { H1, H2, P, Nav, SS } from '../../components/index.js'; import Code from '../../components/Code.js'; import Layout from '../../components/Layout.js'; @@ -17,7 +17,11 @@ export function Head(props: ServerPageProps) { //variables const title = _('Syntax Overview'); const description = _( - 'The .idea file format uses a simplified syntax that eliminates the need for traditional separators like commas (,) and colons (:) found in JSON or JavaScript. The parser can logically determine separations, making the syntax cleaner and more readable.' + 'The .idea file format uses a simplified syntax that eliminates ' + + 'the need for traditional separators like commas (,) and ' + + 'colons (:) found in JSON or JavaScript. The parser can ' + + 'logically determine separations, making the syntax cleaner ' + + 'and more readable.' ); return ( <> @@ -35,7 +39,12 @@ export function Head(props: ServerPageProps) { {styles.map((href, index) => ( - + ))} ) @@ -114,48 +123,106 @@ model User { ] export function Body() { + const { _ } = useLanguage(); + return (
    -

    Syntax Overview

    -

    - The .idea file format uses a simplified syntax that eliminates the need for traditional separators like commas (,) and colons (:) found in JSON or JavaScript. The parser can logically determine separations, making the syntax cleaner and more readable. -

    - -

    Key Syntax Rules

    -
      -
    • No Separators Required: The parser intelligently determines where values begin and end
    • -
    • Double Quotes Only: All strings must use double quotes (") - single quotes are not supported
    • -
    • Context Awareness: The parser understands context and can differentiate between keys, values, and nested structures
    • -
    - -

    Syntax Comparison

    -

    Traditional JavaScript/JSON:

    - - {examples[0]} - - -

    Equivalent .idea syntax:

    - - {examples[1]} - - -

    Data Types Representations

    - - {examples[2]} - - -

    Comments

    -

    Comments in .idea files use the standard // syntax:

    - - {examples[3]} - - -
    ); } diff --git a/packages/www/plugins/docs/views/transformers/api-reference.tsx b/packages/www/plugins/docs/views/transformers/api-reference.tsx index 87abd98..cc70ab1 100644 --- a/packages/www/plugins/docs/views/transformers/api-reference.tsx +++ b/packages/www/plugins/docs/views/transformers/api-reference.tsx @@ -3,10 +3,9 @@ import type { ServerConfigProps, ServerPageProps } from 'stackpress/view/client'; -import { useLanguage } from 'stackpress/view/client'; +import { useLanguage, Translate } from 'r22n'; //docs -import { H1, H2, H3, P, C, Nav, SS } from '../../components/index.js'; -import Code from '../../components/Code.js'; +import { H1, H2, P, C, Nav } from '../../components/index.js'; import Layout from '../../components/Layout.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; @@ -18,7 +17,8 @@ export function Head(props: ServerPageProps) { //variables const title = _('API Reference'); const description = _( - 'Detailed documentation for all components and interfaces in the idea-transformer library' + 'Detailed documentation for all components and interfaces in the ' + + 'idea-transformer library' ); return ( <> @@ -48,12 +48,18 @@ export function Right() {
    {_('API Reference')}
    -
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/app/components/landing-page/PluginEcosystemSection.tsx b/packages/www/plugins/app/components/landing-page/PluginEcosystemSection.tsx index cedb499..a4192e7 100644 --- a/packages/www/plugins/app/components/landing-page/PluginEcosystemSection.tsx +++ b/packages/www/plugins/app/components/landing-page/PluginEcosystemSection.tsx @@ -1,185 +1,190 @@ +//modules import { Translate, useLanguage } from 'r22n'; export default function PluginEcosystemSection() { + //hooks const { _ } = useLanguage(); - + return ( -
    -

    - {_('The Plugin Ecosystem')} -

    - -

    - - The true power of .idea - lies in its plugin system — a bridge from simple schema - definitions to full‑stack applications. - -

    - -
    -
    -
    - - - -

    - {_('Multi‑Language Support')} -

    + <> + {/* Plugin Ecosystem Section Content */} +
    +

    + {_('The Plugin Ecosystem')} +

    + +

    + + The true power of .idea + lies in its plugin system — a bridge from simple schema + definitions to full‑stack applications. + +

    + +
    +
    +
    + + + +

    + {_('Multi‑Language Support')} +

    +
    +
      +
    • + + TypeScript/JavaScript: Interfaces, types, validation + +
    • +
    • + + Python: Dataclasses, Pydantic, SQLAlchemy + +
    • +
    • + + Rust: Structs, enums, serde + +
    • +
    • + + Go: Structs, JSON tags, validation + +
    • +
    • + + Java: POJOs, JPA, annotations + +
    • +
    • + + C#: Classes, EF models + +
    • +
    • + + PHP: Classes, Eloquent, validation + +
    • +
    • + + …and more + +
    • +
    -
      -
    • - - TypeScript/JavaScript: Interfaces, types, validation - -
    • -
    • - - Python: Dataclasses, Pydantic, SQLAlchemy - -
    • -
    • - - Rust: Structs, enums, serde - -
    • -
    • - - Go: Structs, JSON tags, validation - -
    • -
    • - - Java: POJOs, JPA, annotations - -
    • -
    • - - C#: Classes, EF models - -
    • -
    • - - PHP: Classes, Eloquent, validation - -
    • -
    • - - …and more - -
    • -
    -
    - -
    -
    - - - -

    - {_('Framework Integration')} -

    + +
    +
    + + + +

    + {_('Framework Integration')} +

    +
    +
      +
    • + + React, Vue, Angular, Svelte + +
    • +
    • + + Next.js, Express, FastAPI, Django + +
    • +
    • + + Components, routes, models, middleware + +
    • +
    -
      -
    • - - React, Vue, Angular, Svelte - -
    • -
    • - - Next.js, Express, FastAPI, Django - -
    • -
    • - - Components, routes, models, middleware - -
    • -
    -
    - -
    -
    - - - -

    - {_('Database Support')} -

    + +
    +
    + + + +

    + {_('Database Support')} +

    +
    +
      +
    • + + SQL: Postgres, MySQL, SQLite, SQL Server + +
    • +
    • + + NoSQL: MongoDB, DynamoDB, Firestore + +
    • +
    • + + Graph: Neo4j, ArangoDB + +
    • +
    • + + Time‑series: InfluxDB, TimescaleDB + +
    • +
    • + + Search: Elasticsearch, Solr + +
    • +
    -
      -
    • - - SQL: Postgres, MySQL, SQLite, SQL Server - -
    • -
    • - - NoSQL: MongoDB, DynamoDB, Firestore - -
    • -
    • - - Graph: Neo4j, ArangoDB - -
    • -
    • - - Time‑series: InfluxDB, TimescaleDB - -
    • -
    • - - Search: Elasticsearch, Solr - -
    • -
    -
    - -
    -
    - - - -

    - {_('Documentation & Tools')} -

    + +
    +
    + + + +

    + {_('Documentation & Tools')} +

    +
    +
      +
    • + + OpenAPI/Swagger specs + +
    • +
    • + + Schema diagrams & table docs + +
    • +
    • + + Form generators with validation + +
    • +
    • + + Mock data & fixtures + +
    • +
    • + + Migration scripts + +
    • +
    • + + Environment & CI/CD configs + +
    • +
    -
      -
    • - - OpenAPI/Swagger specs - -
    • -
    • - - Schema diagrams & table docs - -
    • -
    • - - Form generators with validation - -
    • -
    • - - Mock data & fixtures - -
    • -
    • - - Migration scripts - -
    • -
    • - - Environment & CI/CD configs - -
    • -
    -
    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/app/components/landing-page/RealWorldExampleSection.tsx b/packages/www/plugins/app/components/landing-page/RealWorldExampleSection.tsx index 0be6d37..9ac9f85 100644 --- a/packages/www/plugins/app/components/landing-page/RealWorldExampleSection.tsx +++ b/packages/www/plugins/app/components/landing-page/RealWorldExampleSection.tsx @@ -1,7 +1,12 @@ +//modules import Code from 'frui/format/Code'; import { Translate, useLanguage } from 'r22n'; -const exampleSchema = `enum UserRole { +//code example +//---------------------------------------------------------------------- + +const exampleSchema = + `enum UserRole { ADMIN "Administrator" CUSTOMER "Customer" VENDOR "Vendor" @@ -63,84 +68,90 @@ plugin "./plugins/api-generator.js" { includeValidation true }`; +//---------------------------------------------------------------------- + export default function RealWorldExampleSection() { + //hooks const { _ } = useLanguage(); - + return ( -
    -
    -
    -

    - {_('Real-World Example')} -

    - -

    - - See how a simple e‑commerce schema can generate a full-stack - application: - -

    - -
    - - {exampleSchema} - + <> + {/* Real-World Example Section Content */} +
    +
    +
    +

    + {_('Real-World Example')} +

    + +

    + + See how a simple e‑commerce schema can generate a full-stack + application: + +

    + +
    + + {exampleSchema} + +
    -
    - -
    -
    +
    -

    - {_('From this single schema, generate:')} -

    - -
      -
    • - - TypeScript interfaces and types - -
    • -
    • - - PostgreSQL database schema - -
    • -
    • - - React form components with Tailwind CSS - -
    • -
    • - - Express.js API routes with validation - -
    • -
    • - - OpenAPI documentation - -
    • -
    • - - Test data and fixtures - -
    • -
    • - - Database migration files - -
    • -
    • - - Validation schemas (Zod, Joi, etc.) - -
    • -
    +

    + {_('From this single schema, generate:')} +

    + +
      +
    • + + TypeScript interfaces and types + +
    • +
    • + + PostgreSQL database schema + +
    • +
    • + + React form components with Tailwind CSS + +
    • +
    • + + Express.js API routes with validation + +
    • +
    • + + OpenAPI documentation + +
    • +
    • + + Test data and fixtures + +
    • +
    • + + Database migration files + +
    • +
    • + + Validation schemas (Zod, Joi, etc.) + +
    • +
    +
    +
    - -
    -
    + + ) } \ No newline at end of file diff --git a/packages/www/plugins/app/components/landing-page/index.tsx b/packages/www/plugins/app/components/landing-page/index.tsx index 85c54ff..9bcbbb7 100644 --- a/packages/www/plugins/app/components/landing-page/index.tsx +++ b/packages/www/plugins/app/components/landing-page/index.tsx @@ -1,3 +1,4 @@ +//exporting all landing page sections from a single file for easier imports export { default as HeroSection } from './HeroSection.js'; export { default as AboutSection } from './AboutSection.js'; export { default as BenefitsSection } from './BenefitsSection.js'; diff --git a/packages/www/plugins/app/views/home.tsx b/packages/www/plugins/app/views/home.tsx index eb0f00f..afab36d 100644 --- a/packages/www/plugins/app/views/home.tsx +++ b/packages/www/plugins/app/views/home.tsx @@ -4,7 +4,7 @@ import { ToastContainer } from 'react-toastify'; //stackpress import type { ServerPageProps } from 'stackpress/view/client'; import Layout from '../Layout.js'; -//components +//multiple section components import { HeroSection, AboutSection, @@ -38,20 +38,37 @@ export default function HomePage(props: ServerPageProps) {
    + {/* Hero Sections */} + + {/* About Section */} + + {/* Benefits Section */} + + {/* Wrap the section with a background */}
    + + {/* Plugin Ecosystem Section */} + + {/* Wrap the section with a background */}
    + + {/* AI Development Workflow Section */} + + {/* Wrap the section with a background */}
    + + {/* Toast Container for notifications */}
    diff --git a/packages/www/plugins/docs/components/api-client-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/api-client-plugin/AdvancedFeatures.tsx index 520e9b5..706d2e6 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/AdvancedFeatures.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const authenticationStrategies = `// Bearer token authentication +//code examples +//---------------------------------------------------------------------- + +const authenticationStrategies = +`// Bearer token authentication authentication: { type: "bearer", headerName: "Authorization" @@ -24,9 +30,12 @@ authentication: { authentication: { type: "custom", headerName: "X-Custom-Auth" -}`; +}` + +//---------------------------------------------------------------------- -const errorHandlingStrategies = `// Return errors in response (default) +const errorHandlingStrategies = +`// Return errors in response (default) errorHandling: "return" const response = await client.user.getById('123'); if (!response.success) { @@ -45,32 +54,42 @@ try { errorHandling: "callback" const response = await client.user.getById('123', { onError: (error) => console.error(error) -});`; +});` -const requestCancellation = `// Using AbortController for request cancellation +//---------------------------------------------------------------------- + +const requestCancellation = +`// Using AbortController for request cancellation const controller = new AbortController(); const response = await client.user.getAll({}, { signal: controller.signal }); + +controller.abort();` -// Cancel the request -controller.abort();`; +//---------------------------------------------------------------------- -const customHeaders = `// Add custom headers to requests +const customHeaders = +`// Add custom headers to requests const response = await client.user.getById('123', { headers: { 'X-Custom-Header': 'value', 'Accept-Language': 'en-US' } -});`; +});` + +//---------------------------------------------------------------------- export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('7. Advanced Features')}

    + <> + {/* Advanced Features Section Content */} +
    +

    {_('7. Advanced Features')}

    Advanced features extend the basic API client functionality with @@ -81,12 +100,12 @@ export default function AdvancedFeatures() {

    -

    {_('7.1. Authentication Strategies')}

    +

    {_('7.1. Authentication Strategies')}

    {authenticationStrategies} -

    {_('7.2. Error Handling Strategies')}

    +

    {_('7.2. Error Handling Strategies')}

    Error handling strategies determine how the API client responds to @@ -100,7 +119,7 @@ export default function AdvancedFeatures() { {errorHandlingStrategies} -

    {_('7.3. Request Cancellation')}

    +

    {_('7.3. Request Cancellation')}

    Request cancellation allows you to abort ongoing API requests when @@ -114,7 +133,7 @@ export default function AdvancedFeatures() { {requestCancellation} -

    {_('7.4. Custom Headers')}

    +

    {_('7.4. Custom Headers')}

    Custom headers allow you to add additional metadata to requests, @@ -126,6 +145,7 @@ export default function AdvancedFeatures() { {customHeaders} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/api-client-plugin/BestPractices.tsx index c3dc2bb..ef039db 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/BestPractices.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const typeSafety = `// Always use generated types +//code examples +//---------------------------------------------------------------------- + +const typeSafety = +`// Always use generated types interface UserWithPosts extends User { posts: Post[]; } @@ -16,9 +22,12 @@ function handleUserResponse(response: APIResponse) { // TypeScript knows response.error exists console.error(response.error); } -}`; +}` + +//---------------------------------------------------------------------- -const errorHandlingPattern = `// Centralized error handling +const errorHandlingPattern = +`// Centralized error handling class APIErrorHandler { static handle(response: APIResponse) { if (!response.success) { @@ -37,9 +46,12 @@ class APIErrorHandler { // Usage const response = await client.user.create(userData); -APIErrorHandler.handle(response);`; +APIErrorHandler.handle(response);` + +//---------------------------------------------------------------------- -const clientExtension = `// Extend base client for custom behavior +const clientExtension = +`// Extend base client for custom behavior class CustomAPIClient extends APIClient { constructor(baseUrl?: string) { super(baseUrl); @@ -54,9 +66,12 @@ class CustomAPIClient extends APIClient { return originalRequest.call(this, method, url, data, options); }; } -}`; +}` -const cachingPattern = `// Simple in-memory cache +//---------------------------------------------------------------------- + +const cachingPattern = +`// Simple in-memory cache class CachedAPIClient extends APIClient { private cache = new Map(); private cacheTimeout = 5 * 60 * 1000; // 5 minutes @@ -79,14 +94,19 @@ class CachedAPIClient extends APIClient { return response; } -}`; +}` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('8. Best Practices')}

    + <> + {/* Best Practices Section Content */} +
    +

    {_('8. Best Practices')}

    Following best practices ensures your API client is maintainable, @@ -96,7 +116,7 @@ export default function BestPractices() {

    -

    {_('8.1. Type Safety')}

    +

    {_('8.1. Type Safety')}

    Leverage TypeScript's type system to catch errors at compile time @@ -108,7 +128,7 @@ export default function BestPractices() { {typeSafety} -

    {_('8.2. Error Handling')}

    +

    {_('8.2. Error Handling')}

    Implement consistent error handling patterns across your @@ -120,7 +140,7 @@ export default function BestPractices() { {errorHandlingPattern} -

    {_('8.3. Client Extension')}

    +

    {_('8.3. Client Extension')}

    Extend the generated client for custom functionality while @@ -132,7 +152,7 @@ export default function BestPractices() { {clientExtension} -

    {_('8.4. Caching Strategies')}

    +

    {_('8.4. Caching Strategies')}

    Implement appropriate caching strategies to improve performance and @@ -143,6 +163,7 @@ export default function BestPractices() { {cachingPattern} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/Implementation.tsx b/packages/www/plugins/docs/components/api-client-plugin/Implementation.tsx index b74371f..bbc8be8 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/Implementation.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/Implementation.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const corePluginFunction = `export default async function generateAPIClient( +//code examples +//---------------------------------------------------------------------- + +const corePluginFunction = +`export default async function generateAPIClient( props: PluginProps<{ config: APIClientConfig }> ) { const { config, schema, transformer } = props; @@ -51,9 +57,12 @@ const corePluginFunction = `export default async function generateAPIClient( console.error('❌ API client generation failed:', error.message); throw error; } -}`; +}` + +//---------------------------------------------------------------------- -const headerAndImports = `function generateFileHeader(config: APIClientConfig): string { +const headerAndImports = +`function generateFileHeader(config: APIClientConfig): string { const timestamp = new Date().toISOString(); return \`/** * Generated API Client @@ -101,9 +110,12 @@ interface RequestOptions { \`; return imports; -}`; +}` + +//---------------------------------------------------------------------- -const typeGeneration = `function generateTypes(schema: any, config: APIClientConfig): string { +const typeGeneration = +`function generateTypes(schema: any, config: APIClientConfig): string { let content = '// Generated Types\\n'; // Generate enums @@ -145,9 +157,12 @@ const typeGeneration = `function generateTypes(schema: any, config: APIClientCon } return content; -}`; +}` -const baseClientGeneration = `function generateBaseClient(config: APIClientConfig): string { +//---------------------------------------------------------------------- + +const baseClientGeneration = +`function generateBaseClient(config: APIClientConfig): string { const authType = config.authentication?.type || 'bearer'; const headerName = config.authentication?.headerName || 'Authorization'; @@ -177,9 +192,12 @@ export class BaseAPIClient { } \`; -}`; +}` + +//---------------------------------------------------------------------- -const restClientGeneration = `function generateRESTClients(models: Record, config: APIClientConfig): string { +const restClientGeneration = +`function generateRESTClients(models: Record, config: APIClientConfig): string { let content = '// REST API Clients\\n'; for (const [modelName, model] of Object.entries(models)) { @@ -231,14 +249,19 @@ export class \${modelName}Client extends BaseAPIClient { } return content; -}`; +}` + +//---------------------------------------------------------------------- export default function Implementation() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Implementation')}

    + <> + {/* Implementation Section Content */} +
    +

    {_('4. Implementation')}

    The implementation section covers the core plugin function and @@ -248,7 +271,7 @@ export default function Implementation() {

    -

    {_('4.1. Core Plugin Function')}

    +

    {_('4.1. Core Plugin Function')}

    The core plugin function serves as the main entry point for API @@ -261,7 +284,7 @@ export default function Implementation() { {corePluginFunction} -

    {_('4.2. Generation Functions')}

    +

    {_('4.2. Generation Functions')}

    The generation functions handle the creation of specific parts of @@ -283,6 +306,7 @@ export default function Implementation() { {restClientGeneration} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/Introduction.tsx b/packages/www/plugins/docs/components/api-client-plugin/Introduction.tsx index beb0967..e365630 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/Introduction.tsx @@ -1,11 +1,16 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* API Client Generator Plugin Tutorial */} +

    {_('API Client Generator Plugin Tutorial')}

    @@ -15,6 +20,7 @@ export default function Introduction() { libraries with full CRUD operations.

    -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/Overview.tsx b/packages/www/plugins/docs/components/api-client-plugin/Overview.tsx index 906bfc0..32eeb03 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('1. Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    API clients provide a convenient interface for interacting with @@ -34,6 +39,7 @@ export default function Overview() { Request cancellation and custom headers -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/api-client-plugin/PluginStructure.tsx index e5cf7b3..0dbc1fa 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/PluginStructure.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/PluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -26,14 +32,19 @@ export default async function generateAPIClient( const { config, schema, transformer } = props; // Implementation here... -}`; +}` + +//---------------------------------------------------------------------- export default function PluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Plugin Structure')}

    + <> + {/* Plugin Structure Section Content */} +
    +

    {_('3. Plugin Structure')}

    The plugin structure defines the core architecture and @@ -45,6 +56,7 @@ export default function PluginStructure() { {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/api-client-plugin/Prerequisites.tsx index 633bc6b..bdd0626 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('2. Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    Before implementing the API client generator plugin, ensure you @@ -32,6 +37,7 @@ export default function Prerequisites() { Understanding of plugin development patterns -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/api-client-plugin/SchemaConfiguration.tsx index ac440e6..b923afd 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/SchemaConfiguration.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/SchemaConfiguration.tsx @@ -1,9 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, SS } from '../index.js'; +//local +import { H1, H2, P, C, SS } from '../index.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; import Code from '../Code.js'; -const schemaConfigExample = `plugin "./plugins/api-client.js" { +//code examples +//---------------------------------------------------------------------- + +const schemaConfigExample = +`plugin "./plugins/api-client.js" { output "./generated/api-client.ts" clientType "rest" httpLibrary "fetch" @@ -15,14 +21,19 @@ const schemaConfigExample = `plugin "./plugins/api-client.js" { generateTypes true includeValidation false errorHandling "return" -}`; +}` + +//---------------------------------------------------------------------- export default function SchemaConfiguration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Schema Configuration')}

    + <> + {/* Schema Configuration Section Content */} +
    +

    {_('5. Schema Configuration')}

    Add the API Client plugin to your .idea schema file: @@ -32,7 +43,7 @@ export default function SchemaConfiguration() { {schemaConfigExample} -

    {_('Configuration Options')}

    +

    {_('Configuration Options')}

    @@ -106,6 +117,7 @@ export default function SchemaConfiguration() {
    -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/api-client-plugin/Troubleshooting.tsx index 2f6b855..98c00bb 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/Troubleshooting.tsx @@ -1,14 +1,23 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const corsIssues = `// Ensure your API server allows CORS +//code examples +//---------------------------------------------------------------------- + +const corsIssues = +`// Ensure your API server allows CORS // Add appropriate headers in your API configuration // For development, you might need to proxy requests -const client = new APIClient('/api/proxy');`; +const client = new APIClient('/api/proxy');` + +//---------------------------------------------------------------------- -const authenticationIssues = `// Check token format and expiration +const authenticationIssues = +`// Check token format and expiration function isTokenValid(token: string): boolean { try { const payload = JSON.parse(atob(token.split('.')[1])); @@ -19,9 +28,12 @@ function isTokenValid(token: string): boolean { } // Refresh token automatically -client.setAuthToken(await refreshToken());`; +client.setAuthToken(await refreshToken());` + +//---------------------------------------------------------------------- -const networkIssues = `// Implement retry logic +const networkIssues = +`// Implement retry logic async function withRetry( operation: () => Promise>, maxRetries: number = 3 @@ -39,32 +51,43 @@ async function withRetry( } throw new Error('Max retries exceeded'); -}`; +}` -const debuggingTips = `// Add to base client +//---------------------------------------------------------------------- + +const debuggingTips = +`// Add to base client private logRequest(method: string, url: string, data?: any) { if (process.env.NODE_ENV === 'development') { console.group(\`API \${method} \${url}\`); if (data) console.log('Data:', data); console.groupEnd(); } -}`; +}` + +//---------------------------------------------------------------------- -const responseValidation = `// Validate response structure +const responseValidation = +`// Validate response structure function validateResponse(response: any): response is APIResponse { return ( typeof response === 'object' && typeof response.success === 'boolean' && (response.success ? 'data' in response : 'error' in response) ); -}`; +}` + +//---------------------------------------------------------------------- export default function Troubleshooting() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('9. Troubleshooting')}

    + <> + {/* Troubleshooting Section Content */} +
    +

    {_('9. Troubleshooting')}

    This section covers common issues you might encounter when using the @@ -73,7 +96,7 @@ export default function Troubleshooting() {

    -

    {_('9.1. CORS Issues')}

    +

    {_('9.1. CORS Issues')}

    Cross-Origin Resource Sharing (CORS) issues are common when making @@ -86,7 +109,7 @@ export default function Troubleshooting() { {corsIssues} -

    {_('9.2. Authentication Problems')}

    +

    {_('9.2. Authentication Problems')}

    Authentication issues often stem from expired tokens, incorrect @@ -98,7 +121,7 @@ export default function Troubleshooting() { {authenticationIssues} -

    {_('9.3. Network Issues')}

    +

    {_('9.3. Network Issues')}

    Network connectivity problems require robust retry logic and proper @@ -110,7 +133,7 @@ export default function Troubleshooting() { {networkIssues} -

    {_('9.4. Debugging Tips')}

    +

    {_('9.4. Debugging Tips')}

    Enable comprehensive logging during development to track request @@ -122,7 +145,7 @@ export default function Troubleshooting() { {debuggingTips} -

    {_('9.5. Response Validation')}

    +

    {_('9.5. Response Validation')}

    Validate API responses to ensure they match expected formats. This @@ -133,6 +156,7 @@ export default function Troubleshooting() { {responseValidation} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/api-client-plugin/UsageExamples.tsx index 3f5a651..1e44729 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/UsageExamples.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/UsageExamples.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const basicSchemaExample = `enum UserRole { +//code examples +//---------------------------------------------------------------------- + +const basicSchemaExample = +`enum UserRole { ADMIN "admin" USER "user" GUEST "guest" @@ -32,9 +38,12 @@ plugin "./plugins/api-client.js" { httpLibrary "fetch" baseUrl "/api/v1" generateTypes true -}`; +}` + +//---------------------------------------------------------------------- -const generatedClientUsageExample = `import APIClient from './api-client'; +const generatedClientUsageExample = +`import APIClient from './api-client'; // Initialize client const client = new APIClient('https://api.example.com'); @@ -81,14 +90,19 @@ async function example() { // Delete user const deleteResponse = await client.user.delete('user-123'); -}`; +}` + +//---------------------------------------------------------------------- export default function UsageExamples() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('6. Usage Examples')}

    + <> + {/* Usage Examples Section Content */} +
    +

    {_('6. Usage Examples')}

    This section demonstrates practical usage of the API client @@ -98,7 +112,7 @@ export default function UsageExamples() {

    -

    {_('6.1. Basic Schema')}

    +

    {_('6.1. Basic Schema')}

    A basic schema example shows the fundamental structure needed to @@ -111,7 +125,7 @@ export default function UsageExamples() { {basicSchemaExample} -

    {_('6.2. Generated Client Usage')}

    +

    {_('6.2. Generated Client Usage')}

    The generated client provides a type-safe interface for interacting @@ -123,6 +137,7 @@ export default function UsageExamples() { {generatedClientUsageExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/api-client-plugin/index.tsx b/packages/www/plugins/docs/components/api-client-plugin/index.tsx index 890be10..0049239 100644 --- a/packages/www/plugins/docs/components/api-client-plugin/index.tsx +++ b/packages/www/plugins/docs/components/api-client-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/AdvancedFeatures.tsx index 81291dd..9c9da38 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/AdvancedFeatures.tsx @@ -1,15 +1,24 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, P, Code, H2 } from '../index.js'; -const customScalarTypesExample = `// In your plugin configuration +//code examples +//---------------------------------------------------------------------- + +const customScalarTypesExample = +`// In your plugin configuration customScalars: { Email: "String", URL: "String", PhoneNumber: "String", BigInt: "String" -}`; +}` + +//---------------------------------------------------------------------- -const relationshipHandlingExample = `function handleRelationships(column: any, models: Record): string { +const relationshipHandlingExample = +`function handleRelationships(column: any, models: Record): string { // Check if the column type is another model if (models[column.type]) { let type = column.type; @@ -26,9 +35,12 @@ const relationshipHandlingExample = `function handleRelationships(column: any, m } return formatFieldType(column); -}`; +}` -const directiveSupportExample = `function generateDirectives(column: any): string { +//---------------------------------------------------------------------- + +const directiveSupportExample = +`function generateDirectives(column: any): string { const directives: string[] = []; if (column.attributes?.unique) { @@ -40,14 +52,19 @@ const directiveSupportExample = `function generateDirectives(column: any): strin } return directives.length > 0 ? \` \${directives.join(' ')}\` : ''; -}`; +}` + +//---------------------------------------------------------------------- export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Advanced Features')}

    + <> + {/* Advanced Features Section Content */} +
    +

    {_('7. Advanced Features')}

    Advanced features extend the basic GraphQL schema generation with @@ -57,7 +74,7 @@ export default function AdvancedFeatures() {

    -

    {_('Custom Scalar Types')}

    +

    {_('Custom Scalar Types')}

    Custom scalar types allow you to define specialized data types that @@ -70,7 +87,7 @@ export default function AdvancedFeatures() { {customScalarTypesExample} -

    {_('Relationship Handling')}

    +

    {_('Relationship Handling')}

    Relationship handling manages references between different types and @@ -83,7 +100,7 @@ export default function AdvancedFeatures() { {relationshipHandlingExample} -

    {_('Directive Support')}

    +

    {_('Directive Support')}

    Directive support enables the addition of GraphQL directives to @@ -95,6 +112,7 @@ export default function AdvancedFeatures() { {directiveSupportExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/BestPractices.tsx index b0b98f9..c7c4eef 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/BestPractices.tsx @@ -1,7 +1,13 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, H2, P, Code } from '../index.js'; -const typeSafetyExample = `interface GraphQLColumn { +//code examples +//---------------------------------------------------------------------- + +const typeSafetyExample = +`interface GraphQLColumn { name: string; type: string; required: boolean; @@ -15,9 +21,12 @@ function validateColumn(column: any): column is GraphQLColumn { typeof column.type === 'string' && typeof column.required === 'boolean' ); -}`; +}` + +//---------------------------------------------------------------------- -const errorHandlingExample = `function generateTypes(models: Record): string { +const errorHandlingExample = +`function generateTypes(models: Record): string { try { let content = '# Types\\n'; @@ -34,9 +43,12 @@ const errorHandlingExample = `function generateTypes(models: Record } catch (error) { throw new Error(\`Failed to generate GraphQL types: \${error.message}\`); } -}`; +}` + +//---------------------------------------------------------------------- -const configurationValidationExample = `function validateConfig(config: any): asserts config is GraphQLConfig { +const configurationValidationExample = +`function validateConfig(config: any): asserts config is GraphQLConfig { if (!config.output || typeof config.output !== 'string') { throw new Error('GraphQL plugin requires "output" configuration as string'); } @@ -44,9 +56,12 @@ const configurationValidationExample = `function validateConfig(config: any): as if (config.customScalars && typeof config.customScalars !== 'object') { throw new Error('customScalars must be an object'); } -}`; +}` -const performanceOptimizationExample = `// Cache type mappings +//---------------------------------------------------------------------- + +const performanceOptimizationExample = +`// Cache type mappings const typeCache = new Map(); function getCachedType(schemaType: string, customScalars: Record): string { @@ -60,14 +75,19 @@ function getCachedType(schemaType: string, customScalars: Record typeCache.set(cacheKey, mappedType); return mappedType; -}`; +}` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Best Practices')}

    + <> + {/* Best Practices Section Content */} +
    +

    {_('8. Best Practices')}

    Best practices ensure your generated GraphQL schemas are @@ -77,7 +97,7 @@ export default function BestPractices() {

    -

    {_('Type Safety')}

    +

    {_('Type Safety')}

    Type safety is crucial for preventing runtime errors and ensuring @@ -90,7 +110,7 @@ export default function BestPractices() { {typeSafetyExample} -

    {_('Error Handling')}

    +

    {_('Error Handling')}

    Proper error handling ensures that schema generation failures @@ -103,7 +123,7 @@ export default function BestPractices() { {errorHandlingExample} -

    {_('Configuration Validation')}

    +

    {_('Configuration Validation')}

    Configuration validation ensures that plugin settings are correct @@ -115,7 +135,7 @@ export default function BestPractices() { {configurationValidationExample} -

    {_('Performance Optimization')}

    +

    {_('Performance Optimization')}

    Performance optimization techniques help maintain reasonable @@ -127,6 +147,7 @@ export default function BestPractices() { {performanceOptimizationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Conclusion.tsx index d80ba24..866425f 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Conclusion.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Conclusion.tsx @@ -1,10 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { P, C, Nav } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; export default function Conclusion() { + //hooks + const { _ } = useLanguage(); + return ( <> + {/* Conclusion Section Content */}
    +

    {_('10. Conclusion')}

    This tutorial provides a comprehensive foundation for creating diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Implementation.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Implementation.tsx index 58461e6..45655cc 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Implementation.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Implementation.tsx @@ -1,7 +1,13 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, Code } from '../index.js'; +//local +import { H1, H2, P, C, Code } from '../index.js'; -const corePluginFunctionExample = `export default async function generateGraphQLSchema( +//code examples +//---------------------------------------------------------------------- + +const corePluginFunctionExample = +`export default async function generateGraphQLSchema( props: PluginProps<{ config: GraphQLConfig }> ) { const { config, schema, transformer } = props; @@ -61,9 +67,12 @@ const corePluginFunctionExample = `export default async function generateGraphQL console.error('❌ GraphQL schema generation failed:', error.message); throw error; } -}`; +}` + +//---------------------------------------------------------------------- -const typeMappingFunctionsExample = `function mapSchemaTypeToGraphQL(schemaType: string, customScalars: Record = {}): string { +const typeMappingFunctionsExample = +`function mapSchemaTypeToGraphQL(schemaType: string, customScalars: Record = {}): string { // Check for custom scalar mappings first if (customScalars[schemaType]) { return customScalars[schemaType]; @@ -97,9 +106,12 @@ function formatFieldType(column: any, customScalars: Record = {} } return type; -}`; +}` + +//---------------------------------------------------------------------- -const customScalarsExample = `function generateCustomScalars(customScalars: Record): string { +const customScalarsExample = +`function generateCustomScalars(customScalars: Record): string { if (Object.keys(customScalars).length === 0) { return \`# Custom Scalars scalar DateTime @@ -117,9 +129,12 @@ scalar JSON } return content + '\\n'; -}`; +}` -const enumsAndTypesExample = `function generateEnums(enums: Record): string { +//---------------------------------------------------------------------- + +const enumsAndTypesExample = +`function generateEnums(enums: Record): string { let content = '# Enums\\n'; for (const [enumName, enumDef] of Object.entries(enums)) { @@ -150,9 +165,12 @@ function generateTypes(models: Record): string { } return content; -}`; +}` + +//---------------------------------------------------------------------- -const inputTypesAndQueriesExample = `function generateInputTypes(models: Record): string { +const inputTypesAndQueriesExample = +`function generateInputTypes(models: Record): string { let content = '# Input Types\\n'; for (const [modelName, model] of Object.entries(models)) { @@ -204,14 +222,19 @@ function generateQueries(models: Record): string { content += '}\\n\\n'; return content; -}`; +}` + +//---------------------------------------------------------------------- export default function Implementation() { + //hooks const { _ } = useLanguage(); return ( -

    -

    {_('Implementation')}

    + <> + {/* Implementation Section Content */} +
    +

    {_('4. Implementation')}

    The implementation section covers the core plugin function and @@ -221,7 +244,7 @@ export default function Implementation() {

    -

    {_('Core Plugin Function')}

    +

    {_('Core Plugin Function')}

    The core plugin function serves as the main entry point for GraphQL @@ -234,7 +257,7 @@ export default function Implementation() { {corePluginFunctionExample} -

    {_('Type Mapping Functions')}

    +

    {_('Type Mapping Functions')}

    Type mapping functions handle the conversion of .idea schema @@ -247,7 +270,7 @@ export default function Implementation() { {typeMappingFunctionsExample} -

    {_('Schema Generation Functions')}

    +

    {_('Schema Generation Functions')}

    Schema generation functions create specific parts of the GraphQL @@ -265,6 +288,7 @@ export default function Implementation() { {inputTypesAndQueriesExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Introduction.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Introduction.tsx index 478f0f2..0d0b810 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Introduction.tsx @@ -1,11 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( <> + {/* GraphQL Schema Generator Plugin Tutorial */}

    {_('GraphQL Schema Generator Plugin Tutorial')}

    diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Overview.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Overview.tsx index adc2ea7..52995c8 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C, SS } from '../index.js'; +//local +import { H1, P, C, SS } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -

    -

    {_('Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    GraphQL is a query language and runtime for APIs that provides a @@ -49,6 +54,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/PluginStructure.tsx index bbe1ac9..a3a6d41 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/PluginStructure.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/PluginStructure.tsx @@ -1,7 +1,13 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, Code } from '../index.js'; +//local +import { H1, P, Code } from '../index.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -20,14 +26,19 @@ export default async function generateGraphQLSchema( const { config, schema, transformer } = props; // Implementation here... -}`; +}` + +//---------------------------------------------------------------------- export default function PluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Plugin Structure')}

    + <> + {/* Plugin Structure Section Content */} +
    +

    {_('3. Plugin Structure')}

    The plugin structure defines the core architecture and configuration @@ -39,6 +50,7 @@ export default function PluginStructure() { {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Prerequisites.tsx index 60ebb83..49ff501 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    Before implementing the GraphQL schema generator plugin, ensure you @@ -37,6 +42,7 @@ export default function Prerequisites() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/SchemaConfiguration.tsx index ff0c8e9..7420374 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/SchemaConfiguration.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/SchemaConfiguration.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, SS, Code } from '../index.js'; +//local +import { H1, H2, P, C, SS, Code } from '../index.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -const schemaConfigurationExample = `plugin "./plugins/graphql-schema.js" { +//code examples +//---------------------------------------------------------------------- + +const schemaConfigurationExample = +`plugin "./plugins/graphql-schema.js" { output "./generated/schema.graphql" includeQueries true includeMutations true @@ -13,14 +19,19 @@ const schemaConfigurationExample = `plugin "./plugins/graphql-schema.js" { URL "String" PhoneNumber "String" } -}`; +}` + +//---------------------------------------------------------------------- export default function SchemaConfiguration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Schema Configuration')}

    + <> + {/* Schema Configuration Section Content */} +
    +

    {_('5. Schema Configuration')}

    Schema configuration demonstrates how to integrate the GraphQL schema @@ -38,7 +49,7 @@ export default function SchemaConfiguration() { {schemaConfigurationExample} -

    {_('Configuration Options')}

    +

    {_('Configuration Options')}

    Configuration options control how GraphQL schema definitions are @@ -114,6 +125,7 @@ export default function SchemaConfiguration() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/Troubleshooting.tsx index ea95225..1d735c0 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/Troubleshooting.tsx @@ -1,12 +1,21 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, H2, P, Code } from '../index.js'; -const invalidGraphQLNamesExample = `function sanitizeGraphQLName(name: string): string { +//code examples +//---------------------------------------------------------------------- + +const invalidGraphQLNamesExample = +`function sanitizeGraphQLName(name: string): string { // GraphQL names must match /^[_A-Za-z][_0-9A-Za-z]*$/ return name.replace(/[^_A-Za-z0-9]/g, '_').replace(/^[0-9]/, '_$&'); -}`; +}` + +//---------------------------------------------------------------------- -const circularDependenciesExample = `function detectCircularDependencies(models: Record): string[] { +const circularDependenciesExample = +`function detectCircularDependencies(models: Record): string[] { const visited = new Set(); const recursionStack = new Set(); const cycles: string[] = []; @@ -14,13 +23,18 @@ const circularDependenciesExample = `function detectCircularDependencies(models: // Implementation for cycle detection... return cycles; -}`; +}` + +//---------------------------------------------------------------------- -const missingRequiredFieldsExample = `function validateRequiredFields(model: any): void { +const missingRequiredFieldsExample = +`function validateRequiredFields(model: any): void { if (!model.columns || model.columns.length === 0) { throw new Error(\`Model must have at least one column\`); } -}`; +}` + +//---------------------------------------------------------------------- const verboseLoggingExample = `const DEBUG = process.env.DEBUG === 'true'; @@ -28,7 +42,9 @@ function debugLog(message: string, data?: any) { if (DEBUG) { console.log(\`[GraphQL Plugin] \${message}\`, data || ''); } -}`; +}` + +//---------------------------------------------------------------------- const validateGeneratedSchemaExample = `import { buildSchema } from 'graphql'; @@ -39,14 +55,19 @@ function validateGeneratedSchema(schemaContent: string): void { } catch (error) { throw new Error(\`Invalid GraphQL schema: \${error.message}\`); } -}`; +}` + +//---------------------------------------------------------------------- export default function Troubleshooting() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Troubleshooting')}

    + <> + {/* Troubleshooting Section Content */} +
    +

    {_('9. Troubleshooting')}

    This section addresses common issues encountered when generating @@ -56,7 +77,7 @@ export default function Troubleshooting() {

    -

    {_('Common Issues')}

    +

    {_('Common Issues')}

    Common issues include invalid GraphQL identifiers, circular @@ -66,7 +87,7 @@ export default function Troubleshooting() {

    -

    {_('Invalid GraphQL Names')}

    +

    {_('Invalid GraphQL Names')}

    Invalid GraphQL names occur when schema identifiers contain @@ -79,7 +100,7 @@ export default function Troubleshooting() { {invalidGraphQLNamesExample} -

    {_('Circular Dependencies')}

    +

    {_('Circular Dependencies')}

    Circular dependencies can cause infinite loops during generation or @@ -92,7 +113,7 @@ export default function Troubleshooting() { {circularDependenciesExample} -

    {_('Missing Required Fields')}

    +

    {_('Missing Required Fields')}

    Missing required fields can result in invalid GraphQL types that @@ -104,7 +125,7 @@ export default function Troubleshooting() { {missingRequiredFieldsExample} -

    {_('Debugging Tips')}

    +

    {_('Debugging Tips')}

    Debugging tips help identify and resolve issues during GraphQL @@ -114,7 +135,7 @@ export default function Troubleshooting() {

    -

    {_('Enable Verbose Logging')}

    +

    {_('Enable Verbose Logging')}

    Verbose logging provides detailed information about the schema @@ -126,7 +147,7 @@ export default function Troubleshooting() { {verboseLoggingExample} -

    {_('Validate Generated Schema')}

    +

    {_('Validate Generated Schema')}

    Validating the generated GraphQL schema ensures that the output is @@ -137,6 +158,7 @@ export default function Troubleshooting() { {validateGeneratedSchemaExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/UsageExamples.tsx index f9561d9..ced11d5 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/UsageExamples.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/UsageExamples.tsx @@ -1,7 +1,13 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, H2, P, Code } from '../index.js'; -const basicSchemaExample = `enum UserRole { +//code examples +//---------------------------------------------------------------------- + +const basicSchemaExample = +`enum UserRole { ADMIN "admin" USER "user" GUEST "guest" @@ -20,7 +26,9 @@ plugin "./plugins/graphql-schema.js" { output "./schema.graphql" includeQueries true includeMutations true -}`; +}` + +//---------------------------------------------------------------------- const generatedOutputExample = `# Custom Scalars scalar DateTime @@ -70,14 +78,19 @@ type Mutation { createUser(input: UserInput!): User updateUser(id: ID!, input: UserUpdateInput!): User deleteUser(id: ID!): Boolean -}`; +}` + +//---------------------------------------------------------------------- export default function UsageExamples() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Usage Examples')}

    + <> + {/* Usage Examples Section Content */} +
    +

    {_('6. Usage Examples')}

    Usage examples demonstrate practical applications of the GraphQL @@ -87,7 +100,7 @@ export default function UsageExamples() {

    -

    {_('Basic Schema')}

    +

    {_('Basic Schema')}

    A basic schema example shows the fundamental structure needed to @@ -100,7 +113,7 @@ export default function UsageExamples() { {basicSchemaExample} -

    {_('Generated Output')}

    +

    {_('Generated Output')}

    The generated output demonstrates the GraphQL schema produced by the @@ -112,6 +125,7 @@ export default function UsageExamples() { {generatedOutputExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/graphql-schema-plugin/index.tsx b/packages/www/plugins/docs/components/graphql-schema-plugin/index.tsx index 948cd42..58d89aa 100644 --- a/packages/www/plugins/docs/components/graphql-schema-plugin/index.tsx +++ b/packages/www/plugins/docs/components/graphql-schema-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/html-form-plugin/CreatePluginStructure.tsx b/packages/www/plugins/docs/components/html-form-plugin/CreatePluginStructure.tsx index f117300..35ebf3c 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/CreatePluginStructure.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/CreatePluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -48,14 +54,19 @@ export default async function htmlFormPlugin( await fs.writeFile(outputPath, htmlContent, 'utf8'); console.log(\`✅ HTML form generated: \${outputPath}\`); -}`; +}` + +//---------------------------------------------------------------------- export default function CreatePluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Create the Plugin Structure')}

    + <> + {/* Create the Plugin Structure Section Content */} +
    +

    {_('4. Create the Plugin Structure')}

    The plugin structure provides the foundation for the HTML @@ -72,6 +83,7 @@ export default function CreatePluginStructure() { {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/ErrorHandlingAndBestPractices.tsx b/packages/www/plugins/docs/components/html-form-plugin/ErrorHandlingAndBestPractices.tsx index dbecffa..42a1ae9 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/ErrorHandlingAndBestPractices.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/ErrorHandlingAndBestPractices.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const errorHandlingExample = `export default async function htmlFormPlugin(props: PluginProps<{}>) { +//code examples +//---------------------------------------------------------------------- + +const errorHandlingExample = +`export default async function htmlFormPlugin(props: PluginProps<{}>) { const { config, schema, transformer, cwd } = props; try { @@ -50,14 +56,19 @@ function validateConfig(config: any): void { if (config.method && !['GET', 'POST'].includes(config.method)) { throw new Error(\`Unsupported HTTP method: \${config.method}\`); } -}`; +}` + +//---------------------------------------------------------------------- export default function ErrorHandlingAndBestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('10. Error Handling and Best Practices')}

    + <> + {/* Error Handling and Best Practices Section Content */} +
    +

    {_('10. Error Handling and Best Practices')}

    Proper error handling and following best practices ensure @@ -74,6 +85,7 @@ export default function ErrorHandlingAndBestPractices() { {errorHandlingExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/GenerateCompleteHtmlDocument.tsx b/packages/www/plugins/docs/components/html-form-plugin/GenerateCompleteHtmlDocument.tsx index d3a0794..d5b88f6 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/GenerateCompleteHtmlDocument.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/GenerateCompleteHtmlDocument.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const htmlGenerationExample = `function generateHTML(schema: any, options: any): string { +//code examples +//---------------------------------------------------------------------- + +const htmlGenerationExample = +`function generateHTML(schema: any, options: any): string { let html = generateHTMLHeader(options); // Generate forms for each model @@ -136,14 +142,19 @@ function generateJavaScript(options: any): string { js += ' \\n'; return js; -}`; +}` + +//---------------------------------------------------------------------- export default function GenerateCompleteHtmlDocument() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('7. Generate Complete HTML Document')}

    + <> + {/* Generate Complete HTML Document Section Content */} +
    +

    {_('7. Generate Complete HTML Document')}

    Generating a complete HTML document involves combining all @@ -161,6 +172,7 @@ export default function GenerateCompleteHtmlDocument() { {htmlGenerationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/GeneratedOutput.tsx b/packages/www/plugins/docs/components/html-form-plugin/GeneratedOutput.tsx index 3e1fb38..6f51b2f 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/GeneratedOutput.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/GeneratedOutput.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const generatedOutputExample = ` +//code examples +//---------------------------------------------------------------------- + +const generatedOutputExample = +` @@ -116,14 +122,19 @@ document.addEventListener('DOMContentLoaded', function() { }); -`; +` + +//---------------------------------------------------------------------- export default function GeneratedOutput() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('9. Generated Output')}

    + <> + {/* Generated Output Section Content */} +
    +

    {_('9. Generated Output')}

    The generated output section shows examples of the HTML code @@ -140,6 +151,7 @@ export default function GeneratedOutput() { {generatedOutputExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/ImplementFormElementGeneration.tsx b/packages/www/plugins/docs/components/html-form-plugin/ImplementFormElementGeneration.tsx index f4300fa..a163c24 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/ImplementFormElementGeneration.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/ImplementFormElementGeneration.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const formElementExample = `function generateFormElement(column: any, schema: any, options: any): string { const { name, type, required, attributes = {} } = column; const fieldConfig = attributes.field || {}; @@ -196,14 +201,19 @@ function autoGenerateElement(column: any, schema: any, options: any): string { // Default to text input return generateInputElement(column, { type: 'text' }, options); } -}`; +}` + +//---------------------------------------------------------------------- export default function ImplementFormElementGeneration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Implement Form Element Generation')}

    + <> + {/* Implement Form Element Generation Section Content */} +
    +

    {_('5. Implement Form Element Generation')}

    Form element generation is the core functionality of the @@ -221,6 +231,7 @@ export default function ImplementFormElementGeneration() { {formElementExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/ImplementFormLayoutAndStyling.tsx b/packages/www/plugins/docs/components/html-form-plugin/ImplementFormLayoutAndStyling.tsx index b459be7..659c881 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/ImplementFormLayoutAndStyling.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/ImplementFormLayoutAndStyling.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const formLayoutExample = `function wrapFormGroup(element: string, label: string, name: string, required: boolean, validation: any, options: any): string { +//code examples +//---------------------------------------------------------------------- + +const formLayoutExample = +`function wrapFormGroup(element: string, label: string, name: string, required: boolean, validation: any, options: any): string { const requiredMark = required ? ' *' : ''; const helpText = generateHelpText(validation); @@ -100,14 +106,19 @@ function getTextareaClasses(theme: string): string { default: return 'form-textarea'; } -}`; +}` + +//---------------------------------------------------------------------- export default function ImplementFormLayoutAndStyling() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('6. Implement Form Layout and Styling')}

    + <> + {/* Implement Form Layout and Styling Section Content */} +
    +

    {_('6. Implement Form Layout and Styling')}

    Form layout and styling ensure that generated forms are @@ -126,6 +137,7 @@ export default function ImplementFormLayoutAndStyling() { {formLayoutExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/Introduction.tsx b/packages/www/plugins/docs/components/html-form-plugin/Introduction.tsx index 8ed4089..91dc6d0 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/Introduction.tsx @@ -1,11 +1,16 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Creating an HTML Form Plugin */} +

    {_('Creating an HTML Form Plugin')}

    @@ -16,6 +21,7 @@ export default function Introduction() { with multiple CSS framework support.

    -
    +
    + ) } diff --git a/packages/www/plugins/docs/components/html-form-plugin/Overview.tsx b/packages/www/plugins/docs/components/html-form-plugin/Overview.tsx index 7d605a2..08f11d9 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('1. Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    This section provides an overview of what the HTML Form @@ -49,6 +54,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/html-form-plugin/Prerequisites.tsx index cd68bf9..c508be7 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, SS, C } from '../index.js'; +//local +import { H1, P, SS, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('2. Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    Before starting this tutorial, ensure you have the necessary @@ -34,6 +39,7 @@ export default function Prerequisites() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/UnderstandingSchemaStructure.tsx b/packages/www/plugins/docs/components/html-form-plugin/UnderstandingSchemaStructure.tsx index 81583d6..ca1961b 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/UnderstandingSchemaStructure.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/UnderstandingSchemaStructure.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const schemaExample = `// Example processed schema { model: { @@ -62,14 +67,19 @@ const schemaExample = `// Example processed schema GUEST: 'Guest User' } } -}`; +}` + +//---------------------------------------------------------------------- export default function UnderstandingSchemaStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Understanding the Schema Structure')}

    + <> + {/* Understanding the Schema Structure Section Content */} +
    +

    {_('3. Understanding the Schema Structure')}

    Understanding how schema attributes map to form elements is @@ -87,6 +97,7 @@ export default function UnderstandingSchemaStructure() { {schemaExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/UsageInSchema.tsx b/packages/www/plugins/docs/components/html-form-plugin/UsageInSchema.tsx index b61d0d7..2610fe0 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/UsageInSchema.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/UsageInSchema.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const usageExample = `// schema.idea plugin "./plugins/html-form-plugin.js" { output "./forms/user-form.html" @@ -28,14 +33,19 @@ enum UserRole { ADMIN "Administrator" USER "Regular User" GUEST "Guest User" -}`; +}` + +//---------------------------------------------------------------------- export default function UsageInSchema() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('8. Usage in Schema')}

    + <> + {/* Usage in Schema Section Content */} +
    +

    {_('8. Usage in Schema')}

    This section demonstrates how to configure and use the HTML @@ -54,6 +64,7 @@ export default function UsageInSchema() { {usageExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/html-form-plugin/index.tsx b/packages/www/plugins/docs/components/html-form-plugin/index.tsx index 090084e..6ae8187 100644 --- a/packages/www/plugins/docs/components/html-form-plugin/index.tsx +++ b/packages/www/plugins/docs/components/html-form-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/index.tsx b/packages/www/plugins/docs/components/index.tsx index ad73143..f56aef1 100644 --- a/packages/www/plugins/docs/components/index.tsx +++ b/packages/www/plugins/docs/components/index.tsx @@ -24,7 +24,7 @@ export function Header1({ children }: { children: string }) { export function Header2({ children }: { children: string }) { const { _ } = useLanguage(); return ( -

    +

    {_(children)}

    ); diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx index 1800854..dbf768f 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/AdvancedFeatures.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Advanced Features')}

    + <> + {/* Advanced Features Section Content */} +
    +

    {_('12. Advanced Features')}

    The plugin can be extended with additional features: @@ -39,6 +44,7 @@ export default function AdvancedFeatures() { -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx index 5544b40..2170e08 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Conclusion.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Conclusion() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Conclusion')}

    + <> + {/* Conclusion Section Content */} +
    +

    {_('13. Conclusion')}

    This Markdown Documentation Plugin demonstrates how to: @@ -48,6 +53,7 @@ export default function Conclusion() { and integration with documentation platforms.

    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx index 15c4385..fc51994 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/CreatePluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -47,14 +53,19 @@ export default async function markdownDocsPlugin( } console.log(\`✅ Markdown documentation generated: \${options.output}\`); -}`; +}` + +//---------------------------------------------------------------------- export default function CreatePluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Create the Plugin Structure')}

    + <> + {/* Create the Plugin Structure Section Content */} +
    +

    {_('4. Create the Plugin Structure')}

    Create a new file markdown-docs-plugin.js: @@ -63,6 +74,7 @@ export default function CreatePluginStructure() { {pluginStructureExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx index a030990..42f86a0 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/ErrorHandlingAndBestPractices.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const errorHandlingExample = `function validateConfig(config: any): void { +//code examples +//---------------------------------------------------------------------- + +const errorHandlingExample = +`function validateConfig(config: any): void { if (!config.output) { throw new Error('Markdown Documentation Plugin requires "output" configuration'); } @@ -14,14 +20,19 @@ const errorHandlingExample = `function validateConfig(config: any): void { if (config.template && !['default', 'api', 'guide'].includes(config.template)) { throw new Error(\`Unsupported template: \${config.template}\`); } -}`; +}` + +//---------------------------------------------------------------------- export default function ErrorHandlingAndBestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Error Handling and Best Practices')}

    + <> + {/* Error Handling and Best Practices Section Content */} +
    +

    {_('11. Error Handling and Best Practices')}

    Add proper error handling and validation: @@ -36,6 +47,7 @@ export default function ErrorHandlingAndBestPractices() { error messages to help users troubleshoot issues.

    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx index 9f61898..907b96d 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateModelsDocumentation.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const modelsGenerationExample = `function generateModelsSection(models: any, schema: any, options: any): string { let content = '## Models\\n\\n'; @@ -12,14 +17,19 @@ const modelsGenerationExample = } return content; -}`; +}` + +//---------------------------------------------------------------------- export default function GenerateModelsDocumentation() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Generate Models Documentation')}

    + <> + {/* Generate Models Documentation Section Content */} +
    +

    {_('6. Generate Models Documentation')}

    Implement model documentation generation: @@ -28,6 +38,7 @@ export default function GenerateModelsDocumentation() { {modelsGenerationExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx index 46b47c3..1b64d37 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GenerateTypesEnumsProps.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function GenerateTypesEnumsProps() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Generate Types, Enums, and Props')}

    + <> + {/* Generate Types, Enums, and Props Section Content */} +
    +

    {_('7. Generate Types, Enums, and Props')}

    Similar to models, you can implement generation functions for @@ -21,6 +26,7 @@ export default function GenerateTypesEnumsProps() { configurations for form fields and validation.

    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx index f2fc397..06a61c3 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/GeneratedOutput.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const generatedOutputExample = `# My Application Schema +//code examples +//---------------------------------------------------------------------- + +const generatedOutputExample = +`# My Application Schema API Reference documentation for the schema definitions. @@ -52,14 +58,19 @@ Enums define sets of named constants with associated values. --- -*Documentation generated on 1/15/2024, 10:30:00 AM*`; +*Documentation generated on 1/15/2024, 10:30:00 AM*` + +//---------------------------------------------------------------------- export default function GeneratedOutput() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Generated Output')}

    + <> + {/* Generated Output Section Content */} +
    +

    {_('10. Generated Output')}

    The plugin will generate markdown documentation like this: @@ -68,6 +79,7 @@ export default function GeneratedOutput() { {generatedOutputExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx index 1add44d..4aa3a5d 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/ImplementDocumentationGeneration.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const documentationGenerationExample = `async function generateSingleFile(schema: any, options: any, transformer: any): Promise { +//code examples +//---------------------------------------------------------------------- + +const documentationGenerationExample = +`async function generateSingleFile(schema: any, options: any, transformer: any): Promise { let content = generateHeader(options); // Generate table of contents @@ -43,14 +49,19 @@ const documentationGenerationExample = `async function generateSingleFile(schema const outputPath = await transformer.loader.absolute(options.output); await fs.mkdir(path.dirname(outputPath), { recursive: true }); await fs.writeFile(outputPath, content, 'utf8'); -}`; +}` + +//---------------------------------------------------------------------- export default function ImplementDocumentationGeneration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Implement Documentation Generation')}

    + <> + {/* Implement Documentation Generation Section Content */} +
    +

    {_('5. Implement Documentation Generation')}

    Create functions to generate different sections of documentation: @@ -59,6 +70,7 @@ export default function ImplementDocumentationGeneration() { {documentationGenerationExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx index 2d8f0ad..671da47 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Introduction.tsx @@ -1,11 +1,16 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Creating a Markdown Documentation Plugin */} +

    {_('Creating a Markdown Documentation Plugin')}

    @@ -16,6 +21,7 @@ export default function Introduction() { examples and cross-references.

    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx index 0053eca..4565ce3 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    The Markdown Documentation Plugin will: @@ -39,6 +44,7 @@ export default function Overview() { -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx index 2af6577..b1a2b80 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, C } from '../index.js'; +//local +import { H1, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    • @@ -24,6 +29,7 @@ export default function Prerequisites() {
    -
    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx index a0b9d3f..44eb035 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UnderstandingSchemaStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const exampleProcessedSchema = `// Example processed schema +//code examples +//---------------------------------------------------------------------- + +const exampleProcessedSchema = +`// Example processed schema { model: { User: { @@ -65,14 +71,19 @@ const exampleProcessedSchema = `// Example processed schema maxLength: 255 } } -}`; +}` + +//---------------------------------------------------------------------- export default function UnderstandingSchemaStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Understanding the Schema Structure')}

    + <> + {/* Understanding the Schema Structure Section Content */} +
    +

    {_('3. Understanding the Schema Structure')}

    Before creating the plugin, let's understand what documentation @@ -82,6 +93,7 @@ export default function UnderstandingSchemaStructure() { {exampleProcessedSchema} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx index 45a128d..d764668 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UsageInSchema.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const schemaUsageExample = `// schema.idea +//code examples +//---------------------------------------------------------------------- + +const schemaUsageExample = +`// schema.idea plugin "./plugins/markdown-docs-plugin.js" { output "./docs/schema.md" title "My Application Schema" @@ -27,14 +33,19 @@ enum UserRole { ADMIN "Administrator" USER "Regular User" GUEST "Guest User" -}`; +}` + +//---------------------------------------------------------------------- export default function UsageInSchema() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Usage in Schema')}

    + <> + {/* Usage in Schema Section Content */} +
    +

    {_('9. Usage in Schema')}

    To use this plugin in your schema file: @@ -43,6 +54,7 @@ export default function UsageInSchema() { {schemaUsageExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx index d763d3c..84e0be6 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/UtilityFunctions.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const utilityFunctionsExample = `function formatType(type: string, multiple: boolean = false): string { +//code examples +//---------------------------------------------------------------------- + +const utilityFunctionsExample = +`function formatType(type: string, multiple: boolean = false): string { let formattedType = type; // Add array notation if multiple @@ -20,14 +26,19 @@ const utilityFunctionsExample = `function formatType(type: string, multiple: boo } return formattedType; -}`; +}` + +//---------------------------------------------------------------------- export default function UtilityFunctions() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Utility Functions')}

    + <> + {/* Utility Functions Section Content */} +
    +

    {_('8. Utility Functions')}

    Create helper functions for formatting and processing: @@ -36,6 +47,7 @@ export default function UtilityFunctions() { {utilityFunctionsExample} -

    +
    + ) } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx b/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx index 41beba8..73a0c98 100644 --- a/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx +++ b/packages/www/plugins/docs/components/markdown-documentation-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx index a1c9b9c..2046548 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/BestPractices.tsx @@ -1,8 +1,14 @@ +//module import { useLanguage, Translate } from 'r22n'; -import { H1, H2 ,P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const enhancedErrorHandling = `export default async function mysqlTablesPlugin(props: PluginProps<{}>) { +//code examples +//---------------------------------------------------------------------- + +const enhancedErrorHandling = + `export default async function mysqlTablesPlugin(props: PluginProps<{}>) { const { config, schema, transformer, cwd } = props; try { @@ -32,9 +38,12 @@ const enhancedErrorHandling = `export default async function mysqlTablesPlugin(p console.error(\`❌ MySQL Tables Plugin failed: \${error.message}\`); throw error; } -}`; +}` + +//---------------------------------------------------------------------- -const configValidation = `function validateConfig(config: any): void { +const configValidation = + `function validateConfig(config: any): void { if (!config.output) { throw new Error('MySQL Tables Plugin requires "output" configuration'); } @@ -42,31 +51,43 @@ const configValidation = `function validateConfig(config: any): void { if (config.engine && !['InnoDB', 'MyISAM', 'Memory'].includes(config.engine)) { throw new Error(\`Unsupported MySQL engine: \${config.engine}\`); } -}`; +}` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('9. Error Handling and Best Practices')}

    -

    - - Add proper error handling and validation to make your plugin - robust and user-friendly. - -

    + <> + {/* Best Practices Section Content */} +
    +

    {_('9. Error Handling and Best Practices')}

    +

    + + Add proper error handling and validation to make your plugin + robust and user-friendly. + +

    -

    {_('9.1. Enhanced Error Handling')}

    - {enhancedErrorHandling} +

    {_('9.1. Enhanced Error Handling')}

    + {enhancedErrorHandling} + -

    {_('9.2. Configuration Validation')}

    - - {configValidation} - -
    +

    {_('9.2. Configuration Validation')}

    + + {configValidation} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx index 4e8dac2..ff45beb 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Conclusion.tsx @@ -1,50 +1,57 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P } from '../index.js'; export default function Conclusion() { + //hooks const { _ } = useLanguage(); - + return ( -
    -

    {_('10. Conclusion')}

    -

    - - This MySQL Tables Plugin demonstrates how to: - -

    -
      -
    • - - Parse schema models and columns - -
    • -
    • - - Map schema types to database-specific types - -
    • -
    • - - Generate SQL DDL statements - -
    • -
    • + <> + {/* Conclusion Section Content */} +
      +

      {_('10. Conclusion')}

      +

      - Handle constraints, indexes, and foreign keys + This MySQL Tables Plugin demonstrates how to: -

    • -
    • +

      +
        +
      • + + Parse schema models and columns + +
      • +
      • + + Map schema types to database-specific types + +
      • +
      • + + Generate SQL DDL statements + +
      • +
      • + + Handle constraints, indexes, and foreign keys + +
      • +
      • + + Provide proper error handling and validation + +
      • +
      +

      - Provide proper error handling and validation + The plugin is flexible and can be extended to support + additional MySQL features like partitioning, triggers, or + stored procedures. -

    • -
    -

    - - The plugin is flexible and can be extended to support additional - MySQL features like partitioning, triggers, or stored procedures. - -

    -
    +

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx index 33d9a3c..9a0e331 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/CreatePluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const basicPluginStructure = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const basicPluginStructure = + `import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -42,27 +48,34 @@ export default async function mysqlTablesPlugin( await fs.writeFile(outputPath, sqlContent, 'utf8'); console.log(\`✅ MySQL tables generated: \${outputPath}\`); -}`; +}` + +//---------------------------------------------------------------------- export default function CreatePluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Create the Plugin Structure')}

    -

    - - Create a new file mysql-tables-plugin.js. This will be the main - entry point for our plugin that handles configuration validation - and orchestrates the SQL generation process. - -

    -

    {_('Basic Plugin Structure')}

    - {basicPluginStructure} - -
    + <> + {/* Create the Plugin Structure Section Content */} +
    +

    {_('4. Create the Plugin Structure')}

    +

    + + Create a new file mysql-tables-plugin.js. This will be the main + entry point for our plugin that handles configuration validation + and orchestrates the SQL generation process. + +

    +

    {_('Basic Plugin Structure')}

    + {basicPluginStructure} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx index 32a7ab8..17d49e1 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/GenerateSqlStatements.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const mainSQLGeneration = `function generateSQL(schema: any, options: any): string { +//code examples +//---------------------------------------------------------------------- + +const mainSQLGeneration = + `function generateSQL(schema: any, options: any): string { let sql = ''; // Add header comment @@ -25,9 +31,12 @@ const mainSQLGeneration = `function generateSQL(schema: any, options: any): stri } return sql; -}`; +}` + +//---------------------------------------------------------------------- -const tableSQLGeneration = `function generateTableSQL(tableName: string, model: any, options: any): string { +const tableSQLGeneration = + `function generateTableSQL(tableName: string, model: any, options: any): string { const columns: string[] = []; const indexes: string[] = []; const foreignKeys: string[] = []; @@ -77,9 +86,12 @@ const tableSQLGeneration = `function generateTableSQL(tableName: string, model: sql += \`\\n) ENGINE=\${options.engine} DEFAULT CHARSET=\${options.charset} COLLATE=\${options.collation};\\n\`; return sql; -}`; +}` + +//---------------------------------------------------------------------- -const columnDefinitionGeneration = `function generateColumnDefinition(column: any, options: any): any { +const columnDefinitionGeneration = + `function generateColumnDefinition(column: any, options: any): any { const { name, required, attributes = {} } = column; const mysqlType = mapSchemaTypeToMySQL(column); @@ -128,9 +140,12 @@ const columnDefinitionGeneration = `function generateColumnDefinition(column: an isIndex: !!attributes.index || !!attributes.searchable || !!attributes.filterable, foreignKey: generateForeignKey(column, options) }; -}`; +}` -const foreignKeyGeneration = `function generateForeignKey(column: any, options: any): string | null { +//---------------------------------------------------------------------- + +const foreignKeyGeneration = + `function generateForeignKey(column: any, options: any): string | null { const { name, type, attributes = {} } = column; // Check if this column references another model @@ -142,53 +157,63 @@ const foreignKeyGeneration = `function generateForeignKey(column: any, options: } return null; -}`; +}` + +//---------------------------------------------------------------------- export default function GenerateSqlStatements() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('6. Generate SQL Statements')}

    -

    - - Implement the main SQL generation function. This section contains - the core logic for creating MySQL CREATE TABLE statements from - the processed schema. - -

    + <> + {/* Generate SQL Statements Section Content */} +
    +

    {_('6. Generate SQL Statements')}

    +

    + + Implement the main SQL generation function. This section + contains the core logic for creating MySQL CREATE TABLE + statements from the processed schema. + +

    -

    {_('6.1. Main SQL Generation')}

    - - {mainSQLGeneration} - +

    {_('6.1. Main SQL Generation')}

    + + {mainSQLGeneration} + -

    {_('6.2. Table SQL Generation')}

    - - {tableSQLGeneration} - +

    {_('6.2. Table SQL Generation')}

    + + {tableSQLGeneration} + -

    {_('6.3. Column Definition Generation')}

    - - {columnDefinitionGeneration} - +

    {_('6.3. Column Definition Generation')}

    + + {columnDefinitionGeneration} + -

    {_('6.4. Foreign Key Generation')}

    - - {foreignKeyGeneration} - -
    +

    {_('6.4. Foreign Key Generation')}

    + + {foreignKeyGeneration} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx index 5ad6650..1e7bc78 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/GeneratedOutput.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const generatedOutputExample = `-- Generated MySQL Tables -- Database: my_app -- Generated at: 2024-01-15T10:30:00.000Z @@ -21,27 +26,35 @@ CREATE TABLE \`User\` ( PRIMARY KEY (\`id\`), UNIQUE KEY \`uk_User_email\` (\`email\`), KEY \`idx_User_age\` (\`age\`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;` + +//---------------------------------------------------------------------- export default function GeneratedOutput() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('8. Generated Output')}

    -

    - - The plugin will generate SQL like this. The output includes - proper MySQL syntax with constraints, indexes, and foreign keys. - -

    -

    {_('Example Generated SQL')}

    - - {generatedOutputExample} - -
    + <> + {/* Generated Output Section Content */} +
    +

    {_('8. Generated Output')}

    +

    + + The plugin will generate SQL like this. The output includes + proper MySQL syntax with constraints, indexes, and foreign + keys. + +

    +

    {_('Example Generated SQL')}

    + + {generatedOutputExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx index 7a246f4..d2f9477 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/ImplementTypeMapping.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const typeMappingFunction = `function mapSchemaTypeToMySQL(column: any): string { +//code examples +//---------------------------------------------------------------------- + +const typeMappingFunction = + `function mapSchemaTypeToMySQL(column: any): string { const { type, attributes = {} } = column; switch (type) { @@ -73,28 +79,35 @@ const typeMappingFunction = `function mapSchemaTypeToMySQL(column: any): string return 'VARCHAR(255)'; // Default fallback } -}`; +}` + +//---------------------------------------------------------------------- export default function ImplementTypeMapping() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Implement Type Mapping')}

    -

    - - Create a function to map schema types to MySQL types. This - function handles the conversion between idea schema types and - their corresponding MySQL data types. - -

    -

    {_('Type Mapping Function')}

    - - {typeMappingFunction} - -
    + <> + {/* Implement Type Mapping */} +
    +

    {_('5. Implement Type Mapping')}

    +

    + + Create a function to map schema types to MySQL types. This + function handles the conversion between idea schema types and + their corresponding MySQL data types. + +

    +

    {_('Type Mapping Function')}

    + + {typeMappingFunction} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx index 296dd08..0b607b7 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Introduction.tsx @@ -1,19 +1,25 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); - + return ( -
    -

    {_('Creating a MySQL Tables Plugin')}

    -

    - - This tutorial will guide you through creating a plugin that - generates MySQL CREATE TABLE statements from a processed .idea - schema. - -

    -
    + <> + {/* Creating a MySQL Tables Plugin */} +
    +

    {_('Creating a MySQL Tables Plugin')}

    +

    + + This tutorial will guide you through creating a plugin that + generates MySQL CREATE TABLE statements from a processed + .idea schema. + +

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx index df955cd..9238edc 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Overview.tsx @@ -1,44 +1,52 @@ + +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); - + return ( -
    -

    {_('1. Overview')}

    -

    - - The MySQL Tables Plugin will: - -

    -
      -
    • - - Parse schema models and their columns - -
    • -
    • - - Map schema types to MySQL data types - -
    • -
    • - - Generate SQL CREATE TABLE statements - -
    • -
    • - - Handle primary keys, foreign keys, and indexes - -
    • -
    • + <> + {/* Overview Section Content */} +
      +

      {_('1. Overview')}

      +

      - Output SQL files that can be executed to create database tables + The MySQL Tables Plugin will: -

    • -
    -
    +

    +
      +
    • + + Parse schema models and their columns + +
    • +
    • + + Map schema types to MySQL data types + +
    • +
    • + + Generate SQL CREATE TABLE statements + +
    • +
    • + + Handle primary keys, foreign keys, and indexes + +
    • +
    • + + Output SQL files that can be executed to create database + tables + +
    • +
    + + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx index ceb29ef..8af8888 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/Prerequisites.tsx @@ -1,35 +1,41 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); - + return ( -
    -

    {_('2. Prerequisites')}

    -

    - - Before creating this plugin, you should have the following - knowledge and tools: - -

    -
      -
    • - - Basic understanding of TypeScript/JavaScript - -
    • -
    • - - Familiarity with MySQL and SQL syntax - -
    • -
    • + <> + {/* Prerequisites Section Content */} +
      +

      {_('2. Prerequisites')}

      +

      - Understanding of the idea-transformer plugin system + Before creating this plugin, you should have the following + knowledge and tools: -

    • -
    -
    +

    +
      +
    • + + Basic understanding of TypeScript/JavaScript + +
    • +
    • + + Familiarity with MySQL and SQL syntax + +
    • +
    • + + Understanding of the idea-transformer plugin system + +
    • +
    + + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx index eb0d4a6..0819d9b 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/UnderstandingSchemaStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const schemaStructureExample = `// Example processed schema +//code examples +//---------------------------------------------------------------------- + +const schemaStructureExample = + `// Example processed schema { model: { User: { @@ -48,29 +54,35 @@ const schemaStructureExample = `// Example processed schema USER: 'user' } } -}`; +}` + +//---------------------------------------------------------------------- export default function UnderstandingSchemaStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Understanding the Schema Structure')}

    -

    - - Before creating the plugin, let's understand what a processed - schema looks like. The schema structure contains models, enums, - and other configuration data that our plugin will process. - -

    -

    {_('Example Schema Structure')}

    - - {schemaStructureExample} - -
    + <> + {/* Understanding Schema Structure Section Content */} +
    +

    {_('3. Understanding the Schema Structure')}

    +

    + + Before creating the plugin, let's understand what a processed + schema looks like. The schema structure contains models, enums, + and other configuration data that our plugin will process. + +

    +

    {_('Example Schema Structure')}

    + + {schemaStructureExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx index fd27a0b..a99a2c9 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/UsageInSchema.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const schemaUsageExample = `// schema.idea plugin "./plugins/mysql-tables-plugin.js" { output "./database/tables.sql" @@ -25,27 +30,34 @@ model User { enum UserRole { ADMIN "admin" USER "user" -}`; +}` + +//---------------------------------------------------------------------- export default function UsageInSchema() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('7. Usage in Schema')}

    -

    - - To use this plugin in your schema file, add the plugin - declaration with appropriate configuration options. - -

    -

    {_('Schema Configuration')}

    - - {schemaUsageExample} - -
    + <> + {/* Usage In Schema Section Content */} +
    +

    {_('7. Usage in Schema')}

    +

    + + To use this plugin in your schema file, add the plugin + declaration with appropriate configuration options. + +

    +

    {_('Schema Configuration')}

    + + {schemaUsageExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx b/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx index fc2b4b7..deee956 100644 --- a/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx +++ b/packages/www/plugins/docs/components/mysql-table-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx index 50230ed..46f7917 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/AdvancedFeatures.tsx @@ -1,4 +1,14 @@ -const advancedConfigExample = `interface AdvancedOpenAPIConfig extends OpenAPIConfig { +//modules +import { useLanguage, Translate } from 'r22n'; +//local +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +//code examples +//---------------------------------------------------------------------- + +const advancedConfigExample = + `interface AdvancedOpenAPIConfig extends OpenAPIConfig { formats?: ('json' | 'yaml' | 'html')[]; validation?: { strict?: boolean; @@ -34,9 +44,12 @@ export default async function generateAdvancedOpenAPISpec( for (const format of formats) { await generateFormat(spec, format, outputBase, transformer); } -}`; +}` + +//---------------------------------------------------------------------- -const formatGenerationExample = `async function generateFormat( +const formatGenerationExample = + `async function generateFormat( spec: any, format: string, outputBase: string, @@ -66,9 +79,12 @@ const formatGenerationExample = `async function generateFormat( const outputPath = await transformer.loader.absolute(\`\${outputBase}\${extension}\`); await fs.writeFile(outputPath, content, 'utf8'); console.log(\`✅ Generated \${format.toUpperCase()} specification: \${outputPath}\`); -}`; +}` + +//---------------------------------------------------------------------- -const exampleGenerationExample = `function addExamples(spec: any, schema: any): void { +const exampleGenerationExample = + `function addExamples(spec: any, schema: any): void { // Add examples to schemas for (const [name, schemaObj] of Object.entries(spec.components.schemas)) { if (schemaObj.type === 'object') { @@ -138,9 +154,12 @@ function generatePropertyExample(propSchema: any): any { default: return null; } -}`; +}` -const validationExample = `function validateSpecification(spec: any): void { +//---------------------------------------------------------------------- + +const validationExample = + `function validateSpecification(spec: any): void { // Basic validation if (!spec.openapi) { throw new Error('OpenAPI version is required'); @@ -168,9 +187,12 @@ const validationExample = `function validateSpecification(spec: any): void { } console.log('✅ OpenAPI specification validation passed'); -}`; +}` + +//---------------------------------------------------------------------- -const htmlGenerationExample = `function generateHTMLDocumentation(spec: any): string { +const htmlGenerationExample = +`function generateHTMLDocumentation(spec: any): string { return \` @@ -218,42 +240,46 @@ const htmlGenerationExample = `function generateHTMLDocumentation(spec: any): st \`; -}`; +}` -import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; -import Code from '../Code.js'; +//---------------------------------------------------------------------- export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Multiple Output Formats')}

    -

    - - Multiple output formats allow you to generate OpenAPI - specifications in JSON, YAML, and HTML formats. This - flexibility ensures compatibility with different tools and - enables both machine-readable specifications and human-friendly - documentation. - -

    - - {advancedConfigExample} - - - {formatGenerationExample} - - - {exampleGenerationExample} - - - {validationExample} - - - {htmlGenerationExample} - -
    + <> + {/* Advanced Features Section Content */} +
    +

    {_('5. Advanced Features')}

    + +

    {_('5.1. Multiple Output Formats')}

    +

    + + Multiple output formats allow you to generate OpenAPI + specifications in JSON, YAML, and HTML formats. This + flexibility ensures compatibility with different tools and + enables both machine-readable specifications and human-friendly + documentation. + +

    + + {advancedConfigExample} + + + {formatGenerationExample} + + + {exampleGenerationExample} + + + {validationExample} + + + {htmlGenerationExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx index 52302fa..a810e66 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/BasicImplementation.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C } from '../index.js'; +//local +import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; -const basicPluginExample = `// plugins/openapi-spec.ts +//code examples +//---------------------------------------------------------------------- + +const basicPluginExample = +`// plugins/openapi-spec.ts import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -57,9 +63,12 @@ export default async function generateOpenAPISpec( await fs.writeFile(outputPath, JSON.stringify(spec, null, 2), 'utf8'); console.log(\`✅ Generated OpenAPI specification: \${outputPath}\`); -}`; +}` + +//---------------------------------------------------------------------- -const schemaGenerationExample = `function generateSpecification(schema: any, config: OpenAPIConfig) { +const schemaGenerationExample = +`function generateSpecification(schema: any, config: OpenAPIConfig) { const spec: any = { openapi: '3.0.3', info: { @@ -118,9 +127,12 @@ const schemaGenerationExample = `function generateSpecification(schema: any, con } return spec; -}`; +}` -const modelSchemaExample = `function generateModelSchema(model: any): any { +//---------------------------------------------------------------------- + +const modelSchemaExample = +`function generateModelSchema(model: any): any { const schema: any = { type: 'object', properties: {}, @@ -169,9 +181,12 @@ function generateEnumSchema(enumDef: any): any { enum: values, example: values[0] }; -}`; +}` + +//---------------------------------------------------------------------- -const propertySchemaExample = `function generatePropertySchema(column: any): any { +const propertySchemaExample = +`function generatePropertySchema(column: any): any { const property: any = {}; // Map idea types to OpenAPI types @@ -248,16 +263,19 @@ function addValidationRules(property: any, attributes: any): void { if (attributes.format) { property.format = attributes.format; } -}`; +}` +//---------------------------------------------------------------------- export default function BasicImplementation() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('2. Basic Implementation')}

    + <> + {/* Basic Implementation Section Content */} +
    +

    {_('2. Basic Implementation')}

    The basic implementation provides the foundation for generating @@ -274,7 +292,7 @@ export default function BasicImplementation() {

    -

    {_('2.1. Plugin Structure')}

    +

    {_('2.1. Plugin Structure')}

    The plugin structure defines the main entry point and @@ -291,7 +309,7 @@ export default function BasicImplementation() { {schemaGenerationExample} -

    {_('2.2. Schema Generation')}

    +

    {_('2.2. Schema Generation')}

    Schema generation transforms @@ -308,6 +326,7 @@ export default function BasicImplementation() { {propertySchemaExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx index a3193f5..c076ebe 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/BestPractices.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const documentationBestPracticesExample = `// Always include detailed descriptions +//code examples +//---------------------------------------------------------------------- + +const documentationBestPracticesExample = + `// Always include detailed descriptions function generateModelSchema(model: any): any { const schema: any = { type: 'object', @@ -210,76 +216,82 @@ function generateInvalidExample(schema: any): any { } return example; -}`; +}` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('7. Best Practices')}

    -

    - - Best practices ensure your generated OpenAPI specifications - are comprehensive, maintainable, and follow industry - standards. These guidelines cover documentation quality, - error handling, security implementation, and validation - strategies. - -

    + <> + {/* Best Practices Section Content */} +
    +

    {_('7. Best Practices')}

    +

    + + Best practices ensure your generated OpenAPI specifications + are comprehensive, maintainable, and follow industry + standards. These guidelines cover documentation quality, + error handling, security implementation, and validation + strategies. + +

    -

    {_('7.1. Comprehensive Documentation')}

    -

    - - Comprehensive documentation practices ensure your API - specifications provide clear, detailed information for both - human readers and automated tools. This includes proper - descriptions, examples, and consistent formatting throughout - the specification. - -

    - - {documentationBestPracticesExample} - +

    {_('7.1. Comprehensive Documentation')}

    +

    + + Comprehensive documentation practices ensure your API + specifications provide clear, detailed information for both + human readers and automated tools. This includes proper + descriptions, examples, and consistent formatting throughout + the specification. + +

    + + {documentationBestPracticesExample} + -

    {_('7.2. Consistent Error Responses')}

    -

    - - Consistent error responses provide standardized error - handling across your API endpoints. This approach ensures - predictable error formats that client applications can - handle reliably, improving the overall developer experience. - -

    - - {errorResponsesExample} - +

    {_('7.2. Consistent Error Responses')}

    +

    + + Consistent error responses provide standardized error + handling across your API endpoints. This approach ensures + predictable error formats that client applications can + handle reliably, improving the overall developer experience. + +

    + + {errorResponsesExample} + -

    {_('7.3. Security Best Practices')}

    -

    - - Security best practices ensure your API documentation - properly represents authentication and authorization - requirements. This includes applying appropriate security - schemes to endpoints and documenting access control patterns. - -

    - - {securityBestPracticesExample} - +

    {_('7.3. Security Best Practices')}

    +

    + + Security best practices ensure your API documentation + properly represents authentication and authorization + requirements. This includes applying appropriate security + schemes to endpoints and documenting access control patterns. + +

    + + {securityBestPracticesExample} + -

    {_('7.4. Validation and Testing')}

    -

    - - Validation and testing practices ensure your generated - OpenAPI specifications are accurate and functional. This - includes adding validation examples, testing request/response - formats, and verifying specification compliance. - -

    - - {validationExamplesExample} - -
    +

    {_('7.4. Validation and Testing')}

    +

    + + Validation and testing practices ensure your generated + OpenAPI specifications are accurate and functional. This + includes adding validation examples, testing request/response + formats, and verifying specification compliance. + +

    + + {validationExamplesExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx index 564090e..dbb2539 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Conclusion.tsx @@ -1,13 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, SS } from '../index.js'; +//local +import { H1, H2, P, C, SS } from '../index.js'; export default function Conclusion() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Conclusion')}

    + <> + {/* Conclusion Section Content */} +
    +

    {_('Conclusion')}

    This OpenAPI Specification Generator plugin provides a @@ -62,7 +66,7 @@ export default function Conclusion() {

    -

    {_('Next Steps')}

    +

    {_('Next Steps')}

    • Extend Schema Mapping: @@ -104,6 +108,7 @@ export default function Conclusion() { like Swagger UI, Postman, and various code generators.

      -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx index baaced1..805ab77 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/ConfigurationOptions.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const configurationExample = `// schema.idea +//code examples +//---------------------------------------------------------------------- + +const configurationExample = +`// schema.idea plugin "./plugins/openapi-spec.js" { output "./docs/api-spec.json" info { @@ -92,15 +98,19 @@ plugin "./plugins/openapi-spec.js" { } } } -}`; +}` + +//---------------------------------------------------------------------- export default function ConfigurationOptions() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Configuration Options')}

    + <> + {/* Configuration Options Section Content */} +
    +

    {_('3. Configuration Options')}

    Configuration options control how the OpenAPI specification @@ -113,6 +123,7 @@ export default function ConfigurationOptions() { {configurationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx index 8f50aed..9a02452 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Introduction.tsx @@ -1,26 +1,32 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('OpenAPI Specification Generator Plugin Tutorial')}

    -

    - - This tutorial demonstrates how to create a plugin for - - @stackpress/idea-transformer - - that generates OpenAPI 3.0 specifications from - - .idea - - schema files. The plugin will create comprehensive API - documentation with endpoints, schemas, and validation rules. - -

    -
    + <> + {/* Creating an OpenAPI Specification Generator Plugin */} +
    +

    {_('OpenAPI Specification Generator Plugin Tutorial')}

    +

    + + This tutorial demonstrates how to create a plugin for + + @stackpress/idea-transformer + + that generates OpenAPI 3.0 specifications from + + .idea + + schema files. The plugin will create comprehensive API + documentation with endpoints, schemas, and validation rules. + +

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx index 6f93d7f..170b2d1 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C } from '../index.js'; +//local +import { H1, H2, P, C } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('1. Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    OpenAPI (formerly Swagger) specifications provide a standard @@ -54,7 +59,7 @@ export default function Overview() { -

    {_('What You\'ll Learn')}

    +

    {_('What You\'ll Learn')}

    This section outlines the key concepts and skills you'll @@ -90,6 +95,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx index 67431e4..07dbb98 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/SchemaProcessing.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const securitySchemesExample = `function generateSecuritySchemes(spec: any, security: any): void { if (security.apiKey) { @@ -36,7 +41,9 @@ const securitySchemesExample = } }; } -}`; +}` + +//---------------------------------------------------------------------- const crudEndpointsExample = `function generateCRUDEndpoints(spec: any, modelName: string, model: any): void { @@ -232,15 +239,19 @@ const crudEndpointsExample = security: [{ BearerAuth: [] }] } }; -}`; +}` + +//---------------------------------------------------------------------- export default function SchemaProcessing() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Schema Processing')}

    + <> + {/* Schema Processing Section Content */} +
    +

    {_('4. Schema Processing')}

    Schema processing handles the transformation of @@ -257,6 +268,7 @@ export default function SchemaProcessing() { {crudEndpointsExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx index af96c9e..6d2183e 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/Troubleshooting.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const circularReferencesExample = `// Problem: Circular references in schemas +//code examples +//---------------------------------------------------------------------- + +const circularReferencesExample = + `// Problem: Circular references in schemas // Solution: Use allOf or oneOf patterns function handleCircularReferences(spec: any): void { @@ -35,9 +41,12 @@ function handleCircularReferences(spec: any): void { for (const [name, schema] of Object.entries(spec.components.schemas)) { checkSchema(schema, name); } -}`; +}` + +//---------------------------------------------------------------------- -const validationErrorsExample = `// Problem: Generated spec doesn't validate +const validationErrorsExample = + `// Problem: Generated spec doesn't validate // Solution: Add comprehensive validation function validateOpenAPISpec(spec: any): void { @@ -83,18 +92,24 @@ function validateOpenAPISpec(spec: any): void { } console.log('✅ OpenAPI specification validation passed'); -}`; +}` + +//---------------------------------------------------------------------- -const dependenciesExample = `# Install required dependencies +const dependenciesExample = + `# Install required dependencies npm install --save-dev yaml swagger-ui-dist # For validation npm install --save-dev swagger-parser # For code generation -npm install --save-dev @openapitools/openapi-generator-cli`; +npm install --save-dev @openapitools/openapi-generator-cli` -const performanceOptimizationExample = `// Problem: Large schemas cause performance issues +//---------------------------------------------------------------------- + +const performanceOptimizationExample = + `// Problem: Large schemas cause performance issues // Solution: Implement schema optimization function optimizeSchema(spec: any): any { @@ -132,9 +147,12 @@ function optimizeSchema(spec: any): any { schemas: optimizedSchemas } }; -}\n`; +}\n` + +//---------------------------------------------------------------------- -const debugModeExample = `interface DebugOpenAPIConfig extends AdvancedOpenAPIConfig { +const debugModeExample = + `interface DebugOpenAPIConfig extends AdvancedOpenAPIConfig { debug?: boolean; logLevel?: 'info' | 'warn' | 'error'; } @@ -187,101 +205,106 @@ export default async function generateOpenAPISpecWithDebug( } throw error; } -}\n`; +}\n` + +//---------------------------------------------------------------------- export default function Troubleshooting() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('8. Troubleshooting')}

    -

    - - This section addresses common issues encountered when - generating OpenAPI specifications and provides solutions - for debugging and resolving problems. Understanding these - troubleshooting techniques helps ensure reliable - specification generation. - -

    + <> + {/* Troubleshooting Section Content */} +
    +

    {_('8. Troubleshooting')}

    +

    + + This section addresses common issues encountered when + generating OpenAPI specifications and provides solutions + for debugging and resolving problems. Understanding these + troubleshooting techniques helps ensure reliable + specification generation. + +

    -

    {_('8.1. Common Issues')}

    -

    - - Common issues include schema reference errors, validation - failures, and performance problems with large specifications. - These problems typically arise from circular references, - invalid configurations, or missing dependencies. - -

    +

    {_('8.1. Common Issues')}

    +

    + + Common issues include schema reference errors, validation + failures, and performance problems with large specifications. + These problems typically arise from circular references, + invalid configurations, or missing dependencies. + +

    -

    {_('8.1.1. Schema Reference Errors')}

    -

    - - Schema reference errors occur when the generator encounters - circular dependencies or invalid references between schema - components. These issues can break the specification - generation process and require careful handling of schema - relationships. - -

    - - {circularReferencesExample} - +

    {_('8.1.1. Schema Reference Errors')}

    +

    + + Schema reference errors occur when the generator encounters + circular dependencies or invalid references between schema + components. These issues can break the specification + generation process and require careful handling of schema + relationships. + +

    + + {circularReferencesExample} + -

    {_('8.1.2. Invalid OpenAPI Format')}

    -

    - - Invalid OpenAPI format errors occur when the generated - specification doesn't conform to OpenAPI standards. These - validation failures can prevent the specification from - working with OpenAPI tools and require comprehensive - validation during generation. - -

    - - {validationErrorsExample} - +

    {_('8.1.2. Invalid OpenAPI Format')}

    +

    + + Invalid OpenAPI format errors occur when the generated + specification doesn't conform to OpenAPI standards. These + validation failures can prevent the specification from + working with OpenAPI tools and require comprehensive + validation during generation. + +

    + + {validationErrorsExample} + -

    {_('8.1.3. Missing Dependencies')}

    -

    - - Missing dependencies can cause the plugin to fail during - execution or limit available features. Ensuring all required - packages are installed and properly configured is essential - for reliable operation. - -

    - - {dependenciesExample} - +

    {_('8.1.3. Missing Dependencies')}

    +

    + + Missing dependencies can cause the plugin to fail during + execution or limit available features. Ensuring all required + packages are installed and properly configured is essential + for reliable operation. + +

    + + {dependenciesExample} + -

    {_('8.1.4. Performance Issues')}

    -

    - - Performance issues can occur when generating specifications - for large schemas with many models and complex relationships. - Optimization techniques help maintain reasonable generation - times and manageable output file sizes. - -

    - - {performanceOptimizationExample} - +

    {_('8.1.4. Performance Issues')}

    +

    + + Performance issues can occur when generating specifications + for large schemas with many models and complex relationships. + Optimization techniques help maintain reasonable generation + times and manageable output file sizes. + +

    + + {performanceOptimizationExample} + -

    {_('8.2. Debug Mode')}

    -

    - - Debug mode provides detailed logging and diagnostic - information during specification generation. This feature - helps identify issues, understand the generation process, - and optimize plugin configuration for better results. - -

    - - {debugModeExample} - -
    +

    {_('8.2. Debug Mode')}

    +

    + + Debug mode provides detailed logging and diagnostic + information during specification generation. This feature + helps identify issues, understand the generation process, + and optimize plugin configuration for better results. + +

    + + {debugModeExample} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx index e400800..1263f99 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/UsageExamples.tsx @@ -1,9 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C } from '../index.js'; +//local +import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; //code examples -const basicUsageExample = `// schema.idea +//---------------------------------------------------------------------- + +const basicUsageExample = +`// schema.idea enum UserRole { ADMIN "admin" USER "user" @@ -33,9 +38,12 @@ plugin "./plugins/openapi-spec.js" { security { bearer true } -}`; +}` + +//---------------------------------------------------------------------- -const advancedUsageExample = `// schema.idea +const advancedUsageExample = +`// schema.idea plugin "./plugins/openapi-spec.js" { output "./docs/api-spec" formats ["json" "yaml" "html"] @@ -167,9 +175,12 @@ plugin "./plugins/openapi-spec.js" { strict true examples true } -}`; +}` + +//---------------------------------------------------------------------- -const cliIntegrationExample = `# Generate OpenAPI specification +const cliIntegrationExample = +`# Generate OpenAPI specification npm run transform # Serve documentation locally @@ -180,16 +191,19 @@ npx swagger-codegen validate -i docs/api-spec.json # Generate client SDKs npx swagger-codegen generate -i docs/api-spec.json -l typescript-fetch -o ./sdk/typescript -npx swagger-codegen generate -i docs/api-spec.json -l python -o ./sdk/python`; +npx swagger-codegen generate -i docs/api-spec.json -l python -o ./sdk/python` +//---------------------------------------------------------------------- export default function UsageExamples() { //hooks const { _ } = useLanguage(); return ( -
    -

    {_('6. Usage Examples')}

    + <> + {/* Usage Examples Section Content */} +
    +

    {_('6. Usage Examples')}

    Usage examples demonstrate practical applications of the @@ -200,7 +214,7 @@ export default function UsageExamples() {

    -

    {_('6.1. Basic Usage')}

    +

    {_('6.1. Basic Usage')}

    Basic usage examples show the fundamental configuration @@ -214,7 +228,7 @@ export default function UsageExamples() { {basicUsageExample} -

    {_('6.2. Advanced Configuration')}

    +

    {_('6.2. Advanced Configuration')}

    Advanced configuration demonstrates comprehensive plugin @@ -228,7 +242,7 @@ export default function UsageExamples() { {advancedUsageExample} -

    {_('6.3. CLI Integration')}

    +

    {_('6.3. CLI Integration')}

    CLI integration shows how to incorporate the OpenAPI @@ -241,6 +255,7 @@ export default function UsageExamples() { {cliIntegrationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx b/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx index 59b80c4..4d87b11 100644 --- a/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx +++ b/packages/www/plugins/docs/components/openapi-specification-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as BasicImplementation } from './BasicImplementation.js'; diff --git a/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx b/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx index 95cf467..f93483b 100644 --- a/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx +++ b/packages/www/plugins/docs/components/specifications/data-types/Enums.tsx @@ -1,14 +1,22 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, SS } from '../../index.js'; import Code from '../../Code.js'; +//code examples +//---------------------------------------------------------------------- + const enumsExamples = [ `enum EnumName { KEY1 "Display Value 1" KEY2 "Display Value 2" KEY3 "Display Value 3" }`, - `enum UserRole { + +//---------------------------------------------------------------------- + +`enum UserRole { ADMIN "Administrator" MODERATOR "Moderator" USER "Regular User" @@ -29,13 +37,19 @@ enum Priority { HIGH "High Priority" URGENT "Urgent" }`, - `export enum UserRole { + +//---------------------------------------------------------------------- + +`export enum UserRole { ADMIN = "Administrator", MODERATOR = "Moderator", USER = "Regular User", GUEST = "Guest User" }`, - `{ + +//---------------------------------------------------------------------- + +`{ "enum": { "UserRole": { "ADMIN": "Administrator", @@ -45,82 +59,88 @@ enum Priority { } } }` -] +]; + +//---------------------------------------------------------------------- export default function Enums() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Enums')}

    - -

    - - Enums define a set of named constants with associated values, - perfect for representing fixed sets of options like user roles, - status values, or categories. - -

    - -

    {_('Syntax')}

    - - - {enumsExamples[0]} - - -

    {_('Structure')}

    -
      -
    • - {_('EnumName: ')} - The identifier used to reference this enum -
    • -
    • - {_('KEY: ')} - The constant name (typically uppercase) -
    • -
    • - {_('"Display Value": ')} - Human-readable label for the constant -
    • -
    - -

    {_('Example')}

    - - - {enumsExamples[1]} - - -

    {_('Generate Output')}

    - -

    - - When processed, enums generate language-specific constants: - -

    - -

    {_('TypeScript:')}

    - - - {enumsExamples[2]} - - -

    {_('JSON:')}

    - - - {enumsExamples[3]} - -
    + <> + {/* Enums Section Content */} +
    +

    {_('Enums')}

    + +

    + + Enums define a set of named constants with associated values, + perfect for representing fixed sets of options like user roles, + status values, or categories. + +

    + +

    {_('Syntax')}

    + + + {enumsExamples[0]} + + +

    {_('Structure')}

    +
      +
    • + {_('EnumName: ')} + The identifier used to reference this enum +
    • +
    • + {_('KEY: ')} + The constant name (typically uppercase) +
    • +
    • + {_('"Display Value": ')} + Human-readable label for the constant +
    • +
    + +

    {_('Example')}

    + + + {enumsExamples[1]} + + +

    {_('Generate Output')}

    + +

    + + When processed, enums generate language-specific constants: + +

    + +

    {_('TypeScript:')}

    + + + {enumsExamples[2]} + + +

    {_('JSON:')}

    + + + {enumsExamples[3]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/specifications/data-types/Models.tsx b/packages/www/plugins/docs/components/specifications/data-types/Models.tsx index f0e94c6..fde2b1e 100644 --- a/packages/www/plugins/docs/components/specifications/data-types/Models.tsx +++ b/packages/www/plugins/docs/components/specifications/data-types/Models.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, SS, C } from '../../index.js'; import Code from '../../Code.js'; +//code examples +//---------------------------------------------------------------------- + const modelsExamples = [ `model ModelName { columnName DataType @attribute1 @attribute2 @@ -11,7 +16,10 @@ const modelsExamples = [ model ModelName! { // Mutable model // columns... }`, - `// base-schema.idea + +//---------------------------------------------------------------------- + +`// base-schema.idea model User { id String @id name String @required @@ -32,7 +40,10 @@ model User! { username String @required password String @required }`, - `model User! { + +//---------------------------------------------------------------------- + +`model User! { id String @id @default("nanoid()") email String @unique @required @field.input(Email) username String @unique @required @field.input(Text) @@ -81,93 +92,98 @@ enum PostStatus { PUBLISHED "Published" ARCHIVED "Archived" }` +]; -] +//---------------------------------------------------------------------- export default function Models() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Models')}

    - -

    - - Models represent the core entities in your application, - typically corresponding to database tables or API resources. - They define the structure, relationships, and behavior of your - data. - -

    - -
    -

    {_('Syntax')}

    - - {modelsExamples[0]} - - -

    {_('Structure')}

    -
      -
    • - {_('ModelName: ')} - The identifier for this model -
    • -
    • - !: - - Optional non-mergeable indicator prevents automatic - merging when using use directives - -
    • -
    • - {_('columnName: ')} - The field name within the model -
    • -
    • - {_('DataType: ')} - - Built-in types (String, Number, Boolean, Date) or custom - types/enums - -
    • -
    • - {_('@attribute: ')} - - Attributes for validation, relationships, UI, etc. - -
    • -
    - -

    {_('Merging Behavior')}

    + <> + {/* Models Section Content */} +
    +

    {_('Models')}

    - By default, when importing schemas with use directives, - models with the same name are automatically merged. The ! - suffix prevents this behavior: + Models represent the core entities in your application, + typically corresponding to database tables or API resources. + They define the structure, relationships, and behavior of your + data.

    - - {modelsExamples[1]} - - -

    {_('Example')}

    - - {modelsExamples[2]} - + +
    +

    {_('Syntax')}

    + + {modelsExamples[0]} + + +

    {_('Structure')}

    +
      +
    • + {_('ModelName: ')} + The identifier for this model +
    • +
    • + !: + + Optional non-mergeable indicator prevents automatic + merging when using use directives + +
    • +
    • + {_('columnName: ')} + The field name within the model +
    • +
    • + {_('DataType: ')} + + Built-in types (String, Number, Boolean, Date) or custom + types/enums + +
    • +
    • + {_('@attribute: ')} + + Attributes for validation, relationships, UI, etc. + +
    • +
    + +

    {_('Merging Behavior')}

    + +

    + + By default, when importing schemas with use directives, + models with the same name are automatically merged. The ! + suffix prevents this behavior: + +

    + + {modelsExamples[1]} + + +

    {_('Example')}

    + + {modelsExamples[2]} + +
    -
    + ) } diff --git a/packages/www/plugins/docs/components/specifications/data-types/Props.tsx b/packages/www/plugins/docs/components/specifications/data-types/Props.tsx index 7245f06..c2bd086 100644 --- a/packages/www/plugins/docs/components/specifications/data-types/Props.tsx +++ b/packages/www/plugins/docs/components/specifications/data-types/Props.tsx @@ -1,15 +1,23 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//locals import { H1, H2, P, SS, C } from '../../index.js'; import Code from '../../Code.js'; +//code examples +//---------------------------------------------------------------------- + const propsExamples = [ - `prop PropName { +`prop PropName { property "value" nested { property "value" } }`, - `prop Email { + +//---------------------------------------------------------------------- + +`prop Email { type "email" format "email" validation { @@ -50,76 +58,85 @@ prop Currency { locale "en-US" } }`, - `model User { + +//---------------------------------------------------------------------- + +`model User { email String @field.input(Email) password String @field.input(Password) }` -] +]; + +//---------------------------------------------------------------------- export default function Props() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Props')}

    - -

    - - Props are reusable property configurations that define common - field behaviors, validation rules, and UI components. They - promote consistency and reduce duplication across your schema. - -

    - -

    {_('Syntax')}

    - - {propsExamples[0]} - - -

    {_('Structure')}

    - -
      -
    • - {_('PropName:')} + <> + {/* Props Section Content */} +
      +

      {_('Props')}

      + +

      - The identifier used to reference this prop + Props are reusable property configurations that define common + field behaviors, validation rules, and UI components. They + promote consistency and reduce duplication across your schema. -

    • -
    • - {_('property:')} - Configuration key-value pairs -
    • -
    • - {_('nested:')} - A nested prop -
    • -
    - -

    {_('Example')}

    - - {propsExamples[1]} - - - {_('Usage in Models')} -

    - Props are referenced using the - {_('@field')} {_('attribute:')} -

    - - {propsExamples[2]} - -
    +

    + +

    {_('Syntax')}

    + + {propsExamples[0]} + + +

    {_('Structure')}

    + +
      +
    • + {_('PropName:')} + + The identifier used to reference this prop + +
    • +
    • + {_('property:')} + Configuration key-value pairs +
    • +
    • + {_('nested:')} + A nested prop +
    • +
    + +

    {_('Example')}

    + + {propsExamples[1]} + + + {_('Usage in Models')} +

    + Props are referenced using the + {_('@field')} {_('attribute:')} +

    + + {propsExamples[2]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/specifications/data-types/Type.tsx b/packages/www/plugins/docs/components/specifications/data-types/Type.tsx index c9c4e21..beec887 100644 --- a/packages/www/plugins/docs/components/specifications/data-types/Type.tsx +++ b/packages/www/plugins/docs/components/specifications/data-types/Type.tsx @@ -1,13 +1,21 @@ +//moudles import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, SS } from '../../index.js'; import Code from '../../Code.js'; +//code examples +//---------------------------------------------------------------------- + const typeExamples = [ `type TypeName { columnName DataType @attribute1 @attribute2 anotherColumn DataType @attribute }`, - `type Address { + +//---------------------------------------------------------------------- + +`type Address { street String @required @field.input(Text) city String @required @field.input(Text) state String @field.select @@ -35,7 +43,10 @@ type Money { currency String @default("USD") @field.select exchangeRate Number @field.input(Number) }`, - `model Company { + +//---------------------------------------------------------------------- + +`model Company { name String @required address Address @required contact ContactInfo @@ -44,76 +55,80 @@ type Money { ] export default function Type() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Type')}

    - -

    - - Types define custom data structures with multiple columns, - similar to objects or structs in programming languages. They - are perfect for representing complex data that doesn't warrant - a full model. - -

    - -

    {_('Syntax')}

    - - {typeExamples[0]} - - -

    {_('Structure')}

    - -
      -
    • - {_('TypeName: ')} - - The identifier used to reference this type - -
    • -
    • - {_('columnName: ')} - The field name within the type -
    • -
    • - {_('DataType: ')} - - The data type (String, Number, Boolean, Date, etc.) - -
    • -
    • - {_('attribute: ')} + <> + {/* Type Section Content */} +
      +

      {_('Type')}

      + +

      - Optional attributes for validation, UI, or behavior + Types define custom data structures with multiple columns, + similar to objects or structs in programming languages. They + are perfect for representing complex data that doesn't warrant + a full model. -

    • -
    - -

    {_('Example')}

    - - - {typeExamples[1]} - - -

    {_('Usage in Models')}

    -

    - Types are used as column data types: -

    - - {typeExamples[2]} - -
    +

    + +

    {_('Syntax')}

    + + {typeExamples[0]} + + +

    {_('Structure')}

    + +
      +
    • + {_('TypeName: ')} + + The identifier used to reference this type + +
    • +
    • + {_('columnName: ')} + The field name within the type +
    • +
    • + {_('DataType: ')} + + The data type (String, Number, Boolean, Date, etc.) + +
    • +
    • + {_('attribute: ')} + + Optional attributes for validation, UI, or behavior + +
    • +
    + +

    {_('Example')}

    + + + {typeExamples[1]} + + +

    {_('Usage in Models')}

    +

    + Types are used as column data types: +

    + + {typeExamples[2]} + + + ) } diff --git a/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx b/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx index adce31b..4e2c63c 100644 --- a/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx +++ b/packages/www/plugins/docs/components/specifications/schema-directives/Plugin.tsx @@ -1,6 +1,11 @@ +//modules +import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, SS, C } from '../../index.js'; import Code from '../../Code.js'; -import { useLanguage, Translate } from 'r22n'; + +//code examples +//---------------------------------------------------------------------- const pluginExamples = [ `plugin "path/to/plugin.js" { @@ -10,6 +15,9 @@ const pluginExamples = [ flag true } }`, + + //---------------------------------------------------------------------- + `// TypeScript interface generation plugin "./plugins/typescript-generator.js" { output "./src/types/schema.ts" @@ -76,6 +84,9 @@ plugin "./plugins/form-generator.js" { errorMessage "ErrorText" } }`, + + //---------------------------------------------------------------------- + `plugin "./plugins/my-plugin.js" { // Output configuration output "./generated/output.ts" @@ -107,6 +118,9 @@ plugin "./plugins/form-generator.js" { compressionLevel 9 } }`, + + //---------------------------------------------------------------------- + `// Generate TypeScript types plugin "./plugins/typescript.js" { output "./src/types/index.ts" @@ -135,7 +149,10 @@ plugin "./plugins/validation.js" { output "./src/validation/index.ts" library "zod" }`, -`// Example plugin structure + + //---------------------------------------------------------------------- + + `// Example plugin structure import type { PluginProps } from '@stackpress/idea-transformer/types'; interface MyPluginConfig { @@ -163,120 +180,130 @@ export default async function myPlugin( console.log(\`✅ Generated: \${outputPath}\`); }` -] +]; + +//---------------------------------------------------------------------- export default function Plugin() { + //hooks const { _ } = useLanguage(); return ( -
    -
    + <> + {/* Plugin Section Content */} +

    {_('Plugin')}

    - The plugin directive configures code generation - plugins that process your schema and generate various - outputs like TypeScript interfaces, database schemas, API + The plugin directive configures code generation + plugins that process your schema and generate various + outputs like TypeScript interfaces, database schemas, API documentation, and more.

    -
    -
    -

    {_('Syntax')}

    - - {pluginExamples[0]} - -
    + {/* Syntax Section Content */} +
    +

    {_('Syntax')}

    + + {pluginExamples[0]} + +
    + + {/* Structure Section Content */} +
    +

    {_('Structure')}

    +
      +
    • + {_('Path:')}{' '} + + Relative or absolute path to the plugin file + +
    • +
    • + {_('Configuration Block:')}{' '} + + Key-value pairs that configure the plugin behavior + +
    • +
    • + {_('Nested Configuration:')}{' '} + + Support for complex configuration structures + +
    • +
    +
    + + {/* Example Section Content */} +
    +

    {_('Example')}

    + + {pluginExamples[1]} + +
    -
    -

    {_('Structure')}

    -
      -
    • - {_('Path:')}{' '} + {/* Plugin Configuration Options Section Content */} +
      +

      {_('Plugin Configuration Options')}

      +

      - Relative or absolute path to the plugin file + Common configuration patterns across different plugin types: -

    • -
    • - {_('Configuration Block:')}{' '} +

      + + {pluginExamples[2]} + +
    + + {/* Multiple Plugins Execution Section Content */} +
    +

    {_('Multiple Plugins Execution')}

    +

    - Key-value pairs that configure the plugin behavior + You can configure multiple plugins to generate different + outputs from the same schema: - -

  • - {_('Nested Configuration:')}{' '} +

    + + {pluginExamples[3]} + +
  • + + {/* Plugin Development Section Content */} +
    +

    {_('Plugin Development')}

    +

    - Support for complex configuration structures + Plugins are JavaScript/TypeScript modules that export a + default function: - - -

    - -
    -

    {_('Example')}

    - - {pluginExamples[1]} - -
    - -
    -

    {_('Plugin Configuration Options')}

    -

    - - Common configuration patterns across different plugin types: - -

    - - {pluginExamples[2]} - -
    - -
    -

    {_('Multiple Plugins Execution')}

    -

    - - You can configure multiple plugins to generate different - outputs from the same schema: - -

    - - {pluginExamples[3]} - -
    - -
    -

    {_('Plugin Development')}

    -

    - - Plugins are JavaScript/TypeScript modules that export a - default function: - -

    - - {pluginExamples[4]} - +

    + + {pluginExamples[4]} + +
    - + ); } diff --git a/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx b/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx index d45d35d..b9d8ac6 100644 --- a/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx +++ b/packages/www/plugins/docs/components/specifications/schema-directives/Use.tsx @@ -1,13 +1,20 @@ +//modules +import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, SS, C } from '../../index.js'; import Code from '../../Code.js'; -import { useLanguage, Translate } from 'r22n'; +//code examples +//---------------------------------------------------------------------- const useExamples = [ - `use "package/to/schema.idea" +`use "package/to/schema.idea" use "./relative/path/schema.idea" use "../parent/directory/schema.idea"`, - `// Common types used across multiple schemas + +//---------------------------------------------------------------------- + +`// Common types used across multiple schemas type Address { street String @required city String @required @@ -26,7 +33,10 @@ prop Email { format "email" } }`, - `// Import common definitions + +//---------------------------------------------------------------------- + +`// Import common definitions use "../shared/common.idea" // Extend the Status enum (will merge with imported one) @@ -42,17 +52,26 @@ model User { address Address status Status @default("PENDING") }`, - `// The Status enum now contains all values + +//---------------------------------------------------------------------- + +`// The Status enum now contains all values enum Status { ACTIVE "Active" // From common.idea INACTIVE "Inactive" // From common.idea PENDING "Pending Approval" // From user-schema.idea SUSPENDED "Temporarily Suspended" // From user-schema.idea }`, + +//---------------------------------------------------------------------- + `enum UserRole { USER "Regular User" ADMIN "Administrator" }`, + +//---------------------------------------------------------------------- + `use "./base-schema.idea" // This will NOT merge with the imported UserRole @@ -63,6 +82,9 @@ enum UserRole! { MODERATOR "Moderator" ADMIN "Administrator" }`, + +//---------------------------------------------------------------------- + `// ✅ Good - organize by domain use "./shared/common-types.idea" use "./auth/user-types.idea" @@ -76,14 +98,18 @@ use "./props/form-props.idea" // ❌ Avoid - unclear imports use "./stuff.idea" use "./misc.idea"` -] +]; + +//---------------------------------------------------------------------- export default function Use() { + //hooks const { _ } = useLanguage(); return ( -
    -
    + <> + {/* Use Section Content */} +

    {_('Use')}

    @@ -94,126 +120,133 @@ export default function Use() { indicator is used.

    -
    -
    -

    {_('Syntax')}

    - - {useExamples[0]} - -
    - -
    -

    {_('Structure')}

    -
      -
    • - {_('Path:')} {_('Relative or absolute path to the')}{' '} - .idea {_('file to import')} -
    • -
    • - {_('Automatic Merging:')}{' '} - {_('Data types with matching names are merged by default')} -
    • -
    • - {_('Merge Prevention:')} {_('Use')} !{' '} - {_('suffix to prevent merging')} -
    • -
    -
    - -
    -

    {_('Example')}

    -

    shared/common.idea

    - - {useExamples[1]} - - -

    user/user-schema.idea:

    - - {useExamples[2]} - - -

    {_('Result after merging:')}

    - - {useExamples[3]} - -
    - -
    - {_('Prevent merging with')} ! -

    - - When you want to prevent automatic merging and keep definitions{' '} - separate, use the ! suffix: - -

    - - {_('base-schema.idea:')} - - {useExamples[4]} - - - {_('extended-schema.idea:')} - - {useExamples[5]} - -
    - -
    -

    {_('Use Cases')}

    -
      -
    • - {_('Shared Types:')}{' '} - {_('Define common types once and reuse across multiple schemas')} -
    • -
    • - {_('Modular Organization:')}{' '} - {_('Split large schemas into manageable, focused files')} -
    • -
    • - {_('Team Collaboration:')}{' '} - {_('Different teams can work on separate schema files')} -
    • -
    • - {_('Environment-Specific:')}{' '} - {_('Override certain definitions for different environments')} -
    • -
    -
    -
    -

    {_('Best Practices')}

    - - {useExamples[6]} - + {/* Syntax Section Content */} +
    +

    {_('Syntax')}

    + + {useExamples[0]} + +
    + + {/* Structure Section Content */} +
    +

    {_('Structure')}

    +
      +
    • + {_('Path:')} {_('Relative or absolute path to the')}{' '} + .idea {_('file to import')} +
    • +
    • + {_('Automatic Merging:')}{' '} + {_('Data types with matching names are merged by default')} +
    • +
    • + {_('Merge Prevention:')} {_('Use')} !{' '} + {_('suffix to prevent merging')} +
    • +
    +
    + + {/* Example Section Content */} +
    +

    {_('Example')}

    +

    shared/common.idea

    + + {useExamples[1]} + + +

    user/user-schema.idea:

    + + {useExamples[2]} + + +

    {_('Result after merging:')}

    + + {useExamples[3]} + +
    + + {/* Prevent Merging with ! Section Content */} +
    + {_('Prevent merging with')} ! +

    + + When you want to prevent automatic merging and keep definitions{' '} + separate, use the ! suffix: + +

    + + {_('base-schema.idea:')} + + {useExamples[4]} + + + {_('extended-schema.idea:')} + + {useExamples[5]} + +
    + + {/* Use Cases Content */} +
    +

    {_('Use Cases')}

    +
      +
    • + {_('Shared Types:')}{' '} + {_('Define common types once and reuse across multiple schemas')} +
    • +
    • + {_('Modular Organization:')}{' '} + {_('Split large schemas into manageable, focused files')} +
    • +
    • + {_('Team Collaboration:')}{' '} + {_('Different teams can work on separate schema files')} +
    • +
    • + {_('Environment-Specific:')}{' '} + {_('Override certain definitions for different environments')} +
    • +
    +
    + + {/* Best Practices Section Content */} +
    +

    {_('Best Practices')}

    + + {useExamples[6]} + +
    -
    + ); } diff --git a/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx b/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx index ece6b34..7409d36 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/Conclusion.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; export default function Conclusion() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Conclusion')}

    + <> + {/* Conclusion Section Content */} +
    +

    {_('Conclusion')}

    This tutorial provides a comprehensive foundation for creating @@ -15,6 +20,7 @@ export default function Conclusion() { workflows.

    -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx b/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx index a34c388..2eb7e82 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/CorePluginFunction.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const corePluginExample = `export default async function generateTestData( +//code examples +//---------------------------------------------------------------------- + +const corePluginExample = +`export default async function generateTestData( props: PluginProps<{ config: TestDataConfig }> ) { const { config, schema, transformer } = props; @@ -47,9 +53,12 @@ const corePluginExample = `export default async function generateTestData( console.error('❌ Test data generation failed:', error.message); throw error; } -}`; +}` + +//---------------------------------------------------------------------- -const headerAndImportsExample = `function generateFileHeader(config: TestDataConfig): string { +const headerAndImportsExample = +`function generateFileHeader(config: TestDataConfig): string { const timestamp = new Date().toISOString(); return \`/** * Generated Test Data and Fixtures @@ -80,14 +89,19 @@ function generateImports(config: TestDataConfig): string { } return imports; -}`; +}` + +//---------------------------------------------------------------------- export default function CorePluginFunction() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Implementation')}

    + <> + {/* Implementation Section Content */} +
    +

    {_('4. Implementation')}

    The implementation section covers the core plugin function and @@ -97,7 +111,7 @@ export default function CorePluginFunction() {

    -

    {_('4.1. Core Plugin Function')}

    +

    {_('4.1. Core Plugin Function')}

    The core plugin function serves as the main entry point for test @@ -110,7 +124,7 @@ export default function CorePluginFunction() { {corePluginExample} -

    {_('4.2. Generation Functions')}

    +

    {_('4.2. Generation Functions')}

    The generation functions provide the core logic for creating @@ -122,6 +136,7 @@ export default function CorePluginFunction() { {headerAndImportsExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx b/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx index 5bd1d07..266841e 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/GenerationFunctions.tsx @@ -1,6 +1,11 @@ +//local import Code from '../Code.js'; -const factoriesExample = `function generateFactories(schema: any, config: TestDataConfig): string { +//code examples +//---------------------------------------------------------------------- + +const factoriesExample = +`function generateFactories(schema: any, config: TestDataConfig): string { let content = '// Data Factories\\n'; // Generate enum factories @@ -52,9 +57,12 @@ export function generate\${modelName}Array(count: number = \${config.count || 10 \`; return content; -}`; +}` + +//---------------------------------------------------------------------- -const fieldGeneratorExample = `function generateFieldGenerator(column: any, config: TestDataConfig): string { +const fieldGeneratorExample = +`function generateFieldGenerator(column: any, config: TestDataConfig): string { // Check for custom generators first if (config.customGenerators && config.customGenerators[column.type]) { return config.customGenerators[column.type]; @@ -187,9 +195,12 @@ function getBaseGenerator(column: any, config: TestDataConfig): string { } return 'faker.lorem.word()'; } -}`; +}` -const mockDataExample = `function generateMockData(models: Record, config: TestDataConfig): string { +//---------------------------------------------------------------------- + +const mockDataExample = +`function generateMockData(models: Record, config: TestDataConfig): string { if (config.format === 'json') { return generateJSONMockData(models, config); } @@ -252,9 +263,12 @@ function generateMockValue(column: any, config: TestDataConfig): any { default: return 'mock_value'; } -}`; +}` + +//---------------------------------------------------------------------- -const fixturesExample = `function generateFixtures(schema: any, config: TestDataConfig): string { +const fixturesExample = +`function generateFixtures(schema: any, config: TestDataConfig): string { let content = '// Test Fixtures\\n'; if (schema.model) { @@ -291,9 +305,12 @@ function generateModelFixtures(modelName: string, model: any, config: TestDataCo }; \`; -}`; +}` -const fixtureUtilsExample = `function generateMinimalFields(model: any): string { +//---------------------------------------------------------------------- + +const fixtureUtilsExample = +`function generateMinimalFields(model: any): string { const requiredFields = model.columns?.filter((col: any) => col.required && !col.attributes?.id && !col.attributes?.default ) || []; @@ -320,9 +337,12 @@ function generateEdgeCaseFields(model: any): string { const edgeValue = getEdgeCaseValue(col); return \`\${col.name}: \${edgeValue}\`; }).join(',\\n '); -}`; +}` + +//---------------------------------------------------------------------- -const valueGeneratorsExample = `function getMinimalValue(column: any): string { +const valueGeneratorsExample = +`function getMinimalValue(column: any): string { switch (column.type) { case 'String': return '"a"'; @@ -373,9 +393,12 @@ function getEdgeCaseValue(column: any): string { default: return '""'; } -}`; +}` -const mainExportExample = `function generateMainExport(schema: any, config: TestDataConfig): string { +//---------------------------------------------------------------------- + +const mainExportExample = +`function generateMainExport(schema: any, config: TestDataConfig): string { if (config.format === 'json') { return ''; // JSON format doesn't need exports } @@ -427,11 +450,15 @@ function validateConfig(config: any): asserts config is TestDataConfig { if (config.count && (typeof config.count !== 'number' || config.count < 1)) { throw new Error('count must be a positive number'); } -}`; +}` + +//---------------------------------------------------------------------- export default function GenerationFunctions() { return ( -
    + <> + {/* Generation Functions Section Content */} +
    {factoriesExample} @@ -453,6 +480,7 @@ export default function GenerationFunctions() { {mainExportExample} -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx b/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx index 4d9942d..b79c40f 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/Overview.tsx @@ -1,11 +1,16 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H1, H2, P, SS } from '../index.js'; +//local +import { H1, P, SS } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Creating a Test Data Generator Plugin */} +

    {_('Test Data Generator Plugin Tutorial')}

    @@ -15,8 +20,11 @@ export default function Overview() { realistic test data for development, testing, and prototyping.

    +
    -

    {_('1. Overview')}

    + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    Test data generation is crucial for development and testing @@ -51,6 +59,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx index cfb3a6e..bc5b93a 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/PluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -24,14 +30,19 @@ export default async function generateTestData( const { config, schema, transformer } = props; // Implementation here... -}`; +}` + +//---------------------------------------------------------------------- export default function PluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Plugin Structure')}

    + <> + {/* Plugin Structure Section Content */} +
    +

    {_('3. Plugin Structure')}

    The following code shows how to generally layout the plugin so @@ -41,6 +52,7 @@ export default function PluginStructure() { {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx index 486bb1d..29f87fd 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('2. Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    Before creating this plugin, you should have the following @@ -33,6 +38,7 @@ export default function Prerequisites() { Understanding of .idea schema format -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx index f60ee70..e3ad8a2 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/SchemaConfiguration.tsx @@ -1,9 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, SS } from '../index.js'; -import Code from '../Code.js'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; +//local +import { H1, H2, P, C, SS } from '../index.js'; +import Code from '../Code.js'; -const schemaConfigExample = `plugin "./plugins/test-data.js" { +//code examples +//---------------------------------------------------------------------- + +const schemaConfigExample = +`plugin "./plugins/test-data.js" { output "./generated/test-data.ts" format "typescript" count 20 @@ -17,14 +23,19 @@ const schemaConfigExample = `plugin "./plugins/test-data.js" { Password "faker.internet.password()" Slug "faker.lorem.slug()" } -}`; +}` + +//---------------------------------------------------------------------- export default function SchemaConfiguration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Schema Configuration')}

    + <> + {/* Schema Configuration Section Content */} +
    +

    {_('5. Schema Configuration')}

    The schema configuration section demonstrates how to integrate @@ -42,7 +53,7 @@ export default function SchemaConfiguration() { {schemaConfigExample} -

    {_('5.1. Configuration Options')}

    +

    {_('5.1. Configuration Options')}

    The following options will be processed by the test data plugin @@ -130,6 +141,7 @@ export default function SchemaConfiguration() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/test-data-plugin/index.tsx b/packages/www/plugins/docs/components/test-data-plugin/index.tsx index d9611ee..6d60e22 100644 --- a/packages/www/plugins/docs/components/test-data-plugin/index.tsx +++ b/packages/www/plugins/docs/components/test-data-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; export { default as PluginStructure } from './PluginStructure.js'; diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx index 0fd16a1..ec90397 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/AdvanceTsMorphPlugin.tsx @@ -1,9 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const examples = [ -`// Add a class with decorators + `// Add a class with decorators sourceFile.addClass({ name: "UserController", isExported: true, @@ -39,7 +44,10 @@ sourceFile.addClass({ }, ], });`, -`// Generate mapped types + +//---------------------------------------------------------------------- + + `// Generate mapped types sourceFile.addTypeAlias({ name: "PartialUser", type: "{ [K in keyof User]?: User[K] }", @@ -58,7 +66,10 @@ sourceFile.addTypeAlias({ typeParameters: [{ name: "T", constraint: "string" }], type: \`on\${Capitalize}\`, });`, -`// Add module declaration + + //---------------------------------------------------------------------- + + `// Add module declaration sourceFile.addModule({ name: "Express", declarationKind: ModuleDeclarationKind.Module, @@ -82,7 +93,10 @@ sourceFile.addModule({ "export function myFunction(): void;", ], });`, -`// Find and modify existing interfaces + + //---------------------------------------------------------------------- + + `// Find and modify existing interfaces const existingInterface = sourceFile.getInterface("User"); if (existingInterface) { // Add new properties @@ -106,88 +120,95 @@ if (existingInterface) { const deprecatedMethod = sourceFile.getFunction("oldFunction"); deprecatedMethod?.remove();` ]; - + +//---------------------------------------------------------------------- + export default function AdvanceTsMorphPlugin() { + //hooks const { _ } = useLanguage(); + return ( -
    -

    {_('6. Advanced ts-morph Features')}

    -

    - - Advanced ts-morph features enable sophisticated code generation - scenarios including decorators, complex type systems, module - declarations, and code manipulation. These features are essential - for building production-ready plugins that handle enterprise-level - requirements. - -

    - -

    {_('6.1. Working with Decorators')}

    -

    - - Decorators are essential for modern TypeScript applications, - especially when working with frameworks like Angular, NestJS, or - TypeORM. ts-morph provides comprehensive support for generating - classes and methods with decorators. - -

    - - {examples[0]} - - -

    {_('6.2. Generating Complex Types')}

    -

    - - Complex type generation includes mapped types, conditional types, - and template literal types that leverage TypeScript's advanced - type system. These features enable the creation of sophisticated - type-safe APIs and utility types. - -

    - - {examples[1]} - - -

    {_('6.3. Working with Modules')}

    -

    - - Module declarations and ambient modules are crucial for creating - type definitions and extending existing libraries. This section - covers both namespace-style modules and modern ES module patterns. - -

    - - {examples[2]} - - -

    {_('6.4. Manipulating Existing Code')}

    -

    - - Code manipulation capabilities allow plugins to modify existing - TypeScript files, add new functionality, and refactor code - structures. This is particularly useful for migration tools and - code modernization plugins. - -

    - - {examples[3]} - -
    + <> + {/* Advanced ts-morph Features Section Content*/} +
    +

    {_('6. Advanced ts-morph Features')}

    +

    + + Advanced ts-morph features enable sophisticated code generation + scenarios including decorators, complex type systems, module + declarations, and code manipulation. These features are essential + for building production-ready plugins that handle enterprise-level + requirements. + +

    + +

    {_('6.1. Working with Decorators')}

    +

    + + Decorators are essential for modern TypeScript applications, + especially when working with frameworks like Angular, NestJS, or + TypeORM. ts-morph provides comprehensive support for generating + classes and methods with decorators. + +

    + + {examples[0]} + + +

    {_('6.2. Generating Complex Types')}

    +

    + + Complex type generation includes mapped types, conditional types, + and template literal types that leverage TypeScript's advanced + type system. These features enable the creation of sophisticated + type-safe APIs and utility types. + +

    + + {examples[1]} + + +

    {_('6.3. Working with Modules')}

    +

    + + Module declarations and ambient modules are crucial for creating + type definitions and extending existing libraries. This section + covers both namespace-style modules and modern ES module patterns. + +

    + + {examples[2]} + + +

    {_('6.4. Manipulating Existing Code')}

    +

    + + Code manipulation capabilities allow plugins to modify existing + TypeScript files, add new functionality, and refactor code + structures. This is particularly useful for migration tools and + code modernization plugins. + +

    + + {examples[3]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx index 314e832..ec99dc5 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/BestPractices.tsx @@ -1,9 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H1, H2, P } from '../index.js' -import Code from '../Code.js' +//local +import { H1, H2, P } from '../index.js'; +import Code from '../Code.js'; + +//code examples +//---------------------------------------------------------------------- const examples = [ -`interface PluginOptions { + `interface PluginOptions { readonly input: string; readonly output: string; readonly strict?: boolean; @@ -24,7 +29,10 @@ function validateOptions(options: unknown): asserts options is PluginOptions { throw new Error('output must be a string'); } }`, -`class PluginError extends Error { + + //---------------------------------------------------------------------- + + `class PluginError extends Error { constructor( message: string, public readonly code: string, @@ -58,7 +66,10 @@ async function safeGenerate(config: PluginConfig): Promise { throw error; } }`, -`class OptimizedGenerator { + + //---------------------------------------------------------------------- + + `class OptimizedGenerator { private typeCache = new Map(); private interfaceCache = new Map(); @@ -88,7 +99,10 @@ async function safeGenerate(config: PluginConfig): Promise { interfaceDecl.addProperties(propertyStructures); } }`, -`// generators/interface-generator.ts + + //---------------------------------------------------------------------- + + `// generators/interface-generator.ts export class InterfaceGenerator { generate(schema: Schema): InterfaceDeclaration { // Interface-specific logic @@ -121,7 +135,10 @@ export class MainPlugin { // Orchestrate all generators } }`, -`function generateJSDocComment( + + //---------------------------------------------------------------------- + + `function generateJSDocComment( property: SchemaProperty, includeExamples: boolean = true ): string { @@ -147,130 +164,137 @@ export class MainPlugin { }` ]; +//---------------------------------------------------------------------- + export default function BestPractices() { + //hooks const { _ } = useLanguage(); + return ( -
    -

    {_('8. Best Practices')}

    -

    - - Following best practices ensures your plugins are maintainable, - performant, and reliable in production environments. These - guidelines cover type safety, error handling, performance - optimization, and code organization strategies. - -

    + <> + {/* Best Practices Section Content */} +
    +

    {_('8. Best Practices')}

    +

    + + Following best practices ensures your plugins are maintainable, + performant, and reliable in production environments. These + guidelines cover type safety, error handling, performance + optimization, and code organization strategies. + +

    -

    {_('8.1. Type Safety')}

    -

    - - Type safety is fundamental to building reliable plugins that catch - errors at compile time rather than runtime. Always use TypeScript - interfaces and proper type validation throughout your plugin - implementation. - -

    -

    - - Always use TypeScript interfaces for your plugin configuration - and data structures: - -

    - - {examples[0]} - +

    {_('8.1. Type Safety')}

    +

    + + Type safety is fundamental to building reliable plugins that catch + errors at compile time rather than runtime. Always use TypeScript + interfaces and proper type validation throughout your plugin + implementation. + +

    +

    + + Always use TypeScript interfaces for your plugin configuration + and data structures: + +

    + + {examples[0]} + -

    {_('8.2. Error Handling')}

    -

    - - Comprehensive error handling provides clear feedback to users and - helps with debugging when things go wrong. Implement custom error - types and meaningful error messages to improve the developer - experience. - -

    -

    - - Implement comprehensive error handling: - -

    - - {examples[1]} - +

    {_('8.2. Error Handling')}

    +

    + + Comprehensive error handling provides clear feedback to users and + helps with debugging when things go wrong. Implement custom error + types and meaningful error messages to improve the developer + experience. + +

    +

    + + Implement comprehensive error handling: + +

    + + {examples[1]} + -

    {_('8.3. Performance Optimization')}

    -

    - - Performance optimization becomes crucial when dealing with large - schemas or generating substantial amounts of code. Implement - caching strategies and batch processing to maintain reasonable - execution times. - -

    -

    - - For large schemas, optimize performance: - -

    - - {examples[2]} - +

    {_('8.3. Performance Optimization')}

    +

    + + Performance optimization becomes crucial when dealing with large + schemas or generating substantial amounts of code. Implement + caching strategies and batch processing to maintain reasonable + execution times. + +

    +

    + + For large schemas, optimize performance: + +

    + + {examples[2]} + -

    {_('8.4. Code Organization')}

    -

    - - Proper code organization makes your plugin easier to maintain, - test, and extend. Separate concerns into focused classes and - modules that each handle specific aspects of the generation - process. - -

    -

    - - Structure your plugin code for maintainability: - -

    - - {examples[3]} - +

    {_('8.4. Code Organization')}

    +

    + + Proper code organization makes your plugin easier to maintain, + test, and extend. Separate concerns into focused classes and + modules that each handle specific aspects of the generation + process. + +

    +

    + + Structure your plugin code for maintainability: + +

    + + {examples[3]} + -

    {_('8.5. Documentation Generation')}

    -

    - - Documentation generation ensures your generated code is - self-documenting and provides valuable context for developers. - Implement comprehensive JSDoc comment generation with examples - and type information. - -

    -

    - - Add comprehensive JSDoc comments: - -

    - - {examples[4]} - -
    +

    {_('8.5. Documentation Generation')}

    +

    + + Documentation generation ensures your generated code is + self-documenting and provides valuable context for developers. + Implement comprehensive JSDoc comment generation with examples + and type information. + +

    +

    + + Add comprehensive JSDoc comments: + +

    + + {examples[4]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx index 9c5c7c8..1e3ca83 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/CreateFirstPlugin.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const examples = [ `// src/types.ts export interface SchemaProperty { @@ -28,6 +33,9 @@ export interface PluginConfig { generateUtilityTypes?: boolean; exportType?: 'named' | 'default' | 'namespace'; }`, + + //---------------------------------------------------------------------- + `// src/plugin.ts import { Project, SourceFile, InterfaceDeclaration } from "ts-morph"; import { Schema, SchemaProperty, PluginConfig } from "./types"; @@ -270,6 +278,9 @@ export class TypeScriptInterfaceGenerator { } } }`, + + //---------------------------------------------------------------------- + `// src/index.ts import { TypeScriptInterfaceGenerator } from "./plugin"; import { PluginConfig } from "./types"; @@ -294,6 +305,9 @@ if (require.main === module) { generateTypeScriptInterfaces(config).catch(console.error); }`, + + //---------------------------------------------------------------------- + `// examples/input.json [ { @@ -382,7 +396,13 @@ if (require.main === module) { "required": ["id", "title", "content", "authorId"] } ]`, + + //---------------------------------------------------------------------- + `npx ts-node src/index.ts examples/input.json examples/output.ts`, + + //---------------------------------------------------------------------- + `// examples/output.ts /** * Generated TypeScript interfaces @@ -477,129 +497,137 @@ export type PostKeys = keyof Post; export type AnyModel = User | Post;` ]; +//---------------------------------------------------------------------- + export default function CreateFirstPlugin() { + //hooks const { _ } = useLanguage(); + return ( -
    -

    {_('5. Creating Your First Plugin')}

    -

    - - Creating your first plugin with ts-morph involves - understanding the complete workflow from schema processing to code - generation. This comprehensive example demonstrates building a - TypeScript interface generator that transforms JSON schemas into - properly typed interfaces with full feature support. - -

    -

    - - Let's create a plugin that generates TypeScript interfaces from - JSON schema definitions. This will demonstrate the core concepts - of using ts-morph for code generation. - -

    - -

    {_('5.1. Define the Plugin Interface')}

    -

    - - Defining clear interfaces for your plugin ensures type safety and - provides a solid foundation for implementation. This section - establishes the data structures and configuration options that - will guide the entire plugin development process. - -

    -

    - - First, let's define the types for our plugin: - -

    - - {examples[0]} - - -

    {_('5.2. Core Plugin Implementation')}

    -

    - - The core plugin implementation orchestrates the entire code - generation process, from loading input schemas to generating and - saving TypeScript files. This comprehensive class demonstrates - best practices for plugin architecture and error handling. - -

    - - {examples[1]} - - -

    {_('5.3. Plugin Entry Point')}

    -

    - - The plugin entry point provides a clean API for consumers and - handles CLI integration. This section shows how to create both - programmatic and command-line interfaces for your plugin, making - it accessible in different usage scenarios. - -

    - - {examples[2]} - - -

    {_('5.4. Example Usage')}

    -

    - - Example usage demonstrates the plugin in action with realistic - data structures. This comprehensive example shows how the plugin - processes complex schemas with various property types, - relationships, and validation rules. - -

    -

    - - Create an example schema file: - -

    - - {examples[3]} - -

    - - Run the plugin: - -

    - - {examples[4]} - -

    - - Generated output: - -

    - - {examples[5]} - -
    + <> + {/* Creating Your First Plugin Section Content */} +
    +

    {_('5. Creating Your First Plugin')}

    +

    + + Creating your first plugin with ts-morph involves + understanding the complete workflow from schema processing + to code generation. This comprehensive example demonstrates + building a TypeScript interface generator that transforms + JSON schemas into properly typed interfaces with full feature + support. + +

    +

    + + Let's create a plugin that generates TypeScript interfaces + from JSON schema definitions. This will demonstrate the core + concepts of using ts-morph for code generation. + +

    + +

    {_('5.1. Define the Plugin Interface')}

    +

    + + Defining clear interfaces for your plugin ensures type safety + and provides a solid foundation for implementation. This + section establishes the data structures and configuration + options that will guide the entire plugin development process. + +

    +

    + + First, let's define the types for our plugin: + +

    + + {examples[0]} + + +

    {_('5.2. Core Plugin Implementation')}

    +

    + + The core plugin implementation orchestrates the entire code + generation process, from loading input schemas to generating and + saving TypeScript files. This comprehensive class demonstrates + best practices for plugin architecture and error handling. + +

    + + {examples[1]} + + +

    {_('5.3. Plugin Entry Point')}

    +

    + + The plugin entry point provides a clean API for consumers and + handles CLI integration. This section shows how to create both + programmatic and command-line interfaces for your plugin, making + it accessible in different usage scenarios. + +

    + + {examples[2]} + + +

    {_('5.4. Example Usage')}

    +

    + + Example usage demonstrates the plugin in action with realistic + data structures. This comprehensive example shows how the plugin + processes complex schemas with various property types, + relationships, and validation rules. + +

    +

    + + Create an example schema file: + +

    + + {examples[3]} + +

    + + Run the plugin: + +

    + + {examples[4]} + +

    + + Generated output: + +

    + + {examples[5]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx index e95c965..8b9bd0d 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Installation.tsx @@ -1,8 +1,13 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C, SS } from '../index.js'; import Code from '../Code.js'; -const examples = [ +//code examples +//---------------------------------------------------------------------- + +const examples = `# Using npm npm install --save-dev ts-morph @@ -11,75 +16,81 @@ yarn add --dev ts-morph # Using Deno deno add ts-morph@jsr:@ts-morph/ts-morph` -] + +//---------------------------------------------------------------------- export default function installation() { + //hooks const { _ } = useLanguage(); - - return ( -
    -

    {_('2. Installation')}

    -

    - - Before starting with ts-morph plugin development, ensure - you have the necessary tools and knowledge. This section outlines - the essential requirements for successful plugin creation and - provides installation guidance. - -

    -

    - - Before starting, ensure you have: - -

    - -
      -
    • - {_('Node.js 16+')} + return ( + <> + {/* Installation Section Content */} +
      +

      {_('2. Installation')}

      +

      - and npm/yarn installed + Before starting with ts-morph plugin development, + ensure you have the necessary tools and knowledge. This + section outlines the essential requirements for successful + plugin creation and provides installation guidance. -

    • -
    • - {_('TypeScript 4.0+')} +

      + +

      - knowledge + Before starting, ensure you have: -

    • -
    • +

      + +
        +
      • + {_('Node.js 16+')} + + and npm/yarn installed + +
      • +
      • + {_('TypeScript 4.0+')} + + knowledge + +
      • +
      • + + Basic understanding of Abstract Syntax Trees (AST) + +
      • +
      • + + Familiarity with TypeScript interfaces, classes, and + modules + +
      • +
      + +

      - Basic understanding of Abstract Syntax Trees (AST) + Installing ts-morph is straightforward and can be + done using your preferred package manager. The library is + available through npm, yarn, and even Deno for different + development environments. -

    • -
    • +

      + +

      - Familiarity with TypeScript interfaces, classes, and modules + Install ts-morph in your project: -

    • -
    - -

    - - Installing ts-morph is straightforward and can be done - using your preferred package manager. The library is available - through npm, yarn, and even Deno for different development - environments. - -

    - -

    - - Install ts-morph in your project: - -

    - - {examples[0]} - -
    +

    + + {examples} + + + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx index d6c5843..025611c 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Introduction.tsx @@ -1,135 +1,142 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, C, SS } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); - return ( -
    -

    {_('Creating Plugins with ts-morph: A Comprehensive Guide')}

    -

    - - This guide demonstrates how to create powerful code generation - plugins using ts-morph, a TypeScript library that provides an - easier way to programmatically navigate and manipulate TypeScript - and JavaScript code. We'll walk through creating a complete plugin - that generates TypeScript interfaces from schema definitions. - -

    -

    {_('1. Introduction')}

    -

    - - ts-morph is a powerful TypeScript library that wraps the - TypeScript Compiler API, making it much easier to work with - TypeScript Abstract Syntax Trees (AST). This introduction covers - the fundamental concepts and advantages of using ts-morph - for plugin development. - -

    -

    - - Unlike string-based code generation, ts-morph provides: - -

    -
      -
    • - {_('Type-safe code manipulation:')} - - Work with actual TypeScript nodes instead of strings - -
    • -
    • - {_('Automatic formatting:')} - - Generated code is properly formatted and follows TypeScript - conventions - -
    • -
    • - {_('IntelliSense support:')} - - Full IDE support when writing your plugins - -
    • -
    • - {_('AST navigation:')} - - Easy traversal and modification of code structures - -
    • -
    • - {_('Validation:')} + return ( + <> + {/* Introduction Section Content */} +
      +

      {_('Creating Plugins with ts-morph: A Comprehensive Guide')}

      +

      - Automatic syntax validation of generated code + This guide demonstrates how to create powerful code generation + plugins using ts-morph, a TypeScript library that provides an + easier way to programmatically navigate and manipulate TypeScript + and JavaScript code. We'll walk through creating a complete plugin + that generates TypeScript interfaces from schema definitions. -

    • -
    +

    -

    {_('Why Use ts-morph for Plugins?')}

    -

    - - Understanding the advantages of ts-morph over traditional - code generation approaches helps you make informed decisions about - plugin architecture. This comparison highlights the key benefits - that make ts-morph an excellent choice for TypeScript code - generation. - -

    -

    - - Traditional code generation often involves: - -

    -
      -
    • - - Concatenating strings to build code - -
    • -
    • - - Manual indentation and formatting - -
    • -
    • +

      {_('1. Introduction')}

      +

      - Error-prone syntax construction + ts-morph is a powerful TypeScript library that wraps the + TypeScript Compiler API, making it much easier to work with + TypeScript Abstract Syntax Trees (AST). This introduction covers + the fundamental concepts and advantages of using ts-morph + for plugin development. -

    • -
    • +

      +

      - Difficulty maintaining complex code structures + Unlike string-based code generation, ts-morph provides: -

    • -
    +

    +
      +
    • + {_('Type-safe code manipulation:')} + + Work with actual TypeScript nodes instead of strings + +
    • +
    • + {_('Automatic formatting:')} + + Generated code is properly formatted and follows TypeScript + conventions + +
    • +
    • + {_('IntelliSense support:')} + + Full IDE support when writing your plugins + +
    • +
    • + {_('AST navigation:')} + + Easy traversal and modification of code structures + +
    • +
    • + {_('Validation:')} + + Automatic syntax validation of generated code + +
    • +
    -

    - - With ts-morph, you can: - -

    -
      -
    • - - Create TypeScript constructs programmatically - -
    • -
    • +

      {_('Why Use ts-morph for Plugins?')}

      +

      - Leverage the compiler's knowledge for validation + Understanding the advantages of ts-morph over traditional + code generation approaches helps you make informed decisions about + plugin architecture. This comparison highlights the key benefits + that make ts-morph an excellent choice for TypeScript code + generation. -

    • -
    • +

      +

      - Generate properly formatted, syntactically correct code + Traditional code generation often involves: -

    • -
    • +

      +
        +
      • + + Concatenating strings to build code + +
      • +
      • + + Manual indentation and formatting + +
      • +
      • + + Error-prone syntax construction + +
      • +
      • + + Difficulty maintaining complex code structures + +
      • +
      + +

      - Easily modify existing code structures + With ts-morph, you can: -

    • -
    -
    +

    +
      +
    • + + Create TypeScript constructs programmatically + +
    • +
    • + + Leverage the compiler's knowledge for validation + +
    • +
    • + + Generate properly formatted, syntactically correct code + +
    • +
    • + + Easily modify existing code structures + +
    • +
    + + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx index b6a7997..01898c1 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/References.tsx @@ -1,10 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, H3, P } from '../index.js' export default function References() { + //hooks const { _ } = useLanguage(); + return ( <> + {/* References Section Content */}

    {_('10. References')}

    @@ -17,6 +22,7 @@ export default function References() {

    + {/* Official Documentation */}

    {_('10.1. Official Documentation')}

    @@ -58,6 +64,7 @@ export default function References() {

    + {/* Useful Resources */}

    {_('10.2. Useful Resources')}

    @@ -97,6 +104,7 @@ export default function References() {

    + {/* Community Examples and Related Tools */}

    {_('10.3. Community Examples')}

    diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx index 57e7ad0..55284d6 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/SettingUpProject.tsx @@ -1,12 +1,20 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const examples = [ `mkdir ts-morph-plugin-tutorial cd ts-morph-plugin-tutorial npm init -y npm install --save-dev typescript ts-morph @types/node`, + + //---------------------------------------------------------------------- + `{ "compilerOptions": { "target": "ES2020", @@ -25,6 +33,9 @@ npm install --save-dev typescript ts-morph @types/node`, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }`, + + //---------------------------------------------------------------------- + `ts-morph-plugin-tutorial/ ├── src/ │ ├── index.ts @@ -37,59 +48,66 @@ npm install --save-dev typescript ts-morph @types/node`, │ └── plugin.test.ts ├── package.json └── tsconfig.json` -] +]; + +//---------------------------------------------------------------------- export default function SettingUpProject() { + //hooks const { _ } = useLanguage(); + return ( -

    -

    {_('3. Setting Up the Project')}

    -

    - - Setting up a proper project structure is crucial for maintainable - plugin development. This section guides you through creating a - well-organized TypeScript project with all necessary configurations - and dependencies - -

    -

    - - Let's create a new TypeScript project for our plugin: - -

    - - {examples[0]} - + <> + {/* Setting Up the Project Section Content */} +
    +

    {_('3. Setting Up the Project')}

    +

    + + Setting up a proper project structure is crucial for + maintainable plugin development. This section guides you + through creating a well-organized TypeScript project with + all necessary configurations and dependencies + +

    +

    + + Let's create a new TypeScript project for our plugin: + +

    + + {examples[0]} + -

    - - Create a basic tsconfig.json: - -

    - - {examples[1]} - +

    + + Create a basic tsconfig.json: + +

    + + {examples[1]} + -

    - - Create the project structure: - -

    - - {examples[2]} - -
    +

    + + Create the project structure: + +

    + + {examples[2]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx index fe0fe8a..12395dd 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/TestingYourPlugin.tsx @@ -1,9 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P } from '../index.js' import Code from '../Code.js' +//code examples +//---------------------------------------------------------------------- + const examples = [ -`// tests/plugin.test.ts + `// tests/plugin.test.ts import { TypeScriptInterfaceGenerator } from "../src/plugin"; import { PluginConfig, Schema } from "../src/types"; import { Project } from "ts-morph"; @@ -122,48 +127,58 @@ describe("TypeScriptInterfaceGenerator", () => { expect(diagnostics).toHaveLength(0); }); });`, -`npm test` + + //---------------------------------------------------------------------- + + `npm test` ]; +//---------------------------------------------------------------------- + export default function TestingYourPlugin() { + //hooks const { _ } = useLanguage(); + return ( -
    -

    {_('7. Testing Your Plugin')}

    -

    - - Comprehensive testing ensures your plugin works correctly across - different scenarios and maintains reliability as it evolves. This - section covers unit testing, integration testing, and validation - strategies for ts-morph plugins. - -

    - -

    - - Create comprehensive tests for your plugin: - -

    - - {examples[0]} - - -

    - - Run tests: - -

    - - {examples[1]} - -
    + <> + {/* Testing Your Plugin Section Content */} +
    +

    {_('7. Testing Your Plugin')}

    +

    + + Comprehensive testing ensures your plugin works correctly + across different scenarios and maintains reliability as it + evolves. This section covers unit testing, integration testing, + and validation strategies for ts-morph plugins. + +

    + +

    + + Create comprehensive tests for your plugin: + +

    + + {examples[0]} + + +

    + + Run tests: + +

    + + {examples[1]} + +
    + ) } diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx index 0b858d1..a850cbe 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/Troubleshooting.tsx @@ -1,7 +1,12 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, H3, P } from '../index.js' import Code from '../Code.js' +//code examples +//---------------------------------------------------------------------- + const examples = [ `function validateGeneratedCode(sourceFile: SourceFile): void { const diagnostics = sourceFile.getPreEmitDiagnostics(); @@ -16,6 +21,9 @@ const examples = [ throw new Error(\`Generated TypeScript has errors: \${JSON.stringify(errors, null, 2)}\`); } }`, + +//---------------------------------------------------------------------- + `function detectCircularReferences(schemas: Schema[]): string[] { const graph = new Map>(); const cycles: string[] = []; @@ -67,6 +75,9 @@ const examples = [ return cycles; }`, + +//---------------------------------------------------------------------- + `class StreamingGenerator { async generateLargeSchema(schemas: Schema[]): Promise { const batchSize = 10; @@ -88,6 +99,9 @@ const examples = [ // Process smaller batches to avoid memory issues } }`, + +//---------------------------------------------------------------------- + `const DEBUG = process.env.DEBUG === 'true'; function debugLog(message: string, data?: any): void { @@ -99,6 +113,9 @@ function debugLog(message: string, data?: any): void { // Usage debugLog('Processing schema', schema); debugLog('Generated interface', interfaceDeclaration.getText());`, + +//---------------------------------------------------------------------- + `async function saveIntermediateResults( sourceFile: SourceFile, step: string @@ -109,6 +126,9 @@ debugLog('Generated interface', interfaceDeclaration.getText());`, console.log(\`Saved intermediate result: \${outputPath}\`); } }`, + +//---------------------------------------------------------------------- + `function validateStep( sourceFile: SourceFile, stepName: string @@ -126,10 +146,15 @@ debugLog('Generated interface', interfaceDeclaration.getText());`, }` ]; +//---------------------------------------------------------------------- + export default function Troubleshooting() { + //hooks const { _ } = useLanguage(); + return ( <> + {/* Troubleshooting Section Content */}

    {_('9. Troubleshooting')}

    @@ -142,7 +167,8 @@ export default function Troubleshooting() {

    -
    + {/* Common Issues Section Content */} +

    {_('9.1. Common Issues')}

    @@ -192,6 +218,7 @@ export default function Troubleshooting() {

    + {/* Debugging Techniques Section Content */}

    {_('9.2. Debugging Tips')}

    diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx index a9766bc..0bdae3b 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/UnderstandingTsMorphBasics.tsx @@ -1,9 +1,14 @@ +//moudles import { useLanguage, Translate } from 'r22n'; +//local import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- + const examples = [ - `import { Project } from "ts-morph"; +`import { Project } from "ts-morph"; // Create a new project const project = new Project({ @@ -32,7 +37,10 @@ console.log(sourceFile.getFullText()); // id: string; // name: string; // }`, - `// Add imports + +//---------------------------------------------------------------------- + +`// Add imports sourceFile.addImportDeclaration({ moduleSpecifier: "react", namedImports: ["useState", "useEffect"], @@ -86,7 +94,10 @@ sourceFile.addEnum({ { name: "GUEST", value: "guest" }, ], });`, - `import { Project } from "ts-morph"; + +//---------------------------------------------------------------------- + +`import { Project } from "ts-morph"; const project = new Project(); @@ -105,12 +116,18 @@ myClass.addMethod({ }); project.saveSync();`, - `export default class MyClass { + +//---------------------------------------------------------------------- + +`export default class MyClass { myMethod(param1: string): void { console.log(param1); } }`, - `import { Project } from "ts-morph"; + +//---------------------------------------------------------------------- + +`import { Project } from "ts-morph"; const project = new Project(); @@ -132,11 +149,17 @@ source.addFunction({ }); project.saveSync();`, - `export async function myFunction(param1: string, param2: number): void { + +//---------------------------------------------------------------------- + +`export async function myFunction(param1: string, param2: number): void { console.log(param1); console.log(param2); }`, - `import { VariableDeclarationKind } from 'ts-morph'; + +//---------------------------------------------------------------------- + +`import { VariableDeclarationKind } from 'ts-morph'; source.addVariableStatement({ isExported: true, @@ -146,17 +169,32 @@ source.addVariableStatement({ initializer: '\'bar\'' }] });`, - `export const foo = 'bar';`, - `source.addExportDeclaration({ + +//---------------------------------------------------------------------- + +`export const foo = 'bar';`, + +//---------------------------------------------------------------------- + +`source.addExportDeclaration({ namedExports: ['ComponentA', 'ComponentB', 'ComponentC'] });`, - `source.addTypeAlias({ + +//---------------------------------------------------------------------- + +`source.addTypeAlias({ name: "ExampleType", isExported: true, type: "string | number" });`, - `export type ExampleType = string | number;`, - `source.addTypeAlias({ + +//---------------------------------------------------------------------- + +`export type ExampleType = string | number;`, + +//---------------------------------------------------------------------- + +`source.addTypeAlias({ name: "AnotherType", isExported: true, type: "boolean" @@ -175,34 +213,58 @@ source.addInterface({ source.addExportDeclaration({ namedExports: ["ExampleType", "AnotherType", "ExampleInterface"] });`, - `export type ExampleType = string | number; + +//---------------------------------------------------------------------- + +`export type ExampleType = string | number; export type AnotherType = boolean; export interface ExampleInterface { id: number; name: string; }`, - `source.addImportDeclaration({ + +//---------------------------------------------------------------------- + +`source.addImportDeclaration({ moduleSpecifier: 'react', namedImports: [ 'useState', 'useEffect' ] });`, - `import { useState, useEffect } from 'react';`, - `source.addImportDeclaration({ + +//---------------------------------------------------------------------- + +`import { useState, useEffect } from 'react';`, + +//---------------------------------------------------------------------- + +`source.addImportDeclaration({ moduleSpecifier: 'next', namedImports: [ 'NextApiRequest as Request', 'NextApiResponse as as Response' ] });`, - `import type { + +//---------------------------------------------------------------------- + +`import type { NextApiRequest as Request, NextApiResponse as Response } from 'next';`, - `source.addImportDeclaration({ + +//---------------------------------------------------------------------- + +`source.addImportDeclaration({ moduleSpecifier: 'react', defaultImport: 'React' });`, - `import React from 'react';`, - `// Load existing files + +//---------------------------------------------------------------------- + +`import React from 'react';`, + +//---------------------------------------------------------------------- + +`// Load existing files project.addSourceFilesAtPaths("src/**/*.ts"); // Get a specific file @@ -228,10 +290,15 @@ if (userInterface) { }` ]; +//---------------------------------------------------------------------- + export default function UnderstandingTsMorphBasics() { + //hooks const { _ } = useLanguage(); + return ( <> + {/* Understanding ts-morph Basics Section Content*/}

    {_('4. Understanding ts-morph Basics')}

    @@ -245,6 +312,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Project and Source Files Section Content */}

    {_('4.1. Project and Source Files')}

    @@ -264,6 +332,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Adding Different Constructs Section Content */}

    {_('4.2. Adding Different Constructs')}

    @@ -283,6 +352,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Exporting a Class Section Content */}

    {_('4.3. Exporting a Class')}

    @@ -331,6 +401,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Exporting a Function Section Content */}

    {_('4.4. Exporting a Function')}

    @@ -379,6 +450,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Exporting a Const Section Content */}

    {_('4.5. Exporting a Const')}

    @@ -420,6 +492,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Exporting an Object Section Content */}

    {_('4.6. Exporting an Object')}

    @@ -449,6 +522,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Exporting Types Section Content */}

    {_('4.7. Exporting Types')}

    @@ -518,6 +592,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Importing Values Section Content */}

    {_('4.8. Importing Values')}

    @@ -585,6 +660,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Importing Defaults Section Content */}

    {_('4.9. Importing Defaults')}

    @@ -622,6 +698,7 @@ export default function UnderstandingTsMorphBasics() {

    + {/* Working with Existing Code Section Content */}

    {_('4.10. Working with Existing Code')}

    diff --git a/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx b/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx index 433648d..999aa3c 100644 --- a/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx +++ b/packages/www/plugins/docs/components/ts-morph-plugin-guide/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Installation } from './Installation.js'; export { default as SettingUpProject } from './SettingUpProject.js'; diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx index 830b6b9..201e45a 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/AdvancedFeatures.tsx @@ -1,5 +1,7 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, H2, P, Code } from '../index.js'; const namespaceConfigurationExample = `// With namespace configuration @@ -19,7 +21,9 @@ export namespace MyApp { name: string; role: UserRole; } -}`; +}` + +//---------------------------------------------------------------------- const standardEnumExample = `// Standard enum (default) @@ -27,12 +31,16 @@ enumType: "enum" export enum UserRole { ADMIN = "admin", USER = "user", -}`; +}` + +//---------------------------------------------------------------------- const unionTypeExample = `// Union type enumType: "union" -export type UserRole = "admin" | "user";`; +export type UserRole = "admin" | "user";` + +//---------------------------------------------------------------------- const constAssertionExample = `// Const assertion @@ -41,7 +49,9 @@ export const UserRole = { ADMIN: "admin", USER: "user", } as const; -export type UserRole = typeof UserRole[keyof typeof UserRole];`; +export type UserRole = typeof UserRole[keyof typeof UserRole];` + +//---------------------------------------------------------------------- const relationshipHandlingExample = `function handleRelationships( @@ -65,7 +75,9 @@ const relationshipHandlingExample = } return formatPropertyType(column, config, availableTypes); -}`; +}` + +//---------------------------------------------------------------------- const genericTypeSupportExample = `function generateGenericTypes( @@ -91,15 +103,19 @@ const genericTypeSupportExample = }\\n\\n\`; return content; -}`; +}` + +//---------------------------------------------------------------------- export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -

    + <> + {/* Advanced Features Section Content */}
    -

    {_('Advanced Features')}

    +

    {_('7. Advanced Features')}

    Advanced features extend the basic TypeScript interface @@ -111,8 +127,9 @@ export default function AdvancedFeatures() {

    + {/* Namespace Support Section Content */}
    -

    {_('Namespace Support')}

    +

    {_('Namespace Support')}

    Namespace support allows you to organize generated types within @@ -129,8 +146,9 @@ export default function AdvancedFeatures() {

    + {/* Different Enum Types Section Content */}
    -

    {_('Different Enum Types')}

    +

    {_('Different Enum Types')}

    Different enum types provide flexibility in how enumerations are @@ -150,8 +168,9 @@ export default function AdvancedFeatures() {

    + {/* Relationship Handling Section Content */}
    -

    {_('Relationship Handling')}

    +

    {_('Relationship Handling')}

    Relationship handling manages references between different types @@ -165,8 +184,9 @@ export default function AdvancedFeatures() {

    + {/* Generic Type Support Section Content */}
    -

    {_('Generic Type Support')}

    +

    {_('Generic Type Support')}

    Generic type support enables the generation of reusable type @@ -179,6 +199,6 @@ export default function AdvancedFeatures() { {genericTypeSupportExample}

    -
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx index d18ce98..9ad68c5 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/BestPractices.tsx @@ -1,46 +1,56 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, Code } from '../index.js'; +//local +import { H1, H2, P, Code } from '../index.js'; -const typeSafetyInterface = -`interface TypeScriptColumn { +const typeSafetyInterface = + `interface TypeScriptColumn { name: string; type: string; required: boolean; multiple: boolean; description?: string; attributes?: Record; -}`; +}` -const columnValidation = -`function validateColumn(column: any): column is TypeScriptColumn { +//---------------------------------------------------------------------- + +const columnValidation = + `function validateColumn(column: any): column is TypeScriptColumn { return ( typeof column.name === 'string' && typeof column.type === 'string' && typeof column.required === 'boolean' ); -}`; +}` + +//---------------------------------------------------------------------- -const typeNameSanitization = -`function sanitizeTypeName(name: string): string { +const typeNameSanitization = + `function sanitizeTypeName(name: string): string { // Ensure TypeScript-valid names return name .replace(/[^a-zA-Z0-9_]/g, '_') .replace(/^[0-9]/, '_$&') .replace(/^_+|_+$/g, ''); -}`; +}` + +//---------------------------------------------------------------------- -const pascalCaseConversion = -`function toPascalCase(str: string): string { +const pascalCaseConversion = + `function toPascalCase(str: string): string { return str .split(/[-_\\s]+/) .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() ) .join(''); -}`; +}` -const jsDocGeneration = -`function generateJSDocComment( +//---------------------------------------------------------------------- + +const jsDocGeneration = + `function generateJSDocComment( column: any, includeAttributes: boolean = true ): string { @@ -67,10 +77,12 @@ const jsDocGeneration = return \` /**\\n\${lines.map(line => \` * \${line}\`).join('\\n')}\\n */\\n\`; -}`; +}` + +//---------------------------------------------------------------------- -const typeCacheOptimization = -`// Cache type mappings +const typeCacheOptimization = + `// Cache type mappings const typeCache = new Map(); function getCachedTypeMapping( @@ -90,32 +102,37 @@ function getCachedTypeMapping( typeCache.set(cacheKey, mappedType); return mappedType; -}`; +}` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Best Practices Section Content */}
    -

    {_('Best Practices')}

    +

    {_('8. Best Practices')}

    - Best practices ensure your generated TypeScript interfaces are - maintainable, reliable, and follow industry standards. These - guidelines cover type safety, naming conventions, documentation + Best practices ensure your generated TypeScript interfaces are + maintainable, reliable, and follow industry standards. These + guidelines cover type safety, naming conventions, documentation generation, and performance optimization.

    + {/* Type Safety Section Content */}
    -

    {_('Type Safety')}

    +

    {_('Type Safety')}

    - Type safety is crucial for preventing runtime errors and - improving developer experience. Always validate input data and - use proper TypeScript types throughout the plugin implementation + Type safety is crucial for preventing runtime errors and + improving developer experience. Always validate input data and + use proper TypeScript types throughout the plugin implementation to ensure reliable code generation.

    @@ -127,13 +144,14 @@ export default function BestPractices() {
    + {/* Naming Conventions Section Content */}
    -

    {_('Naming Conventions')}

    +

    {_('Naming Conventions')}

    - Naming conventions ensure that generated TypeScript identifiers - are valid and follow established patterns. Proper naming improves - code readability and prevents conflicts with reserved keywords + Naming conventions ensure that generated TypeScript identifiers + are valid and follow established patterns. Proper naming improves + code readability and prevents conflicts with reserved keywords or invalid characters.

    @@ -145,13 +163,14 @@ export default function BestPractices() {
    + {/* Documentation Generation Section Content */}
    -

    {_('Documentation Generation')}

    +

    {_('Documentation Generation')}

    - Documentation generation creates comprehensive JSDoc comments that - provide context and examples for the generated types. This - improves the developer experience by providing inline + Documentation generation creates comprehensive JSDoc comments that + provide context and examples for the generated types. This + improves the developer experience by providing inline documentation in IDEs and code editors.

    @@ -161,12 +180,12 @@ export default function BestPractices() {
    -

    {_('Performance Optimization')}

    +

    {_('Performance Optimization')}

    - Performance optimization techniques help maintain reasonable - generation times when working with large schemas. Caching - strategies and efficient algorithms ensure the plugin scales + Performance optimization techniques help maintain reasonable + generation times when working with large schemas. Caching + strategies and efficient algorithms ensure the plugin scales well with complex type hierarchies.

    @@ -174,6 +193,6 @@ export default function BestPractices() { {typeCacheOptimization}
    -
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx index 779c284..f055088 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Implementation.tsx @@ -1,5 +1,10 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, Code } from '../index.js'; +//local +import { H1, H2, H3, P, C, Code } from '../index.js'; + +//code examples +//---------------------------------------------------------------------- const corePluginFunctionExample = `export default async function generateTypeScriptInterfaces( @@ -57,7 +62,9 @@ const corePluginFunctionExample = ); throw error; } -}`; +}` + +//---------------------------------------------------------------------- const typeMappingFunctionsExample = `function mapSchemaTypeToTypeScript( @@ -109,7 +116,9 @@ function formatPropertyType( } return type; -}`; +}` + +//---------------------------------------------------------------------- const generationFunctionsExample = `function generateFileHeader(): string { @@ -211,7 +220,9 @@ function generateInterfaces( } return content; -}`; +}` + +//---------------------------------------------------------------------- const validationFunctionsExample = `function validateConfig(config: any): asserts config is TypeScriptConfig { @@ -232,14 +243,19 @@ const validationFunctionsExample = !['enum', 'union', 'const'].includes(config.enumType)) { throw new Error('enumType must be one of: enum, union, const'); } -}`; +}` + +//---------------------------------------------------------------------- export default function Implementation() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Implementation')}

    + <> + {/* Implementation Section Content */} +
    +

    {_('4. Implementation')}

    The implementation section covers the core plugin function and @@ -249,7 +265,7 @@ export default function Implementation() {

    -

    {_('Core Plugin Function')}

    +

    {_('Core Plugin Function')}

    The core plugin function serves as the main entry point for @@ -262,7 +278,7 @@ export default function Implementation() { {corePluginFunctionExample} -

    {_('Type Mapping Functions')}

    +

    {_('Type Mapping Functions')}

    Type mapping functions handle the conversion of .idea schema @@ -275,7 +291,7 @@ export default function Implementation() { {typeMappingFunctionsExample} -

    {_('Generation Functions')}

    +

    {_('Generation Functions')}

    Generation functions create specific parts of the TypeScript output @@ -288,7 +304,7 @@ export default function Implementation() { {generationFunctionsExample} -

    {_('Validation Functions')}

    +

    {_('Validation Functions')}

    Validation functions ensure that the plugin configuration is correct @@ -300,6 +316,7 @@ export default function Implementation() { {validationFunctionsExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx index 2991162..e07abf3 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Introduction.tsx @@ -1,11 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( <> + {/* TypeScript Interface Generator Plugin Tutorial */}

    {_('TypeScript Interface Generator Plugin Tutorial')}

    diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx index 98e1629..f390ded 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C, SS } from '../index.js'; +//local +import { H1, P, C, SS } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -

    -

    {_('Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    TypeScript interfaces provide compile-time type checking and @@ -49,6 +54,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx index ee275db..a414a9a 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/PluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -23,14 +29,19 @@ export default async function generateTypeScriptInterfaces( const { config, schema, transformer } = props; // Implementation here... -}`; +}` + +//---------------------------------------------------------------------- export default function PluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Plugin Structure')}

    + <> + {/* Plugin Structure Section Content */} +
    +

    {_('3. Plugin Structure')}

    The plugin structure defines the core architecture and @@ -45,6 +56,7 @@ export default function PluginStructure() { > {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx index ee519a7..dcc422e 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Prerequisites.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Prerequisites')}

    + <> + {/* Prerequisites Section Content */} +
    +

    {_('2. Prerequisites')}

    Before implementing the TypeScript interface generator plugin, @@ -37,6 +42,7 @@ export default function Prerequisites() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx index 067a290..c50b385 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/SchemaConfiguration.tsx @@ -1,10 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -import { H2, H3, P, C } from '../index.js'; +//local +import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; +//code examples +//---------------------------------------------------------------------- -const basicConfigurationExample = `plugin "./plugins/typescript-interfaces.js" { +const basicConfigurationExample = +`plugin "./plugins/typescript-interfaces.js" { output "./generated/types.ts" namespace "MyApp" exportType "named" @@ -13,7 +18,9 @@ const basicConfigurationExample = `plugin "./plugins/typescript-interfaces.js" { strictNullChecks true generateEnums true enumType "enum" -}`; +}` + +//---------------------------------------------------------------------- const configurationTableData = [ { @@ -67,11 +74,14 @@ const configurationTableData = [ ]; export default function SchemaConfiguration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Schema Configuration')}

    + <> + {/* Schema Configuration Section Content */} +
    +

    {_('5. Schema Configuration')}

    Schema configuration demonstrates how to integrate the TypeScript @@ -92,7 +102,7 @@ export default function SchemaConfiguration() { {basicConfigurationExample} -

    {_('Configuration Options')}

    +

    {_('Configuration Options')}

    Configuration options control how TypeScript interfaces are @@ -126,6 +136,7 @@ export default function SchemaConfiguration() { ))} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx index f0842a0..e620bf0 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/Troubleshooting.tsx @@ -1,12 +1,19 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P, C, Code } from '../index.js'; +//local +import { H1, H2, P, C, Code } from '../index.js'; + +//code examples +//---------------------------------------------------------------------- const typeNameValidation = `function validateTypeName(name: string): void { if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) { throw new Error(\`Invalid TypeScript identifier: \${name}\`); } -}`; +}` + +//---------------------------------------------------------------------- const circularReferenceDetection = `function detectCircularReferences( @@ -37,7 +44,9 @@ const circularReferenceDetection = } return cycles; -}`; +}` + +//---------------------------------------------------------------------- const dependencyValidation = `function validateTypeDependencies( @@ -50,7 +59,9 @@ const dependencyValidation = ]); // Validate all type references... -}`; +}` + +//---------------------------------------------------------------------- const verboseLogging = `const VERBOSE = process.env.TS_PLUGIN_VERBOSE === 'true'; @@ -59,7 +70,9 @@ function verboseLog(message: string, data?: any) { if (VERBOSE) { console.log(\`[TypeScript Plugin] \${message}\`, data || ''); } -}`; +}` + +//---------------------------------------------------------------------- const typeScriptValidation = `import { transpile, ScriptTarget } from 'typescript'; @@ -74,15 +87,19 @@ function validateGeneratedTypeScript(content: string): void { } catch (error) { throw new Error(\`Invalid TypeScript: \${error.message}\`); } -}`; +}` + +//---------------------------------------------------------------------- export default function Troubleshooting() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Troubleshooting Section Content */}
    -

    {_('Troubleshooting')}

    +

    {_('9. Troubleshooting')}

    This section addresses common issues encountered when generating @@ -93,8 +110,9 @@ export default function Troubleshooting() {

    + {/* Common Issues Section Content */}
    -

    {_('Common Issues')}

    +

    {_('Common Issues')}

    Common issues include invalid TypeScript identifiers, circular @@ -106,7 +124,7 @@ export default function Troubleshooting() {

    -

    {_('Invalid TypeScript Names')}

    +

    {_('Invalid TypeScript Names')}

    Invalid TypeScript names occur when schema identifiers contain @@ -120,8 +138,9 @@ export default function Troubleshooting() {

    + {/* Circular Type References Section Content */}
    -

    {_('Circular Type References')}

    +

    {_('Circular Type References')}

    Circular type references can cause infinite loops during @@ -135,8 +154,9 @@ export default function Troubleshooting() {

    + {/* Missing Type Dependencies Section Content */}
    -

    {_('Missing Type Dependencies')}

    +

    {_('Missing Type Dependencies')}

    Missing type dependencies occur when a type references another @@ -151,8 +171,9 @@ export default function Troubleshooting() {

    + {/* Debugging Tips Section Content */}
    -

    {_('Debugging Tips')}

    +

    {_('Debugging Tips')}

    Debugging tips help identify and resolve issues during TypeScript @@ -162,8 +183,9 @@ export default function Troubleshooting() {

    + {/* Enable Verbose Output Section Content */}
    -

    {_('Enable Verbose Output')}

    +

    {_('Enable Verbose Output')}

    Verbose output provides detailed logging during the generation @@ -176,8 +198,9 @@ export default function Troubleshooting() {

    + {/* Validate Generated TypeScript Section Content */}
    -

    {_('Validate Generated TypeScript')}

    +

    {_('Validate Generated TypeScript')}

    Validating generated TypeScript ensures that the output is @@ -192,6 +215,7 @@ export default function Troubleshooting() {

    + {/* Conclusion Section Content */}

    @@ -202,6 +226,6 @@ export default function Troubleshooting() {

    -
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx index d20ddd0..499503a 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/UsageExamples.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const basicSchemaExample = `enum UserRole { +//code examples +//---------------------------------------------------------------------- + +const basicSchemaExample = +`enum UserRole { ADMIN "admin" USER "user" GUEST "guest" @@ -29,9 +35,12 @@ plugin "./plugins/typescript-interfaces.js" { output "./types.ts" generateUtilityTypes true includeComments true -}`; +}` + +//---------------------------------------------------------------------- -const generatedOutputExample = `/** +const generatedOutputExample = +`/** * Generated TypeScript interfaces * Generated at: 2024-01-15T10:30:00.000Z * @@ -84,14 +93,19 @@ export type UpdateUserInput = Partial; export type AnyModel = User; -export type UserKeys = keyof User;`; +export type UserKeys = keyof User;` + +//---------------------------------------------------------------------- export default function UsageExamples() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('Usage Examples')}

    + <> + {/* Usage Examples Section Content */} +
    +

    {_('6. Usage Examples')}

    Usage examples demonstrate practical applications of the TypeScript @@ -101,7 +115,7 @@ export default function UsageExamples() {

    -

    {_('Basic Schema')}

    +

    {_('Basic Schema')}

    A basic schema example shows the fundamental structure needed to @@ -117,7 +131,7 @@ export default function UsageExamples() { {basicSchemaExample} -

    {_('Generated Output')}

    +

    {_('Generated Output')}

    The generated output demonstrates the TypeScript code produced by @@ -132,7 +146,7 @@ export default function UsageExamples() { > {generatedOutputExample} - -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx b/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx index 890be10..0049239 100644 --- a/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx +++ b/packages/www/plugins/docs/components/typescript-interface-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx b/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx index a8f9b76..fd9fcec 100644 --- a/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/AdvancedFeatures.tsx @@ -1,17 +1,26 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const customValidatorsExample = `// In plugin configuration +//code examples +//---------------------------------------------------------------------- + +const customValidatorsExample = +`// In plugin configuration customValidators: { Email: "z.string().email().transform(val => val.toLowerCase())", Password: "z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/)", Slug: "z.string().regex(/^[a-z0-9-]+$/)", Color: "z.string().regex(/^#[0-9A-F]{6}$/i)", JSON: "z.string().transform(val => JSON.parse(val))" -}`; +}` + +//---------------------------------------------------------------------- -const conditionalValidationExample = `// Generated schema with conditional validation +const conditionalValidationExample = +`// Generated schema with conditional validation export const UserSchema = z.object({ id: z.string(), email: z.string().email(), @@ -26,9 +35,12 @@ export const UserSchema = z.object({ }, { message: "Admin users must provide an admin code", path: ["adminCode"], -});`; +});` + +//---------------------------------------------------------------------- -const transformPreprocessExample = `// Add transforms to generated schemas +const transformPreprocessExample = +`// Add transforms to generated schemas function addTransforms(schema: string, column: any): string { if (column.attributes?.transform) { switch (column.attributes.transform) { @@ -44,9 +56,12 @@ function addTransforms(schema: string, column: any): string { } return schema; -}`; +}` -const asyncValidationExample = `// Generate async validation schemas +//---------------------------------------------------------------------- + +const asyncValidationExample = +`// Generate async validation schemas export const UserSchemaAsync = UserSchema.extend({ email: z.string().email().refine(async (email) => { // Check if email is unique @@ -65,14 +80,19 @@ const validateUserAsync = async (data: unknown) => { } catch (error) { return { success: false, errors: error.errors }; } -};`; +};` + +//---------------------------------------------------------------------- export default function AdvancedFeatures() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('7. Advanced Features')}

    + <> + {/* Advanced Features Section Content */} +
    +

    {_('7. Advanced Features')}

    Advanced features extend the basic Zod schema generation with sophisticated @@ -82,7 +102,7 @@ export default function AdvancedFeatures() {

    -

    {_('7.1. Custom Validators')}

    +

    {_('7.1. Custom Validators')}

    Custom validators allow you to define specialized validation logic for @@ -95,7 +115,7 @@ export default function AdvancedFeatures() { {customValidatorsExample} -

    {_('7.2. Conditional Validation')}

    +

    {_('7.2. Conditional Validation')}

    Conditional validation enables complex validation logic that depends on @@ -108,7 +128,7 @@ export default function AdvancedFeatures() { {conditionalValidationExample} -

    {_('7.3. Transform and Preprocess')}

    +

    {_('7.3. Transform and Preprocess')}

    Transform and preprocess capabilities allow you to modify data during @@ -120,7 +140,7 @@ export default function AdvancedFeatures() { {transformPreprocessExample} -

    {_('7.4. Async Validation')}

    +

    {_('7.4. Async Validation')}

    Async validation enables validation rules that require external data @@ -132,6 +152,7 @@ export default function AdvancedFeatures() { {asyncValidationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx b/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx index 138e4fd..1ff2658 100644 --- a/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/BestPractices.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const errorHandlingExample = `// Centralized validation error handling +//code examples +//---------------------------------------------------------------------- + +const errorHandlingExample = +`// Centralized validation error handling class ValidationError extends Error { constructor(public errors: z.ZodError) { super('Validation failed'); @@ -30,7 +36,9 @@ function validateWithErrorHandling(schema: z.ZodSchema, data: unknown): T } return result.data; -}`; +}` + +//---------------------------------------------------------------------- const schemaCompositionExample = `// Compose schemas for reusability const BaseEntitySchema = z.object({ @@ -48,9 +56,12 @@ const PostSchema = BaseEntitySchema.extend({ title: z.string().min(1), content: z.string(), authorId: z.string(), -});`; +});` -const typeGuardsExample = `// Generate type guards from schemas +//---------------------------------------------------------------------- + +const typeGuardsExample = +`// Generate type guards from schemas export const isUser = (data: unknown): data is User => { return UserSchema.safeParse(data).success; }; @@ -67,7 +78,10 @@ function processUserData(data: unknown) { } }`; -const apiIntegrationExample = `// Middleware for API validation +//---------------------------------------------------------------------- + +const apiIntegrationExample = +`// Middleware for API validation function validateBody(schema: z.ZodSchema) { return (req: Request, res: Response, next: NextFunction) => { const result = schema.safeParse(req.body); @@ -93,14 +107,19 @@ function validateBody(schema: z.ZodSchema) { app.post('/users', validateBody(CreateUserSchema), (req, res) => { // req.body is now typed and validated const user = req.body; // Type: CreateUserInput -});`; +});` + +//---------------------------------------------------------------------- export default function BestPractices() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('8. Best Practices')}

    + <> + {/* Best Practices Section Content */} +
    +

    {_('8. Best Practices')}

    Best practices ensure your generated Zod validation schemas are @@ -110,7 +129,7 @@ export default function BestPractices() {

    -

    {_('8.1. Error Handling')}

    +

    {_('8.1. Error Handling')}

    Proper error handling ensures that validation failures provide clear, @@ -123,7 +142,7 @@ export default function BestPractices() { {errorHandlingExample} -

    {_('8.2. Schema Composition')}

    +

    {_('8.2. Schema Composition')}

    Schema composition enables the creation of reusable validation components @@ -135,7 +154,7 @@ export default function BestPractices() { {schemaCompositionExample} -

    {_('8.3. Type Guards')}

    +

    {_('8.3. Type Guards')}

    Type guards provide runtime type checking that integrates seamlessly @@ -148,7 +167,7 @@ export default function BestPractices() { {typeGuardsExample} -

    {_('8.4. API Integration')}

    +

    {_('8.4. API Integration')}

    API integration patterns show how to use generated Zod schemas for @@ -159,6 +178,7 @@ export default function BestPractices() { {apiIntegrationExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx b/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx index b9616f1..f27fd76 100644 --- a/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/Implementation.tsx @@ -1,9 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const corePluginFunction = -`export default async function generateZodSchemas( +//code examples +//---------------------------------------------------------------------- + +const corePluginFunction = + `export default async function generateZodSchemas( props: PluginProps<{ config: ZodConfig }> ) { const { config, schema, transformer } = props; @@ -51,9 +56,12 @@ const corePluginFunction = console.error('❌ Zod schema generation failed:', error.message); throw error; } -}`; +}` + +//---------------------------------------------------------------------- -const enumGeneration = `function generateEnumSchemas(enums: Record, config: ZodConfig): string { +const enumGeneration = + `function generateEnumSchemas(enums: Record, config: ZodConfig): string { let content = '// Enum Schemas\\n'; for (const [enumName, enumDef] of Object.entries(enums)) { @@ -70,9 +78,12 @@ const enumGeneration = `function generateEnumSchemas(enums: Record, } return content + '\\n'; -}`; +}` -const typeGeneration = `function generateTypeSchemas(types: Record, config: ZodConfig): string { +//---------------------------------------------------------------------- + +const typeGeneration = + `function generateTypeSchemas(types: Record, config: ZodConfig): string { let content = '// Type Schemas\\n'; for (const [typeName, typeDef] of Object.entries(types)) { @@ -100,9 +111,12 @@ const typeGeneration = `function generateTypeSchemas(types: Record, } return content; -}`; +}` + +//---------------------------------------------------------------------- -const modelGeneration = `function generateModelSchemas(models: Record, config: ZodConfig): string { +const modelGeneration = + `function generateModelSchemas(models: Record, config: ZodConfig): string { let content = '// Model Schemas\\n'; for (const [modelName, model] of Object.entries(models)) { @@ -133,9 +147,12 @@ const modelGeneration = `function generateModelSchemas(models: Record(dataSchema: T) = \`; return content; -}`; +}` + +//---------------------------------------------------------------------- -const exportFunctions = `function generateMainExport(schema: any, config: ZodConfig): string { +const exportFunctions = + `function generateMainExport(schema: any, config: ZodConfig): string { if (config.exportStyle === 'namespace') { return generateNamespaceExport(schema, config); } @@ -419,9 +448,12 @@ export default schemas; \`; return content; -}`; +}` -const configValidation = `function validateConfig(config: any): asserts config is ZodConfig { +//---------------------------------------------------------------------- + +const configValidation = +`function validateConfig(config: any): asserts config is ZodConfig { if (!config.output || typeof config.output !== 'string') { throw new Error('Zod plugin requires "output" configuration as string'); } @@ -429,75 +461,81 @@ const configValidation = `function validateConfig(config: any): asserts config i if (config.exportStyle && !['named', 'default', 'namespace'].includes(config.exportStyle)) { throw new Error('exportStyle must be one of: named, default, namespace'); } -}`; - +}` + +//---------------------------------------------------------------------- + export default function Implementation() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('4. Implementation')}

    -

    - - The implementation section covers the core plugin function and - supporting utilities that handle Zod schema generation. This - includes configuration validation, content generation, file writing, - and error handling throughout the generation process. - -

    - -

    {_('4.1. Core Plugin Function')}

    -

    - - The core plugin function serves as the main entry point for Zod - schema generation. It orchestrates the entire process from - configuration validation through content generation to file output, - ensuring proper error handling and logging throughout. - -

    - - {corePluginFunction} - - -

    {_('4.2. Generation Functions')}

    -

    - - Generation functions create specific parts of the Zod validation - output including enum schemas, type schemas, model schemas, and - utility schemas. These functions handle proper Zod syntax - construction and validation rule application. - -

    - - {corePluginFunction} - - - {enumGeneration} - - - {typeGeneration} - - - {modelGeneration} - - - {fieldMapping} - - - {attributeValidations} - - - {inputSchemas} - - - {utilitySchemas} - - - {exportFunctions} - - - {configValidation} - -
    + <> + {/* Implementation Section Content */} +
    +

    {_('4. Implementation')}

    +

    + + The implementation section covers the core plugin function and + supporting utilities that handle Zod schema generation. This + includes configuration validation, content generation, file writing, + and error handling throughout the generation process. + +

    + +

    {_('4.1. Core Plugin Function')}

    +

    + + The core plugin function serves as the main entry point for Zod + schema generation. It orchestrates the entire process from + configuration validation through content generation to file output, + ensuring proper error handling and logging throughout. + +

    + + {corePluginFunction} + + +

    {_('4.2. Generation Functions')}

    +

    + + Generation functions create specific parts of the Zod validation + output including enum schemas, type schemas, model schemas, and + utility schemas. These functions handle proper Zod syntax + construction and validation rule application. + +

    + + {corePluginFunction} + + + {enumGeneration} + + + {typeGeneration} + + + {modelGeneration} + + + {fieldMapping} + + + {attributeValidations} + + + {inputSchemas} + + + {utilitySchemas} + + + {exportFunctions} + + + {configValidation} + +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx b/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx index ad4629f..5d50038 100644 --- a/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/Introduction.tsx @@ -1,11 +1,16 @@ +//modules import { useLanguage, Translate } from 'r22n'; +//local import { H1, P, C } from '../index.js'; export default function Introduction() { + //hooks const { _ } = useLanguage(); return ( -
    + <> + {/* Creating a Validation Schema Generator Plugin */} +

    {_('Validation Schema Generator Plugin Tutorial')}

    @@ -15,6 +20,7 @@ export default function Introduction() { schemas with comprehensive validation rules.

    -
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Overview.tsx b/packages/www/plugins/docs/components/validation-plugin/Overview.tsx index 2b45c50..561f7ef 100644 --- a/packages/www/plugins/docs/components/validation-plugin/Overview.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/Overview.tsx @@ -1,12 +1,17 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C, SS } from '../index.js'; +//local +import { H1, P, C, SS } from '../index.js'; export default function Overview() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('1. Overview')}

    + <> + {/* Overview Section Content */} +
    +

    {_('1. Overview')}

    Zod is a TypeScript-first schema validation library that provides @@ -49,6 +54,7 @@ export default function Overview() { -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx b/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx index 527106c..7e841b6 100644 --- a/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/PluginStructure.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P } from '../index.js'; +//local +import { H1, P } from '../index.js'; import Code from '../Code.js'; -const pluginStructureExample = `import type { PluginProps } from '@stackpress/idea-transformer/types'; +//code examples +//---------------------------------------------------------------------- + +const pluginStructureExample = +`import type { PluginProps } from '@stackpress/idea-transformer/types'; import fs from 'fs/promises'; import path from 'path'; @@ -22,14 +28,19 @@ export default async function generateZodSchemas( const { config, schema, transformer } = props; // Implementation here... -}`; +}` + +//---------------------------------------------------------------------- export default function PluginStructure() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('3. Plugin Structure')}

    + <> + {/* Plugin Structure Section Content */} +
    +

    {_('3. Plugin Structure')}

    The plugin structure defines the core architecture and configuration @@ -41,6 +52,7 @@ export default function PluginStructure() { {pluginStructureExample} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx b/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx index 35e7673..4dccebc 100644 --- a/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/Prerequisites.tsx @@ -1,44 +1,53 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, P, C } from '../index.js'; +//local +import { H1, P, C } from '../index.js'; export default function Prerequisites() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('2. Prerequisites')}

    -

    - - Before implementing the Zod validation schema generator plugin, - ensure you have the necessary development environment and knowledge. - This section covers the essential requirements for successful plugin - creation and Zod integration. - -

    -
      -
    • - Node.js 16+ and npm/yarn -
    • -
    • - TypeScript 4.0+ -
    • -
    • - Zod 3.0+ -
    • -
    • - Basic understanding of validation concepts -
    • -
    • + <> + {/* Prerequisites Section Content */} +
      +

      {_('2. Prerequisites')}

      +

      - Familiarity with the @stackpress/idea-transformer library + Before implementing the Zod validation schema generator + plugin, ensure you have the necessary development environment + and knowledge. This section covers the essential requirements + for successful plugin creation and Zod integration. -

    • -
    • - - Understanding of .idea schema format - -
    • -
    -
    +

    +
      +
    • + Node.js 16+ and npm/yarn +
    • +
    • + TypeScript 4.0+ +
    • +
    • + Zod 3.0+ +
    • +
    • + + Basic understanding of validation concepts + +
    • +
    • + + Familiarity with the @stackpress/idea-transformer + library + +
    • +
    • + + Understanding of .idea schema format + +
    • +
    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx b/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx index ab5ae47..1d63249 100644 --- a/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/SchemaConfiguration.tsx @@ -1,9 +1,15 @@ +//modules import { useLanguage, Translate } from 'r22n'; import { Table, Thead, Trow, Tcol } from 'frui/element/Table'; -import { H2, H3, P, C } from '../index.js'; +//local +import { H1, H2, P, C } from '../index.js'; import Code from '../Code.js'; -const basicConfiguration = `plugin "./plugins/zod-validation.js" { +//code examples +//---------------------------------------------------------------------- + +const basicConfiguration = +`plugin "./plugins/zod-validation.js" { output "./generated/validation.ts" generateTypes true includeEnums true @@ -19,9 +25,9 @@ const basicConfiguration = `plugin "./plugins/zod-validation.js" { password "Password must be at least 8 characters with uppercase, lowercase, and number" required "This field is required" } -}`; - +}` +//---------------------------------------------------------------------- const configurationOptions = [ { @@ -68,12 +74,17 @@ const configurationOptions = [ } ]; +//---------------------------------------------------------------------- + export default function SchemaConfiguration() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('5. Schema Configuration')}

    + <> + {/* Schema Configuration Section Content */} +
    +

    {_('5. Schema Configuration')}

    Schema configuration demonstrates how to integrate the Zod validation @@ -91,7 +102,7 @@ export default function SchemaConfiguration() { {basicConfiguration} -

    {_('Configuration Options')}

    +

    {_('Configuration Options')}

    Configuration options control how Zod validation schemas are generated, @@ -116,6 +127,7 @@ export default function SchemaConfiguration() { ))} -

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx b/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx index 65ccb6d..76e9cbb 100644 --- a/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/Troubleshooting.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const circularDependenciesExample = `// Handle circular references with lazy evaluation +//code examples +//---------------------------------------------------------------------- + +const circularDependenciesExample = + `// Handle circular references with lazy evaluation const UserSchema: z.ZodSchema = z.lazy(() => z.object({ id: z.string(), posts: z.array(PostSchema), @@ -11,9 +17,12 @@ const UserSchema: z.ZodSchema = z.lazy(() => z.object({ const PostSchema: z.ZodSchema = z.lazy(() => z.object({ id: z.string(), author: UserSchema, -}));`; +}));` + +//---------------------------------------------------------------------- -const complexValidationExample = `// Use refinements for complex validation +const complexValidationExample = + `// Use refinements for complex validation const PasswordSchema = z.string() .min(8, "Password must be at least 8 characters") .refine((password) => /[A-Z]/.test(password), { @@ -24,9 +33,12 @@ const PasswordSchema = z.string() }) .refine((password) => /\\d/.test(password), { message: "Password must contain at least one number", - });`; + });` + +//---------------------------------------------------------------------- -const performanceOptimizationExample = `// Use preprocess for expensive operations +const performanceOptimizationExample = + `// Use preprocess for expensive operations const OptimizedSchema = z.preprocess( (data) => { // Expensive preprocessing @@ -35,9 +47,12 @@ const OptimizedSchema = z.preprocess( z.object({ // Schema definition }) -);`; +);` -const schemaTestingExample = `// Test schemas with various inputs +//---------------------------------------------------------------------- + +const schemaTestingExample = + `// Test schemas with various inputs describe('UserSchema', () => { it('should validate valid user data', () => { const validData = { @@ -58,118 +73,130 @@ describe('UserSchema', () => { expect(() => UserSchema.parse(invalidData)).toThrow(); }); -});`; +});` + +//---------------------------------------------------------------------- -const errorCustomizationExample = `// Customize error messages for better UX +const errorCustomizationExample = + `// Customize error messages for better UX const UserSchema = z.object({ email: z.string().email("Please enter a valid email address"), age: z.number().min(18, "You must be at least 18 years old"), -});`; +});` + +//---------------------------------------------------------------------- export default function Troubleshooting() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('9. Troubleshooting')}

    -

    - - This section addresses common issues encountered when generating Zod - validation schemas and provides solutions for debugging and resolving - problems. Understanding these troubleshooting techniques helps ensure - reliable validation schema generation. - -

    - -

    {_('9.1. Common Issues')}

    -

    - - Common issues include circular dependencies, complex validation rules, - and performance problems with large schemas. These problems typically - arise from schema complexity or validation requirements that need - specialized handling. - -

    - -

    {_('9.1.1. Circular Dependencies')}

    -

    - - Circular dependencies occur when schemas reference each other in a way - that creates infinite loops. Zod provides lazy evaluation to handle - these scenarios while maintaining type safety and validation integrity. - -

    - - {circularDependenciesExample} - - -

    {_('9.1.2. Complex Validation Rules')}

    -

    - - Complex validation rules require sophisticated logic that goes beyond - simple type checking. Use Zod's refinement capabilities to implement - business rules and cross-field validation while maintaining clear - error messages. - -

    - - {complexValidationExample} - - -

    {_('9.1.3. Performance Issues')}

    -

    - - Performance issues can arise when validation schemas are complex or - when processing large amounts of data. Optimize validation performance - using preprocessing, caching, and efficient schema design patterns. - -

    - - {performanceOptimizationExample} - - -

    {_('9.2. Debugging Tips')}

    -

    - - Debugging tips help identify and resolve issues during Zod schema - generation and usage. These techniques provide visibility into - validation behavior and help diagnose problems with schema logic - or performance. - -

    - -

    {_('9.2.1. Schema Testing')}

    -

    - - Schema testing ensures that your validation logic works correctly - across different input scenarios. Comprehensive testing helps catch - edge cases and ensures validation behaves as expected in production. - -

    - - {schemaTestingExample} - - -

    {_('9.2.2. Error Message Customization')}

    -

    - - Error message customization improves user experience by providing - clear, actionable feedback when validation fails. Well-crafted error - messages help users understand what went wrong and how to fix it. - -

    - - {errorCustomizationExample} - - -

    - - This tutorial provides a comprehensive foundation for creating - Zod validation schemas from .idea files. The generated schemas - provide runtime type checking and validation with excellent - TypeScript integration. - -

    -
    + <> + {/* Troubleshooting Section Content */} +
    +

    {_('9. Troubleshooting')}

    +

    + + This section addresses common issues encountered when + generating Zod validation schemas and provides solutions + for debugging and resolving problems. Understanding these + troubleshooting techniques helps ensure reliable validation + schema generation. + +

    + +

    {_('9.1. Common Issues')}

    +

    + + Common issues include circular dependencies, complex + validation rules, and performance problems with large + schemas. These problems typically arise from schema + complexity or validation requirements that need specialized + handling. + +

    + +

    {_('9.1.1. Circular Dependencies')}

    +

    + + Circular dependencies occur when schemas reference each + other in a way that creates infinite loops. Zod provides + lazy evaluation to handle these scenarios while maintaining + type safety and validation integrity. + +

    + + {circularDependenciesExample} + + +

    {_('9.1.2. Complex Validation Rules')}

    +

    + + Complex validation rules require sophisticated logic that + goes beyond simple type checking. Use Zod's refinement + capabilities to implement business rules and cross-field + validation while maintaining clear error messages. + +

    + + {complexValidationExample} + + +

    {_('9.1.3. Performance Issues')}

    +

    + + Performance issues can arise when validation schemas are complex or + when processing large amounts of data. Optimize validation performance + using preprocessing, caching, and efficient schema design patterns. + +

    + + {performanceOptimizationExample} + + +

    {_('9.2. Debugging Tips')}

    +

    + + Debugging tips help identify and resolve issues during Zod schema + generation and usage. These techniques provide visibility into + validation behavior and help diagnose problems with schema logic + or performance. + +

    + +

    {_('9.2.1. Schema Testing')}

    +

    + + Schema testing ensures that your validation logic works correctly + across different input scenarios. Comprehensive testing helps catch + edge cases and ensures validation behaves as expected in production. + +

    + + {schemaTestingExample} + + +

    {_('9.2.2. Error Message Customization')}

    +

    + + Error message customization improves user experience by providing + clear, actionable feedback when validation fails. Well-crafted error + messages help users understand what went wrong and how to fix it. + +

    + + {errorCustomizationExample} + + +

    + + This tutorial provides a comprehensive foundation for creating + Zod validation schemas from .idea files. The generated schemas + provide runtime type checking and validation with excellent + TypeScript integration. + +

    +
    + ); } \ No newline at end of file diff --git a/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx b/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx index e6c5902..4fce6d4 100644 --- a/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/UsageExamples.tsx @@ -1,8 +1,14 @@ +//modules import { useLanguage, Translate } from 'r22n'; -import { H2, H3, P } from '../index.js'; +//local +import { H1, H2, P } from '../index.js'; import Code from '../Code.js'; -const basicSchemaExample = `enum UserRole { +//code examples +//---------------------------------------------------------------------- + +const basicSchemaExample = +`enum UserRole { ADMIN "admin" USER "user" GUEST "guest" @@ -22,7 +28,9 @@ plugin "./plugins/zod-validation.js" { output "./validation.ts" generateTypes true strictMode true -}`; +}` + +//---------------------------------------------------------------------- const generatedValidationUsage = `import { UserSchema, @@ -69,9 +77,12 @@ const userData = { role: 'user' as UserRole }; -const validUser = validateCreateUser(userData);`; +const validUser = validateCreateUser(userData);` -const formValidationExample = `import { CreateUserSchema } from './validation'; +//---------------------------------------------------------------------- + +const formValidationExample = +`import { CreateUserSchema } from './validation'; // React form validation function UserForm() { @@ -112,14 +123,19 @@ function UserForm() { ); -}`; +}` + +//---------------------------------------------------------------------- export default function UsageExamples() { + //hooks const { _ } = useLanguage(); return ( -
    -

    {_('6. Usage Examples')}

    + <> + {/* Usage Examples Section Content */} +
    +

    {_('6. Usage Examples')}

    Usage examples demonstrate practical applications of the Zod @@ -130,7 +146,7 @@ export default function UsageExamples() {

    -

    {_('6.1. Basic Schema')}

    +

    {_('6.1. Basic Schema')}

    A basic schema example shows the fundamental structure needed @@ -143,7 +159,7 @@ export default function UsageExamples() { {basicSchemaExample} -

    {_('6.2. Generated Validation Usage')}

    +

    {_('6.2. Generated Validation Usage')}

    The generated validation usage demonstrates how to use the Zod @@ -156,7 +172,7 @@ export default function UsageExamples() { {generatedValidationUsage} -

    {_('6.3. Form Validation Example')}

    +

    {_('6.3. Form Validation Example')}

    Zod schemas with frontend frameworks for user input validation. @@ -167,7 +183,7 @@ export default function UsageExamples() { {formValidationExample} -

    +
    + ); -}; - +} diff --git a/packages/www/plugins/docs/components/validation-plugin/index.tsx b/packages/www/plugins/docs/components/validation-plugin/index.tsx index 890be10..0049239 100644 --- a/packages/www/plugins/docs/components/validation-plugin/index.tsx +++ b/packages/www/plugins/docs/components/validation-plugin/index.tsx @@ -1,3 +1,4 @@ +//exporting all components to have multiple imports from a single file export { default as Introduction } from './Introduction.js'; export { default as Overview } from './Overview.js'; export { default as Prerequisites } from './Prerequisites.js'; diff --git a/packages/www/plugins/docs/views/getting-started.tsx b/packages/www/plugins/docs/views/getting-started.tsx index 0293518..2760d28 100644 --- a/packages/www/plugins/docs/views/getting-started.tsx +++ b/packages/www/plugins/docs/views/getting-started.tsx @@ -5,16 +5,24 @@ import type { } from 'stackpress/view/client'; import { useState } from 'react'; import { useLanguage, Translate } from 'r22n'; -//docs +//local import { H1, H2, P, C, Nav } from '../components/index.js'; import Code from '../components/Code.js'; import Layout from '../components/Layout.js'; +//code examples +//---------------------------------------------------------------------- + const npmInstallCommand = 'npm i -D @stackpress/idea'; +//---------------------------------------------------------------------- + const yarnInstallCommand = 'yarn add --dev @stackpress/idea'; -const schemaExample = `model User { +//---------------------------------------------------------------------- + +const schemaExample = + `model User { id String @id @default("nanoid()") name String @required email String @unique @required @@ -25,8 +33,12 @@ plugin "./plugins/typescript-generator.js" { output "./generated/types.ts" }`; +//---------------------------------------------------------------------- + const generateCommand = 'npx idea transform --input schema.idea'; +//---------------------------------------------------------------------- + export function Head(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -58,11 +70,13 @@ export function Head(props: ServerPageProps) { } export function Body() { + //hooks const [install, setInstall] = useState('npm'); const { _ } = useLanguage(); return (
    + {/* Introduction */}

    {_('Getting Started')}

    @@ -72,22 +86,21 @@ export function Body() {

    + {/* Installation */}

    {_('Installation')}

    setInstall('npm')} >
    setInstall('yarn')} > @@ -110,6 +123,7 @@ export function Body() {
    + {/* Create Schema Content */}

    {_('Create your first schema')}

    @@ -126,6 +140,7 @@ export function Body() {

    + {/* Generate Code Content */}

    {_('Generate Code')}

    + {/* Explore the Results Content */}

    {_('Explore the Results')}

    @@ -146,18 +162,17 @@ export function Body() {

    -
    -
    + {/* Page Navigation */} +
    ); } diff --git a/packages/www/plugins/docs/views/index.tsx b/packages/www/plugins/docs/views/index.tsx index 00a8b0b..3623c93 100644 --- a/packages/www/plugins/docs/views/index.tsx +++ b/packages/www/plugins/docs/views/index.tsx @@ -4,13 +4,14 @@ import type { ServerPageProps } from 'stackpress/view/client'; import { useLanguage, Translate } from 'r22n'; -//docs +//local import { H1, H2, P, Nav } from '../components/index.js'; import Layout from '../components/Layout.js'; import Code from '../components/Code.js'; -const schemaExample = ` -// schema.idea +//code example +const schemaExample = +`// schema.idea enum UserRole { ADMIN "Administrator" CUSTOMER "Customer" @@ -60,6 +61,8 @@ plugin "./plugins/api-generator.js" { includeValidation true }` +//---------------------------------------------------------------------- + export function DocumentationHead(props: ServerPageProps) { //props const { request, styles = [] } = props; @@ -100,166 +103,213 @@ export function DocumentationBody() { return (
    -

    {_('What is .idea?')}

    - -

    - - The .idea file format is a declarative schema definition - language designed to simplify application development by - providing a single source of truth for data structures, - relationships, and code generation. It enables developers - to define their application's data model once and generate - multiple outputs including database schemas, TypeScript - interfaces, API documentation, forms, and more. - -

    - -

    - - Think of it as the bridge between AI prompting and full- - stack code generation - where a simple schema definition can - automatically generate everything from database tables to - React components, API endpoints to documentation sites. - -

    - -

    {_('Why Use .idea?')}

    - -
      -
    • -

      {_('Single Source of Truth')}

      - - Define your data model once, use it everywhere. No more - maintaining separate schemas for database, frontend, and - API. - -
    • -
    • -

      Type Safety Everywhere

      - - Generate type-safe code across languages - TypeScript, - Python, Rust, Go, and more. Catch errors at compile time. - -
    • -
    • -

      Rapid Development

      + {/* Introduction */} +
      +

      {_('What is .idea?')}

      + +

      - Generate boilerplate code, forms, and documentation in - seconds. What used to take hours now happens instantly. + The .idea file format is a declarative schema definition + language designed to simplify application development by + providing a single source of truth for data structures, + relationships, and code generation. It enables developers + to define their application's data model once and generate + multiple outputs including database schemas, TypeScript + interfaces, API documentation, forms, and more. -

    • -
    +

    -

    {_('Who Should Use This?')}

    - -
      -
    • -

      {_('Junior Developers')}

      +

      - Easy syntax, rapid prototyping, learn best practices through - generated code. + Think of it as the bridge between AI prompting and full- + stack code generation - where a simple schema definition can + automatically generate everything from database tables to + React components, API endpoints to documentation sites. -

    • -
    • -

      {_('Senior Developers')}

      +

      +
    + +
    + + {/* Why use .idea? */} +
    +

    {_('Why Use .idea?')}

    + +
      +
    • +

      {_('Single Source of Truth')}

      + + Define your data model once, use it everywhere. No more + maintaining separate schemas for database, frontend, and + API. + +
    • +
    • +

      Type Safety Everywhere

      + + Generate type-safe code across languages - TypeScript, + Python, Rust, Go, and more. Catch errors at compile time. + +
    • +
    • +

      Rapid Development

      + + Generate boilerplate code, forms, and documentation in + seconds. What used to take hours now happens instantly. + +
    • +
    +
    + +
    + + {/* Who Should Use This? */} +
    +

    {_('Who Should Use This?')}

    + +
      +
    • +

      {_('Junior Developers')}

      + + Easy syntax, rapid prototyping, learn best practices through + generated code. + +
    • +
    • +

      {_('Senior Developers')}

      + + Powerful features, extensible plugins, maintain consistency + across large codebases. + +
    • +
    • +

      {_('CTOs & Technical Leaders')}

      + + Reduce development time by 60-80%, improve consistency, + accelerate time-to-market. + +
    • +
    +
    + +
    + + {/* The Plugin Ecosystem */} +
    +

    {_('The Plugin Ecosystem')}

    + +

    - Powerful features, extensible plugins, maintain consistency - across large codebases. + The power of .idea comes from its plugin system. Generate code + for any technology: - -

  • -

    {_('CTOs & Technical Leaders')}

    +

    + +
      +
    • +

      {_('Languages')}

      + + TypeScript, Python, Rust, Go, Java, C#, PHP, and more. + +
    • +
    • +

      {_('Frameworks')}

      + + React, Vue, Angular, Next.js, Express, FastAPI, Django, and + more. + +
    • +
    • +

      {_('Databases')}

      + + PostgreSQL, MySQL, MongoDB, Neo4j, and more. + +
    • +
    +
  • + +
    + + {/* Real-World Example */} +
    +

    {_('Real-World Example')}

    + +

    - Reduce development time by 60-80%, improve consistency, - accelerate time-to-market. + Here's how a simple e-commerce schema becomes a full + application: - - - -

    {_('The Plugin Ecosystem')}

    +

    -

    - - The power of .idea comes from its plugin system. Generate code - for any technology: - -

    + + {schemaExample} + -
      -
    • -

      {_('Languages')}

      +

      - TypeScript, Python, Rust, Go, Java, C#, PHP, and more. + From this single schema, generate: -

    • -
    • -

      {_('Frameworks')}

      +

      + +
        +
      • + + {_('TypeScript interfaces')} +
      • +
      • + + {_('PostgreSQL schema')} +
      • +
      • + + {_('React components')} +
      • +
      • + + {_('API documentation')} +
      • +
      • + + {_('Validation schemas')} +
      • +
      • + + {_('Test data')} +
      • +
      +
    + +
    + + {/* AI-Powered Workflow */} +
    +

    {_('AI-Powered Workflow')}

    + +

    - React, Vue, Angular, Next.js, Express, FastAPI, Django, and - more. + The perfect workflow for AI-driven development: - -

  • -

    {_('Databases')}

    +

    +
      +
    1. {_('Describe your app to an AI')}
    2. +
    3. {_('Get a .idea schema')}
    4. +
    5. {_('Configure plugins')}
    6. +
    7. {_('Generate full-stack code')}
    8. +
    9. {_('Iterate and improve')}
    10. +
    + +

    - PostgreSQL, MySQL, MongoDB, Neo4j, and more. + Go from idea to working application in minutes, not days. -

  • - - -

    {_('Real-World Example')}

    - -

    - - Here's how a simple e-commerce schema becomes a full - application: - -

    - - - {schemaExample} - - -

    - - From this single schema, generate: - -

    - -
      -
    • ✅ {_('TypeScript interfaces')}
    • -
    • ✅ {_('PostgreSQL schema')}
    • -
    • ✅ {_('React components')}
    • -
    • ✅ {_('API documentation')}
    • -
    • ✅ {_('Validation schemas')}
    • -
    • ✅ {_('Test data')}
    • -
    - -

    {_('AI-Powered Workflow')}

    - -

    - - The perfect workflow for AI-driven development: - -

    -
      -
    1. {_('Describe your app to an AI')}
    2. -
    3. {_('Get a .idea schema')}
    4. -
    5. {_('Configure plugins')}
    6. -
    7. {_('Generate full-stack code')}
    8. -
    9. {_('Iterate and improve')}
    10. -
    - -

    - - Go from idea to working application in minutes, not days. - -

    +

    +
    + {/* Page Navigation */}
    - {_('Returns')} -
  • + {/* Horizontal Rule */} +
    + + {/* TypeTree Section */} +
    +

    {_('4. TypeTree')}

    - A DeclarationToken representing the type structure. + Parses type declarations. -
  • - -

    {_('Parsing Type Properties')}

    - - The following example shows how type properties (columns) are parsed. - - - {examples[12]} - - - {_('Returns')} -
  • + +

    {_('4.1 Static Methods')}

    + +

    {_('4.1.1 Parsing Type Declarations')}

    - A PropertyToken representing a type column definition. + The following example shows how to parse type declarations. -
  • - -

    {_('Parsing Type Parameters')}

    - - The following example shows how type parameters are parsed. - - - {examples[13]} - - - {_('Returns')} -
  • - nslate - -
  • - -

    {_('PropTree')}

    - - Parses prop (property configuration) declarations. - - -

    {_('Static Methods')}

    - -

    {_('Parsing Prop Declarations')}

    - - The following example shows how to parse prop declarations. - - - {examples[14]} - - -

    {_('Parameters')}

    - - Parameter - Type - Description - - code - string - {_('The prop declaration code to parse')} - - - start - number - {_('Starting position in the code (default: 0)')} - -
    - - {_('Returns')} -
  • + + {examples[10]} + + +

    {_('Parameters')}

    + + + Parameter + Type + Description + + + code + string + {_('The type declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
      +
    • + + A DeclarationToken representing the parsed type. + +
    • +
    + +

    {_('4.2 Methods')}

    + +

    {_('4.2.1 Parsing Type Structure')}

    - A DeclarationToken representing the parsed prop. + The following example shows how to parse the type structure. -
  • + + {examples[11]} + + + {_('Returns')} +
  • + + A DeclarationToken representing the type structure. + +
  • -

    {_('Methods')}

    +

    {_('4.2.2 Parsing Type Properties')}

    + + The following example shows how type properties (columns) are parsed. + + + {examples[12]} + -

    {_('Parsing Prop Structure')}

    - - The following example shows how to parse the prop structure. - - - {examples[15]} - + {_('Returns')} +
  • + + A PropertyToken representing a type column definition. + +
  • - {_('Returns')} -
  • +

    {_('4.2.3 Parsing Type Parameters')}

    - A DeclarationToken representing the prop configuration. + The following example shows how type parameters are parsed. -
  • - -

    {_('PluginTree')}

    - - Parses plugin declarations. - - -

    {_('Static Methods')}

    - -

    {_('Parsing Plugin Declarations')}

    - - The following example shows how to parse plugin declarations. - - - {examples[16]} - - -

    {_('Parameters')}

    - - Parameter - Type - Description - - code - string - {_('The plugin declaration code to parse')} - - - start - number - {_('Starting position in the code (default: 0)')} - -
    - - {_('Returns')} -
  • - {_('A DeclarationToken representing the parsed plugin.')} -
  • - -

    {_('Methods')}

    - -

    {_('Parsing Plugin Structure')}

    - - The following example shows how to parse the plugin structure. - - - {examples[17]} - - - {_('Returns')} -
  • A DeclarationToken representing the plugin configuration.
  • - -

    {_('UseTree')}

    - - Parses use (import) declarations. - - -

    {_('Static Methods')}

    - -

    {_('Parsing Use Declarations')}

    - - The following example shows how to parse use declarations. - - - {examples[18]} - - -

    {_('Parameters')}

    - - Parameter - Type - Description - - code - string - {_('The use declaration code to parse')} - - - start - number - {_('Starting position in the code (default: 0)')} - -
    - - {_('Returns')} -
  • - {_('An ImportToken representing the parsed use statement.')} -
  • - -

    {_('Methods')}

    - -

    {_('Parsing Use Structure')}

    - - The following example shows how to parse the use structure. - - - {examples[19]} - - - {_('Returns')} -
  • {_('An ImportToken representing the import statement.')}
  • - -

    {_('Usage Patterns')}

    - -

    {_('Parsing Individual Components')}

    - - {examples[20]} - - -

    {_('Using with Compiler')}

    - - {examples[21]} - - -

    {_('Custom AST Classes')}

    - - You can extend AbstractTree to create custom parsers: - - - {examples[22]} - - -

    {_('Error Handling')}

    - - AST classes provide detailed error information when parsing fails: -

    Syntax Errors

    - - {examples[23]} - - -

    {_('Unexpected Tokens')}

    - - {examples[24]} - - -

    {_('Empty Input Handling')}

    - - {examples[25]} - - -

    {_('Invalid Identifiers')}

    - - {examples[26]} - - -

    {_('Integration with Main Functions')}

    - - AST classes are used internally by the main parse and final functions: - - - {examples[27]} - - -

    {_('Performance Considerations')}

    - -

    {_('Lexer Reuse')}

    - - AST classes can share lexer instances for better performance: - - - {examples[28]} - - -

    {_('Cloning for Backtracking')}

    - - AST classes use lexer cloning for safe parsing attempts: - - - {examples[29]} - - -

    {_('Test-Driven Examples')}

    - - Based on the test fixtures, here are real-world examples: - - -

    {_('Enum with Multiple Values')}

    - - {examples[30]} - - -

    {_('Complex Model with Attributes')}

    - - {examples[31]} - - - - This demonstrates the parser's ability to handle: - -
      -
    • Model mutability (! modifier)
    • -
    • Attributes (@label, @id, @default, etc.)
    • -
    • Optional types (Address?, Company?)
    • -
    • Array types (Number[])
    • -
    • Complex attribute parameters (@field.input(Text), @is.clt(80))
    • -
    + + {examples[13]} + + + {_('Returns')} +
      +
    • + + A ParameterToken representing a type parameter. + +
    • +
    +
    + + {/* Horizontal Rule */} +
    + + {/* PropTree Section */} +
    +

    {_('5. PropTree')}

    + + Parses prop (property configuration) declarations. + + +

    {_('5.1 Static Methods')}

    + +

    {_('5.1.1 Parsing Prop Declarations')}

    + + The following example shows how to parse prop declarations. + + + {examples[14]} + + +

    {_('Parameters')}

    + + + Parameter + Type + Description + + + code + string + {_('The prop declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
      +
    • + + A DeclarationToken representing the parsed prop. + +
    • +
    + +

    {_('5.2 Methods')}

    + +

    {_('5.2.1 Parsing Prop Structure')}

    + + The following example shows how to parse the prop structure. + + + {examples[15]} + + + {_('Returns')} +
      +
    • + + A DeclarationToken representing the prop configuration. + +
    • +
    +
    + + {/* Horizontal Rule */} +
    + + {/* PluginTree Section */} +
    +

    {_('6. PluginTree')}

    + + Parses plugin declarations. + + +

    {_('6.1 Static Methods')}

    + +

    {_('6.1.1 Parsing Plugin Declarations')}

    + + The following example shows how to parse plugin declarations. + + + {examples[16]} + + +

    {_('Parameters')}

    + + + Parameter + Type + Description + + + code + string + {_('The plugin declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
      +
    • {_('A DeclarationToken representing the parsed plugin.')}
    • +
    + +

    {_('6.2 Methods')}

    + +

    {_('6.2.1 Parsing Plugin Structure')}

    + + The following example shows how to parse the plugin structure. + + + {examples[17]} + + + {_('Returns')} +
      +
    • + + A DeclarationToken representing the plugin configuration. + +
    • +
    +
    + + {/* Horizontal Rule */} +
    + + {/* UseTree Section Content */} +
    +

    {_('7. UseTree')}

    + + Parses use (import) declarations. + + +

    {_('7.1 Static Methods')}

    + +

    {_('7.1.1Parsing Use Declarations')}

    + + The following example shows how to parse use declarations. + + + {examples[18]} + + +

    {_('Parameters')}

    + + + Parameter + Type + Description + + + code + string + {_('The use declaration code to parse')} + + + start + number + {_('Starting position in the code (default: 0)')} + +
    + + {_('Returns')} +
      +
    • {_('An ImportToken representing the parsed use statement.')}
    • +
    + +

    {_('7.2 Methods')}

    + +

    {_('7.2.1 Parsing Use Structure')}

    + + The following example shows how to parse the use structure. + + + {examples[19]} + + + {_('Returns')} +

    + + An ImportToken representing the import statement. + +

    +
    + + {/* Horizontal Rule */} +
    + + {/* Usage Patterns Section Content */} +
    +

    {_('8. Usage Patterns')}

    + +

    {_('8.1 Parsing Individual Components')}

    + + {examples[20]} + + +

    {_('8.2 Using with Compiler')}

    + + {examples[21]} + + +

    {_('8.3 Custom AST Classes')}

    +

    + + You can extend AbstractTree to create custom parsers: + +

    + + {examples[22]} + +
    + + {/* Horizontal Rule */} +
    + + {/* Error Handling Section Content */} +
    +

    {_('9. Error Handling')}

    + + AST classes provide detailed error information when parsing fails: + + +

    {_('Syntax Errors')}

    + + {examples[23]} + + +

    {_('Unexpected Tokens')}

    + + {examples[24]} + + +

    {_('Empty Input Handling')}

    + + {examples[25]} + + +

    {_('Invalid Identifiers')}

    + + {examples[26]} + +
    + + {/* Horizontal Rule */} +
    + + {/* Integration with Main Functions Section Content */} +
    +

    {_('10. Integration with Main Functions')}

    + + AST classes are used internally by the main parse and final functions: + + + {examples[27]} + +
    + + {/* Horizontal Rule */} +
    + + {/* Performance Considerations Section Content */} +
    +

    {_('11. Performance Considerations')}

    + +

    {_('11.1 Lexer Reuse')}

    +

    + + AST classes can share lexer instances for better performance: + +

    + + {examples[28]} + + +

    {_('11.2 Cloning for Backtracking')}

    +

    + + AST classes use lexer cloning for safe parsing attempts: + +

    + + {examples[29]} + +
    + + {/* Horizontal Rule */} +
    + + {/* Test-Driven Examples Section Content */} +
    +

    {_('12. Test-Driven Examples')}

    +

    + + Based on the test fixtures, here are real-world examples: + +

    + +

    {_('Enum with Multiple Values')}

    + + {examples[30]} + + +

    {_('Complex Model with Attributes')}

    + + {examples[31]} + + +

    + + This demonstrates the parser's ability to handle: + +

    + +
      +
    • + + Model mutability (! modifier) + +
    • +
    • + + Attributes (@label, @id, @default, etc.) + +
    • +
    • + + Optional types (Address?, Company?) + +
    • +
    • + + Array types (Number[]) + +
    • +
    • + + Complex attribute parameters (@field.input(Text), @is.clt(80)) + +
    • +
    +
    + {/* Page Navigation */}

    -