diff --git a/packages/shikicode/.gitignore b/packages/shikicode/.gitignore
new file mode 100644
index 0000000..bd1aa80
--- /dev/null
+++ b/packages/shikicode/.gitignore
@@ -0,0 +1,133 @@
+# 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.*
+
+
+lib/
\ No newline at end of file
diff --git a/packages/shikicode/.npmignore b/packages/shikicode/.npmignore
new file mode 100644
index 0000000..561e15f
--- /dev/null
+++ b/packages/shikicode/.npmignore
@@ -0,0 +1,133 @@
+# 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.*
+
+# lib should be included in npm package
+# lib/
\ No newline at end of file
diff --git a/packages/shikicode/LICENSE b/packages/shikicode/LICENSE
new file mode 100644
index 0000000..2ba6364
--- /dev/null
+++ b/packages/shikicode/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 magic-akari
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/shikicode/README.md b/packages/shikicode/README.md
new file mode 100644
index 0000000..60682a5
--- /dev/null
+++ b/packages/shikicode/README.md
@@ -0,0 +1,9 @@
+# ShikiCode εΌγ³γΌγ
+
+[![NPM version](https://img.shields.io/npm/v/shikicode?color=32A9C3&labelColor=1B3C4A&label=npm)](https://www.npmjs.com/package/shikicode)
+
+A lightweight, beautiful, and extensible code editor based on [Shiki](https://shiki.style).
+
+## License
+
+[MIT](./LICENSE)
diff --git a/packages/shikicode/index.html b/packages/shikicode/index.html
new file mode 100644
index 0000000..ab5486d
--- /dev/null
+++ b/packages/shikicode/index.html
@@ -0,0 +1,156 @@
+
+
+
+
+
+ Shiki Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/shikicode/package-lock.json b/packages/shikicode/package-lock.json
new file mode 100644
index 0000000..5f449c4
--- /dev/null
+++ b/packages/shikicode/package-lock.json
@@ -0,0 +1,853 @@
+{
+ "name": "shikicode",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "shikicode",
+ "version": "0.0.0",
+ "license": "MIT",
+ "devDependencies": {
+ "@types/jest": "^29.5.12",
+ "dprint": "^0.45.0",
+ "oxlint": "^0.2.14",
+ "shiki": "^1.2.0",
+ "typescript": "^5.4.3"
+ },
+ "peerDependencies": {
+ "shiki": "^1.2.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
+ "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.24.2",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
+ "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@dprint/darwin-arm64": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.45.0.tgz",
+ "integrity": "sha512-pkSSmixIKXr5t32bhXIUbpIBm8F8uhsJcUUvfkFNsRbQvNwRp71ribZpE8dKl0ZFOlAFeWD6WLE8smp/QtiGUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@dprint/darwin-x64": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.45.0.tgz",
+ "integrity": "sha512-PHcXSrRO53KH9N+YPbPtr40NnDo2t7hO7KLMfl2ktRNLjrmKg6F8XDDsr2C7Z11k3jyEEU2Jq8hhpaKHwNapmQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@dprint/linux-arm64-glibc": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.45.0.tgz",
+ "integrity": "sha512-NgIpvZHpiQaY4DxSygxknxBtvKE2KLK9dEbUNKNE098yTHhGq7ouPsoM7RtsO34RHJ3tEZLLJEuBHn20XP8LMg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@dprint/linux-arm64-musl": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.45.0.tgz",
+ "integrity": "sha512-Y8p+FC0RNyKCGQjy99Uh1LSPrlQtUTvo4brdvU1THF3pyWu6Bg1p6NiP5a6SjE/6t9CMKZJz39zPreQtnDkSDA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@dprint/linux-x64-glibc": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.45.0.tgz",
+ "integrity": "sha512-u03NCZIpJhE5gIl9Q7jNL4sOPBFd/8BLVBiuLoLtbiTZQ+NNudHKgGNATJBU67q1MKpqKnt8/gQm139cJkHhrw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@dprint/linux-x64-musl": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.45.0.tgz",
+ "integrity": "sha512-DQN8LPtxismkeU1X+sQywa80kWwCBcpQh9fXoJcvTEHrgzHBqbG2SEsUZpM12oKEua1KE/iBh+vgZ+4I3TdI2A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@dprint/win32-x64": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.45.0.tgz",
+ "integrity": "sha512-aZHIWG2jIlEp4BER1QG6YYqPd6TxT9S77AeUkWJixNiMEo+33mPRVCBcugRWI/WJWveX8yWFVXkToORtnSFeEA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@jest/expect-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
+ "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+ "dev": true,
+ "dependencies": {
+ "jest-get-type": "^29.6.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/types": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.8",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@oxlint/darwin-arm64": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/darwin-arm64/-/darwin-arm64-0.2.14.tgz",
+ "integrity": "sha512-ddCNJDIpwdtDy2EveF76jXmHOs63b2AU8vvzHZ4cw6xtHxXgfGSOTAckWfJLKXq+s5LDROMVL2DXIcuizaXYBw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxlint/darwin-x64": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/darwin-x64/-/darwin-x64-0.2.14.tgz",
+ "integrity": "sha512-EvHOIjDpNgMXlDGk7Sr/2C0VszHj7riV+VhjGXyZwVCNFfT6jR2CfJNagTUp9AICkyESPY7UtOHYcsEsEKCtAw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxlint/linux-arm64-gnu": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-gnu/-/linux-arm64-gnu-0.2.14.tgz",
+ "integrity": "sha512-ptX6gC9wLCI3EMgYJd8cUIbcwTZv7aubuFnCg68bop2SdYAtYZIQQfazsOB/+a1pt/ISkheL19rGeaedmRqaPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxlint/linux-arm64-musl": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-musl/-/linux-arm64-musl-0.2.14.tgz",
+ "integrity": "sha512-F7hzgZB65C+K1ZJkUG8vgDzo+AD/DVU2cUU7o0pv6/cn1BGjcERiyJECzrPXsnYSgeaT88eXoUgnDZNf5mH7Lw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxlint/linux-x64-gnu": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-gnu/-/linux-x64-gnu-0.2.14.tgz",
+ "integrity": "sha512-mEkPz/GXOkPC3HNwN5SHGaT+ajk+twTuPHiI6TRKSbNCMHvi4kV9Ftana+t2hV5IfpbieFhnOsO0iH/iUOdKTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxlint/linux-x64-musl": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-musl/-/linux-x64-musl-0.2.14.tgz",
+ "integrity": "sha512-0jmm/NcD78etW+G9jHAuFjQdl9GW2bXxlOR8/y2jYyYTuCtSuqhzJCK2kWoAcBynacDIsDC+fCZF7qHOPrDHDA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxlint/win32-arm64": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/win32-arm64/-/win32-arm64-0.2.14.tgz",
+ "integrity": "sha512-P5vaQFjtVnshk94PMaW/kot/FKH9y8fjhd7vwGp6eRO32QOkSMbG7jOtuvlFOb4E9lGyQaihJ9yVbP9vmkvzvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@oxlint/win32-x64": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/@oxlint/win32-x64/-/win32-x64-0.2.14.tgz",
+ "integrity": "sha512-ORXoR8DpAOWX/3YDBwOCg+yUORu6cK/GUYEq22BpUXn/HRljiFbEBoBWadOhfow/K+/j9OGUxPeepe8zthN2iA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@shikijs/core": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.9.0.tgz",
+ "integrity": "sha512-cbSoY8P/jgGByG8UOl3jnP/CWg/Qk+1q+eAKWtcrU3pNoILF8wTsLB0jT44qUBV8Ce1SvA9uqcM9Xf+u3fJFBw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true
+ },
+ "node_modules/@types/istanbul-lib-coverage": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "dev": true
+ },
+ "node_modules/@types/istanbul-lib-report": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+ "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "dev": true,
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "node_modules/@types/istanbul-reports": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+ "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "node_modules/@types/jest": {
+ "version": "29.5.12",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz",
+ "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==",
+ "dev": true,
+ "dependencies": {
+ "expect": "^29.0.0",
+ "pretty-format": "^29.0.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "20.11.30",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz",
+ "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/stack-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+ "dev": true
+ },
+ "node_modules/@types/yargs": {
+ "version": "17.0.32",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
+ "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
+ "dev": true,
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "node_modules/@types/yargs-parser": {
+ "version": "21.0.3",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "dev": true
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+ "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/dprint": {
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.45.0.tgz",
+ "integrity": "sha512-3444h7V47XoA16qgIWjw3CV/Eo/rQbT/XTGlbJ/6vJ+apQyuo0+M3Ai0GS3wu7X9HBUDcA0zIHA3mOxWNz6toA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "dprint": "bin.js"
+ },
+ "optionalDependencies": {
+ "@dprint/darwin-arm64": "0.45.0",
+ "@dprint/darwin-x64": "0.45.0",
+ "@dprint/linux-arm64-glibc": "0.45.0",
+ "@dprint/linux-arm64-musl": "0.45.0",
+ "@dprint/linux-x64-glibc": "0.45.0",
+ "@dprint/linux-x64-musl": "0.45.0",
+ "@dprint/win32-x64": "0.45.0"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/expect-utils": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/jest-diff": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
+ "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
+ "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-message-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.12.13",
+ "@jest/types": "^29.6.3",
+ "@types/stack-utils": "^2.0.0",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/oxlint": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-0.2.14.tgz",
+ "integrity": "sha512-LFOnbhtpitIqtHqyBDYAvT5g3ckm3fZ6xAMU8zkaDwC4ofC29ZpxAPuF42ZFJOw1UnufJPUutECSwMco2ho/Fg==",
+ "dev": true,
+ "bin": {
+ "oxlint": "bin/oxlint"
+ },
+ "engines": {
+ "node": ">=14.*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxlint/darwin-arm64": "0.2.14",
+ "@oxlint/darwin-x64": "0.2.14",
+ "@oxlint/linux-arm64-gnu": "0.2.14",
+ "@oxlint/linux-arm64-musl": "0.2.14",
+ "@oxlint/linux-x64-gnu": "0.2.14",
+ "@oxlint/linux-x64-musl": "0.2.14",
+ "@oxlint/win32-arm64": "0.2.14",
+ "@oxlint/win32-x64": "0.2.14"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
+ "node_modules/shiki": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.9.0.tgz",
+ "integrity": "sha512-i6//Lqgn7+7nZA0qVjoYH0085YdNk4MC+tJV4bo+HgjgRMJ0JmkLZzFAuvVioJqLkcGDK5GAMpghZEZkCnwxpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/core": "1.9.0"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stack-utils": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+ "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.4.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
+ "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ }
+ }
+}
diff --git a/packages/shikicode/package.json b/packages/shikicode/package.json
new file mode 100644
index 0000000..f05369d
--- /dev/null
+++ b/packages/shikicode/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "shikicode",
+ "version": "0.0.0",
+ "description": "lightweight code editor powered by shiki",
+ "main": "lib/index.js",
+ "type": "module",
+ "scripts": {
+ "start": "tsc --watch",
+ "build": "tsc",
+ "prepack": "tsc",
+ "fix:fmt": "dprint fmt",
+ "check:fmt": "dprint check",
+ "check:lint": "oxlint src -D correctness -D pedantic"
+ },
+ "keywords": [
+ "shiki",
+ "code",
+ "editor"
+ ],
+ "author": "magic-akari ",
+ "license": "MIT",
+ "bugs": "https://github.com/magic-akari/shikicode/issues",
+ "homepage": "https://github.com/magic-akari/shikicode#readme",
+ "devDependencies": {
+ "@types/jest": "^29.5.13",
+ "dprint": "^0.47.2",
+ "oxlint": "^0.9.10",
+ "shiki": "^1.22.0",
+ "typescript": "^5.6.3"
+ },
+ "peerDependencies": {
+ "shiki": "^1.2.0"
+ },
+ "exports": {
+ ".": {
+ "types": "./lib/index.d.ts",
+ "default": "./lib/index.js"
+ },
+ "./plugins": {
+ "types": "./lib/plugins/index.d.ts",
+ "default": "./lib/plugins/index.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "packageManager": "pnpm@9.5.0+sha512.140036830124618d624a2187b50d04289d5a087f326c9edfc0ccd733d76c4f52c3a313d4fc148794a2a9d81553016004e6742e8cf850670268a7387fc220c903"
+}
diff --git a/packages/shikicode/pnpm-lock.yaml b/packages/shikicode/pnpm-lock.yaml
new file mode 100644
index 0000000..d6b16be
--- /dev/null
+++ b/packages/shikicode/pnpm-lock.yaml
@@ -0,0 +1,868 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ '@types/jest':
+ specifier: ^29.5.13
+ version: 29.5.13
+ dprint:
+ specifier: ^0.47.2
+ version: 0.47.2
+ oxlint:
+ specifier: ^0.9.10
+ version: 0.9.10
+ shiki:
+ specifier: ^1.22.0
+ version: 1.22.0
+ typescript:
+ specifier: ^5.6.3
+ version: 5.6.3
+
+packages:
+
+ '@babel/code-frame@7.25.7':
+ resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.25.7':
+ resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/highlight@7.25.7':
+ resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==}
+ engines: {node: '>=6.9.0'}
+
+ '@dprint/darwin-arm64@0.47.2':
+ resolution: {integrity: sha512-mVPFBJsXxGDKHHCAY8wbqOyS4028g1bN15H9tivCnPAjwaZhkUimZHXWejXADjhGn+Xm2SlakugY9PY/68pH3Q==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@dprint/darwin-x64@0.47.2':
+ resolution: {integrity: sha512-T7wzlc+rBV+6BRRiBjoqoy5Hj4TR2Nv2p2s9+ycyPGs10Kj/JXOWD8dnEHeBgUr2r4qe/ZdcxmsFQ5Hf2n0WuA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@dprint/linux-arm64-glibc@0.47.2':
+ resolution: {integrity: sha512-B0m1vT5LdVtrNOVdkqpLPrSxuCD+l5bTIgRzPaDoIB1ChWQkler9IlX8C+RStpujjPj6SYvwo5vTzjQSvRdQkA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@dprint/linux-arm64-musl@0.47.2':
+ resolution: {integrity: sha512-zID6wZZqpg2/Q2Us+ERQkbhLwlW3p3xaeEr00MPf49bpydmEjMiPuSjWPkNv+slQSIyIsVovOxF4lbNZjsdtvw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@dprint/linux-x64-glibc@0.47.2':
+ resolution: {integrity: sha512-rB3WXMdINnRd33DItIp7mObS7dzHW90ZzeJSsoKJLPp+Z7wXjjb27UUowfqVI4baa/1pd7sdbX54DPohMtfu/A==}
+ cpu: [x64]
+ os: [linux]
+
+ '@dprint/linux-x64-musl@0.47.2':
+ resolution: {integrity: sha512-E0+TNbzYdTXJ/jCVjUctVxkda/faw++aDQLfyWGcmdMJnbM7NZz+W4fUpDXzMPsjy+zTWxXcPK7/q2DZz2gnbg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@dprint/win32-arm64@0.47.2':
+ resolution: {integrity: sha512-K1EieTCFjfOCmyIhw9zFSduE6qVCNHEveupqZEfbSkVGw5T9MJQ1I9+n7MDb3RIDYEUk0enJ58/w82q8oDKCyA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@dprint/win32-x64@0.47.2':
+ resolution: {integrity: sha512-LhizWr8VrhHvq4ump8HwOERyFmdLiE8C6A42QSntGXzKdaa2nEOq20x/o56ZIiDcesiV+1TmosMKimPcOZHa+Q==}
+ cpu: [x64]
+ os: [win32]
+
+ '@jest/expect-utils@29.7.0':
+ resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/schemas@29.6.3':
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/types@29.6.3':
+ resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@oxlint/darwin-arm64@0.9.10':
+ resolution: {integrity: sha512-eOXKZYq5bnCSgDefgM5bzAg+4Fc//Rc4yjgKN8iDWUARweCaChiQXb6TXX8MfEfs6qayEMy6yVj0pqoFz0B1aw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxlint/darwin-x64@0.9.10':
+ resolution: {integrity: sha512-UeYICDvLUaUOcY+0ugZUEmBMRLP+x8iTgL7TeY6BlpGw2ahbtUOTbyIIRWtr/0O++TnjZ+v8TzhJ9crw6Ij6dg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxlint/linux-arm64-gnu@0.9.10':
+ resolution: {integrity: sha512-0Zn+vqHhrZyufFBfq9WOgiIool0gCR14BLsdS+0Dwd9o+kNxPGA5q7erQFkiC4rpkxtfBHeD3iIKMMt7d29Kyw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxlint/linux-arm64-musl@0.9.10':
+ resolution: {integrity: sha512-tkQcWpYwF42bA/uRaV2iMFePHkBjTTgomOgeEaiw6XOSJX4nBEqGIIboqqLBWT4JnKCf/L+IG3y/e1MflhKByw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxlint/linux-x64-gnu@0.9.10':
+ resolution: {integrity: sha512-JHbkMUnibqaSMBvLHyqTL5cWxcGW+jw+Ppt2baLISpvo34a6fBR+PI7v/A92sEDWe0W1rPhypzCwA8mKpkQ3DA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxlint/linux-x64-musl@0.9.10':
+ resolution: {integrity: sha512-aBBwN7bQzidwHwEXr7BAdVvMTLWstCy5gikerjLnGDeCSXX9r+o6+yUzTOqZvOo66E+XBgOJaVbY8rsL1MLE0g==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxlint/win32-arm64@0.9.10':
+ resolution: {integrity: sha512-LXDnk7vKHT3IY6G1jq0O7+XMhtcHOYuxLGIx4KP+4xS6vKgBY+Bsq4xV3AtmtKlvnXkP5FxHpfLmcEtm5AWysA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxlint/win32-x64@0.9.10':
+ resolution: {integrity: sha512-w5XRAV4bhgwenjjpGYZGglqzG9Wv/sI+cjQWJBQsvfDXsr2w4vOBXzt1j3/Z3EcSqf4KtkCa/IIuAhQyeShUbA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@shikijs/core@1.22.0':
+ resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
+
+ '@shikijs/engine-javascript@1.22.0':
+ resolution: {integrity: sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==}
+
+ '@shikijs/engine-oniguruma@1.22.0':
+ resolution: {integrity: sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==}
+
+ '@shikijs/types@1.22.0':
+ resolution: {integrity: sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==}
+
+ '@shikijs/vscode-textmate@9.3.0':
+ resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==}
+
+ '@sinclair/typebox@0.27.8':
+ resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+
+ '@types/jest@29.5.13':
+ resolution: {integrity: sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==}
+
+ '@types/mdast@4.0.4':
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
+
+ '@types/node@22.7.5':
+ resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==}
+
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
+ '@types/yargs@17.0.33':
+ resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+
+ '@ungap/structured-clone@1.2.0':
+ resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+
+ ansi-styles@3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ ccount@2.0.1:
+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
+ chalk@2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ character-entities-html4@2.1.0:
+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
+
+ character-entities-legacy@3.0.0:
+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+
+ ci-info@3.9.0:
+ resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
+ engines: {node: '>=8'}
+
+ color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ comma-separated-tokens@2.0.3:
+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
+ diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ dprint@0.47.2:
+ resolution: {integrity: sha512-geUcVIIrmLaY+YtuOl4gD7J/QCjsXZa5gUqre9sO6cgH0X/Fa9heBN3l/AWVII6rKPw45ATuCSDWz1pyO+HkPQ==}
+ hasBin: true
+
+ escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
+ expect@29.7.0:
+ resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ hast-util-to-html@9.0.3:
+ resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==}
+
+ hast-util-whitespace@3.0.0:
+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
+ html-void-elements@3.0.0:
+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ jest-diff@29.7.0:
+ resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-get-type@29.6.3:
+ resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-matcher-utils@29.7.0:
+ resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-message-util@29.7.0:
+ resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-util@29.7.0:
+ resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ mdast-util-to-hast@13.2.0:
+ resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
+
+ micromark-util-character@2.1.0:
+ resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
+
+ micromark-util-encode@2.0.0:
+ resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
+
+ micromark-util-sanitize-uri@2.0.0:
+ resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
+
+ micromark-util-symbol@2.0.0:
+ resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
+
+ micromark-util-types@2.0.0:
+ resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ oniguruma-to-js@0.4.3:
+ resolution: {integrity: sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==}
+
+ oxlint@0.9.10:
+ resolution: {integrity: sha512-bKiiFN7Hnoaist/rditTRBXz+GXKYuLd53/NB7Q6zHB/bifELJarSoRLkAUGElIJKl4PSr3lTh1g6zehh+rX0g==}
+ engines: {node: '>=14.*'}
+ hasBin: true
+
+ picocolors@1.1.0:
+ resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ property-information@6.5.0:
+ resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
+
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
+ regex@4.3.3:
+ resolution: {integrity: sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==}
+
+ shiki@1.22.0:
+ resolution: {integrity: sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==}
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
+ space-separated-tokens@2.0.2:
+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
+ stringify-entities@4.0.4:
+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+
+ supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ trim-lines@3.0.1:
+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+
+ typescript@5.6.3:
+ resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@6.19.8:
+ resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
+
+ unist-util-is@6.0.0:
+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+ unist-util-visit-parents@6.0.1:
+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+
+ unist-util-visit@5.0.0:
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+
+ vfile-message@4.0.2:
+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
+
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
+snapshots:
+
+ '@babel/code-frame@7.25.7':
+ dependencies:
+ '@babel/highlight': 7.25.7
+ picocolors: 1.1.0
+
+ '@babel/helper-validator-identifier@7.25.7': {}
+
+ '@babel/highlight@7.25.7':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.25.7
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+ picocolors: 1.1.0
+
+ '@dprint/darwin-arm64@0.47.2':
+ optional: true
+
+ '@dprint/darwin-x64@0.47.2':
+ optional: true
+
+ '@dprint/linux-arm64-glibc@0.47.2':
+ optional: true
+
+ '@dprint/linux-arm64-musl@0.47.2':
+ optional: true
+
+ '@dprint/linux-x64-glibc@0.47.2':
+ optional: true
+
+ '@dprint/linux-x64-musl@0.47.2':
+ optional: true
+
+ '@dprint/win32-arm64@0.47.2':
+ optional: true
+
+ '@dprint/win32-x64@0.47.2':
+ optional: true
+
+ '@jest/expect-utils@29.7.0':
+ dependencies:
+ jest-get-type: 29.6.3
+
+ '@jest/schemas@29.6.3':
+ dependencies:
+ '@sinclair/typebox': 0.27.8
+
+ '@jest/types@29.6.3':
+ dependencies:
+ '@jest/schemas': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 22.7.5
+ '@types/yargs': 17.0.33
+ chalk: 4.1.2
+
+ '@oxlint/darwin-arm64@0.9.10':
+ optional: true
+
+ '@oxlint/darwin-x64@0.9.10':
+ optional: true
+
+ '@oxlint/linux-arm64-gnu@0.9.10':
+ optional: true
+
+ '@oxlint/linux-arm64-musl@0.9.10':
+ optional: true
+
+ '@oxlint/linux-x64-gnu@0.9.10':
+ optional: true
+
+ '@oxlint/linux-x64-musl@0.9.10':
+ optional: true
+
+ '@oxlint/win32-arm64@0.9.10':
+ optional: true
+
+ '@oxlint/win32-x64@0.9.10':
+ optional: true
+
+ '@shikijs/core@1.22.0':
+ dependencies:
+ '@shikijs/engine-javascript': 1.22.0
+ '@shikijs/engine-oniguruma': 1.22.0
+ '@shikijs/types': 1.22.0
+ '@shikijs/vscode-textmate': 9.3.0
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.3
+
+ '@shikijs/engine-javascript@1.22.0':
+ dependencies:
+ '@shikijs/types': 1.22.0
+ '@shikijs/vscode-textmate': 9.3.0
+ oniguruma-to-js: 0.4.3
+
+ '@shikijs/engine-oniguruma@1.22.0':
+ dependencies:
+ '@shikijs/types': 1.22.0
+ '@shikijs/vscode-textmate': 9.3.0
+
+ '@shikijs/types@1.22.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 9.3.0
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@9.3.0': {}
+
+ '@sinclair/typebox@0.27.8': {}
+
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/istanbul-lib-coverage@2.0.6': {}
+
+ '@types/istanbul-lib-report@3.0.3':
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.6
+
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
+
+ '@types/jest@29.5.13':
+ dependencies:
+ expect: 29.7.0
+ pretty-format: 29.7.0
+
+ '@types/mdast@4.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/node@22.7.5':
+ dependencies:
+ undici-types: 6.19.8
+
+ '@types/stack-utils@2.0.3': {}
+
+ '@types/unist@3.0.3': {}
+
+ '@types/yargs-parser@21.0.3': {}
+
+ '@types/yargs@17.0.33':
+ dependencies:
+ '@types/yargs-parser': 21.0.3
+
+ '@ungap/structured-clone@1.2.0': {}
+
+ ansi-styles@3.2.1:
+ dependencies:
+ color-convert: 1.9.3
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ ansi-styles@5.2.0: {}
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ ccount@2.0.1: {}
+
+ chalk@2.4.2:
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ character-entities-html4@2.1.0: {}
+
+ character-entities-legacy@3.0.0: {}
+
+ ci-info@3.9.0: {}
+
+ color-convert@1.9.3:
+ dependencies:
+ color-name: 1.1.3
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.3: {}
+
+ color-name@1.1.4: {}
+
+ comma-separated-tokens@2.0.3: {}
+
+ dequal@2.0.3: {}
+
+ devlop@1.1.0:
+ dependencies:
+ dequal: 2.0.3
+
+ diff-sequences@29.6.3: {}
+
+ dprint@0.47.2:
+ optionalDependencies:
+ '@dprint/darwin-arm64': 0.47.2
+ '@dprint/darwin-x64': 0.47.2
+ '@dprint/linux-arm64-glibc': 0.47.2
+ '@dprint/linux-arm64-musl': 0.47.2
+ '@dprint/linux-x64-glibc': 0.47.2
+ '@dprint/linux-x64-musl': 0.47.2
+ '@dprint/win32-arm64': 0.47.2
+ '@dprint/win32-x64': 0.47.2
+
+ escape-string-regexp@1.0.5: {}
+
+ escape-string-regexp@2.0.0: {}
+
+ expect@29.7.0:
+ dependencies:
+ '@jest/expect-utils': 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ graceful-fs@4.2.11: {}
+
+ has-flag@3.0.0: {}
+
+ has-flag@4.0.0: {}
+
+ hast-util-to-html@9.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 3.0.0
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.0
+ property-information: 6.5.0
+ space-separated-tokens: 2.0.2
+ stringify-entities: 4.0.4
+ zwitch: 2.0.4
+
+ hast-util-whitespace@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ html-void-elements@3.0.0: {}
+
+ is-number@7.0.0: {}
+
+ jest-diff@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ diff-sequences: 29.6.3
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-get-type@29.6.3: {}
+
+ jest-matcher-utils@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-message-util@29.7.0:
+ dependencies:
+ '@babel/code-frame': 7.25.7
+ '@jest/types': 29.6.3
+ '@types/stack-utils': 2.0.3
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+
+ jest-util@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 22.7.5
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.1
+
+ js-tokens@4.0.0: {}
+
+ mdast-util-to-hast@13.2.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.2.0
+ devlop: 1.1.0
+ micromark-util-sanitize-uri: 2.0.0
+ trim-lines: 3.0.1
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.0.0
+ vfile: 6.0.3
+
+ micromark-util-character@2.1.0:
+ dependencies:
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+
+ micromark-util-encode@2.0.0: {}
+
+ micromark-util-sanitize-uri@2.0.0:
+ dependencies:
+ micromark-util-character: 2.1.0
+ micromark-util-encode: 2.0.0
+ micromark-util-symbol: 2.0.0
+
+ micromark-util-symbol@2.0.0: {}
+
+ micromark-util-types@2.0.0: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ oniguruma-to-js@0.4.3:
+ dependencies:
+ regex: 4.3.3
+
+ oxlint@0.9.10:
+ optionalDependencies:
+ '@oxlint/darwin-arm64': 0.9.10
+ '@oxlint/darwin-x64': 0.9.10
+ '@oxlint/linux-arm64-gnu': 0.9.10
+ '@oxlint/linux-arm64-musl': 0.9.10
+ '@oxlint/linux-x64-gnu': 0.9.10
+ '@oxlint/linux-x64-musl': 0.9.10
+ '@oxlint/win32-arm64': 0.9.10
+ '@oxlint/win32-x64': 0.9.10
+
+ picocolors@1.1.0: {}
+
+ picomatch@2.3.1: {}
+
+ pretty-format@29.7.0:
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.3.1
+
+ property-information@6.5.0: {}
+
+ react-is@18.3.1: {}
+
+ regex@4.3.3: {}
+
+ shiki@1.22.0:
+ dependencies:
+ '@shikijs/core': 1.22.0
+ '@shikijs/engine-javascript': 1.22.0
+ '@shikijs/engine-oniguruma': 1.22.0
+ '@shikijs/types': 1.22.0
+ '@shikijs/vscode-textmate': 9.3.0
+ '@types/hast': 3.0.4
+
+ slash@3.0.0: {}
+
+ space-separated-tokens@2.0.2: {}
+
+ stack-utils@2.0.6:
+ dependencies:
+ escape-string-regexp: 2.0.0
+
+ stringify-entities@4.0.4:
+ dependencies:
+ character-entities-html4: 2.1.0
+ character-entities-legacy: 3.0.0
+
+ supports-color@5.5.0:
+ dependencies:
+ has-flag: 3.0.0
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ trim-lines@3.0.1: {}
+
+ typescript@5.6.3: {}
+
+ undici-types@6.19.8: {}
+
+ unist-util-is@6.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+
+ unist-util-visit@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
+
+ vfile-message@4.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
+
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.2
+
+ zwitch@2.0.4: {}
diff --git a/packages/shikicode/src/core.ts b/packages/shikicode/src/core.ts
new file mode 100644
index 0000000..7768ddf
--- /dev/null
+++ b/packages/shikicode/src/core.ts
@@ -0,0 +1,285 @@
+import type { BundledLanguage, BundledTheme, Highlighter } from 'shiki'
+import type { EditorPlugin } from './plugins/index.js'
+
+import { hookScroll } from './scroll.js'
+import { injectStyle } from './style.js'
+
+export interface IndentOptions {
+ /**
+ * The number of spaces a tab is equal to.
+ * This setting is overridden based on the file contents when `detectIndentation` is on.
+ * Defaults to 4.
+ */
+ readonly tabSize: number
+ /**
+ * Insert spaces when pressing `Tab`.
+ * This setting is overridden based on the file contents when `detectIndentation` is on.
+ * Defaults to true.
+ */
+ readonly insertSpaces: boolean
+}
+
+export interface EditorOptions extends IndentOptions {
+ /**
+ * Control the rendering of line numbers.
+ * Defaults to `on`.
+ */
+ readonly lineNumbers: 'on' | 'off'
+ /**
+ * Should the editor be read only.
+ * Defaults to false.
+ */
+ readonly readOnly: boolean
+ readonly language: BundledLanguage | 'plaintext' | 'txt' | 'text' | 'plain' | (string & {})
+ readonly theme: BundledTheme | 'none' | (string & {})
+}
+
+export interface InitOptions extends Pick {
+ readonly value?: string
+}
+
+export interface UpdateOptions extends Partial {}
+
+interface EditorOptionsWithValue extends EditorOptions {
+ readonly value: string
+}
+
+interface ShikiCodeFactory {
+ create(domElement: HTMLElement, highlighter: Highlighter, options: InitOptions): ShikiCode
+ withOptions(options: UpdateOptions): ShikiCodeFactory
+ withPlugins(...plugins: readonly EditorPlugin[]): ShikiCodeFactory
+}
+
+export interface ShikiCode {
+ readonly input: HTMLTextAreaElement
+ readonly output: HTMLDivElement
+ readonly container: HTMLElement
+
+ /**
+ * The highlighter instance used by the editor.
+ */
+ readonly highlighter: Highlighter
+
+ /**
+ * The current value of the editor.
+ * Setting this value will update the editor and force a re-render.
+ */
+ value: string
+ forceRender(value?: string): void
+
+ /**
+ * Make sure the theme or language is loaded before calling this method.
+ */
+ updateOptions(options: UpdateOptions): void
+
+ addPlugin(plugin: EditorPlugin): void
+
+ dispose(): void
+}
+
+const defaultOptions = {
+ lineNumbers: 'on',
+ readOnly: false,
+ tabSize: 4,
+ insertSpaces: true,
+} as const
+
+export function shikiCode(): ShikiCodeFactory {
+ const editor_options = { ...defaultOptions }
+ const plugin_list: EditorPlugin[] = []
+
+ return {
+ create(domElement: HTMLElement, highlighter: Highlighter, options: InitOptions): ShikiCode {
+ return create(
+ domElement,
+ highlighter,
+ { value: '', ...editor_options, ...options },
+ plugin_list,
+ )
+ },
+ withOptions(options: UpdateOptions): ShikiCodeFactory {
+ Object.assign(editor_options, options)
+ return this
+ },
+ withPlugins(...plugins: EditorPlugin[]): ShikiCodeFactory {
+ plugin_list.push(...plugins)
+ return this
+ },
+ }
+}
+
+function create(
+ domElement: HTMLElement,
+ highlighter: Highlighter,
+ editor_options: EditorOptionsWithValue,
+ plugin_list: EditorPlugin[],
+): ShikiCode {
+ const doc = domElement.ownerDocument
+
+ const output = doc.createElement('div')
+ const input = doc.createElement('textarea')
+
+ initIO(input, output)
+ initContainer(domElement)
+
+ domElement.append(input)
+ domElement.append(output)
+
+ updateIO(input, output, editor_options)
+ updateContainer(domElement, highlighter, editor_options.theme)
+
+ if (editor_options.value) {
+ input.value = editor_options.value
+ }
+
+ const forceRender = (value = input.value) => {
+ render(output, highlighter, value, editor_options.language, editor_options.theme)
+ }
+
+ const onInput = () => {
+ forceRender()
+ }
+ input.addEventListener('input', onInput)
+
+ forceRender()
+
+ const cleanup = [
+ () => {
+ input.removeEventListener('input', onInput)
+ },
+ hookScroll(input, output),
+ injectStyle(doc),
+ ]
+
+ const editor: ShikiCode = {
+ input,
+ output,
+ container: domElement,
+
+ get value() {
+ return input.value
+ },
+ set value(code) {
+ input.value = code
+ forceRender(code)
+ },
+
+ get highlighter() {
+ return highlighter
+ },
+
+ forceRender,
+ updateOptions(newOptions) {
+ if (shouldUpdateIO(editor_options, newOptions)) {
+ updateIO(input, output, newOptions)
+ }
+
+ if (shouldUpdateContainer(editor_options, newOptions)) {
+ updateContainer(domElement, highlighter, newOptions.theme!)
+ }
+
+ const should_rerender = shouldRerender(editor_options, newOptions)
+
+ Object.assign(editor_options, newOptions)
+
+ if (should_rerender) {
+ forceRender()
+ }
+ },
+
+ addPlugin(plugin) {
+ cleanup.push(plugin(this, editor_options))
+ },
+ dispose() {
+ cleanup.forEach(fn => fn())
+ input.remove()
+ output.remove()
+ },
+ }
+
+ for (const plugin of plugin_list) {
+ cleanup.push(plugin(editor, editor_options))
+ }
+
+ return editor
+}
+
+function initContainer(container: HTMLElement) {
+ container.style.color = 'var(--fg)'
+ container.style.backgroundColor = 'var(--bg)'
+ container.style.position = 'relative'
+}
+
+function shouldUpdateContainer(config: EditorOptions, newOptions: UpdateOptions) {
+ return newOptions.theme !== void 0 && newOptions.theme !== config.theme
+}
+
+function updateContainer(container: HTMLElement, highlighter: Highlighter, theme_name: string) {
+ const theme = highlighter.getTheme(theme_name)
+ container.style.setProperty('--fg', theme.fg)
+ container.style.setProperty('--bg', theme.bg)
+}
+
+function initIO(input: HTMLTextAreaElement, output: HTMLElement) {
+ input.setAttribute('autocapitalize', 'off')
+ input.setAttribute('autocomplete', 'off')
+ input.setAttribute('autocorrect', 'off')
+ input.setAttribute('spellcheck', 'false')
+
+ input.classList.add('shikicode', 'input')
+ output.classList.add('shikicode', 'output')
+ output.setAttribute('inert', '')
+}
+
+function shouldUpdateIO(config: EditorOptions, newOptions: UpdateOptions) {
+ return (
+ (newOptions.lineNumbers !== void 0 && newOptions.lineNumbers !== config.lineNumbers) ||
+ (newOptions.tabSize !== void 0 && newOptions.tabSize !== config.tabSize) ||
+ (newOptions.readOnly !== void 0 && newOptions.readOnly !== config.readOnly)
+ )
+}
+
+function updateIO(input: HTMLTextAreaElement, output: HTMLElement, options: UpdateOptions) {
+ switch (options.lineNumbers) {
+ case 'on': {
+ input.classList.add('line-numbers')
+ output.classList.add('line-numbers')
+ break
+ }
+ case 'off': {
+ input.classList.remove('line-numbers')
+ output.classList.remove('line-numbers')
+ break
+ }
+ }
+
+ if (options.tabSize !== void 0) {
+ input.style.setProperty('--tab-size', options.tabSize.toString())
+ output.style.setProperty('--tab-size', options.tabSize.toString())
+ }
+
+ if (options.readOnly !== void 0) {
+ input.readOnly = options.readOnly
+ }
+}
+
+function render(
+ output: HTMLElement,
+ highlighter: Highlighter,
+ value: string,
+ lang: string,
+ theme: string,
+) {
+ const { codeToHtml } = highlighter
+ output.innerHTML = codeToHtml(value, {
+ lang,
+ theme,
+ })
+}
+
+function shouldRerender(options: EditorOptions, newOptions: UpdateOptions) {
+ return (
+ (newOptions.theme !== void 0 && newOptions.theme !== options.theme) ||
+ (newOptions.language !== void 0 && newOptions.language !== options.language)
+ )
+}
diff --git a/packages/shikicode/src/index.ts b/packages/shikicode/src/index.ts
new file mode 100644
index 0000000..4edf852
--- /dev/null
+++ b/packages/shikicode/src/index.ts
@@ -0,0 +1 @@
+export * from './core.js'
diff --git a/packages/shikicode/src/plugins/autoload.ts b/packages/shikicode/src/plugins/autoload.ts
new file mode 100644
index 0000000..0207254
--- /dev/null
+++ b/packages/shikicode/src/plugins/autoload.ts
@@ -0,0 +1,43 @@
+import type { BundledLanguage, BundledTheme } from 'shiki'
+import type { IDisposable, ShikiCode } from './index.js'
+
+/**
+ * Automatically load languages and themes when they are not already loaded.
+ *
+ * It's recommended to handle shiki highlighter by yourself if you know all the languages and themes you will use.
+ * This plugin will convert the `updateOptions` method to async method.
+ */
+export function autoload(editor: ShikiCode): IDisposable {
+ const updateOptions = editor.updateOptions
+
+ editor.updateOptions = async newOptions => {
+ const themes = editor.highlighter.getLoadedThemes()
+ const langs = editor.highlighter.getLoadedLanguages()
+
+ const task_list = []
+
+ if (
+ newOptions.theme !== void 0 &&
+ newOptions.theme !== 'none' &&
+ !themes.includes(newOptions.theme)
+ ) {
+ task_list.push(editor.highlighter.loadTheme(newOptions.theme as unknown as BundledTheme))
+ }
+
+ if (
+ newOptions.language !== void 0 &&
+ newOptions.language !== 'text' &&
+ !langs.includes(newOptions.language)
+ ) {
+ task_list.push(editor.highlighter.loadLanguage(newOptions.language as BundledLanguage))
+ }
+
+ await Promise.all(task_list)
+
+ updateOptions(newOptions)
+ }
+
+ return () => {
+ editor.updateOptions = updateOptions
+ }
+}
diff --git a/packages/shikicode/src/plugins/closing_pairs.ts b/packages/shikicode/src/plugins/closing_pairs.ts
new file mode 100644
index 0000000..55ac654
--- /dev/null
+++ b/packages/shikicode/src/plugins/closing_pairs.ts
@@ -0,0 +1,216 @@
+import { setRangeText } from './common.js'
+import type { EditorPlugin } from './index.js'
+
+export type ClosingPair = readonly [open: string, close: string]
+
+export type ClosingPairsRules = {
+ readonly language: string
+ readonly pairs: ClosingPair[]
+}
+
+interface ResolvedClosingPairsRules {
+ auto_closing_pairs_open: Map
+ auto_closing_pairs_close: Map
+ auto_closing_pairs: Set
+}
+
+const should_auto_close = ' \t\n.,;)]}>='
+
+/**
+ * A plugin that automatically inserts closing pairs.
+ */
+export function hookClosingPairs(...pairs_rule_list: readonly ClosingPairsRules[]): EditorPlugin {
+ const rules = new Map()
+
+ const list = default_pairs.concat(pairs_rule_list)
+
+ for (const { language, pairs } of list) {
+ const auto_closing_pairs_open = new Map()
+ const auto_closing_pairs_close = new Map()
+ const auto_closing_pairs = new Set()
+ pairs.forEach(([open, close]) => {
+ auto_closing_pairs_open.set(open, close)
+ auto_closing_pairs_close.set(close, open)
+ auto_closing_pairs.add(open + close)
+ })
+ rules.set(language, {
+ auto_closing_pairs_open,
+ auto_closing_pairs_close,
+ auto_closing_pairs,
+ })
+ }
+
+ return ({ input }, options) => {
+ const onKeydown = (e: KeyboardEvent) => {
+ const config = rules.get(options.language)
+ if (!config) {
+ return
+ }
+
+ const { selectionStart, selectionEnd } = input
+
+ if (isBackspace(e)) {
+ if (selectionStart !== selectionEnd) {
+ return
+ }
+
+ const slice = input.value.slice(selectionStart - 1, selectionStart + 1)
+ if (config.auto_closing_pairs.has(slice)) {
+ input.setSelectionRange(selectionStart - 1, selectionStart + 1)
+ }
+ return
+ }
+
+ if (
+ !config.auto_closing_pairs_open.has(e.key) &&
+ !config.auto_closing_pairs_close.has(e.key)
+ ) {
+ return
+ }
+
+ // add pairs surrounding the selection
+ if (selectionStart !== selectionEnd && config.auto_closing_pairs_open.has(e.key)) {
+ e.preventDefault()
+ const text = input.value.slice(selectionStart, selectionEnd)
+ const left = e.key
+ const right = config.auto_closing_pairs_open.get(left)!
+ setRangeText(input, left + text + right, selectionStart, selectionEnd, 'select')
+ input.dispatchEvent(new Event('input'))
+ input.dispatchEvent(new Event('change'))
+ input.setSelectionRange(selectionStart + 1, selectionEnd + 1)
+ return
+ }
+
+ // add pairs at the cursor
+ if (
+ selectionStart === selectionEnd &&
+ config.auto_closing_pairs_open.has(e.key) &&
+ should_auto_close.includes(input.value[selectionStart] || '')
+ ) {
+ e.preventDefault()
+ const left = e.key
+ const right = config.auto_closing_pairs_open.get(left)!
+ setRangeText(input, left + right, selectionStart, selectionEnd, 'start')
+ input.dispatchEvent(new Event('input'))
+ input.dispatchEvent(new Event('change'))
+ input.setSelectionRange(selectionStart + 1, selectionEnd + 1)
+ return
+ }
+
+ // skip right pairs
+ if (
+ selectionStart === selectionEnd &&
+ selectionStart > 0 &&
+ config.auto_closing_pairs.has(input.value.slice(selectionStart - 1, selectionStart + 1))
+ ) {
+ input.setSelectionRange(selectionStart, selectionEnd + 1)
+ }
+ }
+
+ input.addEventListener('keydown', onKeydown)
+
+ return () => {
+ input.removeEventListener('keydown', onKeydown)
+ }
+ }
+}
+
+function isBackspace(e: KeyboardEvent) {
+ return e.key === 'Backspace' && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey
+}
+
+export const pairs_parentheses = ['(', ')'] satisfies ClosingPair
+export const pairs_brackets = ['[', ']'] satisfies ClosingPair
+export const pairs_braces = ['{', '}'] satisfies ClosingPair
+export const pairs_angle = ['<', '>'] satisfies ClosingPair
+export const pairs_quotes = ['"', '"'] satisfies ClosingPair
+export const pairs_single_quotes = ["'", "'"] satisfies ClosingPair
+export const pairs_backticks = ['`', '`'] satisfies ClosingPair
+
+const c_lang_pairs: ClosingPair[] = [
+ pairs_parentheses,
+ pairs_brackets,
+ pairs_braces,
+ pairs_quotes,
+ pairs_single_quotes,
+]
+
+const c_lang_pairs_with_backticks: ClosingPair[] = [
+ pairs_parentheses,
+ pairs_brackets,
+ pairs_braces,
+ pairs_quotes,
+ pairs_single_quotes,
+ pairs_backticks,
+]
+
+export const default_pairs: readonly ClosingPairsRules[] = [
+ {
+ language: 'c',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'cpp',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'css',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'csharp',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'dart',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'go',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'java',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'json',
+ pairs: [pairs_brackets, pairs_braces, pairs_quotes],
+ },
+ {
+ language: 'javascript',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'typescript',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'jsx',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'tsx',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'php',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'python',
+ pairs: c_lang_pairs,
+ },
+ {
+ language: 'rust',
+ pairs: [pairs_parentheses, pairs_brackets, pairs_braces, pairs_quotes],
+ },
+ {
+ language: 'ruby',
+ pairs: c_lang_pairs_with_backticks,
+ },
+ {
+ language: 'sql',
+ pairs: c_lang_pairs_with_backticks,
+ },
+]
diff --git a/packages/shikicode/src/plugins/common.ts b/packages/shikicode/src/plugins/common.ts
new file mode 100644
index 0000000..43dcf2b
--- /dev/null
+++ b/packages/shikicode/src/plugins/common.ts
@@ -0,0 +1,131 @@
+export function floorTab(width: number, tabSize: number): number {
+ switch (tabSize) {
+ case 2:
+ return width & ~1
+ case 4:
+ return width & ~3
+ case 8:
+ return width & ~7
+ }
+ return Math.floor(width / tabSize) * tabSize
+}
+
+export function ceilTab(width: number, tabSize: number): number {
+ switch (tabSize) {
+ case 2:
+ return (width + 1) & ~1
+ case 4:
+ return (width + 3) & ~3
+ case 8:
+ return (width + 7) & ~7
+ }
+ return Math.ceil(width / tabSize) * tabSize
+}
+
+/**
+ * A offset in a position is the gap between two adjacent characters. The methods here
+ * work with a concept called "visible width". A visible width is a very rough approximation
+ * of the horizontal screen position of a offset. For example, using a tab size of 4:
+ * ```txt
+ * |||T|ext
+ * | | | \---- offset = 3, visible width = 9
+ * | | \------ offset = 2, visible width = 8
+ * | \------------ offset = 1, visible width = 4
+ * \------------------ offset = 0, visible width = 0
+ * ```
+ *
+ * **ATTENTION**: This offset is 0-based
+ *
+ * **NOTE**: Visual columns do not work well for RTL text or variable-width fonts or characters.
+ *
+ */
+export function visibleWidthFromLeft(
+ content: string,
+ offset: number,
+ tabSize: number,
+ left?: number,
+): [width: number, span: number] {
+ if (left === void 0) {
+ left = offset
+ while (left > 0 && content[left - 1] !== '\n') {
+ left--
+ }
+ }
+ let width = 0
+ for (let i = left; i < offset; i++) {
+ width++
+ if (content[i] === '\t') {
+ width = ceilTab(width, tabSize)
+ }
+ }
+ return [width, offset - left]
+}
+
+export function visibleWidthLeadingSpace(
+ line: string,
+ tabSize: number,
+): [width: number, span: number] {
+ let width = 0
+ let i = 0
+ while (i < line.length) {
+ if (line[i] === ' ') {
+ width++
+ } else if (line[i] === '\t') {
+ width = ceilTab(width + 1, tabSize)
+ } else {
+ break
+ }
+ i++
+ }
+ return [width, i]
+}
+
+/**
+ * Instead of using the `setRangeText` method,
+ * prefer to use the `execCommand` method to preserve the undo stack.
+ */
+export function setRangeText(
+ input: HTMLTextAreaElement,
+ replacement: string,
+ start: number,
+ end: number,
+ selectionMode?: SelectionMode,
+) {
+ input.setSelectionRange(start, end)
+ input.ownerDocument.execCommand('insertText', false, replacement)
+ switch (selectionMode) {
+ case 'start': {
+ input.setSelectionRange(start, start)
+ break
+ }
+ case 'end': {
+ input.setSelectionRange(start + replacement.length, start + replacement.length)
+ break
+ }
+
+ case 'select':
+ default: {
+ input.setSelectionRange(start, start + replacement.length)
+ break
+ }
+ }
+}
+
+export interface InputState {
+ /**
+ * The whole text content.
+ */
+ value: string
+ /**
+ * The start of the selection.
+ */
+ selectionStart: number
+ /**
+ * The end of the selection.
+ */
+ selectionEnd: number
+ /**
+ * The direction of the selection.
+ */
+ selectionDirection?: 'forward' | 'backward' | 'none'
+}
diff --git a/packages/shikicode/src/plugins/index.ts b/packages/shikicode/src/plugins/index.ts
new file mode 100644
index 0000000..ccaf05a
--- /dev/null
+++ b/packages/shikicode/src/plugins/index.ts
@@ -0,0 +1,12 @@
+import type { EditorOptions, ShikiCode } from '../core.js'
+
+export type IDisposable = () => void
+export type { EditorOptions, IndentOptions, ShikiCode } from '../core.js'
+
+export type EditorPlugin = {
+ (editor: ShikiCode, options: EditorOptions): IDisposable
+}
+
+export * from './autoload.js'
+export * from './closing_pairs.js'
+export * from './tab.js'
diff --git a/packages/shikicode/src/plugins/tab.ts b/packages/shikicode/src/plugins/tab.ts
new file mode 100644
index 0000000..99910c8
--- /dev/null
+++ b/packages/shikicode/src/plugins/tab.ts
@@ -0,0 +1,445 @@
+import {
+ ceilTab,
+ floorTab,
+ setRangeText,
+ visibleWidthFromLeft,
+ visibleWidthLeadingSpace,
+ type InputState,
+} from './common.js'
+import type { IDisposable, IndentOptions, ShikiCode } from './index.js'
+
+export interface PatchAction {
+ value: string
+ start: number
+ end: number
+ mode?: SelectionMode
+}
+
+export interface SelectAction {
+ start: number
+ end: number
+ direction?: 'forward' | 'backward' | 'none'
+}
+
+export interface Action {
+ /**
+ * The patched text content.
+ */
+ patch?: PatchAction
+ /**
+ * The new selection.
+ */
+ select?: SelectAction
+}
+
+const empty_action: Action = {}
+
+export function indentText(input: InputState, options: IndentOptions): Action {
+ if (
+ input.selectionStart !== input.selectionEnd &&
+ (bothEndsSelected(input.value, input.selectionStart, input.selectionEnd) ||
+ input.value.slice(input.selectionStart, input.selectionEnd).includes('\n'))
+ ) {
+ return blockIndentText(input, options)
+ }
+
+ return simpleIndentText(input, options)
+}
+
+function simpleIndentText(input: InputState, options: IndentOptions): Action {
+ const { value, selectionStart, selectionEnd } = input
+ const { tabSize, insertSpaces } = options
+
+ if (!insertSpaces) {
+ return {
+ patch: {
+ value: '\t',
+ start: selectionStart,
+ end: selectionEnd,
+ mode: 'end',
+ },
+ }
+ }
+
+ const [width_from_left] = visibleWidthFromLeft(value, selectionStart, tabSize)
+ const indent = ' '.repeat(ceilTab(width_from_left + 1, tabSize) - width_from_left)
+ return {
+ patch: {
+ value: indent,
+ start: selectionStart,
+ end: selectionEnd,
+ mode: 'end',
+ },
+ }
+}
+
+function blockIndentText(input: InputState, options: IndentOptions): Action {
+ const { tabSize, insertSpaces } = options
+ const { value, selectionStart, selectionEnd, selectionDirection } = input
+
+ const block_start = getLineStart(value, selectionStart)
+ const block_end = getBlockLineEnd(value, selectionEnd)
+
+ const block = value.slice(block_start, block_end)
+
+ const replacement = block.replaceAll(/^[ \t]*/gm, (leading, offset, str) => {
+ if (str[offset] === '\n' || str[offset] === '\r' || offset === block_end) return leading
+
+ let [tab_width] = visibleWidthFromLeft(leading, leading.length, tabSize, 0)
+ tab_width = ceilTab(tab_width + 1, tabSize)
+
+ if (insertSpaces) {
+ return ' '.repeat(tab_width)
+ }
+ return '\t'.repeat(tab_width / tabSize)
+ })
+
+ const patch = {
+ value: replacement,
+ start: block_start,
+ end: block_end,
+ mode: 'end',
+ } satisfies PatchAction
+
+ // restore selection
+ // By default, the selection is anchored at both ends.
+ const select = {
+ start: selectionStart,
+ end: selectionEnd + replacement.length - block.length,
+ direction: selectionDirection,
+ } satisfies SelectAction
+
+ if (selectionStart !== block_start) {
+ const line_start = block_start
+ const cursor_offset = selectionStart - line_start
+ const line = value.slice(line_start, selectionStart)
+ const [, old_leading_offset] = visibleWidthLeadingSpace(line, tabSize)
+ const [, max_leading_offset] = visibleWidthLeadingSpace(replacement, tabSize)
+
+ if (cursor_offset > old_leading_offset) {
+ // |||T|ext
+ // ^
+ select.start += max_leading_offset - old_leading_offset
+ } else if (cursor_offset > max_leading_offset) {
+ // | | |Text (old)
+ // ^
+ // ||||Text (new)
+ // ^
+ select.start = line_start + max_leading_offset
+ }
+ }
+
+ if (selectionEnd < block_end) {
+ const line_start = getLineStart(value, selectionEnd)
+ const cursor_offset = selectionEnd - line_start
+ const line = value.slice(line_start, selectionEnd)
+ const [, old_leading_offset] = visibleWidthLeadingSpace(line, tabSize)
+
+ const new_bottom_line_offset = getLineStart(replacement, replacement.length)
+ const new_bottom_line = replacement.slice(new_bottom_line_offset)
+ const [, max_leading_offset] = visibleWidthLeadingSpace(new_bottom_line, tabSize)
+
+ if (cursor_offset <= old_leading_offset) {
+ select.end = block_start + new_bottom_line_offset + cursor_offset
+
+ if (cursor_offset > max_leading_offset) {
+ select.end += max_leading_offset - old_leading_offset
+ }
+ }
+ }
+
+ return {
+ patch,
+ select,
+ } satisfies Action
+}
+
+export function outdentText(input: InputState, options: IndentOptions): Action {
+ const { tabSize, insertSpaces } = options
+ const { value, selectionStart, selectionEnd, selectionDirection } = input
+
+ const block_start = getLineStart(value, selectionStart)
+ const block_end = getBlockLineEnd(value, Math.max(selectionEnd, selectionStart + 1))
+
+ const block = value.slice(block_start, block_end)
+
+ const replacement = block.replaceAll(/^[ \t]*/gm, leading => {
+ let [tab_width] = visibleWidthFromLeft(leading, leading.length, tabSize, 0)
+ tab_width = floorTab(tab_width - 1, tabSize)
+
+ if (tab_width <= 0) return ''
+
+ if (insertSpaces) {
+ return ' '.repeat(tab_width)
+ }
+ return '\t'.repeat(tab_width / tabSize)
+ })
+ if (replacement === block) return empty_action
+
+ const patch = {
+ value: replacement,
+ start: block_start,
+ end: block_end,
+ mode: 'end',
+ } satisfies PatchAction
+
+ // restore selection
+ // By default, the selection is anchored at both ends.
+ const select = {
+ start: selectionStart,
+ end: selectionEnd + replacement.length - block.length,
+ direction: selectionDirection,
+ } satisfies SelectAction
+
+ if (selectionStart !== block_start) {
+ const line_start = block_start
+ const cursor_offset = selectionStart - line_start
+ const line = value.slice(line_start, selectionStart)
+ const [, old_leading_offset] = visibleWidthLeadingSpace(line, tabSize)
+ const [, max_leading_offset] = visibleWidthLeadingSpace(replacement, tabSize)
+
+ if (cursor_offset > old_leading_offset) {
+ // |||T|ext
+ // ^
+ select.start += max_leading_offset - old_leading_offset
+ } else if (cursor_offset > max_leading_offset) {
+ // | | |Text (old)
+ // ^
+ // ||||Text (new)
+ // ^
+ select.start = line_start + max_leading_offset
+ }
+ }
+
+ if (selectionEnd < block_end) {
+ const line_start = getLineStart(value, selectionEnd)
+ const cursor_offset = selectionEnd - line_start
+ const line = value.slice(line_start, selectionEnd)
+ const [, old_leading_offset] = visibleWidthLeadingSpace(line, tabSize)
+
+ const new_bottom_line_offset = getLineStart(replacement, replacement.length)
+ const new_bottom_line = replacement.slice(new_bottom_line_offset)
+ const [, max_leading_offset] = visibleWidthLeadingSpace(new_bottom_line, tabSize)
+
+ if (cursor_offset <= old_leading_offset) {
+ select.end = block_start + new_bottom_line_offset + cursor_offset
+
+ if (cursor_offset > max_leading_offset) {
+ select.end += max_leading_offset - old_leading_offset
+ }
+ }
+ }
+
+ return {
+ patch,
+ select,
+ } satisfies Action
+}
+
+function enter(input: InputState, options: IndentOptions): Action {
+ if (input.selectionStart !== input.selectionEnd) {
+ return empty_action
+ }
+ const { value, selectionStart } = input
+ const line_start = getLineStart(value, selectionStart)
+ if (line_start === selectionStart) {
+ return empty_action
+ }
+
+ const line = value.slice(line_start, selectionStart)
+ let [leading_space] = visibleWidthLeadingSpace(line, options.tabSize)
+ leading_space = floorTab(leading_space, options.tabSize)
+ let indent_space = leading_space
+
+ switch (value[selectionStart - 1]) {
+ case '(':
+ case '[':
+ case '{': {
+ indent_space += options.tabSize
+ }
+ }
+
+ let replacement = '\n'
+ if (options.insertSpaces) {
+ replacement += ' '.repeat(indent_space)
+ } else {
+ replacement += '\t'.repeat(indent_space / options.tabSize)
+ }
+
+ let select: SelectAction | undefined
+
+ switch (value.slice(selectionStart - 1, selectionStart + 1)) {
+ case '{}':
+ case '[]':
+ case '()': {
+ select = {
+ start: selectionStart + replacement.length,
+ end: selectionStart + replacement.length,
+ direction: 'none',
+ }
+
+ if (options.insertSpaces) {
+ replacement += '\n' + ' '.repeat(leading_space)
+ } else {
+ replacement += '\n' + '\t'.repeat(leading_space / options.tabSize)
+ }
+ }
+ }
+
+ return {
+ patch: {
+ value: replacement,
+ start: selectionStart,
+ end: selectionStart,
+ mode: 'end',
+ },
+ select,
+ }
+}
+
+function backspace(input: InputState, options: IndentOptions): Action {
+ const { value, selectionStart, selectionEnd } = input
+ if (selectionStart !== selectionEnd) {
+ return empty_action
+ }
+
+ if (value[selectionStart - 1] !== ' ') {
+ return empty_action
+ }
+
+ const line_start = getLineStart(value, selectionStart)
+ let width = 0
+ let last_tab_stop = line_start
+ for (let i = line_start; i < selectionStart - 1; i++) {
+ switch (value[i]) {
+ case ' ': {
+ width++
+ if (width % options.tabSize === 0) {
+ last_tab_stop = i
+ }
+ break
+ }
+ case '\t': {
+ last_tab_stop = i
+ width = ceilTab(width + 1, options.tabSize)
+ break
+ }
+ default: {
+ return empty_action
+ }
+ }
+ }
+
+ return {
+ select: {
+ start: last_tab_stop,
+ end: selectionStart,
+ direction: 'none',
+ },
+ }
+}
+
+function bothEndsSelected(text: string, start: number, end: number): boolean {
+ const is_start = start === 0 || text[start - 1] === '\n'
+ const is_end = end === text.length || text[end] === '\n' || text[end] === '\r'
+ return start !== end && is_start && is_end
+}
+
+function getLineStart(text: string, index: number): number {
+ while (index > 0 && text[index - 1] !== '\n') {
+ index--
+ }
+ return index
+}
+
+/**
+ * Get the end index of the line.
+ * - all suffix "\n" and "\r" are ignored.
+ * - text[end] === "\n" || text[end] === "\r" || end === text.length
+ * - text.slice(start, end) should not include "\n" at the end.
+ */
+function getBlockLineEnd(text: string, index: number): number {
+ if (text[index - 1] === '\n') {
+ index--
+ }
+
+ while (index > 0 && (index === text.length || text[index] === '\n' || text[index] === '\r')) {
+ index--
+ }
+
+ return getLineEnd(text, index)
+}
+
+function getLineEnd(text: string, index: number): number {
+ while (index < text.length && text[index] !== '\n' && text[index] !== '\r') {
+ index++
+ }
+
+ return index
+}
+
+/**
+ * A plugin that automatically inserts or removes indentation.
+ */
+export function hookTab({ input }: ShikiCode, options: IndentOptions): IDisposable {
+ const onKeydown = (e: KeyboardEvent) => {
+ switch (e.key) {
+ case 'Tab': {
+ e.preventDefault()
+
+ const action = e.shiftKey ? outdentText : indentText
+ const { patch, select } = action(e.target as HTMLTextAreaElement, options)
+ if (patch) {
+ setRangeText(input, patch.value, patch.start, patch.end, patch.mode)
+ input.dispatchEvent(new Event('input'))
+ input.dispatchEvent(new Event('change'))
+ }
+ if (select) {
+ input.setSelectionRange(select.start, select.end, select.direction)
+ input.dispatchEvent(new Event('selectionchange'))
+ }
+ break
+ }
+
+ case 'Enter': {
+ const { patch, select } = enter(e.target as HTMLTextAreaElement, options)
+ if (patch || select) {
+ e.preventDefault()
+ }
+ if (patch) {
+ setRangeText(input, patch.value, patch.start, patch.end, patch.mode)
+ input.dispatchEvent(new Event('input'))
+ input.dispatchEvent(new Event('change'))
+ }
+ if (select) {
+ input.setSelectionRange(select.start, select.end, select.direction)
+ input.dispatchEvent(new Event('selectionchange'))
+ }
+ break
+ }
+
+ case 'Backspace': {
+ const { select } = backspace(e.target as HTMLTextAreaElement, options)
+ if (select) {
+ input.setSelectionRange(select.start, select.end, select.direction)
+ input.dispatchEvent(new Event('selectionchange'))
+ }
+
+ break
+ }
+
+ case 'Escape': {
+ input.blur()
+ break
+ }
+
+ default:
+ return
+ }
+ }
+
+ input.addEventListener('keydown', onKeydown)
+ return () => {
+ input.removeEventListener('keydown', onKeydown)
+ }
+}
diff --git a/packages/shikicode/src/scroll.ts b/packages/shikicode/src/scroll.ts
new file mode 100644
index 0000000..cd63efd
--- /dev/null
+++ b/packages/shikicode/src/scroll.ts
@@ -0,0 +1,11 @@
+export function hookScroll(input: HTMLElement, output: HTMLElement) {
+ const onScroll = () => {
+ output.scrollTo(input.scrollLeft, input.scrollTop)
+ }
+
+ input.addEventListener('scroll', onScroll)
+
+ return () => {
+ input.removeEventListener('scroll', onScroll)
+ }
+}
diff --git a/packages/shikicode/src/style.ts b/packages/shikicode/src/style.ts
new file mode 100644
index 0000000..512e811
--- /dev/null
+++ b/packages/shikicode/src/style.ts
@@ -0,0 +1,113 @@
+const style = `.shikicode.input, .shikicode.output {
+ position: absolute;
+ margin: 0;
+ inset: 0;
+ border: 0;
+ padding: 0;
+ font-size: inherit;
+ line-height: inherit;
+ tab-size: var(--tab-size);
+}
+
+.shikicode.input, .shikicode.output, .shikicode.output code {
+ font-family: var(--font-family, monospace);
+}
+
+.shikicode.input {
+ box-sizing: border-box;
+ outline: none;
+ background-color: transparent;
+ padding-left: 2em;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ resize: none;
+ color: transparent;
+ caret-color: var(--fg, black);
+ white-space: pre;
+}
+
+.shikicode.output {
+ counter-reset: shiki-line 0;
+ overflow: hidden;
+ pointer-events: none;
+}
+
+.shikicode.output > pre {
+ display: contents;
+}
+
+.shikicode.output .line {
+ counter-increment: shiki-line 1;
+}
+
+.shikicode.output .line::before {
+ display: inline-block;
+ position: sticky;
+ left: 0;
+ box-sizing: border-box;
+ background-color: var(--bg);
+ width: 2em;
+ content: counter(shiki-line);
+ color: var(--bg);
+ text-align: right;
+}
+
+.shikicode.output.line-numbers .line::before {
+ padding-right: 2em;
+ width: 5em;
+ color: var(--fg);
+}
+
+.shikicode.input.line-numbers {
+ padding-left: 5em;
+}
+`
+
+function noop() {}
+
+export function injectStyle(doc: Document) {
+ const hash = `shikicode-${djb2(style).toString(36)}`
+ if (doc.getElementById(hash)) return noop
+ const element = doc.createElement('style')
+ element.id = hash
+ element.append(doc.createTextNode(''))
+ doc.head.append(element)
+
+ try {
+ const sheet = getSheet(element, doc)
+ sheet.insertRule(style)
+ } catch (e) {
+ element.append(doc.createTextNode(style))
+ }
+ return () => {
+ element.remove()
+ }
+}
+
+function djb2(s: string, hash = 5381) {
+ let i = s.length
+
+ while (i) {
+ hash = (hash * 33) ^ s.charCodeAt(--i)
+ }
+
+ return hash
+}
+
+function getSheet(tag: HTMLStyleElement, doc: Document): CSSStyleSheet {
+ if (tag.sheet) {
+ return tag.sheet
+ }
+
+ // Avoid Firefox quirk where the style element might not have a sheet property
+ const { styleSheets } = doc
+ for (let i = 0, l = styleSheets.length; i < l; i++) {
+ const sheet = styleSheets[i]
+ if (sheet.ownerNode === tag) {
+ return sheet
+ }
+ }
+
+ throw new Error('Could not find CSSStyleSheet object')
+}
diff --git a/packages/shikicode/test/__snapshots__/tab.test.ts.snap b/packages/shikicode/test/__snapshots__/tab.test.ts.snap
new file mode 100644
index 0000000..2e41d0a
--- /dev/null
+++ b/packages/shikicode/test/__snapshots__/tab.test.ts.snap
@@ -0,0 +1,745 @@
+// Bun Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Editor Commands - ShiftCommand basic usage 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 0,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 4,
+ "selectionStart": 4,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand basic usage 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 2,
+ "selectionStart": 2,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 4,
+ "selectionStart": 4,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand basic usage 3`] = `
+{
+ "config": {
+ "insertSpaces": false,
+ "tabSize": 2,
+ },
+ "input": {
+ "selectionEnd": 33,
+ "selectionStart": 33,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 34,
+ "selectionStart": 34,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand single line 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 13,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 17,
+ "selectionStart": 0,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand single line 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 14,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 18,
+ "selectionStart": 0,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand single line 3`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 31,
+ "selectionStart": 14,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 41,
+ "selectionStart": 14,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 14,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 18,
+ "selectionStart": 7,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 18,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 32,
+ "selectionStart": 13,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 3`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 31,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 45,
+ "selectionStart": 13,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 4`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 15,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 19,
+ "selectionStart": 7,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 5`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 33,
+ "selectionStart": 15,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 43,
+ "selectionStart": 15,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - ShiftCommand multiple lines 6`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 50,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 72,
+ "selectionStart": 0,
+ "value": [
+ " My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ " 123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand basic usage 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 0,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 0,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand basic usage 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 2,
+ "selectionStart": 2,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 2,
+ "selectionStart": 2,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand basic usage 3`] = `
+{
+ "config": {
+ "insertSpaces": false,
+ "tabSize": 2,
+ },
+ "input": {
+ "selectionEnd": 33,
+ "selectionStart": 33,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 32,
+ "selectionStart": 32,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand single line 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 13,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 13,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand single line 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 14,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 14,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand single line 3`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 31,
+ "selectionStart": 14,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 33,
+ "selectionStart": 14,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 1`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 14,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 14,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 2`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 18,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 20,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 3`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 31,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 33,
+ "selectionStart": 9,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 4`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 15,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 15,
+ "selectionStart": 3,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 5`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 33,
+ "selectionStart": 15,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 33,
+ "selectionStart": 15,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ "Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
+
+exports[`Editor Commands - UnShiftCommand multiple lines 6`] = `
+{
+ "config": {
+ "insertSpaces": true,
+ "tabSize": 4,
+ },
+ "input": {
+ "selectionEnd": 50,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ " Third Line",
+ "",
+ "123",
+ ],
+ },
+ "output": {
+ "selectionEnd": 48,
+ "selectionStart": 0,
+ "value": [
+ "My First Line",
+ " My Second Line",
+ "Third Line",
+ "",
+ "123",
+ ],
+ },
+}
+`;
diff --git a/packages/shikicode/test/tab.test.ts b/packages/shikicode/test/tab.test.ts
new file mode 100644
index 0000000..bfca6c9
--- /dev/null
+++ b/packages/shikicode/test/tab.test.ts
@@ -0,0 +1,239 @@
+import { Action, PatchAction, SelectAction, State, indentText, outdentText } from '../src/plugins'
+
+interface TabConfig {
+ tabSize: number
+ insertSpaces: boolean
+}
+
+const space_4 = {
+ tabSize: 4,
+ insertSpaces: true,
+}
+
+const tab_4 = {
+ tabSize: 4,
+ insertSpaces: false,
+}
+
+const space_2 = {
+ tabSize: 2,
+ insertSpaces: true,
+}
+
+const tab_2 = {
+ tabSize: 2,
+ insertSpaces: false,
+}
+
+function setRangeText(state: State, patch: PatchAction): State {
+ const [start, mid, end] = [
+ state.value.slice(0, patch.start),
+ patch.value,
+ state.value.slice(patch.end),
+ ]
+
+ const new_state = { ...state }
+
+ switch (patch.mode) {
+ case 'start':
+ new_state.selectionStart = new_state.selectionEnd = start.length
+ break
+ case 'end':
+ new_state.selectionStart = new_state.selectionEnd = start.length + mid.length
+ break
+ case 'select':
+ default:
+ // Unfortunately, we cannot mimic the behavior of `preserve`.
+ new_state.selectionStart = start.length
+ new_state.selectionEnd = start.length + mid.length
+ break
+ }
+
+ new_state.value = start + mid + end
+ return new_state
+}
+
+function setSelectionRange(state: State, select: SelectAction): State {
+ return { value: state.value, selectionStart: select.start, selectionEnd: select.end }
+}
+
+function applyEdit(state: State, action?: Action): State {
+ if (!action) {
+ return state
+ }
+ if (action.patch) {
+ state = setRangeText(state, action.patch)
+ }
+ if (action.select) {
+ state = setSelectionRange(state, action.select)
+ }
+ return state
+}
+
+const simpleText = 'My First Line\n\t\tMy Second Line\n Third Line\n\n123'
+
+describe('Editor Commands - ShiftCommand', () => {
+ test('basic usage', () => {
+ testShiftCommand(simpleText, 0, 0, space_4)
+ })
+
+ test('basic usage', () => {
+ testShiftCommand(simpleText, 2, 2, space_4)
+ })
+
+ test('basic usage', () => {
+ const select = simpleText.indexOf('Third Line') - 2
+ testShiftCommand(simpleText, select, select, tab_2)
+ })
+
+ test('single line', () => {
+ const select = 'My First Line'
+ testShiftCommand(simpleText, 0, select.length, space_4)
+ })
+
+ test('single line', () => {
+ const select = 'My First Line\n'
+ testShiftCommand(simpleText, 0, select.length, space_4)
+ })
+
+ test('single line', () => {
+ const select = '\t\tMy Second Line\n'
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'First Line\n'
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'Line\n\t\tMy'
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'Line\n\t\tMy Second Line\n'
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'First Line\n\t'
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = '\tMy Second Line\n '
+ const start = simpleText.indexOf(select)
+ testShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ testShiftCommand(simpleText, 0, simpleText.length, space_4)
+ })
+})
+
+describe('Editor Commands - UnShiftCommand', () => {
+ test('basic usage', () => {
+ testUnShiftCommand(simpleText, 0, 0, space_4)
+ })
+
+ test('basic usage', () => {
+ testUnShiftCommand(simpleText, 2, 2, space_4)
+ })
+
+ test('basic usage', () => {
+ const select = simpleText.indexOf('Third Line') - 2
+ testUnShiftCommand(simpleText, select, select, tab_2)
+ })
+
+ test('single line', () => {
+ const select = 'My First Line'
+ testUnShiftCommand(simpleText, 0, select.length, space_4)
+ })
+
+ test('single line', () => {
+ const select = 'My First Line\n'
+ testUnShiftCommand(simpleText, 0, select.length, space_4)
+ })
+
+ test('single line', () => {
+ const select = '\t\tMy Second Line\n'
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'First Line\n'
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'Line\n\t\tMy'
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'Line\n\t\tMy Second Line\n'
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = 'First Line\n\t'
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ const select = '\tMy Second Line\n '
+ const start = simpleText.indexOf(select)
+ testUnShiftCommand(simpleText, start, start + select.length, space_4)
+ })
+
+ test('multiple lines', () => {
+ testUnShiftCommand(simpleText, 0, simpleText.length, space_4)
+ })
+})
+
+function testShiftCommand(
+ value: string,
+ selectionStart: number,
+ selectionEnd: number,
+ config: TabConfig,
+): void {
+ const state = { value, selectionStart, selectionEnd }
+
+ const action = indentText(state, config)
+ const result = applyEdit(state, action)
+
+ expect({ config, input: handleState(state), output: handleState(result) }).toMatchSnapshot()
+}
+
+function testUnShiftCommand(
+ value: string,
+ selectionStart: number,
+ selectionEnd: number,
+ config: TabConfig,
+): void {
+ const state = { value, selectionStart, selectionEnd }
+
+ const action = outdentText(state, config)
+ const result = applyEdit(state, action)
+
+ expect({ config, input: handleState(state), output: handleState(result) }).toMatchSnapshot()
+}
+
+function handleState(state: State) {
+ const lines = state.value.split(/\r\n|\n/)
+ return {
+ ...state,
+ value: lines,
+ }
+}
diff --git a/packages/shikicode/test/test.html b/packages/shikicode/test/test.html
new file mode 100644
index 0000000..b8d44f5
--- /dev/null
+++ b/packages/shikicode/test/test.html
@@ -0,0 +1,75 @@
+
+
+
+
+
diff --git a/packages/shikicode/tsconfig.json b/packages/shikicode/tsconfig.json
new file mode 100644
index 0000000..27074b9
--- /dev/null
+++ b/packages/shikicode/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "skipLibCheck": true,
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "forceConsistentCasingInFileNames": true,
+ "rootDir": "./src",
+ "outDir": "./lib",
+ "sourceMap": true,
+ "declaration": true,
+ "declarationMap": true
+ },
+ "include": ["src"]
+}
diff --git a/playgrounds/app/package.json b/playgrounds/app/package.json
index 409d322..3cb8087 100644
--- a/playgrounds/app/package.json
+++ b/playgrounds/app/package.json
@@ -32,11 +32,13 @@
"ohash": "^1.1.4",
"postcss": "^8.4.38",
"remotion": "^4.0.221",
- "shiki": "^1.21.0",
+ "shiki": "^1.22.0",
"shiki-magic-move": "workspace:*",
+ "shikicode": "workspace:*",
"solid-color": "^0.0.4",
"solid-icons": "^1.1.0",
"solid-js": "^1.9.1",
+ "solid-shiki-textarea": "^0.1.6",
"solid-sonner": "^0.2.8",
"tailwind-merge": "^2.5.3",
"tailwindcss": "^3.4.3",
diff --git a/playgrounds/app/src/components/Editor.tsx b/playgrounds/app/src/components/Editor.tsx
index 5cb3d80..896d8dc 100644
--- a/playgrounds/app/src/components/Editor.tsx
+++ b/playgrounds/app/src/components/Editor.tsx
@@ -14,12 +14,7 @@ import {
} from '~/components/ui/combobox'
import { Button } from '~/components/ui/button'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/components/ui/tabs'
-import {
- TextField,
- TextFieldInput,
- TextFieldLabel,
- TextFieldTextArea,
-} from '~/components/ui/text-field'
+import { TextField, TextFieldInput } from '~/components/ui/text-field'
import { MagicMoveElement } from 'shiki-magic-move/types'
import {
Slider,
@@ -51,6 +46,7 @@ import { toast } from 'solid-sonner'
import { Separator } from './ui/separator'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './ui/accordion'
+import ShikiCodeBlock from './ui/shiki-code-block'
const animationSeconds = 1
const animationFPS = 10
@@ -686,23 +682,26 @@ export default function Editor(props: EditorProps) {
-
- Start Code
-
-
-
-
- End Code
-
-
+
+
diff --git a/playgrounds/app/src/components/ui/shiki-code-block.tsx b/playgrounds/app/src/components/ui/shiki-code-block.tsx
new file mode 100644
index 0000000..c89082b
--- /dev/null
+++ b/playgrounds/app/src/components/ui/shiki-code-block.tsx
@@ -0,0 +1,67 @@
+import { createSignal, onMount, createEffect } from 'solid-js'
+import { createHighlighter } from 'shiki'
+import { autoload, hookClosingPairs, hookTab, ShikiCode } from 'shikicode/plugins'
+import { shikiCode } from 'shikicode'
+
+import { cn } from '~/lib/utils'
+
+interface ShikiCodeBlockProps {
+ code: string
+ lang: string
+ theme: string
+ class?: string
+ onChange?: (value: string) => void
+}
+
+const ShikiCodeBlock = (props: ShikiCodeBlockProps) => {
+ const [source, setSource] = createSignal(props.code)
+ const [theme, setTheme] = createSignal(props.theme)
+ const [lang, setLang] = createSignal(props.lang)
+
+ let containerRef: HTMLDivElement | undefined
+ let editor: ShikiCode
+
+ onMount(async () => {
+ const highlighter = await createHighlighter({
+ langs: [lang()],
+ themes: [theme()],
+ })
+ editor = shikiCode()
+ .withPlugins(hookClosingPairs(), hookTab, autoload)
+ .create(containerRef!, highlighter, {
+ value: source(), // Initial code value
+ language: lang(),
+ theme: theme(),
+ })
+
+ editor.input.addEventListener('input', (e: Event) => {
+ const value = (e.target as HTMLTextAreaElement).value
+ setSource(value)
+ props.onChange?.(value)
+ })
+ })
+
+ createEffect(() => {
+ const { code, theme: newTheme, lang: newLang } = props
+
+ setSource(code)
+ setTheme(newTheme)
+ setLang(newLang)
+
+ if (editor) {
+ editor.updateOptions({
+ theme: newTheme,
+ language: newLang,
+ })
+ }
+ })
+
+ return (
+
+ )
+}
+
+export default ShikiCodeBlock
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b1bbffd..4698a03 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -172,6 +172,24 @@ importers:
specifier: ^2.1.6
version: 2.1.6(typescript@5.6.3)
+ packages/shikicode:
+ devDependencies:
+ '@types/jest':
+ specifier: ^29.5.13
+ version: 29.5.14
+ dprint:
+ specifier: ^0.47.2
+ version: 0.47.5
+ oxlint:
+ specifier: ^0.9.10
+ version: 0.9.10
+ shiki:
+ specifier: ^1.22.0
+ version: 1.22.0
+ typescript:
+ specifier: ^5.6.3
+ version: 5.6.3
+
playgrounds/app:
dependencies:
'@corvu/resizable':
@@ -241,11 +259,14 @@ importers:
specifier: ^4.0.221
version: 4.0.221(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
shiki:
- specifier: ^1.21.0
+ specifier: ^1.22.0
version: 1.22.0
shiki-magic-move:
specifier: workspace:*
version: link:../../packages/shiki-magic-move
+ shikicode:
+ specifier: workspace:*
+ version: link:../../packages/shikicode
solid-color:
specifier: ^0.0.4
version: 0.0.4(solid-js@1.9.2)
@@ -255,6 +276,9 @@ importers:
solid-js:
specifier: ^1.9.1
version: 1.9.2
+ solid-shiki-textarea:
+ specifier: ^0.1.6
+ version: 0.1.6(@babel/core@7.25.8)(@types/react@18.3.11)(shiki@1.22.0)(solid-js@1.9.2)
solid-sonner:
specifier: ^0.2.8
version: 0.2.8(solid-js@1.9.2)
@@ -608,6 +632,46 @@ packages:
'@deno/shim-deno@0.19.2':
resolution: {integrity: sha512-q3VTHl44ad8T2Tw2SpeAvghdGOjlnLPDNO2cpOxwMrBE/PVas6geWpbpIgrM+czOCH0yejp0yi8OaTuB+NU40Q==}
+ '@dprint/darwin-arm64@0.47.5':
+ resolution: {integrity: sha512-aVa3F//dkvEeNA7DCSlVcLxB0CV6zXpfbJZ/xsd+xgbayCXFuFr7qt0M6T4WP3gkQn5D7Zu8/pbXfRXQXo9qlQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@dprint/darwin-x64@0.47.5':
+ resolution: {integrity: sha512-84lmSLM/idIQ4UBkBHU1chP0WTldRjzLOEN22/XbdB1JGOIVN1pJIIU0lsmVWXaNI4SvGfty+thhGn73SSlQwA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@dprint/linux-arm64-glibc@0.47.5':
+ resolution: {integrity: sha512-Zk7Ut9Trgl2ssGWx0u3YegnRQFXivKaK1fPEimg/uMwdaLtWFGvNs6DACAJk34d883zmDkTQvllqY1kc78CeBg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@dprint/linux-arm64-musl@0.47.5':
+ resolution: {integrity: sha512-KmCu1yX5+/2MbT9n0iAgSK1gc6sQBcDayq8QRO7TRSs+gTDAZ/yQXHkhLdlk5fWsTR1mDQPVRG+2nAjHDhk8EA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@dprint/linux-x64-glibc@0.47.5':
+ resolution: {integrity: sha512-oBwENMikvcM+eT6JdliMIM+TOiV4VuBJGK+AN1sTOW45VeiYvmzGPOQwCxVeFq4MnZkMfrycC/PAY3C7Vcuh6w==}
+ cpu: [x64]
+ os: [linux]
+
+ '@dprint/linux-x64-musl@0.47.5':
+ resolution: {integrity: sha512-B1IGyaP0k25JDhqmR/UpvgyNtnclBoXV7ZNQbvygehBkTeC69afwzpUxjQ2pKj2F9bl1Rby//fhsAFOg60PzsA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@dprint/win32-arm64@0.47.5':
+ resolution: {integrity: sha512-tKSPwGWsKc+QAdsx6UQav9AY8WXm+B5Mx23ujliJJMRss6Dnlmg17NjbAnSBSqXSrfqaMeQx6d4gujPpOS3F9A==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@dprint/win32-x64@0.47.5':
+ resolution: {integrity: sha512-ljbrGv5rDR00ziBFY6V+qLhtLHm2dsjgiFG9OU7kr3vHEj4eN31nwxU5W2mh0eMoRk7IbcJ5ahTJDLgoYdvfgw==}
+ cpu: [x64]
+ os: [win32]
+
'@drizzle-team/brocli@0.10.1':
resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==}
@@ -1727,10 +1791,18 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
+ '@jest/expect-utils@29.7.0':
+ resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
'@jest/schemas@29.6.3':
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jest/types@29.6.3':
+ resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -1822,6 +1894,11 @@ packages:
cpu: [x64]
os: [win32]
+ '@lume/element@0.11.9':
+ resolution: {integrity: sha512-YR4sLA8vCu1bZo5jN4sua2AB66RrDUisMMWOV79KRfLiM8Q3Nxxmb3S1Kocdy56XWz/eZr1scITMiAQNqpN+dg==}
+ peerDependencies:
+ '@types/react': '*'
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -1859,6 +1936,46 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@oxlint/darwin-arm64@0.9.10':
+ resolution: {integrity: sha512-eOXKZYq5bnCSgDefgM5bzAg+4Fc//Rc4yjgKN8iDWUARweCaChiQXb6TXX8MfEfs6qayEMy6yVj0pqoFz0B1aw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxlint/darwin-x64@0.9.10':
+ resolution: {integrity: sha512-UeYICDvLUaUOcY+0ugZUEmBMRLP+x8iTgL7TeY6BlpGw2ahbtUOTbyIIRWtr/0O++TnjZ+v8TzhJ9crw6Ij6dg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxlint/linux-arm64-gnu@0.9.10':
+ resolution: {integrity: sha512-0Zn+vqHhrZyufFBfq9WOgiIool0gCR14BLsdS+0Dwd9o+kNxPGA5q7erQFkiC4rpkxtfBHeD3iIKMMt7d29Kyw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxlint/linux-arm64-musl@0.9.10':
+ resolution: {integrity: sha512-tkQcWpYwF42bA/uRaV2iMFePHkBjTTgomOgeEaiw6XOSJX4nBEqGIIboqqLBWT4JnKCf/L+IG3y/e1MflhKByw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxlint/linux-x64-gnu@0.9.10':
+ resolution: {integrity: sha512-JHbkMUnibqaSMBvLHyqTL5cWxcGW+jw+Ppt2baLISpvo34a6fBR+PI7v/A92sEDWe0W1rPhypzCwA8mKpkQ3DA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxlint/linux-x64-musl@0.9.10':
+ resolution: {integrity: sha512-aBBwN7bQzidwHwEXr7BAdVvMTLWstCy5gikerjLnGDeCSXX9r+o6+yUzTOqZvOo66E+XBgOJaVbY8rsL1MLE0g==}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxlint/win32-arm64@0.9.10':
+ resolution: {integrity: sha512-LXDnk7vKHT3IY6G1jq0O7+XMhtcHOYuxLGIx4KP+4xS6vKgBY+Bsq4xV3AtmtKlvnXkP5FxHpfLmcEtm5AWysA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxlint/win32-x64@0.9.10':
+ resolution: {integrity: sha512-w5XRAV4bhgwenjjpGYZGglqzG9Wv/sI+cjQWJBQsvfDXsr2w4vOBXzt1j3/Z3EcSqf4KtkCa/IIuAhQyeShUbA==}
+ cpu: [x64]
+ os: [win32]
+
'@parcel/watcher-android-arm64@2.4.1':
resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==}
engines: {node: '>= 10.0.0'}
@@ -2159,6 +2276,11 @@ packages:
peerDependencies:
solid-js: ^1.6.12
+ '@solid-primitives/list@0.0.100':
+ resolution: {integrity: sha512-SZsGouBzUkrZJlJkjVf1rDgRA6FD/+Qar3s7yD1h5uTe1ZIQM89D4RiGxnVjA+KUdfBFQtocT6J76eQ1aIbJxQ==}
+ peerDependencies:
+ solid-js: ^1.6.12
+
'@solid-primitives/map@0.4.13':
resolution: {integrity: sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew==}
peerDependencies:
@@ -2313,6 +2435,18 @@ packages:
'@types/http-proxy@1.17.15':
resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+
+ '@types/jest@29.5.14':
+ resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -2352,6 +2486,9 @@ packages:
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@@ -2361,6 +2498,12 @@ packages:
'@types/ws@8.5.12':
resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==}
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
+ '@types/yargs@17.0.33':
+ resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+
'@typescript-eslint/eslint-plugin@8.8.1':
resolution: {integrity: sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2978,6 +3121,9 @@ packages:
class-variance-authority@0.7.0:
resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
+ classy-solid@0.3.9:
+ resolution: {integrity: sha512-QVAERy8PtkA2eozU/XCCeLamaokprPlCYS5Q7gK05eeE5/gCmIuiGV1F9SMurLpnVy9w6ZKSnNjxUd69btorzQ==}
+
clean-regexp@1.0.0:
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
engines: {node: '>=4'}
@@ -3368,6 +3514,10 @@ packages:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
+ dprint@0.47.5:
+ resolution: {integrity: sha512-EAP3OLYZXiW66HKMlhu6Gu0o7mzBVTWyMyuAAgT7dBtMX+W+pPJmIwyRUnTRQNyyFO4S7bAaa21rzIgo97Bg9A==}
+ hasBin: true
+
drizzle-kit@0.26.2:
resolution: {integrity: sha512-cMq8omEKywjIy5KcqUo6LvEFxkl8/zYHsgYjFVXjmPWWtuW4blcz+YW9+oIhoaALgs2ebRjzXwsJgN9i6P49Dw==}
hasBin: true
@@ -3576,6 +3726,10 @@ packages:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
@@ -3903,6 +4057,10 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
+ expect@29.7.0:
+ resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
extendable-error@0.1.7:
resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==}
@@ -4400,6 +4558,18 @@ packages:
resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-matcher-utils@29.7.0:
+ resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-message-util@29.7.0:
+ resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-util@29.7.0:
+ resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
jiti@1.21.6:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
@@ -4535,7 +4705,6 @@ packages:
libsql@0.4.6:
resolution: {integrity: sha512-F5M+ltteK6dCcpjMahrkgT96uFJvVI8aQ4r9f2AzHQjC7BkAYtvfMSTWGvRBezRgMUIU2h1Sy0pF9nOGOD5iyA==}
- cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32]
lilconfig@2.1.0:
@@ -4647,6 +4816,12 @@ packages:
loupe@3.1.2:
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
+ lowclass@7.0.1:
+ resolution: {integrity: sha512-MUCYry/VsWP3jfShf0TUyQ9tnmo6qsNUGnxbRo02GHtnyz1pq12ZlI7ep+H1s+FqpoDgA/TVrGqSScrvYhaWAQ==}
+
+ lowclass@8.0.2:
+ resolution: {integrity: sha512-F/SMc8Kn34lNfjhlMDZYiOqmdtROR8sndSl7I/HJooxBekpgFxBcZL7LFsugc/sSGg0PV+or74+M5Q1/F4dP9g==}
+
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -5090,6 +5265,11 @@ packages:
outdent@0.5.0:
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
+ oxlint@0.9.10:
+ resolution: {integrity: sha512-bKiiFN7Hnoaist/rditTRBXz+GXKYuLd53/NB7Q6zHB/bifELJarSoRLkAUGElIJKl4PSr3lTh1g6zehh+rX0g==}
+ engines: {node: '>=14.*'}
+ hasBin: true
+
p-filter@2.1.0:
resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
engines: {node: '>=8'}
@@ -5876,6 +6056,13 @@ packages:
peerDependencies:
solid-js: ^1.3
+ solid-shiki-textarea@0.1.6:
+ resolution: {integrity: sha512-SyXGpQ/zlMy0LDPBcPeMapSI/Oyo1WgYe84MSTcxyOdE5UJB+5eLucyyXRX/riDBUS6WS08sR9h86HL3aX/0hQ==}
+ engines: {node: '>=18', pnpm: '>=9.0.0'}
+ peerDependencies:
+ shiki: ^1.6.2
+ solid-js: ^1.6.0
+
solid-sonner@0.2.8:
resolution: {integrity: sha512-EQ2EIznvHHpAmkYh2CTu0AdCgmPJRJWLGFRWygE8j+vMEfvIV2wotHU5qgWzqzVTG1SODGsay2Lwq6ENWx/rPA==}
peerDependencies:
@@ -5936,6 +6123,10 @@ packages:
stable-hash@0.0.4:
resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
@@ -7339,6 +7530,30 @@ snapshots:
'@deno/shim-deno-test': 0.5.0
which: 4.0.0
+ '@dprint/darwin-arm64@0.47.5':
+ optional: true
+
+ '@dprint/darwin-x64@0.47.5':
+ optional: true
+
+ '@dprint/linux-arm64-glibc@0.47.5':
+ optional: true
+
+ '@dprint/linux-arm64-musl@0.47.5':
+ optional: true
+
+ '@dprint/linux-x64-glibc@0.47.5':
+ optional: true
+
+ '@dprint/linux-x64-musl@0.47.5':
+ optional: true
+
+ '@dprint/win32-arm64@0.47.5':
+ optional: true
+
+ '@dprint/win32-x64@0.47.5':
+ optional: true
+
'@drizzle-team/brocli@0.10.1': {}
'@es-joy/jsdoccomment@0.48.0':
@@ -8066,10 +8281,23 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
+ '@jest/expect-utils@29.7.0':
+ dependencies:
+ jest-get-type: 29.6.3
+
'@jest/schemas@29.6.3':
dependencies:
'@sinclair/typebox': 0.27.8
+ '@jest/types@29.6.3':
+ dependencies:
+ '@jest/schemas': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 22.7.5
+ '@types/yargs': 17.0.33
+ chalk: 4.1.2
+
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
@@ -8183,6 +8411,16 @@ snapshots:
'@libsql/win32-x64-msvc@0.4.6':
optional: true
+ '@lume/element@0.11.9(@babel/core@7.25.8)(@types/react@18.3.11)':
+ dependencies:
+ '@types/react': 18.3.11
+ babel-preset-solid: 1.9.2(@babel/core@7.25.8)
+ classy-solid: 0.3.9
+ lowclass: 7.0.1
+ solid-js: 1.9.2
+ transitivePeerDependencies:
+ - '@babel/core'
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.25.7
@@ -8239,6 +8477,30 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
+ '@oxlint/darwin-arm64@0.9.10':
+ optional: true
+
+ '@oxlint/darwin-x64@0.9.10':
+ optional: true
+
+ '@oxlint/linux-arm64-gnu@0.9.10':
+ optional: true
+
+ '@oxlint/linux-arm64-musl@0.9.10':
+ optional: true
+
+ '@oxlint/linux-x64-gnu@0.9.10':
+ optional: true
+
+ '@oxlint/linux-x64-musl@0.9.10':
+ optional: true
+
+ '@oxlint/win32-arm64@0.9.10':
+ optional: true
+
+ '@oxlint/win32-x64@0.9.10':
+ optional: true
+
'@parcel/watcher-android-arm64@2.4.1':
optional: true
@@ -8524,6 +8786,10 @@ snapshots:
dependencies:
solid-js: 1.9.2
+ '@solid-primitives/list@0.0.100(solid-js@1.9.2)':
+ dependencies:
+ solid-js: 1.9.2
+
'@solid-primitives/map@0.4.13(solid-js@1.9.2)':
dependencies:
'@solid-primitives/trigger': 1.1.0(solid-js@1.9.2)
@@ -8714,6 +8980,21 @@ snapshots:
dependencies:
'@types/node': 22.7.5
+ '@types/istanbul-lib-coverage@2.0.6': {}
+
+ '@types/istanbul-lib-report@3.0.3':
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.6
+
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
+
+ '@types/jest@29.5.14':
+ dependencies:
+ expect: 29.7.0
+ pretty-format: 29.7.0
+
'@types/json-schema@7.0.15': {}
'@types/jsonwebtoken@9.0.7':
@@ -8755,6 +9036,8 @@ snapshots:
'@types/resolve@1.20.2': {}
+ '@types/stack-utils@2.0.3': {}
+
'@types/unist@3.0.3': {}
'@types/web-bluetooth@0.0.20': {}
@@ -8763,6 +9046,12 @@ snapshots:
dependencies:
'@types/node': 22.7.5
+ '@types/yargs-parser@21.0.3': {}
+
+ '@types/yargs@17.0.33':
+ dependencies:
+ '@types/yargs-parser': 21.0.3
+
'@typescript-eslint/eslint-plugin@8.8.1(@typescript-eslint/parser@8.8.1(eslint@9.12.0(jiti@2.3.3))(typescript@5.6.3))(eslint@9.12.0(jiti@2.3.3))(typescript@5.6.3)':
dependencies:
'@eslint-community/regexpp': 4.11.1
@@ -9582,6 +9871,11 @@ snapshots:
dependencies:
clsx: 2.0.0
+ classy-solid@0.3.9:
+ dependencies:
+ lowclass: 8.0.2
+ solid-js: 1.9.2
+
clean-regexp@1.0.0:
dependencies:
escape-string-regexp: 1.0.5
@@ -9925,6 +10219,17 @@ snapshots:
dotenv@16.4.5: {}
+ dprint@0.47.5:
+ optionalDependencies:
+ '@dprint/darwin-arm64': 0.47.5
+ '@dprint/darwin-x64': 0.47.5
+ '@dprint/linux-arm64-glibc': 0.47.5
+ '@dprint/linux-arm64-musl': 0.47.5
+ '@dprint/linux-x64-glibc': 0.47.5
+ '@dprint/linux-x64-musl': 0.47.5
+ '@dprint/win32-arm64': 0.47.5
+ '@dprint/win32-x64': 0.47.5
+
drizzle-kit@0.26.2:
dependencies:
'@drizzle-team/brocli': 0.10.1
@@ -10193,6 +10498,8 @@ snapshots:
escape-string-regexp@1.0.5: {}
+ escape-string-regexp@2.0.0: {}
+
escape-string-regexp@4.0.0: {}
escape-string-regexp@5.0.0: {}
@@ -10693,6 +11000,14 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
+ expect@29.7.0:
+ dependencies:
+ '@jest/expect-utils': 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+
extendable-error@0.1.7: {}
external-editor@3.1.0:
@@ -11229,6 +11544,34 @@ snapshots:
jest-get-type@29.6.3: {}
+ jest-matcher-utils@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-message-util@29.7.0:
+ dependencies:
+ '@babel/code-frame': 7.25.7
+ '@jest/types': 29.6.3
+ '@types/stack-utils': 2.0.3
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+
+ jest-util@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 22.7.5
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.1
+
jiti@1.21.6: {}
jiti@2.0.0-beta.3: {}
@@ -11508,6 +11851,10 @@ snapshots:
loupe@3.1.2: {}
+ lowclass@7.0.1: {}
+
+ lowclass@8.0.2: {}
+
lru-cache@10.4.3: {}
lru-cache@11.0.1: {}
@@ -12188,6 +12535,17 @@ snapshots:
outdent@0.5.0: {}
+ oxlint@0.9.10:
+ optionalDependencies:
+ '@oxlint/darwin-arm64': 0.9.10
+ '@oxlint/darwin-x64': 0.9.10
+ '@oxlint/linux-arm64-gnu': 0.9.10
+ '@oxlint/linux-arm64-musl': 0.9.10
+ '@oxlint/linux-x64-gnu': 0.9.10
+ '@oxlint/linux-x64-musl': 0.9.10
+ '@oxlint/win32-arm64': 0.9.10
+ '@oxlint/win32-x64': 0.9.10
+
p-filter@2.1.0:
dependencies:
p-map: 2.1.0
@@ -12919,6 +13277,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ solid-shiki-textarea@0.1.6(@babel/core@7.25.8)(@types/react@18.3.11)(shiki@1.22.0)(solid-js@1.9.2):
+ dependencies:
+ '@lume/element': 0.11.9(@babel/core@7.25.8)(@types/react@18.3.11)
+ '@solid-primitives/list': 0.0.100(solid-js@1.9.2)
+ clsx: 2.1.1
+ shiki: 1.22.0
+ solid-js: 1.9.2
+ transitivePeerDependencies:
+ - '@babel/core'
+ - '@types/react'
+
solid-sonner@0.2.8(solid-js@1.9.2):
dependencies:
solid-js: 1.9.2
@@ -12974,6 +13343,10 @@ snapshots:
stable-hash@0.0.4: {}
+ stack-utils@2.0.6:
+ dependencies:
+ escape-string-regexp: 2.0.0
+
stackback@0.0.2: {}
stackframe@1.3.4: {}