wrote a usbip module
This commit is contained in:
@ -23,5 +23,6 @@
|
||||
"fmt": {
|
||||
"indentWidth": 4
|
||||
},
|
||||
"nodeModulesDir": "auto"
|
||||
"nodeModulesDir": "auto",
|
||||
"vendor": true
|
||||
}
|
||||
|
||||
437
deno.lock
generated
437
deno.lock
generated
@ -36,18 +36,18 @@
|
||||
"jsr:@std/path@^1.0.6": "1.0.8",
|
||||
"jsr:@std/path@^1.0.8": "1.0.8",
|
||||
"jsr:@std/streams@^1.0.8": "1.0.8",
|
||||
"npm:@ryanflorence/sqlite-typegen@0.2": "0.2.0",
|
||||
"npm:@minify-html/node-linux-x64@*": "0.15.0",
|
||||
"npm:@minify-html/node-linux-x64@0.15": "0.15.0",
|
||||
"npm:@minify-html/wasm@*": "0.15.0",
|
||||
"npm:@tauri-apps/api@2": "2.2.0",
|
||||
"npm:@tauri-apps/cli@2": "2.2.5",
|
||||
"npm:@tauri-apps/plugin-shell@2": "2.2.0",
|
||||
"npm:better-sqlite3@^11.8.0": "11.8.1",
|
||||
"npm:esbuild-plugin-tsc@*": "0.4.0_typescript@5.7.3",
|
||||
"npm:esbuild-plugin-tsc@0.4": "0.4.0_typescript@5.7.3",
|
||||
"npm:esbuild@*": "0.24.2",
|
||||
"npm:esbuild@~0.24.2": "0.24.2",
|
||||
"npm:fast-glob@*": "3.3.3",
|
||||
"npm:fast-glob@^3.3.3": "3.3.3",
|
||||
"npm:mariadb@^3.4.0": "3.4.0",
|
||||
"npm:typescript@^5.2.2": "5.7.3",
|
||||
"npm:typescript@^5.7.3": "5.7.3",
|
||||
"npm:vite@^5.3.1": "5.4.13"
|
||||
@ -332,6 +332,12 @@
|
||||
"@esbuild/win32-x64@0.24.2": {
|
||||
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="
|
||||
},
|
||||
"@minify-html/node-linux-x64@0.15.0": {
|
||||
"integrity": "sha512-cO893EV6O9ZHUFX+2Yge546OCo/eCiatjzJDmUmrPP56fQ7pzTRquHs4ko3t8Rg6tMKG7RT49mBuF09JWPnrgg=="
|
||||
},
|
||||
"@minify-html/wasm@0.15.0": {
|
||||
"integrity": "sha512-xsd4FFypUayUNS4LvokyfiRQwYbyKVITnGHCaGsvlu36jZTYMSeQ7vn5LpEjW20Tbw7CYBQmD2JWCak/V+na5w=="
|
||||
},
|
||||
"@nodelib/fs.scandir@2.1.5": {
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dependencies": [
|
||||
@ -406,16 +412,6 @@
|
||||
"@rollup/rollup-win32-x64-msvc@4.31.0": {
|
||||
"integrity": "sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw=="
|
||||
},
|
||||
"@ryanflorence/sqlite-typegen@0.2.0": {
|
||||
"integrity": "sha512-5zDtou8+wd0Qoz5COkX2Nf8JgrSFukjMZVEZdoXct2q5EmH1TcrQc1vjngniDNAKIMDQBZHSIaMEyvtDBtkpXA==",
|
||||
"dependencies": [
|
||||
"arg",
|
||||
"better-sqlite3@11.6.0",
|
||||
"cli-highlight",
|
||||
"picocolors",
|
||||
"tiny-invariant"
|
||||
]
|
||||
},
|
||||
"@tauri-apps/api@2.2.0": {
|
||||
"integrity": "sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg=="
|
||||
},
|
||||
@ -473,136 +469,12 @@
|
||||
"@types/estree@1.0.6": {
|
||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
|
||||
},
|
||||
"@types/geojson@7946.0.15": {
|
||||
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA=="
|
||||
},
|
||||
"@types/node@22.10.7": {
|
||||
"integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
|
||||
"dependencies": [
|
||||
"undici-types"
|
||||
]
|
||||
},
|
||||
"ansi-regex@5.0.1": {
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles@4.3.0": {
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": [
|
||||
"color-convert"
|
||||
]
|
||||
},
|
||||
"any-promise@1.3.0": {
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
|
||||
},
|
||||
"arg@5.0.2": {
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
||||
},
|
||||
"base64-js@1.5.1": {
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"better-sqlite3@11.6.0": {
|
||||
"integrity": "sha512-2J6k/eVxcFYY2SsTxsXrj6XylzHWPxveCn4fKPKZFv/Vqn/Cd7lOuX4d7rGQXT5zL+97MkNL3nSbCrIoe3LkgA==",
|
||||
"dependencies": [
|
||||
"bindings",
|
||||
"prebuild-install"
|
||||
]
|
||||
},
|
||||
"better-sqlite3@11.8.1": {
|
||||
"integrity": "sha512-9BxNaBkblMjhJW8sMRZxnxVTRgbRmssZW0Oxc1MPBTfiR+WW21e2Mk4qu8CzrcZb1LwPCnFsfDEzq+SNcBU8eg==",
|
||||
"dependencies": [
|
||||
"bindings",
|
||||
"prebuild-install"
|
||||
]
|
||||
},
|
||||
"bindings@1.5.0": {
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dependencies": [
|
||||
"file-uri-to-path"
|
||||
]
|
||||
},
|
||||
"bl@4.1.0": {
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dependencies": [
|
||||
"buffer",
|
||||
"inherits",
|
||||
"readable-stream"
|
||||
]
|
||||
},
|
||||
"braces@3.0.3": {
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dependencies": [
|
||||
"fill-range"
|
||||
]
|
||||
},
|
||||
"buffer@5.7.1": {
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dependencies": [
|
||||
"base64-js",
|
||||
"ieee754"
|
||||
]
|
||||
},
|
||||
"chalk@4.1.2": {
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dependencies": [
|
||||
"ansi-styles",
|
||||
"supports-color"
|
||||
]
|
||||
},
|
||||
"chownr@1.1.4": {
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
},
|
||||
"cli-highlight@2.1.11": {
|
||||
"integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
|
||||
"dependencies": [
|
||||
"chalk",
|
||||
"highlight.js",
|
||||
"mz",
|
||||
"parse5@5.1.1",
|
||||
"parse5-htmlparser2-tree-adapter",
|
||||
"yargs"
|
||||
]
|
||||
},
|
||||
"cliui@7.0.4": {
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dependencies": [
|
||||
"string-width",
|
||||
"strip-ansi",
|
||||
"wrap-ansi"
|
||||
]
|
||||
},
|
||||
"color-convert@2.0.1": {
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": [
|
||||
"color-name"
|
||||
]
|
||||
},
|
||||
"color-name@1.1.4": {
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"decompress-response@6.0.0": {
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"dependencies": [
|
||||
"mimic-response"
|
||||
]
|
||||
},
|
||||
"deep-extend@0.6.0": {
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
|
||||
},
|
||||
"denque@2.1.0": {
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
|
||||
},
|
||||
"detect-libc@2.0.3": {
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="
|
||||
},
|
||||
"emoji-regex@8.0.0": {
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"end-of-stream@1.4.4": {
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dependencies": [
|
||||
"once"
|
||||
]
|
||||
},
|
||||
"esbuild-plugin-tsc@0.4.0_typescript@5.7.3": {
|
||||
"integrity": "sha512-q9gWIovt1nkwchMLc2zhyksaiHOv3kDK4b0AUol8lkMCRhJ1zavgfb2fad6BKp7FT9rh/OHmEBXVjczLoi/0yw==",
|
||||
"dependencies": [
|
||||
@ -668,12 +540,6 @@
|
||||
"@esbuild/win32-x64@0.24.2"
|
||||
]
|
||||
},
|
||||
"escalade@3.2.0": {
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="
|
||||
},
|
||||
"expand-template@2.0.3": {
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
|
||||
},
|
||||
"fast-glob@3.3.3": {
|
||||
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||
"dependencies": [
|
||||
@ -690,60 +556,24 @@
|
||||
"reusify"
|
||||
]
|
||||
},
|
||||
"file-uri-to-path@1.0.0": {
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
|
||||
},
|
||||
"fill-range@7.1.1": {
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": [
|
||||
"to-regex-range"
|
||||
]
|
||||
},
|
||||
"fs-constants@1.0.0": {
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"fsevents@2.3.3": {
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="
|
||||
},
|
||||
"get-caller-file@2.0.5": {
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"github-from-package@0.0.0": {
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
|
||||
},
|
||||
"glob-parent@5.1.2": {
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dependencies": [
|
||||
"is-glob"
|
||||
]
|
||||
},
|
||||
"has-flag@4.0.0": {
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"highlight.js@10.7.3": {
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
||||
},
|
||||
"iconv-lite@0.6.3": {
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": [
|
||||
"safer-buffer"
|
||||
]
|
||||
},
|
||||
"ieee754@1.2.1": {
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"inherits@2.0.4": {
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini@1.3.8": {
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
||||
},
|
||||
"is-extglob@2.1.1": {
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
|
||||
},
|
||||
"is-fullwidth-code-point@3.0.0": {
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"is-glob@4.0.3": {
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dependencies": [
|
||||
@ -753,19 +583,6 @@
|
||||
"is-number@7.0.0": {
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
},
|
||||
"lru-cache@10.4.3": {
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
||||
},
|
||||
"mariadb@3.4.0": {
|
||||
"integrity": "sha512-hdRPcAzs+MTxK5VG1thBW18gGTlw6yWBe9YnLB65GLo7q0fO5DWsgomIevV/pXSaWRmD3qi6ka4oSFRTExRiEQ==",
|
||||
"dependencies": [
|
||||
"@types/geojson",
|
||||
"@types/node",
|
||||
"denque",
|
||||
"iconv-lite",
|
||||
"lru-cache"
|
||||
]
|
||||
},
|
||||
"merge2@1.4.1": {
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
|
||||
},
|
||||
@ -776,56 +593,9 @@
|
||||
"picomatch"
|
||||
]
|
||||
},
|
||||
"mimic-response@3.1.0": {
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
|
||||
},
|
||||
"minimist@1.2.8": {
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
|
||||
},
|
||||
"mkdirp-classic@0.5.3": {
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
},
|
||||
"mz@2.7.0": {
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"dependencies": [
|
||||
"any-promise",
|
||||
"object-assign",
|
||||
"thenify-all"
|
||||
]
|
||||
},
|
||||
"nanoid@3.3.8": {
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="
|
||||
},
|
||||
"napi-build-utils@1.0.2": {
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
||||
},
|
||||
"node-abi@3.73.0": {
|
||||
"integrity": "sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==",
|
||||
"dependencies": [
|
||||
"semver"
|
||||
]
|
||||
},
|
||||
"object-assign@4.1.1": {
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"once@1.4.0": {
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": [
|
||||
"wrappy"
|
||||
]
|
||||
},
|
||||
"parse5-htmlparser2-tree-adapter@6.0.1": {
|
||||
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
|
||||
"dependencies": [
|
||||
"parse5@6.0.1"
|
||||
]
|
||||
},
|
||||
"parse5@5.1.1": {
|
||||
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
|
||||
},
|
||||
"parse5@6.0.1": {
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||
},
|
||||
"picocolors@1.1.1": {
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||
},
|
||||
@ -840,53 +610,9 @@
|
||||
"source-map-js"
|
||||
]
|
||||
},
|
||||
"prebuild-install@7.1.2": {
|
||||
"integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==",
|
||||
"dependencies": [
|
||||
"detect-libc",
|
||||
"expand-template",
|
||||
"github-from-package",
|
||||
"minimist",
|
||||
"mkdirp-classic",
|
||||
"napi-build-utils",
|
||||
"node-abi",
|
||||
"pump",
|
||||
"rc",
|
||||
"simple-get",
|
||||
"tar-fs",
|
||||
"tunnel-agent"
|
||||
]
|
||||
},
|
||||
"pump@3.0.2": {
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"dependencies": [
|
||||
"end-of-stream",
|
||||
"once"
|
||||
]
|
||||
},
|
||||
"queue-microtask@1.2.3": {
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
|
||||
},
|
||||
"rc@1.2.8": {
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dependencies": [
|
||||
"deep-extend",
|
||||
"ini",
|
||||
"minimist",
|
||||
"strip-json-comments"
|
||||
]
|
||||
},
|
||||
"readable-stream@3.6.2": {
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dependencies": [
|
||||
"inherits",
|
||||
"string_decoder",
|
||||
"util-deprecate"
|
||||
]
|
||||
},
|
||||
"require-directory@2.1.1": {
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
|
||||
},
|
||||
"reusify@1.0.4": {
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
|
||||
},
|
||||
@ -922,116 +648,21 @@
|
||||
"queue-microtask"
|
||||
]
|
||||
},
|
||||
"safe-buffer@5.2.1": {
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"safer-buffer@2.1.2": {
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"semver@7.6.3": {
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="
|
||||
},
|
||||
"simple-concat@1.0.1": {
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||
},
|
||||
"simple-get@4.0.1": {
|
||||
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||
"dependencies": [
|
||||
"decompress-response",
|
||||
"once",
|
||||
"simple-concat"
|
||||
]
|
||||
},
|
||||
"source-map-js@1.2.1": {
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
|
||||
},
|
||||
"string-width@4.2.3": {
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": [
|
||||
"emoji-regex",
|
||||
"is-fullwidth-code-point",
|
||||
"strip-ansi"
|
||||
]
|
||||
},
|
||||
"string_decoder@1.3.0": {
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": [
|
||||
"safe-buffer"
|
||||
]
|
||||
},
|
||||
"strip-ansi@6.0.1": {
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": [
|
||||
"ansi-regex"
|
||||
]
|
||||
},
|
||||
"strip-comments@2.0.1": {
|
||||
"integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw=="
|
||||
},
|
||||
"strip-json-comments@2.0.1": {
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
|
||||
},
|
||||
"supports-color@7.2.0": {
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dependencies": [
|
||||
"has-flag"
|
||||
]
|
||||
},
|
||||
"tar-fs@2.1.2": {
|
||||
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
|
||||
"dependencies": [
|
||||
"chownr",
|
||||
"mkdirp-classic",
|
||||
"pump",
|
||||
"tar-stream"
|
||||
]
|
||||
},
|
||||
"tar-stream@2.2.0": {
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dependencies": [
|
||||
"bl",
|
||||
"end-of-stream",
|
||||
"fs-constants",
|
||||
"inherits",
|
||||
"readable-stream"
|
||||
]
|
||||
},
|
||||
"thenify-all@1.6.0": {
|
||||
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||
"dependencies": [
|
||||
"thenify"
|
||||
]
|
||||
},
|
||||
"thenify@3.3.1": {
|
||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||
"dependencies": [
|
||||
"any-promise"
|
||||
]
|
||||
},
|
||||
"tiny-invariant@1.3.3": {
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
|
||||
},
|
||||
"to-regex-range@5.0.1": {
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dependencies": [
|
||||
"is-number"
|
||||
]
|
||||
},
|
||||
"tunnel-agent@0.6.0": {
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"dependencies": [
|
||||
"safe-buffer"
|
||||
]
|
||||
},
|
||||
"typescript@5.7.3": {
|
||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="
|
||||
},
|
||||
"undici-types@6.20.0": {
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
|
||||
},
|
||||
"util-deprecate@1.0.2": {
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"vite@5.4.13": {
|
||||
"integrity": "sha512-7zp3N4YSjXOSAFfdBe9pPD3FrO398QlJ/5QpFGm3L8xDP1IxDn1XRxArPw4ZKk5394MM8rcTVPY4y1Hvo62bog==",
|
||||
"dependencies": [
|
||||
@ -1040,37 +671,23 @@
|
||||
"postcss",
|
||||
"rollup"
|
||||
]
|
||||
},
|
||||
"wrap-ansi@7.0.0": {
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dependencies": [
|
||||
"ansi-styles",
|
||||
"string-width",
|
||||
"strip-ansi"
|
||||
]
|
||||
},
|
||||
"wrappy@1.0.2": {
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"y18n@5.0.8": {
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yargs-parser@20.2.9": {
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
|
||||
},
|
||||
"yargs@16.2.0": {
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dependencies": [
|
||||
"cliui",
|
||||
"escalade",
|
||||
"get-caller-file",
|
||||
"require-directory",
|
||||
"string-width",
|
||||
"y18n",
|
||||
"yargs-parser"
|
||||
]
|
||||
}
|
||||
},
|
||||
"remote": {
|
||||
"https://deno.land/std@0.203.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
|
||||
"https://deno.land/std@0.203.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
|
||||
"https://deno.land/std@0.203.0/async/abortable.ts": "fd682fa46f3b7b16b4606a5ab52a7ce309434b76f820d3221bdfb862719a15d7",
|
||||
"https://deno.land/std@0.203.0/async/deadline.ts": "58f72a3cc0fcb731b2cc055ba046f4b5be3349ff6bf98f2e793c3b969354aab2",
|
||||
"https://deno.land/std@0.203.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332",
|
||||
"https://deno.land/std@0.203.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8",
|
||||
"https://deno.land/std@0.203.0/async/delay.ts": "a6142eb44cdd856b645086af2b811b1fcce08ec06bb7d50969e6a872ee9b8659",
|
||||
"https://deno.land/std@0.203.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576",
|
||||
"https://deno.land/std@0.203.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9",
|
||||
"https://deno.land/std@0.203.0/async/pool.ts": "47c1841cfa9c036144943d11747ddd44064f5baf8cb7ece25473ba873c6aceb0",
|
||||
"https://deno.land/std@0.203.0/async/retry.ts": "296fb9c323e1325a69bee14ba947e7da7409a8dd9dd646d70cb51ea0d301f24e",
|
||||
"https://deno.land/std@0.203.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757",
|
||||
"https://wilsonl.in/minify-html/deno/0.15.0/index.js": "8e7ee5067ca84fb5d5a1f33118cac4998de0b7d80b3f56cc5c6728b84e6bfb70"
|
||||
},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
"jsr:@luca/esbuild-deno-loader@~0.11.1",
|
||||
@ -1101,10 +718,8 @@
|
||||
"jsr:@std/crypto@^1.0.3",
|
||||
"jsr:@std/dotenv@~0.225.3",
|
||||
"jsr:@std/http@^1.0.12",
|
||||
"npm:@ryanflorence/sqlite-typegen@0.2",
|
||||
"npm:better-sqlite3@^11.8.0",
|
||||
"npm:esbuild@~0.24.2",
|
||||
"npm:mariadb@^3.4.0"
|
||||
"npm:@minify-html/node-linux-x64@0.15",
|
||||
"npm:esbuild@~0.24.2"
|
||||
]
|
||||
},
|
||||
"shared": {
|
||||
|
||||
@ -6,6 +6,7 @@ import authMiddleware from "@src/middleware/auth.ts";
|
||||
import { ok, ResultFromJSON } from "@shared/utils/result.ts";
|
||||
import { ResultResponseFromJSON } from "@src/lib/context.ts";
|
||||
import admin from "@src/lib/admin.ts";
|
||||
import UsbipManager from "@shared/utils/usbip.ts";
|
||||
|
||||
const router = new HttpRouter();
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import { AdminPasswordNotSetError, QueryExecutionError } from "@lib/errors.ts";
|
||||
import { AdminRaw, AdminSessionRaw } from "@lib/db/types/index.ts";
|
||||
import { generateRandomString, passwd } from "@lib/utils.ts";
|
||||
import { errAsync, ResultAsync } from "@shared/utils/resultasync.ts";
|
||||
import log from "@shared/utils/logger.ts";
|
||||
|
||||
const TOKEN_LENGTH = 128;
|
||||
const EXPIRED_TOKENS_DELETION_INTERVAL = 120 * 60 * 1000;
|
||||
@ -49,7 +50,12 @@ class Admin {
|
||||
password: string,
|
||||
): ResultAsync<boolean, QueryExecutionError | AdminPasswordNotSetError> {
|
||||
const result = this.getPasswordHash().flattenOption(
|
||||
() => new AdminPasswordNotSetError("Admin password is not set"),
|
||||
() => {
|
||||
log.warn("Tried to verify password when it is not set");
|
||||
return new AdminPasswordNotSetError(
|
||||
"Admin password is not set",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (result.isErr()) {
|
||||
@ -75,8 +81,7 @@ class Admin {
|
||||
this.statements.insertPasswordHash(hash);
|
||||
this.passwordHash = hash;
|
||||
},
|
||||
)
|
||||
.toAsync(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -121,8 +126,7 @@ class AdminSessions {
|
||||
);
|
||||
}
|
||||
},
|
||||
(error) =>
|
||||
console.error(`failed to clear expired tokens: ${error}`),
|
||||
() => log.error("Failed to clear expired tokens!"),
|
||||
);
|
||||
}, EXPIRED_TOKENS_DELETION_INTERVAL);
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ export class Context<S extends string = string> {
|
||||
private _port?: number;
|
||||
private _cookies?: Record<string, string>;
|
||||
private _responseHeaders: Headers = new Headers();
|
||||
public res: Response = new Response();
|
||||
|
||||
constructor(
|
||||
public readonly req: Request,
|
||||
|
||||
@ -2,6 +2,7 @@ import { Database, RestBindParameters } from "@db/sqlite";
|
||||
import { err, getMessageFromError, ok, Result } from "@shared/utils/result.ts";
|
||||
import { QueryExecutionError } from "@lib/errors.ts";
|
||||
import { fromNullableVal, none, Option, some } from "@shared/utils/option.ts";
|
||||
import log from "@shared/utils/logger.ts";
|
||||
|
||||
export class DatabaseClient {
|
||||
constructor(private readonly db: Database) {}
|
||||
@ -11,6 +12,7 @@ export class DatabaseClient {
|
||||
return ok(fn());
|
||||
} catch (e) {
|
||||
const message = getMessageFromError(e);
|
||||
log.error(`Failed to execute sql! Error: ${e}`);
|
||||
return err(new QueryExecutionError(message));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Database } from "jsr:@db/sqlite";
|
||||
import log from "@shared/utils/logger.ts";
|
||||
|
||||
const MIGRATION_TABLE = "_keyborgMigrations";
|
||||
|
||||
@ -39,7 +40,7 @@ export class MigrationManager {
|
||||
public init() {
|
||||
if (!this.doesMigrationTableExist()) {
|
||||
if (this.hasExistingTables()) {
|
||||
console.error(
|
||||
log.critical(
|
||||
"Attempting to initialize migrations on a non-empty database.",
|
||||
);
|
||||
Deno.exit(1);
|
||||
@ -49,7 +50,7 @@ export class MigrationManager {
|
||||
}
|
||||
|
||||
if (!this.areMigrationsSequential()) {
|
||||
console.error("Migrations are not applied in sequential order!");
|
||||
log.critical("Migrations are not applied in sequential order!");
|
||||
Deno.exit(1);
|
||||
}
|
||||
this.applyPendingMigrations();
|
||||
@ -182,7 +183,9 @@ export class MigrationManager {
|
||||
try {
|
||||
this.db.exec(sql, params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.critical(
|
||||
`Failed to execute sql while applying migrations! Error: ${e}`,
|
||||
);
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
@ -194,7 +197,9 @@ export class MigrationManager {
|
||||
try {
|
||||
return this.db.prepare(sql).all<T>(params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.critical(
|
||||
`Failed to execute sql while applying migrations! Error: ${e}`,
|
||||
);
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
@ -206,7 +211,9 @@ export class MigrationManager {
|
||||
try {
|
||||
return this.db.prepare(sql).get<T>(params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.critical(
|
||||
`Failed to execute sql while applying migrations! Error: ${e}`,
|
||||
);
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,9 @@ import { Context } from "@lib/context.ts";
|
||||
type RequestHandler<S extends string> = (
|
||||
c: Context<S>,
|
||||
) => Promise<Response> | Response;
|
||||
|
||||
export type Middleware = (
|
||||
c: Context<string>,
|
||||
next: () => Promise<Response>,
|
||||
next: () => Promise<void>,
|
||||
) => Promise<Response | undefined> | Response | undefined;
|
||||
|
||||
type MethodHandlers<S extends string> = Partial<
|
||||
@ -100,12 +99,8 @@ class HttpRouter {
|
||||
): Promise<Response> {
|
||||
const c = new Context(req, connInfo, {});
|
||||
|
||||
for (const mw of this.middlewareChain) {
|
||||
const res = await mw(c);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
let i = 0;
|
||||
const mw = this.middlewareChain[i++];
|
||||
|
||||
const path = this.pathPreprocessor
|
||||
? this.pathPreprocessor(c.path)
|
||||
|
||||
5
server/src/lib/usbip.ts
Normal file
5
server/src/lib/usbip.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import UsbipManager from "@shared/utils/usbip.ts";
|
||||
|
||||
const usbip = new UsbipManager();
|
||||
|
||||
export default usbip;
|
||||
@ -1,4 +1,5 @@
|
||||
import { Middleware } from "@lib/router.ts";
|
||||
import log from "@shared/utils/logger.ts";
|
||||
|
||||
const requestCounts: Partial<
|
||||
Record<string, { count: number; lastReset: number }>
|
||||
@ -27,6 +28,7 @@ const rateLimitMiddleware: Middleware = (c) => {
|
||||
}
|
||||
|
||||
if (c.preferredType.isSome()) {
|
||||
log.info(`client ${hostname} is rate limeted`);
|
||||
switch (c.preferredType.value) {
|
||||
case "html": {
|
||||
return c.html("429 Too Many Requests", {
|
||||
|
||||
3
server/test.tex
Normal file
3
server/test.tex
Normal file
@ -0,0 +1,3 @@
|
||||
quantile
|
||||
|
||||
quntile
|
||||
29
shared/utils/'
Normal file
29
shared/utils/'
Normal file
@ -0,0 +1,29 @@
|
||||
const shellCmd = new Deno.Command("/bin/sh", {
|
||||
stdin: "piped",
|
||||
stdout: "piped",
|
||||
stderr: "piped",
|
||||
});
|
||||
|
||||
const shell = shellCmd.spawn();
|
||||
|
||||
const writer = shell.stdin.getWriter();
|
||||
const stdoutR = shell.stdout.pipeThrough(new TextDecoderStream()).getReader();
|
||||
const stderrR = shell.stderr.pipeThrough(new TextDecoderStream()).getReader();
|
||||
|
||||
const encode = new TextEncoder();
|
||||
//
|
||||
//await writer.write(encode.encode("usbip list -l\n"));
|
||||
//
|
||||
//const value = await stdoutR.read();
|
||||
//
|
||||
//await stdoutR.cancel();
|
||||
//
|
||||
//console.log(value);
|
||||
|
||||
await writer.write(encode.encode("usbip port\n"));
|
||||
|
||||
while (true) {
|
||||
const { value, done } = stderrR.read();
|
||||
}
|
||||
|
||||
shell.kill("SIGTERM");
|
||||
1
shared/utils/2
Normal file
1
shared/utils/2
Normal file
@ -0,0 +1 @@
|
||||
error_
|
||||
2
shared/utils/2usbip
Normal file
2
shared/utils/2usbip
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
1 list -l
|
||||
@ -2,6 +2,8 @@ import { some } from "@shared/utils/option.ts";
|
||||
import { None, type Option, Some } from "@shared/utils/option.ts";
|
||||
import { errAsync, okAsync, ResultAsync } from "@shared/utils/resultasync.ts";
|
||||
|
||||
type ResultJSON<T, E> = { tag: "ok"; value: T } | { tag: "err"; error: E };
|
||||
|
||||
//#region Ok, Err and Result
|
||||
interface IResult<T, E> {
|
||||
isOk(): this is Ok<T, E>;
|
||||
@ -14,8 +16,11 @@ interface IResult<T, E> {
|
||||
unwrapOrElse<U>(fn: () => U): T | U;
|
||||
match<A, B = A>(ok: (value: T) => A, err: (error: E) => B): A | B;
|
||||
map<U>(fn: (value: T) => U): Result<U, E>;
|
||||
mapAsync<U>(fn: (value: T) => Promise<U>): ResultAsync<U, E>;
|
||||
mapErr<U>(fn: (err: E) => U): Result<T, U>;
|
||||
mapErrAsync<U>(fn: (err: E) => Promise<U>): ResultAsync<T, U>;
|
||||
andThen<U, F>(fn: (value: T) => Result<U, F>): Result<U, E | F>;
|
||||
andThenAsync<U, F>(fn: (value: T) => ResultAsync<U, F>): ResultAsync<U, F>;
|
||||
flatten(): FlattenResult<Result<T, E>>;
|
||||
flattenOption<U>(errFn: () => U): Result<UnwrapOption<T>, U | E>;
|
||||
flattenOptionOr<D = UnwrapOption<T>>(
|
||||
@ -29,6 +34,8 @@ interface IResult<T, E> {
|
||||
toNullable(): T | null;
|
||||
toAsync(): ResultAsync<T, E>;
|
||||
void(): Result<void, E>;
|
||||
|
||||
toJSON(): ResultJSON<T, E>;
|
||||
}
|
||||
|
||||
export class Ok<T, E> implements IResult<T, E> {
|
||||
@ -93,6 +100,10 @@ export class Ok<T, E> implements IResult<T, E> {
|
||||
return new Ok<U, E>(mappedValue);
|
||||
}
|
||||
|
||||
mapAsync<U>(fn: (value: T) => Promise<U>): ResultAsync<U, E> {
|
||||
return ResultAsync.fromSafePromise(fn(this.value));
|
||||
}
|
||||
|
||||
mapOption<U>(fn: (value: UnwrapOption<T>) => U): Result<Option<U>, E> {
|
||||
if (this.value instanceof None || this.value instanceof Some) {
|
||||
return ok(this.value.map(fn));
|
||||
@ -104,10 +115,18 @@ export class Ok<T, E> implements IResult<T, E> {
|
||||
return fn(this.value) as Result<U, E | F>;
|
||||
}
|
||||
|
||||
andThenAsync<U, F>(fn: (value: T) => ResultAsync<U, F>): ResultAsync<U, F> {
|
||||
return fn(this.value);
|
||||
}
|
||||
|
||||
mapErr<U>(fn: (err: E) => U): Result<T, U> {
|
||||
return new Ok<T, U>(this.value);
|
||||
}
|
||||
|
||||
mapErrAsync<U>(fn: (err: E) => Promise<U>): ResultAsync<T, U> {
|
||||
return okAsync(this.value);
|
||||
}
|
||||
|
||||
flatten(): FlattenResult<Result<T, E>> {
|
||||
return flattenResult(this);
|
||||
}
|
||||
@ -149,6 +168,13 @@ export class Ok<T, E> implements IResult<T, E> {
|
||||
void(): Result<void, E> {
|
||||
return ok();
|
||||
}
|
||||
|
||||
toJSON(): ResultJSON<T, E> {
|
||||
return {
|
||||
tag: "ok",
|
||||
value: this.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Err<T, E> implements IResult<T, E> {
|
||||
@ -199,10 +225,23 @@ export class Err<T, E> implements IResult<T, E> {
|
||||
map<U>(fn: (value: T) => U): Result<U, E> {
|
||||
return new Err<U, E>(this.error);
|
||||
}
|
||||
mapAsync<U>(fn: (value: T) => Promise<U>): ResultAsync<U, E> {
|
||||
return errAsync(this.error);
|
||||
}
|
||||
mapErr<U>(fn: (err: E) => U): Result<T, U> {
|
||||
const mappedError = fn(this.error);
|
||||
return new Err<T, U>(mappedError);
|
||||
}
|
||||
mapErrAsync<U>(fn: (err: E) => Promise<U>): ResultAsync<T, U> {
|
||||
return ResultAsync.fromPromise(
|
||||
new Promise(() => {
|
||||
throw "";
|
||||
}),
|
||||
() => {
|
||||
return fn(this.error);
|
||||
},
|
||||
);
|
||||
}
|
||||
mapOption<U>(fn: (value: UnwrapOption<T>) => U): Result<Option<U>, E> {
|
||||
return err(this.error);
|
||||
}
|
||||
@ -236,6 +275,12 @@ export class Err<T, E> implements IResult<T, E> {
|
||||
void(): Result<void, E> {
|
||||
return err(this.error);
|
||||
}
|
||||
toJSON(): { tag: "ok"; value: T } | { tag: "err"; error: E } {
|
||||
return {
|
||||
tag: "err",
|
||||
error: this.error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type Result<T, E> = Ok<T, E> | Err<T, E>;
|
||||
@ -314,20 +359,6 @@ export function flattenResult<R extends Result<any, any>>(
|
||||
return currentResult as FlattenResult<R>;
|
||||
}
|
||||
|
||||
export function ResultFromJSON<T = unknown, E = unknown>(
|
||||
str: string,
|
||||
): Result<T, E> {
|
||||
const result: { value: T } | { error: E } = JSON.parse(str);
|
||||
|
||||
if (obj.value) {
|
||||
return ok(obj.value);
|
||||
}
|
||||
|
||||
if (obj.error) {
|
||||
return err(obj.error);
|
||||
}
|
||||
}
|
||||
|
||||
export type UnwrapOption<T> = T extends Option<infer V> ? V : T;
|
||||
|
||||
export type FlattenResult<R> = R extends Result<infer T, infer E>
|
||||
@ -337,3 +368,59 @@ export type FlattenResult<R> = R extends Result<infer T, infer E>
|
||||
: never
|
||||
: R
|
||||
: never;
|
||||
|
||||
class FailedToParseResult extends Error {
|
||||
constructor(json: string) {
|
||||
super(`Failed to parse ${json} as result`);
|
||||
}
|
||||
}
|
||||
|
||||
export function ResultFromJSON<T = unknown, E = unknown>(
|
||||
input: string | unknown,
|
||||
): Result<T, E | FailedToParseResult> {
|
||||
let data: unknown;
|
||||
|
||||
if (typeof input === "string") {
|
||||
try {
|
||||
data = JSON.parse(input);
|
||||
} catch (e) {
|
||||
return err(
|
||||
new FailedToParseResult(getMessageFromError(e)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
data = input;
|
||||
}
|
||||
|
||||
if (typeof data !== "object" || data === null) {
|
||||
return err(
|
||||
new FailedToParseResult(
|
||||
"Expected an object but received type ${typeof data}.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const resultObj = data as ResultJSON<T, E>;
|
||||
if ("tag" in resultObj) {
|
||||
switch (resultObj.tag) {
|
||||
case "ok": {
|
||||
if ("value" in resultObj) {
|
||||
return ok(resultObj.value as T);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "err": {
|
||||
if ("error" in resultObj) {
|
||||
return err(resultObj.error as E);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err(
|
||||
new FailedToParseResult(
|
||||
"Object does not contain 'tag' and 'value' or 'error' property",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {
|
||||
Err,
|
||||
type UnwrapOption,
|
||||
FlattenResult,
|
||||
Ok,
|
||||
type Result,
|
||||
FlattenResult,
|
||||
type UnwrapOption,
|
||||
} from "@shared/utils/result.ts";
|
||||
import { none, None, Option, some, Some } from "@shared/utils/option.ts";
|
||||
import { None, none, Option, Some, some } from "@shared/utils/option.ts";
|
||||
|
||||
export class ResultAsync<T, E> implements PromiseLike<Result<T, E>> {
|
||||
constructor(private readonly _promise: Promise<Result<T, E>>) {
|
||||
@ -37,22 +37,33 @@ export class ResultAsync<T, E> implements PromiseLike<Result<T, E>> {
|
||||
return new ResultAsync<T, never>(promiseOfResult);
|
||||
}
|
||||
|
||||
static fromThrowable<Fn extends (...args: readonly any[]) => any, E>(
|
||||
static fromThrowable<
|
||||
Fn extends (...args: readonly any[]) => Promise<any>,
|
||||
Em extends ErrorMapper<any>,
|
||||
>(
|
||||
fn: Fn,
|
||||
errorMapper?: (e: unknown) => E,
|
||||
): (...args: Parameters<Fn>) => ResultAsync<ReturnType<Fn>, E> {
|
||||
return (...args: Parameters<Fn>): ResultAsync<ReturnType<Fn>, E> => {
|
||||
try {
|
||||
return okAsync(fn(args));
|
||||
} catch (e) {
|
||||
return errAsync(errorMapper ? errorMapper(e) : e);
|
||||
}
|
||||
errorMapper?: Em,
|
||||
): (
|
||||
...args: Parameters<Fn>
|
||||
) => ResultAsync<
|
||||
UnwrapPromise<ReturnType<Fn>>,
|
||||
ExtractErrorFromMapper<Em>
|
||||
> {
|
||||
return (
|
||||
...args: Parameters<Fn>
|
||||
): ResultAsync<
|
||||
UnwrapPromise<ReturnType<Fn>>,
|
||||
ExtractErrorFromMapper<Em>
|
||||
> => {
|
||||
return ResultAsync.fromPromise(
|
||||
fn(args),
|
||||
(e) => errorMapper ? errorMapper(e) : e,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
async unwrap(): Promise<T> {
|
||||
const result = await this._promise;
|
||||
|
||||
if (result.isErr()) {
|
||||
throw result.error;
|
||||
}
|
||||
@ -124,7 +135,23 @@ export class ResultAsync<T, E> implements PromiseLike<Result<T, E>> {
|
||||
);
|
||||
}
|
||||
|
||||
andThen<U, F>(fn: (value: T) => ResultAsync<U, F>): ResultAsync<U, E | F> {
|
||||
andThen<U, F>(fn: (value: T) => Result<U, F>): ResultAsync<U, E | F> {
|
||||
return new ResultAsync(
|
||||
this._promise.then(
|
||||
(result: Result<T, E>): ResultAsync<U, E | F> => {
|
||||
if (result.isErr()) {
|
||||
return errAsync(result.error);
|
||||
}
|
||||
|
||||
return fn(result.value).toAsync() as ResultAsync<U, E | F>;
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
andThenAsync<U, F>(
|
||||
fn: (value: T) => ResultAsync<U, F>,
|
||||
): ResultAsync<U, E | F> {
|
||||
return new ResultAsync(
|
||||
this._promise.then(
|
||||
(result: Result<T, E>): ResultAsync<U, E | F> => {
|
||||
@ -227,11 +254,19 @@ export function errAsync<E, T = never>(err: E): ResultAsync<T, E> {
|
||||
return new ResultAsync(Promise.resolve(new Err<T, E>(err)));
|
||||
}
|
||||
|
||||
export type FlattenResultAsync<R> =
|
||||
R extends ResultAsync<infer T, infer E>
|
||||
export type FlattenResultAsync<R> = R extends ResultAsync<infer T, infer E>
|
||||
? T extends ResultAsync<any, any>
|
||||
? FlattenResultAsync<T> extends ResultAsync<infer V, infer innerE>
|
||||
? ResultAsync<V, E | innerE>
|
||||
: never
|
||||
: R
|
||||
: never;
|
||||
|
||||
type UnwrapPromise<Pr extends Promise<unknown>> = Pr extends Promise<infer U>
|
||||
? U
|
||||
: never;
|
||||
|
||||
type ErrorMapper<E> = ((e: unknown) => E) | undefined;
|
||||
|
||||
type ExtractErrorFromMapper<Em extends ErrorMapper<unknown>> = Em extends
|
||||
(e: unknown) => infer E ? E : unknown;
|
||||
|
||||
283
shared/utils/usbip.ts
Normal file
283
shared/utils/usbip.ts
Normal file
@ -0,0 +1,283 @@
|
||||
import { okAsync, ResultAsync } from "@shared/utils/resultasync.ts";
|
||||
import { err, getMessageFromError, ok } from "@shared/utils/result.ts";
|
||||
import { errAsync } from "@shared/utils/index.ts";
|
||||
import log from "@shared/utils/logger.ts";
|
||||
import {
|
||||
fromNullableVal,
|
||||
none,
|
||||
type Option,
|
||||
some,
|
||||
} from "@shared/utils/option.ts";
|
||||
|
||||
class CommandExecutionError extends Error {
|
||||
code = "CommandExecutionError";
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceDoesNotExistError extends Error {
|
||||
code = "DeviceDoesNotExist";
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceAlreadyBoundError extends Error {
|
||||
code = "DeviceAlreadyBound";
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceNotBound extends Error {
|
||||
code = "DeviceNotBound";
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
class UsbipUknownError extends Error {
|
||||
code = "UsbipUknownError";
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
type UsbipCommonError = DeviceDoesNotExistError | UsbipUknownError;
|
||||
|
||||
class UsbipManager {
|
||||
private readonly listDeatiledCmd = new Deno.Command("usbip", {
|
||||
args: ["list", "-l"],
|
||||
});
|
||||
private readonly listParsableCmd = new Deno.Command("usbip", {
|
||||
args: ["list", "-pl"],
|
||||
});
|
||||
private readonly decoder = new TextDecoder();
|
||||
|
||||
private readonly usbidRegex = /[0-9abcdef]{4}:[0-9abcdef]{4}/;
|
||||
private readonly busidRegex =
|
||||
/(?:[0-9]+(?:\.[0-9]+)*-)*[0-9]+(?:\.[0-9]+)*/;
|
||||
|
||||
private executeCommand(
|
||||
cmd: Deno.Command,
|
||||
): ResultAsync<CommandOutput, CommandExecutionError> {
|
||||
const promise = cmd.output();
|
||||
|
||||
return ResultAsync.fromPromise(
|
||||
promise,
|
||||
(e) => new CommandExecutionError(getMessageFromError(e)),
|
||||
)
|
||||
.map(({ stdout, stderr, code }) =>
|
||||
new CommandOutput(
|
||||
this.decoder.decode(stdout).trim(),
|
||||
this.decoder.decode(stderr).trim(),
|
||||
code,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private handleCommonErrors(stderr: string): UsbipCommonError {
|
||||
if (
|
||||
stderr.includes("device with the specified bus ID does not exist")
|
||||
) {
|
||||
return new DeviceDoesNotExistError(stderr);
|
||||
}
|
||||
|
||||
return new UsbipUknownError(stderr);
|
||||
}
|
||||
|
||||
private parseDetailedList(stdout: string): Option<DeviceDetailed[]> {
|
||||
const devices: DeviceDetailed[] = [];
|
||||
|
||||
const deviceEntries = stdout.trim().split("\n\n");
|
||||
|
||||
for (const deviceEntry of deviceEntries) {
|
||||
const busid = deviceEntry.match(this.busidRegex)?.shift();
|
||||
|
||||
if (!busid) {
|
||||
log.error(
|
||||
`Failed to parse busid of a device:\n ${deviceEntry}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const usbid = fromNullableVal(
|
||||
deviceEntry.match(this.usbidRegex)?.shift(),
|
||||
);
|
||||
|
||||
const [_, line2] = deviceEntry.split("\n");
|
||||
|
||||
const [vendorVal, nameVal] = line2
|
||||
? line2.split(" : ").map((s) => s.trim())
|
||||
: [undefined, undefined];
|
||||
|
||||
const vendor = fromNullableVal(vendorVal);
|
||||
const name = nameVal
|
||||
? some(
|
||||
nameVal.replace(
|
||||
usbid.isSome() ? usbid.value : this.usbidRegex,
|
||||
"",
|
||||
).replace("()", "")
|
||||
.trim(),
|
||||
)
|
||||
: none;
|
||||
|
||||
[["usbid", usbid], ["vendor", vendor], ["name", name]].filter((v) =>
|
||||
(v[1] as Option<string>).isNone()
|
||||
).map((v) => log.warn(`Failed to parse ${v[0]}:\n ${deviceEntry}`));
|
||||
|
||||
devices.push({
|
||||
busid,
|
||||
usbid,
|
||||
vendor,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
return devices.length > 0 ? some(devices) : none;
|
||||
}
|
||||
|
||||
public getDevicesDetailed(): ResultAsync<
|
||||
Option<DeviceDetailed[]>,
|
||||
CommandExecutionError | UsbipUknownError
|
||||
> {
|
||||
return this.executeCommand(this.listDeatiledCmd).andThen(
|
||||
({ stdout, stderr, success }) => {
|
||||
if (success) {
|
||||
if (stderr) {
|
||||
log.warn(
|
||||
`usbip list -l succeeded but encountered an error: ${stderr}`,
|
||||
);
|
||||
}
|
||||
return ok(this.parseDetailedList(stdout));
|
||||
}
|
||||
|
||||
return err(new UsbipUknownError(stderr));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private parseParsableList(stdout: string): Option<Device[]> {
|
||||
const devices: Device[] = [];
|
||||
|
||||
const devicesEntries = stdout.trim().split("\n");
|
||||
|
||||
for (const deviceEntry of devicesEntries) {
|
||||
const [busid, usbid] = deviceEntry
|
||||
.slice(0, -1)
|
||||
.split("#")
|
||||
.map((v) => v.split("=")[1].trim() || undefined);
|
||||
|
||||
if (!busid) {
|
||||
log.error(
|
||||
`Failed to parse busid of a device:\n ${deviceEntry}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!usbid) {
|
||||
log.warn(
|
||||
`Failed to parse usbid of a device:\n ${deviceEntry}`,
|
||||
);
|
||||
}
|
||||
|
||||
devices.push({
|
||||
busid,
|
||||
usbid: fromNullableVal(usbid),
|
||||
});
|
||||
}
|
||||
|
||||
return devices.length > 0 ? some(devices) : none;
|
||||
}
|
||||
|
||||
public getDevices(): ResultAsync<
|
||||
Option<Device[]>,
|
||||
CommandExecutionError | UsbipUknownError
|
||||
> {
|
||||
return this.executeCommand(this.listParsableCmd).andThenAsync(
|
||||
({ stdout, stderr, success }) => {
|
||||
if (success) {
|
||||
if (stderr) {
|
||||
log.warn(
|
||||
`usbip list -lp succeeded but encountered an error: ${stderr}`,
|
||||
);
|
||||
}
|
||||
return okAsync(this.parseParsableList(stdout));
|
||||
}
|
||||
return errAsync(new UsbipUknownError(stderr));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public bindDevice(
|
||||
busid: string,
|
||||
): ResultAsync<
|
||||
string,
|
||||
UsbipCommonError | DeviceAlreadyBoundError | CommandExecutionError
|
||||
> {
|
||||
const cmd = new Deno.Command("usbip", { args: ["bind", "-b", busid] });
|
||||
|
||||
return this.executeCommand(cmd).andThen(
|
||||
({ stderr, success }) => {
|
||||
if (success) {
|
||||
return ok(stderr.trim() || "Device bound successfully");
|
||||
}
|
||||
|
||||
if (stderr.includes("is already bound to usbip-host")) {
|
||||
return err(new DeviceAlreadyBoundError(stderr));
|
||||
}
|
||||
|
||||
return err(this.handleCommonErrors(stderr));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public unbindDevice(
|
||||
busid: string,
|
||||
): ResultAsync<
|
||||
string,
|
||||
CommandExecutionError | DeviceNotBound | UsbipCommonError
|
||||
> {
|
||||
const cmd = new Deno.Command("usbip", {
|
||||
args: ["unbind", "-b", busid],
|
||||
});
|
||||
|
||||
return this.executeCommand(cmd).andThen(({ stderr, success }) => {
|
||||
if (success) {
|
||||
return ok(stderr.trim() || "Device unbound successfully");
|
||||
}
|
||||
|
||||
if (stderr.includes("device is not bound to usbip-host driver")) {
|
||||
return err(new DeviceNotBound(stderr));
|
||||
}
|
||||
|
||||
return err(this.handleCommonErrors(stderr));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CommandOutput {
|
||||
constructor(
|
||||
public readonly stdout: string,
|
||||
public readonly stderr: string,
|
||||
public readonly code: number,
|
||||
) {}
|
||||
get success(): boolean {
|
||||
return this.code === 0;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeviceDetailed {
|
||||
busid: string;
|
||||
usbid: Option<string>;
|
||||
vendor: Option<string>;
|
||||
name: Option<string>;
|
||||
}
|
||||
|
||||
interface Device {
|
||||
busid: string;
|
||||
usbid: Option<string>;
|
||||
}
|
||||
|
||||
export default UsbipManager;
|
||||
107
shared/utils/usbipTest.ts
Normal file
107
shared/utils/usbipTest.ts
Normal file
@ -0,0 +1,107 @@
|
||||
import { ResultAsync } from "@shared/utils/resultasync.ts";
|
||||
import { getMessageFromError } from "@shared/utils/result.ts";
|
||||
|
||||
const shellCmd = new Deno.Command("/bin/sh", {
|
||||
stdin: "piped",
|
||||
stdout: "piped",
|
||||
stderr: "piped",
|
||||
});
|
||||
|
||||
class UsbipController {
|
||||
private shell = shellCmd.spawn();
|
||||
private stdinWriter = this.shell.stdin.getWriter();
|
||||
private stdoutReader = this.shell.stdout.pipeThrough(
|
||||
new TextDecoderStream(),
|
||||
).getReader();
|
||||
private stderrReader = this.shell.stderr.pipeThrough(
|
||||
new TextDecoderStream(),
|
||||
).getReader();
|
||||
private readonly encoder = new TextEncoder();
|
||||
private readonly marker = "___FINISHED___";
|
||||
|
||||
constructor() {}
|
||||
|
||||
run(cmd: string): ResultAsync<CommandOutput, string> {
|
||||
return ResultAsync.fromPromise(
|
||||
(async () => {
|
||||
cmd = `${cmd}\necho ${this.marker}\necho ${this.marker} >&2\n`;
|
||||
|
||||
await this.stdinWriter.write(this.encoder.encode(
|
||||
cmd,
|
||||
));
|
||||
|
||||
let outFinished = false, errFinished = false;
|
||||
let stdout = "", stderr = "";
|
||||
|
||||
while (!outFinished || !errFinished) {
|
||||
if (!outFinished) {
|
||||
const { value } = await this.stdoutReader.read();
|
||||
if (!outFinished) {
|
||||
if (
|
||||
value?.includes(this.marker)
|
||||
) {
|
||||
stdout = stdout.trim();
|
||||
outFinished = true;
|
||||
} else {
|
||||
stdout += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!errFinished) {
|
||||
const { value } = await this.stderrReader.read();
|
||||
if (!errFinished) {
|
||||
if (
|
||||
value?.includes(this.marker)
|
||||
) {
|
||||
stderr = stderr.trim();
|
||||
errFinished = true;
|
||||
} else {
|
||||
stderr += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
stdout: stdout.trim(),
|
||||
stderr: stderr.trim(),
|
||||
};
|
||||
})(),
|
||||
(e) => getMessageFromError(e),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface CommandOutput {
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
const usbip = new UsbipController();
|
||||
|
||||
let a = 0;
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const t = performance.now();
|
||||
console.log(await usbip.run("usbip list -l"));
|
||||
a += performance.now() - t;
|
||||
}
|
||||
|
||||
console.log(a / 100);
|
||||
|
||||
//await usbip.run("usbip list -l");
|
||||
//await usbip.run("usbip list -l");
|
||||
//await usbip.run("usbip list -l");
|
||||
//await usbip.run("usbip list -l");
|
||||
|
||||
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
|
||||
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
|
||||
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
|
||||
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
|
||||
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
|
||||
|
||||
//const decoder = new TextDecoder();
|
||||
//
|
||||
//const now1 = new Date().getTime();
|
||||
//
|
||||
Deno.exit(0);
|
||||
9
vendor/deno.land/std@0.203.0/assert/assert.ts
vendored
Normal file
9
vendor/deno.land/std@0.203.0/assert/assert.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Make an assertion, error will be thrown if `expr` does not have truthy value. */
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
7
vendor/deno.land/std@0.203.0/assert/assertion_error.ts
vendored
Normal file
7
vendor/deno.land/std@0.203.0/assert/assertion_error.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
export class AssertionError extends Error {
|
||||
override name = "AssertionError";
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
151
vendor/deno.land/std@0.203.0/async/abortable.ts
vendored
Normal file
151
vendor/deno.land/std@0.203.0/async/abortable.ts
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { deferred } from "./deferred.ts";
|
||||
|
||||
/**
|
||||
* Make Promise abortable with the given signal.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { abortable } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
*
|
||||
* const p = delay(1000);
|
||||
* const c = new AbortController();
|
||||
* setTimeout(() => c.abort(), 100);
|
||||
*
|
||||
* // Below throws `DOMException` after 100 ms
|
||||
* await abortable(p, c.signal);
|
||||
* ```
|
||||
*/
|
||||
export function abortable<T>(p: Promise<T>, signal: AbortSignal): Promise<T>;
|
||||
/**
|
||||
* Make AsyncIterable abortable with the given signal.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { abortable } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
*
|
||||
* const p = async function* () {
|
||||
* yield "Hello";
|
||||
* await delay(1000);
|
||||
* yield "World";
|
||||
* };
|
||||
* const c = new AbortController();
|
||||
* setTimeout(() => c.abort(), 100);
|
||||
*
|
||||
* // Below throws `DOMException` after 100 ms
|
||||
* // and items become `["Hello"]`
|
||||
* const items: string[] = [];
|
||||
* for await (const item of abortable(p(), c.signal)) {
|
||||
* items.push(item);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function abortable<T>(
|
||||
p: AsyncIterable<T>,
|
||||
signal: AbortSignal,
|
||||
): AsyncGenerator<T>;
|
||||
export function abortable<T>(
|
||||
p: Promise<T> | AsyncIterable<T>,
|
||||
signal: AbortSignal,
|
||||
): Promise<T> | AsyncIterable<T> {
|
||||
if (p instanceof Promise) {
|
||||
return abortablePromise(p, signal);
|
||||
} else {
|
||||
return abortableAsyncIterable(p, signal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make Promise abortable with the given signal.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { abortablePromise } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
*
|
||||
* const request = fetch("https://example.com");
|
||||
*
|
||||
* const c = new AbortController();
|
||||
* setTimeout(() => c.abort(), 100);
|
||||
*
|
||||
* const p = abortablePromise(request, c.signal);
|
||||
*
|
||||
* // The below throws if the request didn't resolve in 100ms
|
||||
* await p;
|
||||
* ```
|
||||
*/
|
||||
export function abortablePromise<T>(
|
||||
p: Promise<T>,
|
||||
signal: AbortSignal,
|
||||
): Promise<T> {
|
||||
if (signal.aborted) {
|
||||
return Promise.reject(createAbortError(signal.reason));
|
||||
}
|
||||
const waiter = deferred<never>();
|
||||
const abort = () => waiter.reject(createAbortError(signal.reason));
|
||||
signal.addEventListener("abort", abort, { once: true });
|
||||
return Promise.race([
|
||||
waiter,
|
||||
p.finally(() => {
|
||||
signal.removeEventListener("abort", abort);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make AsyncIterable abortable with the given signal.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { abortableAsyncIterable } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
*
|
||||
* const p = async function* () {
|
||||
* yield "Hello";
|
||||
* await delay(1000);
|
||||
* yield "World";
|
||||
* };
|
||||
* const c = new AbortController();
|
||||
* setTimeout(() => c.abort(), 100);
|
||||
*
|
||||
* // Below throws `DOMException` after 100 ms
|
||||
* // and items become `["Hello"]`
|
||||
* const items: string[] = [];
|
||||
* for await (const item of abortableAsyncIterable(p(), c.signal)) {
|
||||
* items.push(item);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export async function* abortableAsyncIterable<T>(
|
||||
p: AsyncIterable<T>,
|
||||
signal: AbortSignal,
|
||||
): AsyncGenerator<T> {
|
||||
if (signal.aborted) {
|
||||
throw createAbortError(signal.reason);
|
||||
}
|
||||
const waiter = deferred<never>();
|
||||
const abort = () => waiter.reject(createAbortError(signal.reason));
|
||||
signal.addEventListener("abort", abort, { once: true });
|
||||
|
||||
const it = p[Symbol.asyncIterator]();
|
||||
while (true) {
|
||||
const { done, value } = await Promise.race([waiter, it.next()]);
|
||||
if (done) {
|
||||
signal.removeEventListener("abort", abort);
|
||||
return;
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
|
||||
// This `reason` comes from `AbortSignal` thus must be `any`.
|
||||
// deno-lint-ignore no-explicit-any
|
||||
function createAbortError(reason?: any): DOMException {
|
||||
return new DOMException(
|
||||
reason ? `Aborted: ${reason}` : "Aborted",
|
||||
"AbortError",
|
||||
);
|
||||
}
|
||||
48
vendor/deno.land/std@0.203.0/async/deadline.ts
vendored
Normal file
48
vendor/deno.land/std@0.203.0/async/deadline.ts
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { delay } from "./delay.ts";
|
||||
|
||||
export interface DeadlineOptions {
|
||||
/** Signal used to abort the deadline. */
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
export class DeadlineError extends Error {
|
||||
constructor() {
|
||||
super("Deadline");
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a promise which will be rejected with {@linkcode DeadlineError} when a given delay is exceeded.
|
||||
*
|
||||
* NOTE: Prefer to use `AbortSignal.timeout` instead for the APIs accept `AbortSignal`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { deadline } from "https://deno.land/std@$STD_VERSION/async/deadline.ts";
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/delay.ts";
|
||||
*
|
||||
* const delayedPromise = delay(1000);
|
||||
* // Below throws `DeadlineError` after 10 ms
|
||||
* const result = await deadline(delayedPromise, 10);
|
||||
* ```
|
||||
*/
|
||||
export function deadline<T>(
|
||||
p: Promise<T>,
|
||||
ms: number,
|
||||
options: DeadlineOptions = {},
|
||||
): Promise<T> {
|
||||
const controller = new AbortController();
|
||||
const { signal } = options;
|
||||
if (signal?.aborted) {
|
||||
return Promise.reject(new DeadlineError());
|
||||
}
|
||||
signal?.addEventListener("abort", () => controller.abort(signal.reason));
|
||||
const d = delay(ms, { signal: controller.signal })
|
||||
.catch(() => {}) // Do NOTHING on abort.
|
||||
.then(() => Promise.reject(new DeadlineError()));
|
||||
return Promise.race([p.finally(() => controller.abort()), d]);
|
||||
}
|
||||
79
vendor/deno.land/std@0.203.0/async/debounce.ts
vendored
Normal file
79
vendor/deno.land/std@0.203.0/async/debounce.ts
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* A debounced function that will be delayed by a given `wait`
|
||||
* time in milliseconds. If the method is called again before
|
||||
* the timeout expires, the previous call will be aborted.
|
||||
*/
|
||||
export interface DebouncedFunction<T extends Array<unknown>> {
|
||||
(...args: T): void;
|
||||
/** Clears the debounce timeout and omits calling the debounced function. */
|
||||
clear(): void;
|
||||
/** Clears the debounce timeout and calls the debounced function immediately. */
|
||||
flush(): void;
|
||||
/** Returns a boolean whether a debounce call is pending or not. */
|
||||
readonly pending: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a debounced function that delays the given `func`
|
||||
* by a given `wait` time in milliseconds. If the method is called
|
||||
* again before the timeout expires, the previous call will be
|
||||
* aborted.
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* import { debounce } from "https://deno.land/std@$STD_VERSION/async/debounce.ts";
|
||||
*
|
||||
* const log = debounce(
|
||||
* (event: Deno.FsEvent) =>
|
||||
* console.log("[%s] %s", event.kind, event.paths[0]),
|
||||
* 200,
|
||||
* );
|
||||
*
|
||||
* for await (const event of Deno.watchFs("./")) {
|
||||
* log(event);
|
||||
* }
|
||||
* // wait 200ms ...
|
||||
* // output: Function debounced after 200ms with baz
|
||||
* ```
|
||||
*
|
||||
* @param fn The function to debounce.
|
||||
* @param wait The time in milliseconds to delay the function.
|
||||
*/
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export function debounce<T extends Array<any>>(
|
||||
fn: (this: DebouncedFunction<T>, ...args: T) => void,
|
||||
wait: number,
|
||||
): DebouncedFunction<T> {
|
||||
let timeout: number | null = null;
|
||||
let flush: (() => void) | null = null;
|
||||
|
||||
const debounced: DebouncedFunction<T> = ((...args: T) => {
|
||||
debounced.clear();
|
||||
flush = () => {
|
||||
debounced.clear();
|
||||
fn.call(debounced, ...args);
|
||||
};
|
||||
timeout = setTimeout(flush, wait);
|
||||
}) as DebouncedFunction<T>;
|
||||
|
||||
debounced.clear = () => {
|
||||
if (typeof timeout === "number") {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
flush = null;
|
||||
}
|
||||
};
|
||||
|
||||
debounced.flush = () => {
|
||||
flush?.();
|
||||
};
|
||||
|
||||
Object.defineProperty(debounced, "pending", {
|
||||
get: () => typeof timeout === "number",
|
||||
});
|
||||
|
||||
return debounced;
|
||||
}
|
||||
48
vendor/deno.land/std@0.203.0/async/deferred.ts
vendored
Normal file
48
vendor/deno.land/std@0.203.0/async/deferred.ts
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
// TODO(ry) It'd be better to make Deferred a class that inherits from
|
||||
// Promise, rather than an interface. This is possible in ES2016, however
|
||||
// typescript produces broken code when targeting ES5 code.
|
||||
// See https://github.com/Microsoft/TypeScript/issues/15202
|
||||
// At the time of writing, the github issue is closed but the problem remains.
|
||||
export interface Deferred<T> extends Promise<T> {
|
||||
readonly state: "pending" | "fulfilled" | "rejected";
|
||||
resolve(value?: T | PromiseLike<T>): void;
|
||||
// deno-lint-ignore no-explicit-any
|
||||
reject(reason?: any): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Promise with the `reject` and `resolve` functions placed as methods
|
||||
* on the promise object itself.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { deferred } from "https://deno.land/std@$STD_VERSION/async/deferred.ts";
|
||||
*
|
||||
* const p = deferred<number>();
|
||||
* // ...
|
||||
* p.resolve(42);
|
||||
* ```
|
||||
*/
|
||||
export function deferred<T>(): Deferred<T> {
|
||||
let methods;
|
||||
let state = "pending";
|
||||
const promise = new Promise<T>((resolve, reject) => {
|
||||
methods = {
|
||||
async resolve(value: T | PromiseLike<T>) {
|
||||
await value;
|
||||
state = "fulfilled";
|
||||
resolve(value);
|
||||
},
|
||||
// deno-lint-ignore no-explicit-any
|
||||
reject(reason?: any) {
|
||||
state = "rejected";
|
||||
reject(reason);
|
||||
},
|
||||
};
|
||||
});
|
||||
Object.defineProperty(promise, "state", { get: () => state });
|
||||
return Object.assign(promise, methods) as Deferred<T>;
|
||||
}
|
||||
65
vendor/deno.land/std@0.203.0/async/delay.ts
vendored
Normal file
65
vendor/deno.land/std@0.203.0/async/delay.ts
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
export interface DelayOptions {
|
||||
/** Signal used to abort the delay. */
|
||||
signal?: AbortSignal;
|
||||
/** Indicates whether the process should continue to run as long as the timer exists.
|
||||
*
|
||||
* @default {true}
|
||||
*/
|
||||
persistent?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a Promise after a given amount of milliseconds.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```typescript
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/delay.ts";
|
||||
*
|
||||
* // ...
|
||||
* const delayedPromise = delay(100);
|
||||
* const result = await delayedPromise;
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* To allow the process to continue to run as long as the timer exists. Requires
|
||||
* `--unstable` flag.
|
||||
*
|
||||
* ```typescript
|
||||
* import { delay } from "https://deno.land/std@$STD_VERSION/async/delay.ts";
|
||||
*
|
||||
* // ...
|
||||
* await delay(100, { persistent: false });
|
||||
* // ...
|
||||
* ```
|
||||
*/
|
||||
export function delay(ms: number, options: DelayOptions = {}): Promise<void> {
|
||||
const { signal, persistent } = options;
|
||||
if (signal?.aborted) return Promise.reject(signal.reason);
|
||||
return new Promise((resolve, reject) => {
|
||||
const abort = () => {
|
||||
clearTimeout(i);
|
||||
reject(signal?.reason);
|
||||
};
|
||||
const done = () => {
|
||||
signal?.removeEventListener("abort", abort);
|
||||
resolve();
|
||||
};
|
||||
const i = setTimeout(done, ms);
|
||||
signal?.addEventListener("abort", abort, { once: true });
|
||||
if (persistent === false) {
|
||||
try {
|
||||
// @ts-ignore For browser compatibility
|
||||
Deno.unrefTimer(i);
|
||||
} catch (error) {
|
||||
if (!(error instanceof ReferenceError)) {
|
||||
throw error;
|
||||
}
|
||||
console.error("`persistent` option is only available in Deno");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
18
vendor/deno.land/std@0.203.0/async/mod.ts
vendored
Normal file
18
vendor/deno.land/std@0.203.0/async/mod.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/**
|
||||
* Provide help with asynchronous tasks like delays, debouncing, deferring, or
|
||||
* pooling.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
export * from "./abortable.ts";
|
||||
export * from "./deadline.ts";
|
||||
export * from "./debounce.ts";
|
||||
export * from "./deferred.ts";
|
||||
export * from "./delay.ts";
|
||||
export * from "./mux_async_iterator.ts";
|
||||
export * from "./pool.ts";
|
||||
export * from "./tee.ts";
|
||||
export * from "./retry.ts";
|
||||
97
vendor/deno.land/std@0.203.0/async/mux_async_iterator.ts
vendored
Normal file
97
vendor/deno.land/std@0.203.0/async/mux_async_iterator.ts
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { Deferred, deferred } from "./deferred.ts";
|
||||
|
||||
interface TaggedYieldedValue<T> {
|
||||
iterator: AsyncIterator<T>;
|
||||
value: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* The MuxAsyncIterator class multiplexes multiple async iterators into a single
|
||||
* stream. It currently makes an assumption that the final result (the value
|
||||
* returned and not yielded from the iterator) does not matter; if there is any
|
||||
* result, it is discarded.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { MuxAsyncIterator } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
*
|
||||
* async function* gen123(): AsyncIterableIterator<number> {
|
||||
* yield 1;
|
||||
* yield 2;
|
||||
* yield 3;
|
||||
* }
|
||||
*
|
||||
* async function* gen456(): AsyncIterableIterator<number> {
|
||||
* yield 4;
|
||||
* yield 5;
|
||||
* yield 6;
|
||||
* }
|
||||
*
|
||||
* const mux = new MuxAsyncIterator<number>();
|
||||
* mux.add(gen123());
|
||||
* mux.add(gen456());
|
||||
* for await (const value of mux) {
|
||||
* // ...
|
||||
* }
|
||||
* // ..
|
||||
* ```
|
||||
*/
|
||||
export class MuxAsyncIterator<T> implements AsyncIterable<T> {
|
||||
#iteratorCount = 0;
|
||||
#yields: Array<TaggedYieldedValue<T>> = [];
|
||||
// deno-lint-ignore no-explicit-any
|
||||
#throws: any[] = [];
|
||||
#signal: Deferred<void> = deferred();
|
||||
|
||||
add(iterable: AsyncIterable<T>) {
|
||||
++this.#iteratorCount;
|
||||
this.#callIteratorNext(iterable[Symbol.asyncIterator]());
|
||||
}
|
||||
|
||||
async #callIteratorNext(
|
||||
iterator: AsyncIterator<T>,
|
||||
) {
|
||||
try {
|
||||
const { value, done } = await iterator.next();
|
||||
if (done) {
|
||||
--this.#iteratorCount;
|
||||
} else {
|
||||
this.#yields.push({ iterator, value });
|
||||
}
|
||||
} catch (e) {
|
||||
this.#throws.push(e);
|
||||
}
|
||||
this.#signal.resolve();
|
||||
}
|
||||
|
||||
async *iterate(): AsyncIterableIterator<T> {
|
||||
while (this.#iteratorCount > 0) {
|
||||
// Sleep until any of the wrapped iterators yields.
|
||||
await this.#signal;
|
||||
|
||||
// Note that while we're looping over `yields`, new items may be added.
|
||||
for (let i = 0; i < this.#yields.length; i++) {
|
||||
const { iterator, value } = this.#yields[i];
|
||||
yield value;
|
||||
this.#callIteratorNext(iterator);
|
||||
}
|
||||
|
||||
if (this.#throws.length) {
|
||||
for (const e of this.#throws) {
|
||||
throw e;
|
||||
}
|
||||
this.#throws.length = 0;
|
||||
}
|
||||
// Clear the `yields` list and reset the `signal` promise.
|
||||
this.#yields.length = 0;
|
||||
this.#signal = deferred();
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.asyncIterator](): AsyncIterator<T> {
|
||||
return this.iterate();
|
||||
}
|
||||
}
|
||||
108
vendor/deno.land/std@0.203.0/async/pool.ts
vendored
Normal file
108
vendor/deno.land/std@0.203.0/async/pool.ts
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
export const ERROR_WHILE_MAPPING_MESSAGE = "Threw while mapping.";
|
||||
|
||||
/**
|
||||
* pooledMap transforms values from an (async) iterable into another async
|
||||
* iterable. The transforms are done concurrently, with a max concurrency
|
||||
* defined by the poolLimit.
|
||||
*
|
||||
* If an error is thrown from `iterableFn`, no new transformations will begin.
|
||||
* All currently executing transformations are allowed to finish and still
|
||||
* yielded on success. After that, the rejections among them are gathered and
|
||||
* thrown by the iterator in an `AggregateError`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { pooledMap } from "https://deno.land/std@$STD_VERSION/async/pool.ts";
|
||||
*
|
||||
* const results = pooledMap(
|
||||
* 2,
|
||||
* [1, 2, 3],
|
||||
* (i) => new Promise((r) => setTimeout(() => r(i), 1000)),
|
||||
* );
|
||||
*
|
||||
* for await (const value of results) {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param poolLimit The maximum count of items being processed concurrently.
|
||||
* @param array The input array for mapping.
|
||||
* @param iteratorFn The function to call for every item of the array.
|
||||
*/
|
||||
export function pooledMap<T, R>(
|
||||
poolLimit: number,
|
||||
array: Iterable<T> | AsyncIterable<T>,
|
||||
iteratorFn: (data: T) => Promise<R>,
|
||||
): AsyncIterableIterator<R> {
|
||||
// Create the async iterable that is returned from this function.
|
||||
const res = new TransformStream<Promise<R>, R>({
|
||||
async transform(
|
||||
p: Promise<R>,
|
||||
controller: TransformStreamDefaultController<R>,
|
||||
) {
|
||||
try {
|
||||
const s = await p;
|
||||
controller.enqueue(s);
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof AggregateError &&
|
||||
e.message === ERROR_WHILE_MAPPING_MESSAGE
|
||||
) {
|
||||
controller.error(e as unknown);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
// Start processing items from the iterator
|
||||
(async () => {
|
||||
const writer = res.writable.getWriter();
|
||||
const executing: Array<Promise<unknown>> = [];
|
||||
try {
|
||||
for await (const item of array) {
|
||||
const p = Promise.resolve().then(() => iteratorFn(item));
|
||||
// Only write on success. If we `writer.write()` a rejected promise,
|
||||
// that will end the iteration. We don't want that yet. Instead let it
|
||||
// fail the race, taking us to the catch block where all currently
|
||||
// executing jobs are allowed to finish and all rejections among them
|
||||
// can be reported together.
|
||||
writer.write(p);
|
||||
const e: Promise<unknown> = p.then(() =>
|
||||
executing.splice(executing.indexOf(e), 1)
|
||||
);
|
||||
executing.push(e);
|
||||
if (executing.length >= poolLimit) {
|
||||
await Promise.race(executing);
|
||||
}
|
||||
}
|
||||
// Wait until all ongoing events have processed, then close the writer.
|
||||
await Promise.all(executing);
|
||||
writer.close();
|
||||
} catch {
|
||||
const errors = [];
|
||||
for (const result of await Promise.allSettled(executing)) {
|
||||
if (result.status === "rejected") {
|
||||
errors.push(result.reason);
|
||||
}
|
||||
}
|
||||
writer.write(Promise.reject(
|
||||
new AggregateError(errors, ERROR_WHILE_MAPPING_MESSAGE),
|
||||
)).catch(() => {});
|
||||
}
|
||||
})();
|
||||
// Feature test until browser coverage is adequate
|
||||
return Symbol.asyncIterator in res.readable &&
|
||||
typeof res.readable[Symbol.asyncIterator] === "function"
|
||||
? (res.readable[Symbol.asyncIterator] as () => AsyncIterableIterator<R>)()
|
||||
: (async function* () {
|
||||
const reader = res.readable.getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
yield value;
|
||||
}
|
||||
reader.releaseLock();
|
||||
})();
|
||||
}
|
||||
129
vendor/deno.land/std@0.203.0/async/retry.ts
vendored
Normal file
129
vendor/deno.land/std@0.203.0/async/retry.ts
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { assert } from "../assert/assert.ts";
|
||||
|
||||
export class RetryError extends Error {
|
||||
constructor(cause: unknown, attempts: number) {
|
||||
super(`Retrying exceeded the maxAttempts (${attempts}).`);
|
||||
this.name = "RetryError";
|
||||
this.cause = cause;
|
||||
}
|
||||
}
|
||||
|
||||
export interface RetryOptions {
|
||||
/** How much to backoff after each retry. This is `2` by default. */
|
||||
multiplier?: number;
|
||||
/** The maximum milliseconds between attempts. This is `60000` by default. */
|
||||
maxTimeout?: number;
|
||||
/** The maximum amount of attempts until failure. This is `5` by default. */
|
||||
maxAttempts?: number;
|
||||
/** The initial and minimum amount of milliseconds between attempts. This is `1000` by default. */
|
||||
minTimeout?: number;
|
||||
/** Amount of jitter to introduce to the time between attempts. This is `1` for full jitter by default. */
|
||||
jitter?: number;
|
||||
}
|
||||
|
||||
const defaultRetryOptions: Required<RetryOptions> = {
|
||||
multiplier: 2,
|
||||
maxTimeout: 60000,
|
||||
maxAttempts: 5,
|
||||
minTimeout: 1000,
|
||||
jitter: 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the given (possibly asynchronous) function up to `maxAttempts` times.
|
||||
* Retries as long as the given function throws.
|
||||
* If the attempts are exhausted, throws an `RetryError` with `cause` set to the inner exception.
|
||||
*
|
||||
* The backoff is calculated by multiplying `minTimeout` with `multiplier` to the power of the current attempt counter (starting at 0 up to `maxAttempts - 1`). It is capped at `maxTimeout` however.
|
||||
* How long the actual delay is, depends on `jitter`.
|
||||
*
|
||||
* When `jitter` is the default value of `1`, waits between two attempts for a randomized amount between 0 and the backoff time.
|
||||
* With the default options the maximal delay will be `15s = 1s + 2s + 4s + 8s`. If all five attempts are exhausted the mean delay will be `9.5s = ½(4s + 15s)`.
|
||||
*
|
||||
* When `jitter` is `0`, waits the full backoff time.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { retry } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
* const req = async () => {
|
||||
* // some function that throws sometimes
|
||||
* };
|
||||
*
|
||||
* // Below resolves to the first non-error result of `req`
|
||||
* const retryPromise = await retry(req, {
|
||||
* multiplier: 2,
|
||||
* maxTimeout: 60000,
|
||||
* maxAttempts: 5,
|
||||
* minTimeout: 100,
|
||||
* jitter: 1,
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { retry } from "https://deno.land/std@$STD_VERSION/async/mod.ts";
|
||||
* const req = async () => {
|
||||
* // some function that throws sometimes
|
||||
* };
|
||||
*
|
||||
* // Make sure we wait at least 1 minute, but at most 2 minutes
|
||||
* const retryPromise = await retry(req, {
|
||||
* multiplier: 2.34,
|
||||
* maxTimeout: 80000,
|
||||
* maxAttempts: 7,
|
||||
* minTimeout: 1000,
|
||||
* jitter: 0.5,
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export async function retry<T>(
|
||||
fn: (() => Promise<T>) | (() => T),
|
||||
opts?: RetryOptions,
|
||||
) {
|
||||
const options: Required<RetryOptions> = {
|
||||
...defaultRetryOptions,
|
||||
...opts,
|
||||
};
|
||||
|
||||
assert(options.maxTimeout >= 0, "maxTimeout is less than 0");
|
||||
assert(
|
||||
options.minTimeout <= options.maxTimeout,
|
||||
"minTimeout is greater than maxTimeout",
|
||||
);
|
||||
assert(options.jitter <= 1, "jitter is greater than 1");
|
||||
|
||||
let attempt = 0;
|
||||
while (true) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (error) {
|
||||
if (attempt + 1 >= options.maxAttempts) {
|
||||
throw new RetryError(error, options.maxAttempts);
|
||||
}
|
||||
|
||||
const timeout = _exponentialBackoffWithJitter(
|
||||
options.maxTimeout,
|
||||
options.minTimeout,
|
||||
attempt,
|
||||
options.multiplier,
|
||||
options.jitter,
|
||||
);
|
||||
await new Promise((r) => setTimeout(r, timeout));
|
||||
}
|
||||
attempt++;
|
||||
}
|
||||
}
|
||||
|
||||
export function _exponentialBackoffWithJitter(
|
||||
cap: number,
|
||||
base: number,
|
||||
attempt: number,
|
||||
multiplier: number,
|
||||
jitter: number,
|
||||
) {
|
||||
const exp = Math.min(cap, base * multiplier ** attempt);
|
||||
return (1 - jitter * Math.random()) * exp;
|
||||
}
|
||||
100
vendor/deno.land/std@0.203.0/async/tee.ts
vendored
Normal file
100
vendor/deno.land/std@0.203.0/async/tee.ts
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
// Utility for representing n-tuple
|
||||
type Tuple<T, N extends number> = N extends N
|
||||
? number extends N ? T[] : TupleOf<T, N, []>
|
||||
: never;
|
||||
type TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N
|
||||
? R
|
||||
: TupleOf<T, N, [T, ...R]>;
|
||||
|
||||
interface QueueNode<T> {
|
||||
value: T;
|
||||
next: QueueNode<T> | undefined;
|
||||
}
|
||||
|
||||
class Queue<T> {
|
||||
#source: AsyncIterator<T>;
|
||||
#queue: QueueNode<T>;
|
||||
head: QueueNode<T>;
|
||||
|
||||
done: boolean;
|
||||
|
||||
constructor(iterable: AsyncIterable<T>) {
|
||||
this.#source = iterable[Symbol.asyncIterator]();
|
||||
this.#queue = {
|
||||
value: undefined!,
|
||||
next: undefined,
|
||||
};
|
||||
this.head = this.#queue;
|
||||
this.done = false;
|
||||
}
|
||||
|
||||
async next() {
|
||||
const result = await this.#source.next();
|
||||
if (!result.done) {
|
||||
const nextNode: QueueNode<T> = {
|
||||
value: result.value,
|
||||
next: undefined,
|
||||
};
|
||||
this.#queue.next = nextNode;
|
||||
this.#queue = nextNode;
|
||||
} else {
|
||||
this.done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Branches the given async iterable into the n branches.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { tee } from "https://deno.land/std@$STD_VERSION/async/tee.ts";
|
||||
*
|
||||
* const gen = async function* gen() {
|
||||
* yield 1;
|
||||
* yield 2;
|
||||
* yield 3;
|
||||
* };
|
||||
*
|
||||
* const [branch1, branch2] = tee(gen());
|
||||
*
|
||||
* for await (const n of branch1) {
|
||||
* console.log(n); // => 1, 2, 3
|
||||
* }
|
||||
*
|
||||
* for await (const n of branch2) {
|
||||
* console.log(n); // => 1, 2, 3
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function tee<T, N extends number = 2>(
|
||||
iterable: AsyncIterable<T>,
|
||||
n: N = 2 as N,
|
||||
): Tuple<AsyncIterable<T>, N> {
|
||||
const queue = new Queue<T>(iterable);
|
||||
|
||||
async function* generator(): AsyncGenerator<T> {
|
||||
let buffer = queue.head;
|
||||
while (true) {
|
||||
if (buffer.next) {
|
||||
buffer = buffer.next;
|
||||
yield buffer.value;
|
||||
} else if (queue.done) {
|
||||
return;
|
||||
} else {
|
||||
await queue.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const branches = Array.from({ length: n }).map(
|
||||
() => generator(),
|
||||
) as Tuple<
|
||||
AsyncIterable<T>,
|
||||
N
|
||||
>;
|
||||
return branches;
|
||||
}
|
||||
49
vendor/jsr.io/@db/sqlite/0.12.0/deno.json
generated
vendored
Normal file
49
vendor/jsr.io/@db/sqlite/0.12.0/deno.json
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@db/sqlite",
|
||||
"version": "0.12.0",
|
||||
"github": "https://github.com/denodrivers/sqlite3",
|
||||
|
||||
"exports": "./mod.ts",
|
||||
|
||||
"exclude": [
|
||||
"sqlite",
|
||||
"scripts"
|
||||
],
|
||||
|
||||
"tasks": {
|
||||
"test": "deno test --unstable-ffi -A test/test.ts",
|
||||
"build": "deno run -A scripts/build.ts",
|
||||
"bench-deno": "deno run -A --unstable-ffi bench/bench_deno.js 50 1000000",
|
||||
"bench-deno-ffi": "deno run -A --unstable-ffi bench/bench_deno_ffi.js 50 1000000",
|
||||
"bench-deno-wasm": "deno run -A --unstable-ffi bench/bench_deno_wasm.js 50 1000000",
|
||||
"bench-node": "node bench/bench_node.js 50 1000000",
|
||||
"bench-bun": "bun run bench/bench_bun.js 50 1000000",
|
||||
"bench-bun-ffi": "bun run bench/bench_bun_ffi.js 50 1000000",
|
||||
"bench-c": "./bench/bench 50 1000000",
|
||||
"bench-python": "python ./bench/bench_python.py",
|
||||
"bench:northwind": "deno bench -A --unstable-ffi bench/northwind/deno.js",
|
||||
"bench-wasm:northwind": "deno run -A --unstable-ffi bench/northwind/deno_wasm.js",
|
||||
"bench-node:northwind": "node bench/northwind/node.mjs",
|
||||
"bench-bun:northwind": "bun run bench/northwind/bun.js"
|
||||
},
|
||||
|
||||
"fmt": {
|
||||
"exclude": [
|
||||
"sqlite"
|
||||
]
|
||||
},
|
||||
|
||||
"lint": {
|
||||
"rules": {
|
||||
"exclude": [
|
||||
"camelcase",
|
||||
"no-explicit-any"
|
||||
],
|
||||
"include": [
|
||||
"explicit-function-return-type",
|
||||
"eqeqeq",
|
||||
"explicit-module-boundary-types"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/jsr.io/@db/sqlite/0.12.0/deps.ts
generated
vendored
Normal file
2
vendor/jsr.io/@db/sqlite/0.12.0/deps.ts
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export { fromFileUrl } from "jsr:@std/path@0.217";
|
||||
export { dlopen } from "jsr:@denosaurs/plug@1";
|
||||
18
vendor/jsr.io/@db/sqlite/0.12.0/mod.ts
generated
vendored
Normal file
18
vendor/jsr.io/@db/sqlite/0.12.0/mod.ts
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
export {
|
||||
type AggregateFunctionOptions,
|
||||
Database,
|
||||
type DatabaseOpenOptions,
|
||||
type FunctionOptions,
|
||||
isComplete,
|
||||
SQLITE_SOURCEID,
|
||||
SQLITE_VERSION,
|
||||
type Transaction,
|
||||
} from "./src/database.ts";
|
||||
export { type BlobOpenOptions, SQLBlob } from "./src/blob.ts";
|
||||
export {
|
||||
type BindParameters,
|
||||
type BindValue,
|
||||
type RestBindParameters,
|
||||
Statement,
|
||||
} from "./src/statement.ts";
|
||||
export { SqliteError } from "./src/util.ts";
|
||||
149
vendor/jsr.io/@db/sqlite/0.12.0/src/blob.ts
generated
vendored
Normal file
149
vendor/jsr.io/@db/sqlite/0.12.0/src/blob.ts
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
import type { Database } from "./database.ts";
|
||||
import ffi from "./ffi.ts";
|
||||
import { toCString, unwrap } from "./util.ts";
|
||||
|
||||
const {
|
||||
sqlite3_blob_open,
|
||||
sqlite3_blob_bytes,
|
||||
sqlite3_blob_close,
|
||||
sqlite3_blob_read,
|
||||
sqlite3_blob_write,
|
||||
} = ffi;
|
||||
|
||||
/** Various options that can be configured when opening a Blob via `Database#openBlob`. */
|
||||
export interface BlobOpenOptions {
|
||||
/** Whether to open Blob in readonly mode. True by default. */
|
||||
readonly?: boolean;
|
||||
/** Database to open Blob from, "main" by default. */
|
||||
db?: string;
|
||||
/** Table the Blob is in */
|
||||
table: string;
|
||||
/** Column name of the Blob Field */
|
||||
column: string;
|
||||
/** Row ID of which column to select */
|
||||
row: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates SQLite3 Blob opened for streamed I/O.
|
||||
*
|
||||
* BLOB columns still return a `Uint8Array` of the data.
|
||||
* You can instead open this from `Database.openBlob()`.
|
||||
*
|
||||
* @see https://www.sqlite.org/c3ref/blob_open.html
|
||||
*/
|
||||
export class SQLBlob {
|
||||
#handle: Deno.PointerValue;
|
||||
|
||||
constructor(db: Database, options: BlobOpenOptions) {
|
||||
options = Object.assign({
|
||||
readonly: true,
|
||||
db: "main",
|
||||
}, options);
|
||||
const pHandle = new BigUint64Array(1);
|
||||
unwrap(sqlite3_blob_open(
|
||||
db.unsafeHandle,
|
||||
toCString(options.db ?? "main"),
|
||||
toCString(options.table),
|
||||
toCString(options.column),
|
||||
BigInt(options.row),
|
||||
options.readonly === false ? 1 : 0,
|
||||
pHandle,
|
||||
));
|
||||
this.#handle = Deno.UnsafePointer.create(pHandle[0]);
|
||||
}
|
||||
|
||||
/** Byte size of the Blob */
|
||||
get byteLength(): number {
|
||||
return sqlite3_blob_bytes(this.#handle);
|
||||
}
|
||||
|
||||
/** Read from the Blob at given offset into a buffer (Uint8Array) */
|
||||
readSync(offset: number, p: Uint8Array): void {
|
||||
unwrap(sqlite3_blob_read(this.#handle, p, p.byteLength, offset));
|
||||
}
|
||||
|
||||
/** Write a buffer (Uint8Array) at given offset in the Blob */
|
||||
writeSync(offset: number, p: Uint8Array): void {
|
||||
unwrap(sqlite3_blob_write(this.#handle, p, p.byteLength, offset));
|
||||
}
|
||||
|
||||
/** Close the Blob. It **must** be called to prevent leaks. */
|
||||
close(): void {
|
||||
unwrap(sqlite3_blob_close(this.#handle));
|
||||
}
|
||||
|
||||
/** Obtains Web Stream for reading the Blob */
|
||||
get readable(): ReadableStream<Uint8Array> {
|
||||
const length = this.byteLength;
|
||||
let offset = 0;
|
||||
return new ReadableStream({
|
||||
type: "bytes",
|
||||
pull: (ctx) => {
|
||||
try {
|
||||
const byob = ctx.byobRequest;
|
||||
if (byob) {
|
||||
const toRead = Math.min(
|
||||
length - offset,
|
||||
byob.view!.byteLength,
|
||||
);
|
||||
this.readSync(
|
||||
offset,
|
||||
(byob.view as Uint8Array).subarray(0, toRead),
|
||||
);
|
||||
offset += toRead;
|
||||
byob.respond(toRead);
|
||||
} else {
|
||||
const toRead = Math.min(
|
||||
length - offset,
|
||||
ctx.desiredSize || 1024 * 16,
|
||||
);
|
||||
if (toRead === 0) {
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
const buffer = new Uint8Array(toRead);
|
||||
this.readSync(offset, buffer);
|
||||
offset += toRead;
|
||||
ctx.enqueue(buffer);
|
||||
}
|
||||
} catch (e) {
|
||||
ctx.error(e);
|
||||
ctx.byobRequest?.respond(0);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** Obtains Web Stream for writing to the Blob */
|
||||
get writable(): WritableStream<Uint8Array> {
|
||||
const length = this.byteLength;
|
||||
let offset = 0;
|
||||
return new WritableStream({
|
||||
write: (chunk, ctx) => {
|
||||
if (offset + chunk.byteLength > length) {
|
||||
ctx.error(new Error("Write exceeds blob length"));
|
||||
return;
|
||||
}
|
||||
this.writeSync(offset, chunk);
|
||||
offset += chunk.byteLength;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
*[Symbol.iterator](): IterableIterator<Uint8Array> {
|
||||
const length = this.byteLength;
|
||||
let offset = 0;
|
||||
while (offset < length) {
|
||||
const toRead = Math.min(length - offset, 1024 * 16);
|
||||
const buffer = new Uint8Array(toRead);
|
||||
this.readSync(offset, buffer);
|
||||
offset += toRead;
|
||||
yield buffer;
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.for("Deno.customInspect")](): string {
|
||||
return `SQLite3.Blob(0x${this.byteLength.toString(16)})`;
|
||||
}
|
||||
}
|
||||
67
vendor/jsr.io/@db/sqlite/0.12.0/src/constants.ts
generated
vendored
Normal file
67
vendor/jsr.io/@db/sqlite/0.12.0/src/constants.ts
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// Result Codes
|
||||
export const SQLITE3_OK = 0;
|
||||
export const SQLITE3_ERROR = 1;
|
||||
export const SQLITE3_INTERNAL = 2;
|
||||
export const SQLITE3_PERM = 3;
|
||||
export const SQLITE3_ABORT = 4;
|
||||
export const SQLITE3_BUSY = 5;
|
||||
export const SQLITE3_LOCKED = 6;
|
||||
export const SQLITE3_NOMEM = 7;
|
||||
export const SQLITE3_READONLY = 8;
|
||||
export const SQLITE3_INTERRUPT = 9;
|
||||
export const SQLITE3_IOERR = 10;
|
||||
export const SQLITE3_CORRUPT = 11;
|
||||
export const SQLITE3_NOTFOUND = 12;
|
||||
export const SQLITE3_FULL = 13;
|
||||
export const SQLITE3_CANTOPEN = 14;
|
||||
export const SQLITE3_PROTOCOL = 15;
|
||||
export const SQLITE3_EMPTY = 16;
|
||||
export const SQLITE3_SCHEMA = 17;
|
||||
export const SQLITE3_TOOBIG = 18;
|
||||
export const SQLITE3_CONSTRAINT = 19;
|
||||
export const SQLITE3_MISMATCH = 20;
|
||||
export const SQLITE3_MISUSE = 21;
|
||||
export const SQLITE3_NOLFS = 22;
|
||||
export const SQLITE3_AUTH = 23;
|
||||
export const SQLITE3_FORMAT = 24;
|
||||
export const SQLITE3_RANGE = 25;
|
||||
export const SQLITE3_NOTADB = 26;
|
||||
export const SQLITE3_NOTICE = 27;
|
||||
export const SQLITE3_WARNING = 28;
|
||||
export const SQLITE3_ROW = 100;
|
||||
export const SQLITE3_DONE = 101;
|
||||
|
||||
// Open Flags
|
||||
export const SQLITE3_OPEN_READONLY = 0x00000001;
|
||||
export const SQLITE3_OPEN_READWRITE = 0x00000002;
|
||||
export const SQLITE3_OPEN_CREATE = 0x00000004;
|
||||
export const SQLITE3_OPEN_DELETEONCLOSE = 0x00000008;
|
||||
export const SQLITE3_OPEN_EXCLUSIVE = 0x00000010;
|
||||
export const SQLITE3_OPEN_AUTOPROXY = 0x00000020;
|
||||
export const SQLITE3_OPEN_URI = 0x00000040;
|
||||
export const SQLITE3_OPEN_MEMORY = 0x00000080;
|
||||
export const SQLITE3_OPEN_MAIN_DB = 0x00000100;
|
||||
export const SQLITE3_OPEN_TEMP_DB = 0x00000200;
|
||||
export const SQLITE3_OPEN_TRANSIENT_DB = 0x00000400;
|
||||
export const SQLITE3_OPEN_MAIN_JOURNAL = 0x00000800;
|
||||
export const SQLITE3_OPEN_TEMP_JOURNAL = 0x00001000;
|
||||
export const SQLITE3_OPEN_SUBJOURNAL = 0x00002000;
|
||||
export const SQLITE3_OPEN_SUPER_JOURNAL = 0x00004000;
|
||||
export const SQLITE3_OPEN_NONMUTEX = 0x00008000;
|
||||
export const SQLITE3_OPEN_FULLMUTEX = 0x00010000;
|
||||
export const SQLITE3_OPEN_SHAREDCACHE = 0x00020000;
|
||||
export const SQLITE3_OPEN_PRIVATECACHE = 0x00040000;
|
||||
export const SQLITE3_OPEN_WAL = 0x00080000;
|
||||
export const SQLITE3_OPEN_NOFOLLOW = 0x01000000;
|
||||
|
||||
// Prepare Flags
|
||||
export const SQLITE3_PREPARE_PERSISTENT = 0x00000001;
|
||||
export const SQLITE3_PREPARE_NORMALIZE = 0x00000002;
|
||||
export const SQLITE3_PREPARE_NO_VTAB = 0x00000004;
|
||||
|
||||
// Fundamental Datatypes
|
||||
export const SQLITE_INTEGER = 1;
|
||||
export const SQLITE_FLOAT = 2;
|
||||
export const SQLITE_TEXT = 3;
|
||||
export const SQLITE_BLOB = 4;
|
||||
export const SQLITE_NULL = 5;
|
||||
884
vendor/jsr.io/@db/sqlite/0.12.0/src/database.ts
generated
vendored
Normal file
884
vendor/jsr.io/@db/sqlite/0.12.0/src/database.ts
generated
vendored
Normal file
@ -0,0 +1,884 @@
|
||||
import ffi from "./ffi.ts";
|
||||
import { fromFileUrl } from "../deps.ts";
|
||||
import {
|
||||
SQLITE3_OPEN_CREATE,
|
||||
SQLITE3_OPEN_MEMORY,
|
||||
SQLITE3_OPEN_READONLY,
|
||||
SQLITE3_OPEN_READWRITE,
|
||||
SQLITE_BLOB,
|
||||
SQLITE_FLOAT,
|
||||
SQLITE_INTEGER,
|
||||
SQLITE_NULL,
|
||||
SQLITE_TEXT,
|
||||
} from "./constants.ts";
|
||||
import { readCstr, toCString, unwrap } from "./util.ts";
|
||||
import {
|
||||
type RestBindParameters,
|
||||
Statement,
|
||||
STATEMENTS_TO_DB,
|
||||
} from "./statement.ts";
|
||||
import { type BlobOpenOptions, SQLBlob } from "./blob.ts";
|
||||
|
||||
/** Various options that can be configured when opening Database connection. */
|
||||
export interface DatabaseOpenOptions {
|
||||
/** Whether to open database only in read-only mode. By default, this is false. */
|
||||
readonly?: boolean;
|
||||
/** Whether to create a new database file at specified path if one does not exist already. By default this is true. */
|
||||
create?: boolean;
|
||||
/** Raw SQLite C API flags. Specifying this ignores all other options. */
|
||||
flags?: number;
|
||||
/** Opens an in-memory database. */
|
||||
memory?: boolean;
|
||||
/** Whether to support BigInt columns. False by default, integers larger than 32 bit will be inaccurate. */
|
||||
int64?: boolean;
|
||||
/** Apply agressive optimizations that are not possible with concurrent clients. */
|
||||
unsafeConcurrency?: boolean;
|
||||
/** Enable or disable extension loading */
|
||||
enableLoadExtension?: boolean;
|
||||
}
|
||||
|
||||
/** Transaction function created using `Database#transaction`. */
|
||||
export type Transaction<T extends (...args: any[]) => void> =
|
||||
& ((...args: Parameters<T>) => ReturnType<T>)
|
||||
& {
|
||||
/** BEGIN */
|
||||
default: Transaction<T>;
|
||||
/** BEGIN DEFERRED */
|
||||
deferred: Transaction<T>;
|
||||
/** BEGIN IMMEDIATE */
|
||||
immediate: Transaction<T>;
|
||||
/** BEGIN EXCLUSIVE */
|
||||
exclusive: Transaction<T>;
|
||||
database: Database;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for user-defined functions.
|
||||
*
|
||||
* @link https://www.sqlite.org/c3ref/c_deterministic.html
|
||||
*/
|
||||
export interface FunctionOptions {
|
||||
varargs?: boolean;
|
||||
deterministic?: boolean;
|
||||
directOnly?: boolean;
|
||||
innocuous?: boolean;
|
||||
subtype?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for user-defined aggregate functions.
|
||||
*/
|
||||
export interface AggregateFunctionOptions extends FunctionOptions {
|
||||
start: any | (() => any);
|
||||
step: (aggregate: any, ...args: any[]) => void;
|
||||
final?: (aggregate: any) => any;
|
||||
}
|
||||
|
||||
const {
|
||||
sqlite3_open_v2,
|
||||
sqlite3_close_v2,
|
||||
sqlite3_changes,
|
||||
sqlite3_total_changes,
|
||||
sqlite3_last_insert_rowid,
|
||||
sqlite3_get_autocommit,
|
||||
sqlite3_exec,
|
||||
sqlite3_free,
|
||||
sqlite3_libversion,
|
||||
sqlite3_sourceid,
|
||||
sqlite3_complete,
|
||||
sqlite3_finalize,
|
||||
sqlite3_result_blob,
|
||||
sqlite3_result_double,
|
||||
sqlite3_result_error,
|
||||
sqlite3_result_int64,
|
||||
sqlite3_result_null,
|
||||
sqlite3_result_text,
|
||||
sqlite3_value_blob,
|
||||
sqlite3_value_bytes,
|
||||
sqlite3_value_double,
|
||||
sqlite3_value_int64,
|
||||
sqlite3_value_text,
|
||||
sqlite3_value_type,
|
||||
sqlite3_create_function,
|
||||
sqlite3_result_int,
|
||||
sqlite3_aggregate_context,
|
||||
sqlite3_enable_load_extension,
|
||||
sqlite3_load_extension,
|
||||
sqlite3_backup_init,
|
||||
sqlite3_backup_step,
|
||||
sqlite3_backup_finish,
|
||||
sqlite3_errcode,
|
||||
} = ffi;
|
||||
|
||||
/** SQLite version string */
|
||||
export const SQLITE_VERSION: string = readCstr(sqlite3_libversion()!);
|
||||
/** SQLite source ID string */
|
||||
export const SQLITE_SOURCEID: string = readCstr(sqlite3_sourceid()!);
|
||||
|
||||
/**
|
||||
* Whether the given SQL statement is complete.
|
||||
*
|
||||
* @param statement SQL statement string
|
||||
*/
|
||||
export function isComplete(statement: string): boolean {
|
||||
return Boolean(sqlite3_complete(toCString(statement)));
|
||||
}
|
||||
|
||||
const BIG_MAX = BigInt(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
/**
|
||||
* Represents a SQLite3 database connection.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* // Open a database from file, creates if doesn't exist.
|
||||
* const db = new Database("myfile.db");
|
||||
*
|
||||
* // Open an in-memory database.
|
||||
* const db = new Database(":memory:");
|
||||
*
|
||||
* // Open a read-only database.
|
||||
* const db = new Database("myfile.db", { readonly: true });
|
||||
*
|
||||
* // Or open using File URL
|
||||
* const db = new Database(new URL("./myfile.db", import.meta.url));
|
||||
* ```
|
||||
*/
|
||||
export class Database {
|
||||
#path: string;
|
||||
#handle: Deno.PointerValue;
|
||||
#open = true;
|
||||
#enableLoadExtension = false;
|
||||
|
||||
/** Whether to support BigInt columns. False by default, integers larger than 32 bit will be inaccurate. */
|
||||
int64: boolean;
|
||||
|
||||
unsafeConcurrency: boolean;
|
||||
|
||||
/** Whether DB connection is open */
|
||||
get open(): boolean {
|
||||
return this.#open;
|
||||
}
|
||||
|
||||
/** Unsafe Raw (pointer) to the sqlite object */
|
||||
get unsafeHandle(): Deno.PointerValue {
|
||||
return this.#handle;
|
||||
}
|
||||
|
||||
/** Path of the database file. */
|
||||
get path(): string {
|
||||
return this.#path;
|
||||
}
|
||||
|
||||
/** Number of rows changed by the last executed statement. */
|
||||
get changes(): number {
|
||||
return sqlite3_changes(this.#handle);
|
||||
}
|
||||
|
||||
/** Number of rows changed since the database connection was opened. */
|
||||
get totalChanges(): number {
|
||||
return sqlite3_total_changes(this.#handle);
|
||||
}
|
||||
|
||||
/** Gets last inserted Row ID */
|
||||
get lastInsertRowId(): number {
|
||||
return Number(sqlite3_last_insert_rowid(this.#handle));
|
||||
}
|
||||
|
||||
/** Whether autocommit is enabled. Enabled by default, can be disabled using BEGIN statement. */
|
||||
get autocommit(): boolean {
|
||||
return sqlite3_get_autocommit(this.#handle) === 1;
|
||||
}
|
||||
|
||||
/** Whether DB is in mid of a transaction */
|
||||
get inTransaction(): boolean {
|
||||
return this.#open && !this.autocommit;
|
||||
}
|
||||
|
||||
get enableLoadExtension(): boolean {
|
||||
return this.#enableLoadExtension;
|
||||
}
|
||||
|
||||
set enableLoadExtension(enabled: boolean) {
|
||||
if (sqlite3_enable_load_extension === null) {
|
||||
throw new Error(
|
||||
"Extension loading is not supported by the shared library that was used.",
|
||||
);
|
||||
}
|
||||
const result = sqlite3_enable_load_extension(this.#handle, Number(enabled));
|
||||
unwrap(result, this.#handle);
|
||||
this.#enableLoadExtension = enabled;
|
||||
}
|
||||
|
||||
constructor(path: string | URL, options: DatabaseOpenOptions = {}) {
|
||||
this.#path = path instanceof URL ? fromFileUrl(path) : path;
|
||||
let flags = 0;
|
||||
this.int64 = options.int64 ?? false;
|
||||
this.unsafeConcurrency = options.unsafeConcurrency ?? false;
|
||||
if (options.flags !== undefined) {
|
||||
flags = options.flags;
|
||||
} else {
|
||||
if (options.memory) {
|
||||
flags |= SQLITE3_OPEN_MEMORY;
|
||||
}
|
||||
|
||||
if (options.readonly ?? false) {
|
||||
flags |= SQLITE3_OPEN_READONLY;
|
||||
} else {
|
||||
flags |= SQLITE3_OPEN_READWRITE;
|
||||
}
|
||||
|
||||
if ((options.create ?? true) && !options.readonly) {
|
||||
flags |= SQLITE3_OPEN_CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
const pHandle = new BigUint64Array(1);
|
||||
const result = sqlite3_open_v2(toCString(this.#path), pHandle, flags, null);
|
||||
this.#handle = Deno.UnsafePointer.create(pHandle[0]);
|
||||
if (result !== 0) sqlite3_close_v2(this.#handle);
|
||||
unwrap(result);
|
||||
|
||||
if (options.enableLoadExtension) {
|
||||
this.enableLoadExtension = options.enableLoadExtension;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Prepared Statement from the given SQL statement.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* const stmt = db.prepare("SELECT * FROM mytable WHERE id = ?");
|
||||
*
|
||||
* for (const row of stmt.all(1)) {
|
||||
* console.log(row);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Bind parameters can be either provided as an array of values, or as an object
|
||||
* mapping the parameter name to the value.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* const stmt = db.prepare("SELECT * FROM mytable WHERE id = ?");
|
||||
* const row = stmt.get(1);
|
||||
*
|
||||
* // or
|
||||
*
|
||||
* const stmt = db.prepare("SELECT * FROM mytable WHERE id = :id");
|
||||
* const row = stmt.get({ id: 1 });
|
||||
* ```
|
||||
*
|
||||
* Statements are automatically freed once GC catches them, however
|
||||
* you can also manually free using `finalize` method.
|
||||
*
|
||||
* @param sql SQL statement string
|
||||
* @returns Statement object
|
||||
*/
|
||||
prepare(sql: string): Statement {
|
||||
return new Statement(this, sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a Blob for incremental I/O.
|
||||
*
|
||||
* Make sure to close the blob after you are done with it,
|
||||
* otherwise you will have memory leaks.
|
||||
*/
|
||||
openBlob(options: BlobOpenOptions): SQLBlob {
|
||||
return new SQLBlob(this, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply executes the SQL statement (supports multiple statements separated by semicolon).
|
||||
* Returns the number of changes made by last statement.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* // Create table
|
||||
* db.exec("create table users (id integer not null, username varchar(20) not null)");
|
||||
*
|
||||
* // Inserts
|
||||
* db.exec("insert into users (id, username) values(?, ?)", id, username);
|
||||
*
|
||||
* // Insert with named parameters
|
||||
* db.exec("insert into users (id, username) values(:id, :username)", { id, username });
|
||||
*
|
||||
* // Pragma statements
|
||||
* db.exec("pragma journal_mode = WAL");
|
||||
* db.exec("pragma synchronous = normal");
|
||||
* db.exec("pragma temp_store = memory");
|
||||
* ```
|
||||
*
|
||||
* Under the hood, it uses `sqlite3_exec` if no parameters are given to bind
|
||||
* with the SQL statement, a prepared statement otherwise.
|
||||
*/
|
||||
exec(sql: string, ...params: RestBindParameters): number {
|
||||
if (params.length === 0) {
|
||||
const pErr = new BigUint64Array(1);
|
||||
sqlite3_exec(
|
||||
this.#handle,
|
||||
toCString(sql),
|
||||
null,
|
||||
null,
|
||||
new Uint8Array(pErr.buffer),
|
||||
);
|
||||
const errPtr = Deno.UnsafePointer.create(pErr[0]);
|
||||
if (errPtr !== null) {
|
||||
const err = readCstr(errPtr);
|
||||
sqlite3_free(errPtr);
|
||||
throw new Error(err);
|
||||
}
|
||||
return sqlite3_changes(this.#handle);
|
||||
}
|
||||
|
||||
const stmt = this.prepare(sql);
|
||||
stmt.run(...params);
|
||||
return sqlite3_changes(this.#handle);
|
||||
}
|
||||
|
||||
/** Alias for `exec`. */
|
||||
run(sql: string, ...params: RestBindParameters): number {
|
||||
return this.exec(sql, ...params);
|
||||
}
|
||||
|
||||
/** Safely execute SQL with parameters using a tagged template */
|
||||
sql<T extends Record<string, unknown> = Record<string, any>>(
|
||||
strings: TemplateStringsArray,
|
||||
...parameters: RestBindParameters
|
||||
): T[] {
|
||||
const sql = strings.join("?");
|
||||
const stmt = this.prepare(sql);
|
||||
return stmt.all(...parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a callback function in a transaction.
|
||||
*
|
||||
* - When function is called, the transaction is started.
|
||||
* - When function returns, the transaction is committed.
|
||||
* - When function throws an error, the transaction is rolled back.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* const stmt = db.prepare("insert into users (id, username) values(?, ?)");
|
||||
*
|
||||
* interface User {
|
||||
* id: number;
|
||||
* username: string;
|
||||
* }
|
||||
*
|
||||
* const insertUsers = db.transaction((data: User[]) => {
|
||||
* for (const user of data) {
|
||||
* stmt.run(user);
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* insertUsers([
|
||||
* { id: 1, username: "alice" },
|
||||
* { id: 2, username: "bob" },
|
||||
* ]);
|
||||
*
|
||||
* // May also use `insertUsers.deferred`, `immediate`, or `exclusive`.
|
||||
* // They corresspond to using `BEGIN DEFERRED`, `BEGIN IMMEDIATE`, and `BEGIN EXCLUSIVE`.
|
||||
* // For eg.
|
||||
*
|
||||
* insertUsers.deferred([
|
||||
* { id: 1, username: "alice" },
|
||||
* { id: 2, username: "bob" },
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
transaction<T extends (this: Transaction<T>, ...args: any[]) => void>(
|
||||
fn: T,
|
||||
): Transaction<T> {
|
||||
// Based on https://github.com/WiseLibs/better-sqlite3/blob/master/lib/methods/transaction.js
|
||||
const controller = getController(this);
|
||||
|
||||
// Each version of the transaction function has these same properties
|
||||
const properties = {
|
||||
default: { value: wrapTransaction(fn, this, controller.default) },
|
||||
deferred: { value: wrapTransaction(fn, this, controller.deferred) },
|
||||
immediate: { value: wrapTransaction(fn, this, controller.immediate) },
|
||||
exclusive: { value: wrapTransaction(fn, this, controller.exclusive) },
|
||||
database: { value: this, enumerable: true },
|
||||
};
|
||||
|
||||
Object.defineProperties(properties.default.value, properties);
|
||||
Object.defineProperties(properties.deferred.value, properties);
|
||||
Object.defineProperties(properties.immediate.value, properties);
|
||||
Object.defineProperties(properties.exclusive.value, properties);
|
||||
|
||||
// Return the default version of the transaction function
|
||||
return properties.default.value as Transaction<T>;
|
||||
}
|
||||
|
||||
#callbacks = new Set<Deno.UnsafeCallback>();
|
||||
|
||||
/**
|
||||
* Creates a new user-defined function.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* db.function("add", (a: number, b: number) => a + b);
|
||||
* db.prepare("select add(1, 2)").value<[number]>()!; // [3]
|
||||
* ```
|
||||
*/
|
||||
function(
|
||||
name: string,
|
||||
fn: CallableFunction,
|
||||
options?: FunctionOptions,
|
||||
): void {
|
||||
if (sqlite3_create_function === null) {
|
||||
throw new Error(
|
||||
"User-defined functions are not supported by the shared library that was used.",
|
||||
);
|
||||
}
|
||||
|
||||
const cb = new Deno.UnsafeCallback(
|
||||
{
|
||||
parameters: ["pointer", "i32", "pointer"],
|
||||
result: "void",
|
||||
} as const,
|
||||
(ctx, nArgs, pArgs) => {
|
||||
const argptr = new Deno.UnsafePointerView(pArgs!);
|
||||
const args: any[] = [];
|
||||
for (let i = 0; i < nArgs; i++) {
|
||||
const arg = Deno.UnsafePointer.create(
|
||||
argptr.getBigUint64(i * 8),
|
||||
);
|
||||
const type = sqlite3_value_type(arg);
|
||||
switch (type) {
|
||||
case SQLITE_INTEGER: {
|
||||
const value = sqlite3_value_int64(arg);
|
||||
if (value < -BIG_MAX || value > BIG_MAX) {
|
||||
args.push(value);
|
||||
} else {
|
||||
args.push(Number(value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT:
|
||||
args.push(sqlite3_value_double(arg));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
args.push(
|
||||
new TextDecoder().decode(
|
||||
new Uint8Array(
|
||||
Deno.UnsafePointerView.getArrayBuffer(
|
||||
sqlite3_value_text(arg)!,
|
||||
sqlite3_value_bytes(arg),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
args.push(
|
||||
new Uint8Array(
|
||||
Deno.UnsafePointerView.getArrayBuffer(
|
||||
sqlite3_value_blob(arg)!,
|
||||
sqlite3_value_bytes(arg),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case SQLITE_NULL:
|
||||
args.push(null);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
let result: any;
|
||||
try {
|
||||
result = fn(...args);
|
||||
} catch (err) {
|
||||
const buf = new TextEncoder().encode(err.message);
|
||||
sqlite3_result_error(ctx, buf, buf.byteLength);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result === undefined || result === null) {
|
||||
sqlite3_result_null(ctx);
|
||||
} else if (typeof result === "boolean") {
|
||||
sqlite3_result_int(ctx, result ? 1 : 0);
|
||||
} else if (typeof result === "number") {
|
||||
if (Number.isSafeInteger(result)) {
|
||||
sqlite3_result_int64(ctx, BigInt(result));
|
||||
} else sqlite3_result_double(ctx, result);
|
||||
} else if (typeof result === "bigint") {
|
||||
sqlite3_result_int64(ctx, result);
|
||||
} else if (typeof result === "string") {
|
||||
const buffer = new TextEncoder().encode(result);
|
||||
sqlite3_result_text(ctx, buffer, buffer.byteLength, 0n);
|
||||
} else if (result instanceof Uint8Array) {
|
||||
sqlite3_result_blob(ctx, result, result.length, -1n);
|
||||
} else {
|
||||
const buffer = new TextEncoder().encode(
|
||||
`Invalid return value: ${Deno.inspect(result)}`,
|
||||
);
|
||||
sqlite3_result_error(ctx, buffer, buffer.byteLength);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let flags = 1;
|
||||
|
||||
if (options?.deterministic) {
|
||||
flags |= 0x000000800;
|
||||
}
|
||||
|
||||
if (options?.directOnly) {
|
||||
flags |= 0x000080000;
|
||||
}
|
||||
|
||||
if (options?.subtype) {
|
||||
flags |= 0x000100000;
|
||||
}
|
||||
|
||||
if (options?.directOnly) {
|
||||
flags |= 0x000200000;
|
||||
}
|
||||
|
||||
const err = sqlite3_create_function(
|
||||
this.#handle,
|
||||
toCString(name),
|
||||
options?.varargs ? -1 : fn.length,
|
||||
flags,
|
||||
null,
|
||||
cb.pointer,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
unwrap(err, this.#handle);
|
||||
|
||||
this.#callbacks.add(cb as Deno.UnsafeCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new user-defined aggregate function.
|
||||
*/
|
||||
aggregate(name: string, options: AggregateFunctionOptions): void {
|
||||
if (
|
||||
sqlite3_aggregate_context === null || sqlite3_create_function === null
|
||||
) {
|
||||
throw new Error(
|
||||
"User-defined functions are not supported by the shared library that was used.",
|
||||
);
|
||||
}
|
||||
|
||||
const contexts = new Map<number | bigint, any>();
|
||||
|
||||
const cb = new Deno.UnsafeCallback(
|
||||
{
|
||||
parameters: ["pointer", "i32", "pointer"],
|
||||
result: "void",
|
||||
} as const,
|
||||
(ctx, nArgs, pArgs) => {
|
||||
const aggrCtx = sqlite3_aggregate_context(ctx, 8);
|
||||
const aggrPtr = Deno.UnsafePointer.value(aggrCtx);
|
||||
let aggregate;
|
||||
if (contexts.has(aggrPtr)) {
|
||||
aggregate = contexts.get(aggrPtr);
|
||||
} else {
|
||||
aggregate = typeof options.start === "function"
|
||||
? options.start()
|
||||
: options.start;
|
||||
contexts.set(aggrPtr, aggregate);
|
||||
}
|
||||
const argptr = new Deno.UnsafePointerView(pArgs!);
|
||||
const args: any[] = [];
|
||||
for (let i = 0; i < nArgs; i++) {
|
||||
const arg = Deno.UnsafePointer.create(
|
||||
argptr.getBigUint64(i * 8),
|
||||
);
|
||||
const type = sqlite3_value_type(arg);
|
||||
switch (type) {
|
||||
case SQLITE_INTEGER: {
|
||||
const value = sqlite3_value_int64(arg);
|
||||
if (value < -BIG_MAX || value > BIG_MAX) {
|
||||
args.push(value);
|
||||
} else {
|
||||
args.push(Number(value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT:
|
||||
args.push(sqlite3_value_double(arg));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
args.push(
|
||||
new TextDecoder().decode(
|
||||
new Uint8Array(
|
||||
Deno.UnsafePointerView.getArrayBuffer(
|
||||
sqlite3_value_text(arg)!,
|
||||
sqlite3_value_bytes(arg),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
args.push(
|
||||
new Uint8Array(
|
||||
Deno.UnsafePointerView.getArrayBuffer(
|
||||
sqlite3_value_blob(arg)!,
|
||||
sqlite3_value_bytes(arg),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case SQLITE_NULL:
|
||||
args.push(null);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
let result: any;
|
||||
try {
|
||||
result = options.step(aggregate, ...args);
|
||||
} catch (err) {
|
||||
const buf = new TextEncoder().encode(err.message);
|
||||
sqlite3_result_error(ctx, buf, buf.byteLength);
|
||||
return;
|
||||
}
|
||||
|
||||
contexts.set(aggrPtr, result);
|
||||
},
|
||||
);
|
||||
|
||||
const cbFinal = new Deno.UnsafeCallback(
|
||||
{
|
||||
parameters: ["pointer"],
|
||||
result: "void",
|
||||
} as const,
|
||||
(ctx) => {
|
||||
const aggrCtx = sqlite3_aggregate_context(ctx, 0);
|
||||
const aggrPtr = Deno.UnsafePointer.value(aggrCtx);
|
||||
const aggregate = contexts.get(aggrPtr);
|
||||
contexts.delete(aggrPtr);
|
||||
let result: any;
|
||||
try {
|
||||
result = options.final ? options.final(aggregate) : aggregate;
|
||||
} catch (err) {
|
||||
const buf = new TextEncoder().encode(err.message);
|
||||
sqlite3_result_error(ctx, buf, buf.byteLength);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result === undefined || result === null) {
|
||||
sqlite3_result_null(ctx);
|
||||
} else if (typeof result === "boolean") {
|
||||
sqlite3_result_int(ctx, result ? 1 : 0);
|
||||
} else if (typeof result === "number") {
|
||||
if (Number.isSafeInteger(result)) {
|
||||
sqlite3_result_int64(ctx, BigInt(result));
|
||||
} else sqlite3_result_double(ctx, result);
|
||||
} else if (typeof result === "bigint") {
|
||||
sqlite3_result_int64(ctx, result);
|
||||
} else if (typeof result === "string") {
|
||||
const buffer = new TextEncoder().encode(result);
|
||||
sqlite3_result_text(ctx, buffer, buffer.byteLength, 0n);
|
||||
} else if (result instanceof Uint8Array) {
|
||||
sqlite3_result_blob(ctx, result, result.length, -1n);
|
||||
} else {
|
||||
const buffer = new TextEncoder().encode(
|
||||
`Invalid return value: ${Deno.inspect(result)}`,
|
||||
);
|
||||
sqlite3_result_error(ctx, buffer, buffer.byteLength);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let flags = 1;
|
||||
|
||||
if (options?.deterministic) {
|
||||
flags |= 0x000000800;
|
||||
}
|
||||
|
||||
if (options?.directOnly) {
|
||||
flags |= 0x000080000;
|
||||
}
|
||||
|
||||
if (options?.subtype) {
|
||||
flags |= 0x000100000;
|
||||
}
|
||||
|
||||
if (options?.directOnly) {
|
||||
flags |= 0x000200000;
|
||||
}
|
||||
|
||||
const err = sqlite3_create_function(
|
||||
this.#handle,
|
||||
toCString(name),
|
||||
options?.varargs ? -1 : options.step.length - 1,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
cb.pointer,
|
||||
cbFinal.pointer,
|
||||
);
|
||||
|
||||
unwrap(err, this.#handle);
|
||||
|
||||
this.#callbacks.add(cb as Deno.UnsafeCallback);
|
||||
this.#callbacks.add(cbFinal as Deno.UnsafeCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an SQLite extension library from the named file.
|
||||
*/
|
||||
loadExtension(file: string, entryPoint?: string): void {
|
||||
if (sqlite3_load_extension === null) {
|
||||
throw new Error(
|
||||
"Extension loading is not supported by the shared library that was used.",
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.enableLoadExtension) {
|
||||
throw new Error("Extension loading is not enabled");
|
||||
}
|
||||
|
||||
const pzErrMsg = new BigUint64Array(1);
|
||||
|
||||
const result = sqlite3_load_extension(
|
||||
this.#handle,
|
||||
toCString(file),
|
||||
entryPoint ? toCString(entryPoint) : null,
|
||||
pzErrMsg,
|
||||
);
|
||||
|
||||
const pzErrPtr = Deno.UnsafePointer.create(
|
||||
pzErrMsg[0],
|
||||
);
|
||||
if (pzErrPtr !== null) {
|
||||
const pzErr = readCstr(pzErrPtr);
|
||||
sqlite3_free(pzErrPtr);
|
||||
throw new Error(pzErr);
|
||||
}
|
||||
|
||||
unwrap(result, this.#handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the database connection.
|
||||
*
|
||||
* Calling this method more than once is no-op.
|
||||
*/
|
||||
close(): void {
|
||||
if (!this.#open) return;
|
||||
for (const [stmt, db] of STATEMENTS_TO_DB) {
|
||||
if (db === this.#handle) {
|
||||
sqlite3_finalize(stmt);
|
||||
STATEMENTS_TO_DB.delete(stmt);
|
||||
}
|
||||
}
|
||||
for (const cb of this.#callbacks) {
|
||||
cb.close();
|
||||
}
|
||||
unwrap(sqlite3_close_v2(this.#handle));
|
||||
this.#open = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dest The destination database connection.
|
||||
* @param name Destination database name. "main" for main database, "temp" for temporary database, or the name specified after the AS keyword in an ATTACH statement for an attached database.
|
||||
* @param pages The number of pages to copy. If it is negative, all remaining pages are copied (default).
|
||||
*/
|
||||
backup(dest: Database, name = "main", pages = -1): void {
|
||||
const backup = sqlite3_backup_init(
|
||||
dest.#handle,
|
||||
toCString(name),
|
||||
this.#handle,
|
||||
toCString("main"),
|
||||
);
|
||||
if (backup) {
|
||||
unwrap(sqlite3_backup_step(backup, pages));
|
||||
unwrap(sqlite3_backup_finish(backup));
|
||||
} else {
|
||||
unwrap(sqlite3_errcode(dest.#handle), dest.#handle);
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.for("Deno.customInspect")](): string {
|
||||
return `SQLite3.Database { path: ${this.path} }`;
|
||||
}
|
||||
}
|
||||
|
||||
const controllers = new WeakMap();
|
||||
|
||||
// Return the database's cached transaction controller, or create a new one
|
||||
const getController = (db: Database) => {
|
||||
let controller = controllers.get(db);
|
||||
if (!controller) {
|
||||
const shared = {
|
||||
commit: db.prepare("COMMIT"),
|
||||
rollback: db.prepare("ROLLBACK"),
|
||||
savepoint: db.prepare("SAVEPOINT `\t_bs3.\t`"),
|
||||
release: db.prepare("RELEASE `\t_bs3.\t`"),
|
||||
rollbackTo: db.prepare("ROLLBACK TO `\t_bs3.\t`"),
|
||||
};
|
||||
|
||||
controllers.set(
|
||||
db,
|
||||
controller = {
|
||||
default: Object.assign(
|
||||
{ begin: db.prepare("BEGIN") },
|
||||
shared,
|
||||
),
|
||||
deferred: Object.assign(
|
||||
{ begin: db.prepare("BEGIN DEFERRED") },
|
||||
shared,
|
||||
),
|
||||
immediate: Object.assign(
|
||||
{ begin: db.prepare("BEGIN IMMEDIATE") },
|
||||
shared,
|
||||
),
|
||||
exclusive: Object.assign(
|
||||
{ begin: db.prepare("BEGIN EXCLUSIVE") },
|
||||
shared,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
return controller;
|
||||
};
|
||||
|
||||
// Return a new transaction function by wrapping the given function
|
||||
const wrapTransaction = <T extends (...args: any[]) => void>(
|
||||
fn: T,
|
||||
db: Database,
|
||||
{ begin, commit, rollback, savepoint, release, rollbackTo }: any,
|
||||
) =>
|
||||
function sqliteTransaction(...args: Parameters<T>): ReturnType<T> {
|
||||
const { apply } = Function.prototype;
|
||||
let before, after, undo;
|
||||
if (db.inTransaction) {
|
||||
before = savepoint;
|
||||
after = release;
|
||||
undo = rollbackTo;
|
||||
} else {
|
||||
before = begin;
|
||||
after = commit;
|
||||
undo = rollback;
|
||||
}
|
||||
before.run();
|
||||
try {
|
||||
// @ts-ignore An outer value of 'this' is shadowed by this container.
|
||||
const result = apply.call(fn, this, args);
|
||||
after.run();
|
||||
return result;
|
||||
} catch (ex) {
|
||||
if (!db.autocommit) {
|
||||
undo.run();
|
||||
if (undo !== rollback) after.run();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
};
|
||||
641
vendor/jsr.io/@db/sqlite/0.12.0/src/ffi.ts
generated
vendored
Normal file
641
vendor/jsr.io/@db/sqlite/0.12.0/src/ffi.ts
generated
vendored
Normal file
@ -0,0 +1,641 @@
|
||||
import meta from "../deno.json" with { type: "json" };
|
||||
import { dlopen } from "../deps.ts";
|
||||
|
||||
const symbols = {
|
||||
sqlite3_open_v2: {
|
||||
parameters: [
|
||||
"buffer", // const char *filename
|
||||
"buffer", // sqlite3 **ppDb
|
||||
"i32", // int flags
|
||||
"pointer", // const char *zVfs
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_close_v2: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_changes: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_total_changes: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_last_insert_rowid: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_get_autocommit: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_prepare_v2: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
"buffer", // const char *zSql
|
||||
"i32", // int nByte
|
||||
"buffer", // sqlite3_stmt **ppStmt
|
||||
"pointer", // const char **pzTail
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_reset: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_clear_bindings: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_step: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_column_count: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_column_type: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_column_text: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
sqlite3_column_value: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_finalize: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_exec: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
"buffer", // const char *sql
|
||||
"pointer", // sqlite3_callback callback
|
||||
"pointer", // void *arg
|
||||
"buffer", // char **errmsg
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_free: {
|
||||
parameters: [
|
||||
"pointer", // void *p
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_column_int: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_column_double: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "f64",
|
||||
},
|
||||
|
||||
sqlite3_column_blob: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_column_bytes: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_column_name: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_column_decltype: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "u64",
|
||||
},
|
||||
|
||||
sqlite3_bind_parameter_index: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"buffer", // const char *zName
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_text: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
"buffer", // const char *zData
|
||||
"i32", // int nData
|
||||
"pointer", // void (*xDel)(void*)
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_blob: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
"buffer", // const void *zData
|
||||
"i32", // int nData
|
||||
"pointer", // void (*xDel)(void*)
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_double: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
"f64", // double rValue
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_int: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
"i32", // int iValue
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_int64: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
"i64", // i64 iValue
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_null: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_expanded_sql: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_bind_parameter_count: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_complete: {
|
||||
parameters: [
|
||||
"buffer", // const char *sql
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_sourceid: {
|
||||
parameters: [],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_libversion: {
|
||||
parameters: [],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_blob_open: {
|
||||
parameters: [
|
||||
"pointer", /* sqlite3 *db */
|
||||
"buffer", /* const char *zDb */
|
||||
"buffer", /* const char *zTable */
|
||||
"buffer", /* const char *zColumn */
|
||||
"i64", /* sqlite3_int64 iRow */
|
||||
"i32", /* int flags */
|
||||
"buffer", /* sqlite3_blob **ppBlob */
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_blob_read: {
|
||||
parameters: [
|
||||
"pointer", /* sqlite3_blob *blob */
|
||||
"buffer", /* void *Z */
|
||||
"i32", /* int N */
|
||||
"i32", /* int iOffset */
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_blob_write: {
|
||||
parameters: [
|
||||
"pointer", /* sqlite3_blob *blob */
|
||||
"buffer", /* const void *z */
|
||||
"i32", /* int n */
|
||||
"i32", /* int iOffset */
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_blob_bytes: {
|
||||
parameters: ["pointer" /* sqlite3_blob *blob */],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_blob_close: {
|
||||
parameters: ["pointer" /* sqlite3_blob *blob */],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_sql: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_stmt_readonly: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_bind_parameter_name: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_errcode: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_errmsg: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_errstr: {
|
||||
parameters: [
|
||||
"i32", // int rc
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_column_int64: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_stmt *pStmt
|
||||
"i32", // int iCol
|
||||
],
|
||||
result: "i64",
|
||||
},
|
||||
|
||||
sqlite3_backup_init: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *pDest
|
||||
"buffer", // const char *zDestName
|
||||
"pointer", // sqlite3 *pSource
|
||||
"buffer", // const char *zSourceName
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_backup_step: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_backup *p
|
||||
"i32", // int nPage
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_backup_finish: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_backup *p
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_backup_remaining: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_backup *p
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_backup_pagecount: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_backup *p
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_create_function: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
"buffer", // const char *zFunctionName
|
||||
"i32", // int nArg
|
||||
"i32", // int eTextRep
|
||||
"pointer", // void *pApp
|
||||
"pointer", // void (*xFunc)(sqlite3_context*,int,sqlite3_value**)
|
||||
"pointer", // void (*xStep)(sqlite3_context*,int,sqlite3_value**)
|
||||
"pointer", // void (*xFinal)(sqlite3_context*)
|
||||
],
|
||||
result: "i32",
|
||||
optional: true,
|
||||
},
|
||||
|
||||
sqlite3_result_blob: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"buffer", // const void *z
|
||||
"i32", // int n
|
||||
"isize", // void (*xDel)(void*)
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_double: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"f64", // double rVal
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_error: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"buffer", // const char *z
|
||||
"i32", // int n
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_int: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"i32", // int iVal
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_int64: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"i64", // sqlite3_int64 iVal
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_null: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_result_text: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"buffer", // const char *z
|
||||
"i32", // int n
|
||||
"isize", // void (*xDel)(void*)
|
||||
],
|
||||
result: "void",
|
||||
},
|
||||
|
||||
sqlite3_value_type: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
sqlite3_value_subtype: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_value_blob: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_value_double: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "f64",
|
||||
},
|
||||
|
||||
sqlite3_value_int: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_value_int64: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "i64",
|
||||
},
|
||||
|
||||
sqlite3_value_text: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
sqlite3_value_bytes: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_value *pVal
|
||||
],
|
||||
result: "i32",
|
||||
},
|
||||
|
||||
sqlite3_aggregate_context: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3_context *p
|
||||
"i32", // int nBytes
|
||||
],
|
||||
result: "pointer",
|
||||
optional: true,
|
||||
},
|
||||
|
||||
sqlite3_enable_load_extension: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
"i32", // int onoff
|
||||
],
|
||||
result: "i32",
|
||||
optional: true,
|
||||
},
|
||||
|
||||
sqlite3_load_extension: {
|
||||
parameters: [
|
||||
"pointer", // sqlite3 *db
|
||||
"buffer", // const char *zFile
|
||||
"buffer", // const char *zProc
|
||||
"buffer", // const char **pzErrMsg
|
||||
],
|
||||
result: "i32",
|
||||
optional: true,
|
||||
},
|
||||
|
||||
sqlite3_initialize: {
|
||||
parameters: [],
|
||||
result: "i32",
|
||||
},
|
||||
} as const satisfies Deno.ForeignLibraryInterface;
|
||||
|
||||
let lib: Deno.DynamicLibrary<typeof symbols>["symbols"];
|
||||
|
||||
function tryGetEnv(key: string): string | undefined {
|
||||
try {
|
||||
return Deno.env.get(key);
|
||||
} catch (e) {
|
||||
if (e instanceof Deno.errors.PermissionDenied) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const customPath = tryGetEnv("DENO_SQLITE_PATH");
|
||||
const sqliteLocal = tryGetEnv("DENO_SQLITE_LOCAL");
|
||||
|
||||
if (sqliteLocal === "1") {
|
||||
lib = Deno.dlopen(
|
||||
new URL(
|
||||
`../build/${Deno.build.os === "windows" ? "" : "lib"}sqlite3${
|
||||
Deno.build.arch !== "x86_64" ? `_${Deno.build.arch}` : ""
|
||||
}.${
|
||||
Deno.build.os === "windows"
|
||||
? "dll"
|
||||
: Deno.build.os === "darwin"
|
||||
? "dylib"
|
||||
: "so"
|
||||
}`,
|
||||
import.meta.url,
|
||||
),
|
||||
symbols,
|
||||
).symbols;
|
||||
} else if (customPath) {
|
||||
lib = Deno.dlopen(customPath, symbols).symbols;
|
||||
} else {
|
||||
lib = (
|
||||
await dlopen(
|
||||
{
|
||||
name: "sqlite3",
|
||||
url: `${meta.github}/releases/download/${meta.version}/`,
|
||||
suffixes: {
|
||||
aarch64: "_aarch64",
|
||||
},
|
||||
},
|
||||
symbols,
|
||||
)
|
||||
).symbols;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Deno.errors.PermissionDenied) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
throw new Error("Failed to load SQLite3 Dynamic Library", { cause: e });
|
||||
}
|
||||
|
||||
const init = lib.sqlite3_initialize();
|
||||
if (init !== 0) {
|
||||
throw new Error(`Failed to initialize SQLite3: ${init}`);
|
||||
}
|
||||
|
||||
export default lib;
|
||||
727
vendor/jsr.io/@db/sqlite/0.12.0/src/statement.ts
generated
vendored
Normal file
727
vendor/jsr.io/@db/sqlite/0.12.0/src/statement.ts
generated
vendored
Normal file
@ -0,0 +1,727 @@
|
||||
import type { Database } from "./database.ts";
|
||||
import { readCstr, toCString, unwrap } from "./util.ts";
|
||||
import ffi from "./ffi.ts";
|
||||
import {
|
||||
SQLITE3_DONE,
|
||||
SQLITE3_ROW,
|
||||
SQLITE_BLOB,
|
||||
SQLITE_FLOAT,
|
||||
SQLITE_INTEGER,
|
||||
SQLITE_TEXT,
|
||||
} from "./constants.ts";
|
||||
|
||||
const {
|
||||
sqlite3_prepare_v2,
|
||||
sqlite3_reset,
|
||||
sqlite3_clear_bindings,
|
||||
sqlite3_step,
|
||||
sqlite3_column_count,
|
||||
sqlite3_column_type,
|
||||
sqlite3_column_value,
|
||||
sqlite3_value_subtype,
|
||||
sqlite3_column_text,
|
||||
sqlite3_finalize,
|
||||
sqlite3_column_int64,
|
||||
sqlite3_column_double,
|
||||
sqlite3_column_blob,
|
||||
sqlite3_column_bytes,
|
||||
sqlite3_column_name,
|
||||
sqlite3_expanded_sql,
|
||||
sqlite3_bind_parameter_count,
|
||||
sqlite3_bind_int,
|
||||
sqlite3_bind_int64,
|
||||
sqlite3_bind_text,
|
||||
sqlite3_bind_blob,
|
||||
sqlite3_bind_double,
|
||||
sqlite3_bind_parameter_index,
|
||||
sqlite3_sql,
|
||||
sqlite3_stmt_readonly,
|
||||
sqlite3_bind_parameter_name,
|
||||
sqlite3_changes,
|
||||
sqlite3_column_int,
|
||||
} = ffi;
|
||||
|
||||
/** Types that can be possibly serialized as SQLite bind values */
|
||||
export type BindValue =
|
||||
| number
|
||||
| string
|
||||
| symbol
|
||||
| bigint
|
||||
| boolean
|
||||
| null
|
||||
| undefined
|
||||
| Date
|
||||
| Uint8Array
|
||||
| BindValue[]
|
||||
| { [key: string]: BindValue };
|
||||
|
||||
export type BindParameters = BindValue[] | Record<string, BindValue>;
|
||||
export type RestBindParameters = BindValue[] | [BindParameters];
|
||||
|
||||
/** Maps sqlite_stmt* pointers to sqlite* db pointers. */
|
||||
export const STATEMENTS_TO_DB = new Map<Deno.PointerValue, Deno.PointerValue>();
|
||||
|
||||
const emptyStringBuffer = new Uint8Array(1);
|
||||
|
||||
const statementFinalizer = new FinalizationRegistry(
|
||||
(ptr: Deno.PointerValue) => {
|
||||
if (STATEMENTS_TO_DB.has(ptr)) {
|
||||
sqlite3_finalize(ptr);
|
||||
STATEMENTS_TO_DB.delete(ptr);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// https://github.com/sqlite/sqlite/blob/195611d8e6fc0bba559a49e91e6ceb42e4bdd6ba/src/json.c#L125-L126
|
||||
const JSON_SUBTYPE = 74;
|
||||
|
||||
const BIG_MAX = BigInt(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
function getColumn(handle: Deno.PointerValue, i: number, int64: boolean): any {
|
||||
const ty = sqlite3_column_type(handle, i);
|
||||
|
||||
if (ty === SQLITE_INTEGER && !int64) return sqlite3_column_int(handle, i);
|
||||
|
||||
switch (ty) {
|
||||
case SQLITE_TEXT: {
|
||||
const ptr = sqlite3_column_text(handle, i);
|
||||
if (ptr === null) return null;
|
||||
const text = readCstr(ptr, 0);
|
||||
const value = sqlite3_column_value(handle, i);
|
||||
const subtype = sqlite3_value_subtype(value);
|
||||
if (subtype === JSON_SUBTYPE) {
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (_error) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
case SQLITE_INTEGER: {
|
||||
const val = sqlite3_column_int64(handle, i);
|
||||
if (val < -BIG_MAX || val > BIG_MAX) {
|
||||
return val;
|
||||
}
|
||||
return Number(val);
|
||||
}
|
||||
|
||||
case SQLITE_FLOAT: {
|
||||
return sqlite3_column_double(handle, i);
|
||||
}
|
||||
|
||||
case SQLITE_BLOB: {
|
||||
const ptr = sqlite3_column_blob(handle, i);
|
||||
|
||||
if (ptr === null) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
|
||||
const bytes = sqlite3_column_bytes(handle, i);
|
||||
return new Uint8Array(
|
||||
Deno.UnsafePointerView.getArrayBuffer(ptr, bytes).slice(0),
|
||||
);
|
||||
}
|
||||
|
||||
default: {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a prepared statement.
|
||||
*
|
||||
* See `Database#prepare` for more information.
|
||||
*/
|
||||
export class Statement {
|
||||
#handle: Deno.PointerValue;
|
||||
#finalizerToken: { handle: Deno.PointerValue };
|
||||
#bound = false;
|
||||
#hasNoArgs = false;
|
||||
#unsafeConcurrency;
|
||||
|
||||
/**
|
||||
* Whether the query might call into JavaScript or not.
|
||||
*
|
||||
* Must enable if the query makes use of user defined functions,
|
||||
* otherwise there can be V8 crashes.
|
||||
*
|
||||
* Off by default. Causes performance degradation.
|
||||
*/
|
||||
callback = false;
|
||||
|
||||
/** Unsafe Raw (pointer) to the sqlite object */
|
||||
get unsafeHandle(): Deno.PointerValue {
|
||||
return this.#handle;
|
||||
}
|
||||
|
||||
/** SQL string including bindings */
|
||||
get expandedSql(): string {
|
||||
return readCstr(sqlite3_expanded_sql(this.#handle)!);
|
||||
}
|
||||
|
||||
/** The SQL string that we passed when creating statement */
|
||||
get sql(): string {
|
||||
return readCstr(sqlite3_sql(this.#handle)!);
|
||||
}
|
||||
|
||||
/** Whether this statement doesn't make any direct changes to the DB */
|
||||
get readonly(): boolean {
|
||||
return sqlite3_stmt_readonly(this.#handle) !== 0;
|
||||
}
|
||||
|
||||
/** Simply run the query without retrieving any output there may be. */
|
||||
run(...args: RestBindParameters): number {
|
||||
return this.#runWithArgs(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the query and return the resulting rows where rows are array of columns.
|
||||
*/
|
||||
values<T extends unknown[] = any[]>(...args: RestBindParameters): T[] {
|
||||
return this.#valuesWithArgs(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the query and return the resulting rows where rows are objects
|
||||
* mapping column name to their corresponding values.
|
||||
*/
|
||||
all<T extends object = Record<string, any>>(
|
||||
...args: RestBindParameters
|
||||
): T[] {
|
||||
return this.#allWithArgs(...args);
|
||||
}
|
||||
|
||||
#bindParameterCount: number;
|
||||
|
||||
/** Number of parameters (to be) bound */
|
||||
get bindParameterCount(): number {
|
||||
return this.#bindParameterCount;
|
||||
}
|
||||
|
||||
constructor(public db: Database, sql: string) {
|
||||
const pHandle = new BigUint64Array(1);
|
||||
unwrap(
|
||||
sqlite3_prepare_v2(
|
||||
db.unsafeHandle,
|
||||
toCString(sql),
|
||||
sql.length,
|
||||
pHandle,
|
||||
null,
|
||||
),
|
||||
db.unsafeHandle,
|
||||
);
|
||||
this.#handle = Deno.UnsafePointer.create(pHandle[0]);
|
||||
STATEMENTS_TO_DB.set(this.#handle, db.unsafeHandle);
|
||||
this.#unsafeConcurrency = db.unsafeConcurrency;
|
||||
this.#finalizerToken = { handle: this.#handle };
|
||||
statementFinalizer.register(this, this.#handle, this.#finalizerToken);
|
||||
|
||||
if (
|
||||
(this.#bindParameterCount = sqlite3_bind_parameter_count(
|
||||
this.#handle,
|
||||
)) === 0
|
||||
) {
|
||||
this.#hasNoArgs = true;
|
||||
this.all = this.#allNoArgs;
|
||||
this.values = this.#valuesNoArgs;
|
||||
this.run = this.#runNoArgs;
|
||||
this.value = this.#valueNoArgs;
|
||||
this.get = this.#getNoArgs;
|
||||
}
|
||||
}
|
||||
|
||||
/** Shorthand for `this.callback = true`. Enables calling user defined functions. */
|
||||
enableCallback(): this {
|
||||
this.callback = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Get bind parameter name by index */
|
||||
bindParameterName(i: number): string {
|
||||
return readCstr(sqlite3_bind_parameter_name(this.#handle, i)!);
|
||||
}
|
||||
|
||||
/** Get bind parameter index by name */
|
||||
bindParameterIndex(name: string): number {
|
||||
if (name[0] !== ":" && name[0] !== "@" && name[0] !== "$") {
|
||||
name = ":" + name;
|
||||
}
|
||||
return sqlite3_bind_parameter_index(this.#handle, toCString(name));
|
||||
}
|
||||
|
||||
#begin(): void {
|
||||
sqlite3_reset(this.#handle);
|
||||
if (!this.#bound && !this.#hasNoArgs) {
|
||||
sqlite3_clear_bindings(this.#handle);
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#bindRefs: Set<any> = new Set();
|
||||
|
||||
#bind(i: number, param: BindValue): void {
|
||||
switch (typeof param) {
|
||||
case "number": {
|
||||
if (Number.isInteger(param)) {
|
||||
if (
|
||||
Number.isSafeInteger(param) && param >= -(2 ** 31) &&
|
||||
param < 2 ** 31
|
||||
) {
|
||||
unwrap(sqlite3_bind_int(this.#handle, i + 1, param));
|
||||
} else {
|
||||
unwrap(sqlite3_bind_int64(this.#handle, i + 1, BigInt(param)));
|
||||
}
|
||||
} else {
|
||||
unwrap(sqlite3_bind_double(this.#handle, i + 1, param));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "string": {
|
||||
if (param === "") {
|
||||
// Empty string is encoded as empty buffer in Deno. And as of
|
||||
// right now (Deno 1.29.1), ffi layer converts it to NULL pointer,
|
||||
// which causes sqlite3_bind_text to bind the NULL value instead
|
||||
// of an empty string. As a workaround let's use a special
|
||||
// non-empty buffer, but specify zero length.
|
||||
unwrap(
|
||||
sqlite3_bind_text(this.#handle, i + 1, emptyStringBuffer, 0, null),
|
||||
);
|
||||
} else {
|
||||
const str = new TextEncoder().encode(param);
|
||||
this.#bindRefs.add(str);
|
||||
unwrap(
|
||||
sqlite3_bind_text(this.#handle, i + 1, str, str.byteLength, null),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "object": {
|
||||
if (param === null) {
|
||||
// pass
|
||||
} else if (param instanceof Uint8Array) {
|
||||
this.#bindRefs.add(param);
|
||||
unwrap(
|
||||
sqlite3_bind_blob(
|
||||
this.#handle,
|
||||
i + 1,
|
||||
param.byteLength === 0 ? emptyStringBuffer : param,
|
||||
param.byteLength,
|
||||
null,
|
||||
),
|
||||
);
|
||||
} else if (param instanceof Date) {
|
||||
const cstring = toCString(param.toISOString());
|
||||
this.#bindRefs.add(cstring);
|
||||
unwrap(
|
||||
sqlite3_bind_text(
|
||||
this.#handle,
|
||||
i + 1,
|
||||
cstring,
|
||||
-1,
|
||||
null,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
const cstring = toCString(JSON.stringify(param));
|
||||
this.#bindRefs.add(cstring);
|
||||
unwrap(
|
||||
sqlite3_bind_text(
|
||||
this.#handle,
|
||||
i + 1,
|
||||
cstring,
|
||||
-1,
|
||||
null,
|
||||
),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "bigint": {
|
||||
unwrap(sqlite3_bind_int64(this.#handle, i + 1, param));
|
||||
break;
|
||||
}
|
||||
|
||||
case "boolean":
|
||||
unwrap(sqlite3_bind_int(
|
||||
this.#handle,
|
||||
i + 1,
|
||||
param ? 1 : 0,
|
||||
));
|
||||
break;
|
||||
default: {
|
||||
throw new Error(`Value of unsupported type: ${Deno.inspect(param)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind parameters to the statement. This method can only be called once
|
||||
* to set the parameters to be same throughout the statement. You cannot
|
||||
* change the parameters after this method is called.
|
||||
*
|
||||
* This method is merely just for optimization to avoid binding parameters
|
||||
* each time in prepared statement.
|
||||
*/
|
||||
bind(...params: RestBindParameters): this {
|
||||
this.#bindAll(params);
|
||||
this.#bound = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
#bindAll(params: RestBindParameters | BindParameters): void {
|
||||
if (this.#bound) throw new Error("Statement already bound to values");
|
||||
if (
|
||||
typeof params[0] === "object" && params[0] !== null &&
|
||||
!(params[0] instanceof Uint8Array) && !(params[0] instanceof Date)
|
||||
) {
|
||||
params = params[0];
|
||||
}
|
||||
if (Array.isArray(params)) {
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
this.#bind(i, (params as BindValue[])[i]);
|
||||
}
|
||||
} else {
|
||||
for (const [name, param] of Object.entries(params)) {
|
||||
const i = this.bindParameterIndex(name);
|
||||
if (i === 0) {
|
||||
throw new Error(`No such parameter "${name}"`);
|
||||
}
|
||||
this.#bind(i - 1, param as BindValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#runNoArgs(): number {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
const status = sqlite3_step(handle);
|
||||
if (status !== SQLITE3_ROW && status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return sqlite3_changes(this.db.unsafeHandle);
|
||||
}
|
||||
|
||||
#runWithArgs(...params: RestBindParameters): number {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
this.#bindAll(params);
|
||||
const status = sqlite3_step(handle);
|
||||
if (!this.#hasNoArgs && !this.#bound && params.length) {
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
if (status !== SQLITE3_ROW && status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return sqlite3_changes(this.db.unsafeHandle);
|
||||
}
|
||||
|
||||
#valuesNoArgs<T extends Array<unknown>>(): T[] {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
const columnCount = sqlite3_column_count(handle);
|
||||
const result: T[] = [];
|
||||
const getRowArray = new Function(
|
||||
"getColumn",
|
||||
`
|
||||
return function(h) {
|
||||
return [${
|
||||
Array.from({ length: columnCount }).map((_, i) =>
|
||||
`getColumn(h, ${i}, ${this.db.int64})`
|
||||
)
|
||||
.join(", ")
|
||||
}];
|
||||
};
|
||||
`,
|
||||
)(getColumn);
|
||||
let status = sqlite3_step(handle);
|
||||
while (status === SQLITE3_ROW) {
|
||||
result.push(getRowArray(handle));
|
||||
status = sqlite3_step(handle);
|
||||
}
|
||||
if (status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return result as T[];
|
||||
}
|
||||
|
||||
#valuesWithArgs<T extends Array<unknown>>(
|
||||
...params: RestBindParameters
|
||||
): T[] {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
this.#bindAll(params);
|
||||
const columnCount = sqlite3_column_count(handle);
|
||||
const result: T[] = [];
|
||||
const getRowArray = new Function(
|
||||
"getColumn",
|
||||
`
|
||||
return function(h) {
|
||||
return [${
|
||||
Array.from({ length: columnCount }).map((_, i) =>
|
||||
`getColumn(h, ${i}, ${this.db.int64})`
|
||||
)
|
||||
.join(", ")
|
||||
}];
|
||||
};
|
||||
`,
|
||||
)(getColumn);
|
||||
let status = sqlite3_step(handle);
|
||||
while (status === SQLITE3_ROW) {
|
||||
result.push(getRowArray(handle));
|
||||
status = sqlite3_step(handle);
|
||||
}
|
||||
if (!this.#hasNoArgs && !this.#bound && params.length) {
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
if (status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return result as T[];
|
||||
}
|
||||
|
||||
#rowObjectFn: ((h: Deno.PointerValue) => any) | undefined;
|
||||
|
||||
getRowObject(): (h: Deno.PointerValue) => any {
|
||||
if (!this.#rowObjectFn || !this.#unsafeConcurrency) {
|
||||
const columnNames = this.columnNames();
|
||||
const getRowObject = new Function(
|
||||
"getColumn",
|
||||
`
|
||||
return function(h) {
|
||||
return {
|
||||
${
|
||||
columnNames.map((name, i) =>
|
||||
`"${name}": getColumn(h, ${i}, ${this.db.int64})`
|
||||
).join(",\n")
|
||||
}
|
||||
};
|
||||
};
|
||||
`,
|
||||
)(getColumn);
|
||||
this.#rowObjectFn = getRowObject;
|
||||
}
|
||||
return this.#rowObjectFn!;
|
||||
}
|
||||
|
||||
#allNoArgs<T extends object>(): T[] {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
const getRowObject = this.getRowObject();
|
||||
const result: T[] = [];
|
||||
let status = sqlite3_step(handle);
|
||||
while (status === SQLITE3_ROW) {
|
||||
result.push(getRowObject(handle));
|
||||
status = sqlite3_step(handle);
|
||||
}
|
||||
if (status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return result as T[];
|
||||
}
|
||||
|
||||
#allWithArgs<T extends object>(
|
||||
...params: RestBindParameters
|
||||
): T[] {
|
||||
const handle = this.#handle;
|
||||
this.#begin();
|
||||
this.#bindAll(params);
|
||||
const getRowObject = this.getRowObject();
|
||||
const result: T[] = [];
|
||||
let status = sqlite3_step(handle);
|
||||
while (status === SQLITE3_ROW) {
|
||||
result.push(getRowObject(handle));
|
||||
status = sqlite3_step(handle);
|
||||
}
|
||||
if (!this.#hasNoArgs && !this.#bound && params.length) {
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
if (status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return result as T[];
|
||||
}
|
||||
|
||||
/** Fetch only first row as an array, if any. */
|
||||
value<T extends Array<unknown>>(
|
||||
...params: RestBindParameters
|
||||
): T | undefined {
|
||||
const handle = this.#handle;
|
||||
const int64 = this.db.int64;
|
||||
const arr = new Array(sqlite3_column_count(handle));
|
||||
sqlite3_reset(handle);
|
||||
if (!this.#hasNoArgs && !this.#bound) {
|
||||
sqlite3_clear_bindings(handle);
|
||||
this.#bindRefs.clear();
|
||||
if (params.length) {
|
||||
this.#bindAll(params);
|
||||
}
|
||||
}
|
||||
|
||||
const status = sqlite3_step(handle);
|
||||
|
||||
if (!this.#hasNoArgs && !this.#bound && params.length) {
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
|
||||
if (status === SQLITE3_ROW) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
arr[i] = getColumn(handle, i, int64);
|
||||
}
|
||||
sqlite3_reset(this.#handle);
|
||||
return arr as T;
|
||||
} else if (status === SQLITE3_DONE) {
|
||||
return;
|
||||
} else {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
#valueNoArgs<T extends Array<unknown>>(): T | undefined {
|
||||
const handle = this.#handle;
|
||||
const int64 = this.db.int64;
|
||||
const cc = sqlite3_column_count(handle);
|
||||
const arr = new Array(cc);
|
||||
sqlite3_reset(handle);
|
||||
const status = sqlite3_step(handle);
|
||||
if (status === SQLITE3_ROW) {
|
||||
for (let i = 0; i < cc; i++) {
|
||||
arr[i] = getColumn(handle, i, int64);
|
||||
}
|
||||
sqlite3_reset(this.#handle);
|
||||
return arr as T;
|
||||
} else if (status === SQLITE3_DONE) {
|
||||
return;
|
||||
} else {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
#columnNames: string[] | undefined;
|
||||
#rowObject: Record<string, unknown> = {};
|
||||
|
||||
columnNames(): string[] {
|
||||
if (!this.#columnNames || !this.#unsafeConcurrency) {
|
||||
const columnCount = sqlite3_column_count(this.#handle);
|
||||
const columnNames = new Array(columnCount);
|
||||
for (let i = 0; i < columnCount; i++) {
|
||||
columnNames[i] = readCstr(sqlite3_column_name(this.#handle, i)!);
|
||||
}
|
||||
this.#columnNames = columnNames;
|
||||
this.#rowObject = {};
|
||||
for (const name of columnNames) {
|
||||
this.#rowObject![name] = undefined;
|
||||
}
|
||||
}
|
||||
return this.#columnNames!;
|
||||
}
|
||||
|
||||
/** Fetch only first row as an object, if any. */
|
||||
get<T extends object>(
|
||||
...params: RestBindParameters
|
||||
): T | undefined {
|
||||
const handle = this.#handle;
|
||||
const int64 = this.db.int64;
|
||||
|
||||
const columnNames = this.columnNames();
|
||||
|
||||
const row: Record<string, unknown> = {};
|
||||
sqlite3_reset(handle);
|
||||
if (!this.#hasNoArgs && !this.#bound) {
|
||||
sqlite3_clear_bindings(handle);
|
||||
this.#bindRefs.clear();
|
||||
if (params.length) {
|
||||
this.#bindAll(params);
|
||||
}
|
||||
}
|
||||
|
||||
const status = sqlite3_step(handle);
|
||||
|
||||
if (!this.#hasNoArgs && !this.#bound && params.length) {
|
||||
this.#bindRefs.clear();
|
||||
}
|
||||
|
||||
if (status === SQLITE3_ROW) {
|
||||
for (let i = 0; i < columnNames.length; i++) {
|
||||
row[columnNames[i]] = getColumn(handle, i, int64);
|
||||
}
|
||||
sqlite3_reset(this.#handle);
|
||||
return row as T;
|
||||
} else if (status === SQLITE3_DONE) {
|
||||
return;
|
||||
} else {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
#getNoArgs<T extends object>(): T | undefined {
|
||||
const handle = this.#handle;
|
||||
const int64 = this.db.int64;
|
||||
const columnNames = this.columnNames();
|
||||
const row: Record<string, unknown> = this.#rowObject;
|
||||
sqlite3_reset(handle);
|
||||
const status = sqlite3_step(handle);
|
||||
if (status === SQLITE3_ROW) {
|
||||
for (let i = 0; i < columnNames?.length; i++) {
|
||||
row[columnNames[i]] = getColumn(handle, i, int64);
|
||||
}
|
||||
sqlite3_reset(handle);
|
||||
return row as T;
|
||||
} else if (status === SQLITE3_DONE) {
|
||||
return;
|
||||
} else {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/** Free up the statement object. */
|
||||
finalize(): void {
|
||||
if (!STATEMENTS_TO_DB.has(this.#handle)) return;
|
||||
this.#bindRefs.clear();
|
||||
statementFinalizer.unregister(this.#finalizerToken);
|
||||
STATEMENTS_TO_DB.delete(this.#handle);
|
||||
unwrap(sqlite3_finalize(this.#handle));
|
||||
}
|
||||
|
||||
/** Coerces the statement to a string, which in this case is expanded SQL. */
|
||||
toString(): string {
|
||||
return readCstr(sqlite3_expanded_sql(this.#handle)!);
|
||||
}
|
||||
|
||||
/** Iterate over resultant rows from query. */
|
||||
*iter(...params: RestBindParameters): IterableIterator<any> {
|
||||
this.#begin();
|
||||
this.#bindAll(params);
|
||||
const getRowObject = this.getRowObject();
|
||||
let status = sqlite3_step(this.#handle);
|
||||
while (status === SQLITE3_ROW) {
|
||||
yield getRowObject(this.#handle);
|
||||
status = sqlite3_step(this.#handle);
|
||||
}
|
||||
if (status !== SQLITE3_DONE) {
|
||||
unwrap(status, this.db.unsafeHandle);
|
||||
}
|
||||
sqlite3_reset(this.#handle);
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<any> {
|
||||
return this.iter();
|
||||
}
|
||||
|
||||
[Symbol.dispose](): void {
|
||||
this.finalize();
|
||||
}
|
||||
|
||||
[Symbol.for("Deno.customInspect")](): string {
|
||||
return `Statement { ${this.expandedSql} }`;
|
||||
}
|
||||
}
|
||||
48
vendor/jsr.io/@db/sqlite/0.12.0/src/util.ts
generated
vendored
Normal file
48
vendor/jsr.io/@db/sqlite/0.12.0/src/util.ts
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
import { SQLITE3_DONE, SQLITE3_MISUSE, SQLITE3_OK } from "./constants.ts";
|
||||
import ffi from "./ffi.ts";
|
||||
|
||||
const {
|
||||
sqlite3_errmsg,
|
||||
sqlite3_errstr,
|
||||
} = ffi;
|
||||
|
||||
export const encoder = new TextEncoder();
|
||||
|
||||
export function toCString(str: string): Uint8Array {
|
||||
return encoder.encode(str + "\0");
|
||||
}
|
||||
|
||||
export function isObject(value: unknown): boolean {
|
||||
return typeof value === "object" && value !== null;
|
||||
}
|
||||
|
||||
export class SqliteError extends Error {
|
||||
name = "SqliteError";
|
||||
|
||||
constructor(
|
||||
public code: number = 1,
|
||||
message: string = "Unknown Error",
|
||||
) {
|
||||
super(`${code}: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function unwrap(code: number, db?: Deno.PointerValue): void {
|
||||
if (code === SQLITE3_OK || code === SQLITE3_DONE) return;
|
||||
if (code === SQLITE3_MISUSE) {
|
||||
throw new SqliteError(code, "SQLite3 API misuse");
|
||||
} else if (db !== undefined) {
|
||||
const errmsg = sqlite3_errmsg(db);
|
||||
if (errmsg === null) throw new SqliteError(code);
|
||||
throw new Error(Deno.UnsafePointerView.getCString(errmsg));
|
||||
} else {
|
||||
throw new SqliteError(
|
||||
code,
|
||||
Deno.UnsafePointerView.getCString(sqlite3_errstr(code)!),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const buf = Deno.UnsafePointerView.getArrayBuffer;
|
||||
|
||||
export const readCstr = Deno.UnsafePointerView.getCString;
|
||||
532
vendor/jsr.io/@db/sqlite/0.12.0_meta.json
generated
vendored
Normal file
532
vendor/jsr.io/@db/sqlite/0.12.0_meta.json
generated
vendored
Normal file
@ -0,0 +1,532 @@
|
||||
{
|
||||
"manifest": {
|
||||
"/src/statement.ts": {
|
||||
"size": 19811,
|
||||
"checksum": "sha256-e8ccde898aef47c7a2514953aca5359a44a285bc3dc0de5819d66f891f477be1"
|
||||
},
|
||||
"/src/ffi.ts": {
|
||||
"size": 12263,
|
||||
"checksum": "sha256-795b598eeae4d12f182e7bcdab524b74b0f01d6deae7f4d8ce63f25c06a46154"
|
||||
},
|
||||
"/bench/northwind/deno.js": {
|
||||
"size": 993,
|
||||
"checksum": "sha256-8009f531181554cc0b7e00f2e0a32f00aa5debad08347bc0c340959034155b0c"
|
||||
},
|
||||
"/src/util.ts": {
|
||||
"size": 1252,
|
||||
"checksum": "sha256-c6604183d2ec5fb17fa0a018572ed5f2317b319dbd7bf48d88a5d06ff25b2cc3"
|
||||
},
|
||||
"/bench/northwind/deno_old.js": {
|
||||
"size": 845,
|
||||
"checksum": "sha256-2c739731eff0b14572b71480fea6daa1a7233733998a9b2fbe82457116d25c08"
|
||||
},
|
||||
"/.gitmodules": {
|
||||
"size": 76,
|
||||
"checksum": "sha256-5f8d6b06ad75304ae8f1cac12dee879165b7a49f4e5a716b06f5ff1ddcee0418"
|
||||
},
|
||||
"/src/constants.ts": {
|
||||
"size": 2478,
|
||||
"checksum": "sha256-85fd27aa6e199093f25f5f437052e16fd0e0870b96ca9b24a98e04ddc8b7d006"
|
||||
},
|
||||
"/.github/FUNDING.yml": {
|
||||
"size": 23,
|
||||
"checksum": "sha256-bb4e0cedf30e330abf572013ee6220f4928273d8cc8dd90242b5b6888d4c8e6a"
|
||||
},
|
||||
"/bench/northwind/deno_wasm.js": {
|
||||
"size": 1028,
|
||||
"checksum": "sha256-f91a88e2eb8b6e10b4ca9a86eb8f36453792d4ef075ccbf7a756e701fab20ff0"
|
||||
},
|
||||
"/test/test.ts": {
|
||||
"size": 14434,
|
||||
"checksum": "sha256-6ef55635b1143b7dbf121eb9d3458a91537334f058f6d57c603bc413e72caa17"
|
||||
},
|
||||
"/bench/northwind/node.mjs": {
|
||||
"size": 1091,
|
||||
"checksum": "sha256-cd3759ab841b5f0c1c0406dfd5c169f63a535f748b0a2a11fe25822e6bc12db8"
|
||||
},
|
||||
"/bench/makefile": {
|
||||
"size": 79,
|
||||
"checksum": "sha256-58559ec25fcf986ce9250db85784722e622332ab854611428d7c717abd896b7b"
|
||||
},
|
||||
"/bench/northwind/bun.js": {
|
||||
"size": 968,
|
||||
"checksum": "sha256-9433ae459a7acbd9f78c7d37ba0ff8fd247186f3aed0c6a64a6073be24ca9a52"
|
||||
},
|
||||
"/LICENSE": {
|
||||
"size": 11543,
|
||||
"checksum": "sha256-23583fa34c041cdeb82b28bb117d8697cd5c212effff70efb831f173c0c68b66"
|
||||
},
|
||||
"/mod.ts": {
|
||||
"size": 432,
|
||||
"checksum": "sha256-3169f246c0eddd6ed82862758f4109f167b7ba5538236240fbb26a129f1bc16c"
|
||||
},
|
||||
"/bench/bench.js": {
|
||||
"size": 3409,
|
||||
"checksum": "sha256-f54929af49c5c1d5825ba3689064161717315e35df25117daf0167da672a3f72"
|
||||
},
|
||||
"/bench/bench_python.py": {
|
||||
"size": 666,
|
||||
"checksum": "sha256-c85d12f7a1d88e54418b58fcb20b1c9628dd721997d74bfdcce4e38194bd5293"
|
||||
},
|
||||
"/bench/bench_node.js": {
|
||||
"size": 740,
|
||||
"checksum": "sha256-2524a7f6c2c9350c5a8ab1a05df9977075350f97a9cad2640b9bd51da43e897e"
|
||||
},
|
||||
"/bench/bench_deno_ffi.js": {
|
||||
"size": 1826,
|
||||
"checksum": "sha256-53c02fc0ae9bd7b84b5d06220d0a6fff9d0daac1abf117d1dc30a2ded46f23e2"
|
||||
},
|
||||
"/bench/download.sh": {
|
||||
"size": 375,
|
||||
"checksum": "sha256-07c52368f7a13765303430ec1797bcb098dcc66482191219bb154ea07441928a"
|
||||
},
|
||||
"/bench/bench_bun.js": {
|
||||
"size": 828,
|
||||
"checksum": "sha256-03a7c603a5c55b21b3f6febeaf5061f245875be47ba76dbd474024ac4a926105"
|
||||
},
|
||||
"/bench/bench.c": {
|
||||
"size": 1359,
|
||||
"checksum": "sha256-275247e3bcd62935376369940abc8617787113b31d76911a1431b65650ef2547"
|
||||
},
|
||||
"/test/deps.ts": {
|
||||
"size": 66,
|
||||
"checksum": "sha256-5da2bf33a7a61aa2680f1aba05b07f1a687a682d7b8f4f8a8a1481ee6163260a"
|
||||
},
|
||||
"/bench/bench_deno.js": {
|
||||
"size": 729,
|
||||
"checksum": "sha256-2ca30ec55aac5b48bfc4bca27305c7171a111743783dc138f45a56827dae46f7"
|
||||
},
|
||||
"/src/blob.ts": {
|
||||
"size": 4161,
|
||||
"checksum": "sha256-330886fae9714e4a612786f44d8117d65f91e778cf3f40de59b34879fc7ca9ab"
|
||||
},
|
||||
"/package.json": {
|
||||
"size": 1093,
|
||||
"checksum": "sha256-062ecb8336c9921ba20523b172fe4fcd0547bcb885b482fe3089ee6d84b7a177"
|
||||
},
|
||||
"/src/database.ts": {
|
||||
"size": 25465,
|
||||
"checksum": "sha256-4d380d7f0e5a2cf74635a9fcd2b4e27373533f2816cde5357067e51fd22ad8d0"
|
||||
},
|
||||
"/deno.json": {
|
||||
"size": 1415,
|
||||
"checksum": "sha256-b03d6de05f953886662ea987212539af8456a91352684c84af2188520449d42a"
|
||||
},
|
||||
"/.github/workflows/ci.yml": {
|
||||
"size": 2949,
|
||||
"checksum": "sha256-9d5758dae05df104fcc5252808b6b23347aa588ac8a833624a064205dffe57e3"
|
||||
},
|
||||
"/.github/workflows/publish.yml": {
|
||||
"size": 238,
|
||||
"checksum": "sha256-8b6aee1b0b7b5c7a50623ce94e54b936219ea23e319c5d448551ce1d8691ff12"
|
||||
},
|
||||
"/bench/bench_bun_ffi.js": {
|
||||
"size": 3100,
|
||||
"checksum": "sha256-62ce7a93d735becb71188cb642d5ed07f9860631ccd8aed2d5b5e58770b4cc25"
|
||||
},
|
||||
"/README.md": {
|
||||
"size": 2679,
|
||||
"checksum": "sha256-769ae29ef3e5235160b53a7d1e2a3746bbdc1c8a0c6d715e721a262040ef7941"
|
||||
},
|
||||
"/bench/bench_deno_wasm.js": {
|
||||
"size": 818,
|
||||
"checksum": "sha256-90e7cb8198452efb5bd1a14e720a77ea3bac76be38249406ad8208d9cbe12b03"
|
||||
},
|
||||
"/doc.md": {
|
||||
"size": 12287,
|
||||
"checksum": "sha256-5052824d485ec61794dca20fe904900f48f47dab096b3282b9eba86ac0015a26"
|
||||
},
|
||||
"/bench/results.png": {
|
||||
"size": 42888,
|
||||
"checksum": "sha256-b6fd903c2f4977e2ad89ccc22988495eb21bb51b6876665ad22b02d24266d16a"
|
||||
},
|
||||
"/deps.ts": {
|
||||
"size": 99,
|
||||
"checksum": "sha256-d2f23a4489d27ed7ba1f601b86a85ff488a87603e4be7a15f3ea15154fc288ec"
|
||||
}
|
||||
},
|
||||
"moduleGraph2": {
|
||||
"/src/util.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./constants.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
57
|
||||
],
|
||||
[
|
||||
0,
|
||||
73
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./ffi.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
16
|
||||
],
|
||||
[
|
||||
1,
|
||||
26
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/deps.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "jsr:@std/path@0.217",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
28
|
||||
],
|
||||
[
|
||||
0,
|
||||
49
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "jsr:@denosaurs/plug@1",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
23
|
||||
],
|
||||
[
|
||||
1,
|
||||
46
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/database.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./ffi.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
16
|
||||
],
|
||||
[
|
||||
0,
|
||||
26
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "../deps.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
28
|
||||
],
|
||||
[
|
||||
1,
|
||||
40
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./constants.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
12,
|
||||
7
|
||||
],
|
||||
[
|
||||
12,
|
||||
23
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./util.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
13,
|
||||
44
|
||||
],
|
||||
[
|
||||
13,
|
||||
55
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./statement.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
18,
|
||||
7
|
||||
],
|
||||
[
|
||||
18,
|
||||
23
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./blob.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
19,
|
||||
46
|
||||
],
|
||||
[
|
||||
19,
|
||||
57
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/blob.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./database.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
45
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./ffi.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
16
|
||||
],
|
||||
[
|
||||
1,
|
||||
26
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./util.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
34
|
||||
],
|
||||
[
|
||||
2,
|
||||
45
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/statement.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./database.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
45
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./util.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
44
|
||||
],
|
||||
[
|
||||
1,
|
||||
55
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./ffi.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
16
|
||||
],
|
||||
[
|
||||
2,
|
||||
26
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./constants.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
10,
|
||||
7
|
||||
],
|
||||
[
|
||||
10,
|
||||
23
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/mod.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./src/database.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
9,
|
||||
7
|
||||
],
|
||||
[
|
||||
9,
|
||||
26
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./src/blob.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
10,
|
||||
46
|
||||
],
|
||||
[
|
||||
10,
|
||||
61
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./src/statement.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
16,
|
||||
7
|
||||
],
|
||||
[
|
||||
16,
|
||||
27
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./src/util.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
17,
|
||||
28
|
||||
],
|
||||
[
|
||||
17,
|
||||
43
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/constants.ts": {},
|
||||
"/src/ffi.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "../deno.json",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
17
|
||||
],
|
||||
[
|
||||
0,
|
||||
31
|
||||
]
|
||||
],
|
||||
"importAttributes": {
|
||||
"known": {
|
||||
"type": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "../deps.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
23
|
||||
],
|
||||
[
|
||||
1,
|
||||
35
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
}
|
||||
}
|
||||
10
vendor/jsr.io/@db/sqlite/meta.json
generated
vendored
Normal file
10
vendor/jsr.io/@db/sqlite/meta.json
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"scope": "db",
|
||||
"name": "sqlite",
|
||||
"latest": "0.12.0",
|
||||
"versions": {
|
||||
"0.11.0": {},
|
||||
"0.12.0": {},
|
||||
"0.11.1": {}
|
||||
}
|
||||
}
|
||||
322
vendor/jsr.io/@denosaurs/plug/1.0.6/download.ts
generated
vendored
Normal file
322
vendor/jsr.io/@denosaurs/plug/1.0.6/download.ts
generated
vendored
Normal file
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* This module contains the common types used in plug.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import {
|
||||
dirname,
|
||||
extname,
|
||||
fromFileUrl,
|
||||
join,
|
||||
normalize,
|
||||
resolve,
|
||||
} from "jsr:@std/path@^0.221.0";
|
||||
import { ensureDir } from "jsr:@std/fs@^0.221.0";
|
||||
import { green } from "jsr:@std/fmt@^0.221.0/colors";
|
||||
import type {
|
||||
ArchRecord,
|
||||
CacheLocation,
|
||||
FetchOptions,
|
||||
NestedCrossRecord,
|
||||
OsRecord,
|
||||
} from "./types.ts";
|
||||
import {
|
||||
cacheDir,
|
||||
denoCacheDir,
|
||||
isFile,
|
||||
stringToURL,
|
||||
urlToFilename,
|
||||
} from "./util.ts";
|
||||
|
||||
/**
|
||||
* A list of all possible system architectures.
|
||||
*
|
||||
* This should match the {@link Deno.build.arch} type.
|
||||
*/
|
||||
export const ALL_ARCHS: (typeof Deno.build.arch)[] = [
|
||||
"x86_64",
|
||||
"aarch64",
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of all possible system operating systems.
|
||||
*
|
||||
* This should match the {@link Deno.build.os} type.
|
||||
*/
|
||||
export const ALL_OSS: (typeof Deno.build.os)[] = [
|
||||
"darwin",
|
||||
"linux",
|
||||
"android",
|
||||
"windows",
|
||||
"freebsd",
|
||||
"netbsd",
|
||||
"aix",
|
||||
"solaris",
|
||||
"illumos",
|
||||
];
|
||||
|
||||
/**
|
||||
* The default file extensions for dynamic libraries in the different operating
|
||||
* systems.
|
||||
*/
|
||||
export const defaultExtensions: OsRecord<string> = {
|
||||
darwin: "dylib",
|
||||
linux: "so",
|
||||
windows: "dll",
|
||||
freebsd: "so",
|
||||
netbsd: "so",
|
||||
aix: "so",
|
||||
solaris: "so",
|
||||
illumos: "so",
|
||||
android: "so",
|
||||
};
|
||||
|
||||
/**
|
||||
* The default file prefixes for dynamic libraries in the different operating
|
||||
* systems.
|
||||
*/
|
||||
export const defaultPrefixes: OsRecord<string> = {
|
||||
darwin: "lib",
|
||||
linux: "lib",
|
||||
netbsd: "lib",
|
||||
freebsd: "lib",
|
||||
aix: "lib",
|
||||
solaris: "lib",
|
||||
illumos: "lib",
|
||||
windows: "",
|
||||
android: "lib",
|
||||
};
|
||||
|
||||
function getCrossOption<T>(record?: NestedCrossRecord<T>): T | undefined {
|
||||
if (record === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ALL_OSS.some((os) => os in record)) {
|
||||
const subrecord = (record as OsRecord<T>)[Deno.build.os];
|
||||
|
||||
if (
|
||||
subrecord &&
|
||||
typeof subrecord === "object" &&
|
||||
ALL_ARCHS.some((arch) => arch in subrecord)
|
||||
) {
|
||||
return (subrecord as ArchRecord<T>)[Deno.build.arch];
|
||||
} else {
|
||||
return subrecord as T;
|
||||
}
|
||||
}
|
||||
|
||||
if (ALL_ARCHS.some((arch) => arch in record)) {
|
||||
const subrecord = (record as ArchRecord<T>)[Deno.build.arch];
|
||||
|
||||
if (
|
||||
subrecord &&
|
||||
typeof subrecord === "object" &&
|
||||
ALL_OSS.some((os) => os in subrecord)
|
||||
) {
|
||||
return (subrecord as OsRecord<T>)[Deno.build.os];
|
||||
} else {
|
||||
return subrecord as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cross-platform url for the specified options
|
||||
*
|
||||
* @param options See {@link FetchOptions}
|
||||
* @returns A fully specified url to the specified file
|
||||
*/
|
||||
export function createDownloadURL(options: FetchOptions): URL {
|
||||
if (typeof options === "string" || options instanceof URL) {
|
||||
options = { url: options };
|
||||
}
|
||||
|
||||
// Initialize default options
|
||||
options.extensions ??= defaultExtensions;
|
||||
options.prefixes ??= defaultPrefixes;
|
||||
|
||||
// Clean extensions to not contain a leading dot
|
||||
for (const key in options.extensions) {
|
||||
const os = key as typeof Deno.build.os;
|
||||
if (options.extensions[os] !== undefined) {
|
||||
options.extensions[os] = options.extensions[os].replace(/\.?(.+)/, "$1");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the os-specific url
|
||||
let url: URL;
|
||||
if (options.url instanceof URL) {
|
||||
url = options.url;
|
||||
} else if (typeof options.url === "string") {
|
||||
url = stringToURL(options.url);
|
||||
} else {
|
||||
const tmpUrl = getCrossOption(options.url);
|
||||
if (tmpUrl === undefined) {
|
||||
throw new TypeError(
|
||||
`An URL for the "${Deno.build.os}-${Deno.build.arch}" target was not provided.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof tmpUrl === "string") {
|
||||
url = stringToURL(tmpUrl);
|
||||
} else {
|
||||
url = tmpUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble automatic cross-platform named urls here
|
||||
if (
|
||||
"name" in options &&
|
||||
!Object.values(options.extensions).includes(extname(url.pathname))
|
||||
) {
|
||||
if (!url.pathname.endsWith("/")) {
|
||||
url.pathname = `${url.pathname}/`;
|
||||
}
|
||||
|
||||
const prefix = getCrossOption(options.prefixes) ?? "";
|
||||
const suffix = getCrossOption(options.suffixes) ?? "";
|
||||
const extension = options.extensions[Deno.build.os];
|
||||
|
||||
if (options.name === undefined) {
|
||||
throw new TypeError(
|
||||
`Expected the "name" property for an automatically assembled URL.`,
|
||||
);
|
||||
}
|
||||
|
||||
const filename = `${prefix}${options.name}${suffix}.${extension}`;
|
||||
|
||||
url = new URL(filename, url);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the cache location along with ensuring its existance
|
||||
*
|
||||
* @param location See the {@link CacheLocation} type
|
||||
* @returns The cache location path
|
||||
*/
|
||||
export async function ensureCacheLocation(
|
||||
location: CacheLocation = "deno",
|
||||
): Promise<string> {
|
||||
if (location === "deno") {
|
||||
const dir = denoCacheDir();
|
||||
|
||||
if (dir === undefined) {
|
||||
throw new Error(
|
||||
"Could not get the deno cache directory, try using another CacheLocation in the plug options.",
|
||||
);
|
||||
}
|
||||
|
||||
location = join(dir, "plug");
|
||||
} else if (location === "cache") {
|
||||
const dir = cacheDir();
|
||||
|
||||
if (dir === undefined) {
|
||||
throw new Error(
|
||||
"Could not get the cache directory, try using another CacheLocation in the plug options.",
|
||||
);
|
||||
}
|
||||
|
||||
location = join(dir, "plug");
|
||||
} else if (location === "cwd") {
|
||||
location = join(Deno.cwd(), "plug");
|
||||
} else if (location === "tmp") {
|
||||
location = await Deno.makeTempDir({ prefix: "plug" });
|
||||
} else if (typeof location === "string" && location.startsWith("file://")) {
|
||||
location = fromFileUrl(location);
|
||||
} else if (location instanceof URL) {
|
||||
if (location?.protocol !== "file:") {
|
||||
throw new TypeError(
|
||||
"Cannot use any other protocol than file:// for an URL cache location.",
|
||||
);
|
||||
}
|
||||
|
||||
location = fromFileUrl(location);
|
||||
}
|
||||
|
||||
location = resolve(normalize(location));
|
||||
|
||||
await ensureDir(location);
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file using the specified {@link FetchOptions}
|
||||
*
|
||||
* @param options See {@link FetchOptions}
|
||||
* @returns The path to the downloaded file in its cached location
|
||||
*/
|
||||
export async function download(options: FetchOptions): Promise<string> {
|
||||
const location =
|
||||
(typeof options === "object" && "location" in options
|
||||
? options.location
|
||||
: undefined) ?? "deno";
|
||||
const setting =
|
||||
(typeof options === "object" && "cache" in options
|
||||
? options.cache
|
||||
: undefined) ?? "use";
|
||||
const url = createDownloadURL(options);
|
||||
const directory = await ensureCacheLocation(location);
|
||||
const cacheBasePath = join(directory, await urlToFilename(url));
|
||||
const cacheFilePath = `${cacheBasePath}${extname(url.pathname)}`;
|
||||
const cacheMetaPath = `${cacheBasePath}.metadata.json`;
|
||||
const cached = setting === "use"
|
||||
? await isFile(cacheFilePath)
|
||||
: setting === "only" || setting !== "reloadAll";
|
||||
|
||||
await ensureDir(dirname(cacheBasePath));
|
||||
|
||||
if (!cached) {
|
||||
const meta = { url };
|
||||
switch (url.protocol) {
|
||||
case "http:":
|
||||
case "https:": {
|
||||
console.log(`${green("Downloading")} ${url}`);
|
||||
const response = await fetch(url.toString());
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
throw new Error(`Could not find ${url}`);
|
||||
} else {
|
||||
throw new Deno.errors.Http(
|
||||
`${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await Deno.writeFile(
|
||||
cacheFilePath,
|
||||
new Uint8Array(await response.arrayBuffer()),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "file:": {
|
||||
console.log(`${green("Copying")} ${url}`);
|
||||
await Deno.copyFile(fromFileUrl(url), cacheFilePath);
|
||||
if (Deno.build.os !== "windows") {
|
||||
await Deno.chmod(cacheFilePath, 0o644);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new TypeError(
|
||||
`Cannot fetch to cache using the "${url.protocol}" protocol`,
|
||||
);
|
||||
}
|
||||
}
|
||||
await Deno.writeTextFile(cacheMetaPath, JSON.stringify(meta));
|
||||
}
|
||||
|
||||
if (!(await isFile(cacheFilePath))) {
|
||||
throw new Error(`Could not find "${url}" in cache.`);
|
||||
}
|
||||
|
||||
return cacheFilePath;
|
||||
}
|
||||
159
vendor/jsr.io/@denosaurs/plug/1.0.6/mod.ts
generated
vendored
Normal file
159
vendor/jsr.io/@denosaurs/plug/1.0.6/mod.ts
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Plug is a drop in extension for using remote dynamic libraries in deno. It
|
||||
* automatically handles caching and loading with minimal overhead. It can
|
||||
* automatically create the URL for your cross-operating-system, cross-architecture
|
||||
* libraries if you so wish using a simple configuration which deviates from
|
||||
* the standard URL/string path input.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dlopen } from "@denosaurs/plug";
|
||||
*
|
||||
* // Drop-in replacement for `Deno.dlopen` which fetches the following depending
|
||||
* // on operating system:
|
||||
* // * darwin: "https://example.com/some/path/libexample.dylib"
|
||||
* // * windows: "https://example.com/some/path/example.dll"
|
||||
* // * linux: "https://example.com/some/path/libexample.so"
|
||||
* const library = await dlopen("https://example.com/some/path/", {
|
||||
* noop: { parameters: [], result: "void" },
|
||||
* });
|
||||
*
|
||||
* library.symbols.noop();
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dlopen, FetchOptions } from "@denosaurs/plug";
|
||||
*
|
||||
* // If you want plug to guess your binary names
|
||||
* const options: FetchOptions = {
|
||||
* name: "example",
|
||||
* url: "https://example.com/some/path/",
|
||||
* // Becomes:
|
||||
* // darwin: "https://example.com/some/path/libexample.dylib"
|
||||
* // windows: "https://example.com/some/path/example.dll"
|
||||
* // linux: "https://example.com/some/path/libexample.so"
|
||||
* };
|
||||
*
|
||||
* const library = await dlopen(options, {
|
||||
* noop: { parameters: [], result: "void" },
|
||||
* });
|
||||
*
|
||||
* library.symbols.noop();
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dlopen, FetchOptions } from "@denosaurs/plug";
|
||||
*
|
||||
* // Also you can specify the path for certain architecture
|
||||
* const options: FetchOptions = {
|
||||
* name: "example",
|
||||
* url: {
|
||||
* darwin: {
|
||||
* aarch64: `https://example.com/some/path/libexample.aarch64.dylib`,
|
||||
* x86_64: `https://example.com/some/path/libexample.x86_64.dylib`,
|
||||
* },
|
||||
* windows: `https://example.com/some/path/example.dll`,
|
||||
* linux: `https://example.com/some/path/libexample.so`,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* await dlopen(options, {});
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dlopen, FetchOptions } from "@denosaurs/plug";
|
||||
*
|
||||
* // Or even configure plug to automatically guess the binary names for you,
|
||||
* // even when there are special rules for naming on specific architectures
|
||||
* const options: FetchOptions = {
|
||||
* name: "test",
|
||||
* url: "https://example.com/some/path/",
|
||||
* suffixes: {
|
||||
* darwin: {
|
||||
* aarch64: ".aarch64",
|
||||
* x86_64: ".x86_64",
|
||||
* },
|
||||
* },
|
||||
* // Becomes:
|
||||
* // darwin-aarch64: "https://example.com/some/path/libexample.aarch64.dylib"
|
||||
* // darwin-x86_64: "https://example.com/some/path/libexample.x86_64.dylib"
|
||||
* };
|
||||
*
|
||||
* await dlopen(options, {});
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { download } from "./download.ts";
|
||||
import type { FetchOptions } from "./types.ts";
|
||||
|
||||
export type {
|
||||
ArchRecord,
|
||||
CacheLocation,
|
||||
CacheOptions,
|
||||
CacheSetting,
|
||||
CrossOptions,
|
||||
FetchOptions,
|
||||
NamedOptions,
|
||||
NestedCrossRecord,
|
||||
OsRecord,
|
||||
URLOptions,
|
||||
} from "./types.ts";
|
||||
export { download } from "./download.ts";
|
||||
|
||||
/* Magic types from deno which help implement better FFI type checking */
|
||||
type Cast<A, B> = A extends B ? A : B;
|
||||
type Const<T> = Cast<
|
||||
T,
|
||||
| (T extends string | number | bigint | boolean ? T : never)
|
||||
| { [K in keyof T]: Const<T[K]> }
|
||||
| []
|
||||
>;
|
||||
|
||||
/**
|
||||
* Opens a dynamic library and registers symbols, compatible with
|
||||
* {@link Deno.dlopen} yet with extended functionality allowing you to use
|
||||
* remote (or local) binaries, automatically building the binary name and
|
||||
* controlling the caching policy.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dlopen, FetchOptions } from "@denosaurs/plug";
|
||||
*
|
||||
* // Configure plug to automatically guess the binary names for you, even when
|
||||
* // there for example are special rules for naming on specific architectures
|
||||
* const options: FetchOptions = {
|
||||
* name: "test",
|
||||
* url: "https://example.com/some/path/",
|
||||
* suffixes: {
|
||||
* darwin: {
|
||||
* aarch64: ".aarch64",
|
||||
* x86_64: ".x86_64",
|
||||
* },
|
||||
* },
|
||||
* // Becomes:
|
||||
* // darwin-aarch64: "https://example.com/some/path/libexample.aarch64.dylib"
|
||||
* // darwin-x86_64: "https://example.com/some/path/libexample.x86_64.dylib"
|
||||
* };
|
||||
*
|
||||
* await dlopen(options, {});
|
||||
* ```
|
||||
*
|
||||
* @param options See {@link FetchOptions}
|
||||
* @param symbols A record extending {@link Deno.ForeignLibraryInterface}
|
||||
* @returns An opened {@link Deno.DynamicLibrary}
|
||||
*/
|
||||
export async function dlopen<S extends Deno.ForeignLibraryInterface>(
|
||||
options: FetchOptions,
|
||||
symbols: Const<S>,
|
||||
): Promise<Deno.DynamicLibrary<S>> {
|
||||
if (Deno.dlopen === undefined) {
|
||||
throw new Error("`--unstable-ffi` is required");
|
||||
}
|
||||
// deno-lint-ignore no-explicit-any
|
||||
return Deno.dlopen<S>(await download(options), symbols as any);
|
||||
}
|
||||
152
vendor/jsr.io/@denosaurs/plug/1.0.6/types.ts
generated
vendored
Normal file
152
vendor/jsr.io/@denosaurs/plug/1.0.6/types.ts
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* This module contains the common types used in plug.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* A record keyed by possible operating system identifiers
|
||||
*/
|
||||
export type OsRecord<T> = { [os in typeof Deno.build.os]: T };
|
||||
/**
|
||||
* A record keyed by possible system architecture identifiers
|
||||
*/
|
||||
export type ArchRecord<T> = { [os in typeof Deno.build.arch]: T };
|
||||
/**
|
||||
* An optionally nested record of either an {@link OsRecord} or
|
||||
* {@link ArchRecord} containing either the generic T or the opposite record
|
||||
* type from the parent. That way we can query for the record entry of a target
|
||||
* keyed by both an architecture and operating system in the ordered entered in
|
||||
* this record.
|
||||
*/
|
||||
export type NestedCrossRecord<T> = Partial<
|
||||
| OsRecord<T | Partial<ArchRecord<T>>>
|
||||
| ArchRecord<T | Partial<OsRecord<T>>>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Where the plug cache is stored:
|
||||
*
|
||||
* | Option | Description |
|
||||
* | ------- | ----------------------------------------------------------------------------------------- |
|
||||
* | `deno` | The location of the default deno cache, this is the default option. |
|
||||
* | `cwd` | A `plug` folder in the current working directory. |
|
||||
* | `cache` | A `plug` folder in default cache directory for the current os. |
|
||||
* | `tmp` | A temporary `plug` prefixed folder in the default temporary directory for the current os. |
|
||||
* | string | A file path pointing to the folder where the plug cache should be stored. |
|
||||
* | URL | A file protocol URL pointing to the folder where the plug cache should be stored. |
|
||||
*/
|
||||
export type CacheLocation = "deno" | "cwd" | "cache" | "tmp" | string | URL;
|
||||
|
||||
/** A setting that determines how the cache is handled for remote dependencies.
|
||||
*
|
||||
* | Option | Description |
|
||||
* | ----------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
* | `use` | The cache will be used, meaning existing remote files will not be reloaded, this is the default option. |
|
||||
* | `only` | Only the cache will be re-used, and any remote files not in the cache will error. |
|
||||
* | `reloadAll` | Any cached modules will be ignored and their values will be fetched. |
|
||||
*/
|
||||
export type CacheSetting = "use" | "only" | "reloadAll";
|
||||
|
||||
/**
|
||||
* Options for controlling how plug caches files
|
||||
*/
|
||||
export interface CacheOptions {
|
||||
/**
|
||||
* The location where plug should cache the fetched file
|
||||
*/
|
||||
location?: CacheLocation;
|
||||
/**
|
||||
* The cache policy plug should use, see {@link CacheSetting}
|
||||
*/
|
||||
cache?: CacheSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for using a single url as the source for either creating a
|
||||
* {@link NamedOptions named url} or using it simply as is if the platforms
|
||||
* extension is specified or no name is specified.
|
||||
*/
|
||||
export interface URLOptions {
|
||||
/**
|
||||
* The url to either a dynamic library or its directory if {@link NamedOptions named}
|
||||
*/
|
||||
url: string | URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for fetching cross-platform urls.
|
||||
*/
|
||||
export interface CrossOptions {
|
||||
/**
|
||||
* See {@link NestedCrossRecord}, basically a record optionally keyed by
|
||||
* either or operating-system and architecture letting us get the correct
|
||||
* url for fetching the right file for the platform.
|
||||
*/
|
||||
url: NestedCrossRecord<string | URL>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used for automatically assembling an os and arch specific file name
|
||||
*/
|
||||
export interface NamedOptions {
|
||||
/**
|
||||
* The base name of the library.
|
||||
*
|
||||
* ```
|
||||
* libplug.x86_64.dll
|
||||
* ^^^^
|
||||
* ```
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* A {@link OsRecord} containing the extensions for the respective
|
||||
* operating-systems. By default this is `.so` for linux, freebsd, netbsd, aix, solaris and illumos, `.dylib` for darwin
|
||||
* and `.dll` for windows.
|
||||
*
|
||||
* ```
|
||||
* libplug.x86_64.dll
|
||||
* ^^^
|
||||
* ```
|
||||
*/
|
||||
extensions?: OsRecord<string>;
|
||||
/**
|
||||
* A {@link NestedCrossRecord} containing the prefixes for the respective
|
||||
* operating-systems and architectures. By default this is `lib` for all
|
||||
* architectures on linux, darwin, freebsd, netbsd, aix, solaris and illumos and empty for windows.
|
||||
*
|
||||
* ```
|
||||
* libplug.x86_64.dll
|
||||
* ^^^
|
||||
* ```
|
||||
*/
|
||||
prefixes?: NestedCrossRecord<string>;
|
||||
/**
|
||||
* A {@link NestedCrossRecord} containing the suffixes for the respective
|
||||
* operating-systems and architectures. By default this is empty for all
|
||||
* architectures and operating-systems. An idea would be to use this to
|
||||
* automatically select the suffix for the correct architecture.
|
||||
*
|
||||
* ```
|
||||
* libplug.x86_64.dll
|
||||
* ^^^^^^^
|
||||
* ```
|
||||
*/
|
||||
suffixes?: NestedCrossRecord<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for fetching files (usually being dynamic libraries, but could
|
||||
* possibly also be other dependencies) using plug. This can be either a
|
||||
* string or an URL. All urls in plug can be either local or remote. If it is
|
||||
* not an string or URL it can be some combination of the following options:
|
||||
*
|
||||
* * {@link URLOptions} or {@link CrossOptions} for controlling the source url
|
||||
* * {@link NamedOptions} for automatically creating cross-platform binary names
|
||||
* * {@link CacheOptions} for controlling the cache behaviour
|
||||
*/
|
||||
export type FetchOptions =
|
||||
| string
|
||||
| URL
|
||||
| ((((URLOptions | CrossOptions) & Partial<NamedOptions>)) & CacheOptions);
|
||||
161
vendor/jsr.io/@denosaurs/plug/1.0.6/util.ts
generated
vendored
Normal file
161
vendor/jsr.io/@denosaurs/plug/1.0.6/util.ts
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* This file contains useful utility functions used by plug.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { isAbsolute, join, normalize, resolve, toFileUrl } from "jsr:@std/path@^0.221.0";
|
||||
import { encodeHex } from "jsr:@std/encoding@^0.221.0/hex";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
function baseUrlToFilename(url: URL): string {
|
||||
const out = [];
|
||||
const protocol = url.protocol.replace(":", "");
|
||||
out.push(protocol);
|
||||
|
||||
switch (protocol) {
|
||||
case "http":
|
||||
case "https": {
|
||||
const host = url.hostname;
|
||||
const hostPort = url.port;
|
||||
out.push(hostPort ? `${host}_PORT${hostPort}` : host);
|
||||
break;
|
||||
}
|
||||
case "file":
|
||||
case "data":
|
||||
case "blob":
|
||||
break;
|
||||
default:
|
||||
throw new TypeError(
|
||||
`Don't know how to create cache name for protocol: ${protocol}`,
|
||||
);
|
||||
}
|
||||
|
||||
return join(...out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a string into a URL.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export function stringToURL(url: string): URL {
|
||||
// deno-fmt-ignore
|
||||
return url.startsWith("file://")
|
||||
|| url.startsWith("http://")
|
||||
|| url.startsWith("https://")
|
||||
? new URL(url)
|
||||
: toFileUrl(resolve(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-256 hashes a string. Used internally to hash URLs for cache filenames.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export async function hash(value: string): Promise<string> {
|
||||
return encodeHex(
|
||||
new Uint8Array(
|
||||
await crypto.subtle.digest("SHA-256", encoder.encode(value)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a URL into a filename for the cache.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export async function urlToFilename(url: URL): Promise<string> {
|
||||
const cacheFilename = baseUrlToFilename(url);
|
||||
const hashedFilename = await hash(url.pathname + url.search);
|
||||
return join(cacheFilename, hashedFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file exists.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export async function isFile(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
const stats = await Deno.lstat(filePath);
|
||||
return stats.isFile;
|
||||
} catch (err) {
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
return false;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of is based on code from denoland/deno_cache by the Deno authors
|
||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/**
|
||||
* @returns The home directory of the user.
|
||||
*/
|
||||
export function homeDir(): string | undefined {
|
||||
switch (Deno.build.os) {
|
||||
case "windows":
|
||||
return Deno.env.get("USERPROFILE");
|
||||
case "linux":
|
||||
case "darwin":
|
||||
case "freebsd":
|
||||
case "netbsd":
|
||||
case "aix":
|
||||
case "solaris":
|
||||
case "illumos":
|
||||
return Deno.env.get("HOME");
|
||||
default:
|
||||
throw Error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The cache directory of the user.
|
||||
*/
|
||||
export function cacheDir(): string | undefined {
|
||||
if (Deno.build.os === "darwin") {
|
||||
const home = homeDir();
|
||||
if (home) {
|
||||
return join(home, "Library/Caches");
|
||||
}
|
||||
} else if (Deno.build.os === "windows") {
|
||||
return Deno.env.get("LOCALAPPDATA");
|
||||
} else {
|
||||
const cacheHome = Deno.env.get("XDG_CACHE_HOME");
|
||||
if (cacheHome) {
|
||||
return cacheHome;
|
||||
} else {
|
||||
const home = homeDir();
|
||||
if (home) {
|
||||
return join(home, ".cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The cache directory for Deno.
|
||||
*/
|
||||
export function denoCacheDir(): string | undefined {
|
||||
const dd = Deno.env.get("DENO_DIR");
|
||||
let root;
|
||||
if (dd) {
|
||||
root = normalize(isAbsolute(dd) ? dd : join(Deno.cwd(), dd));
|
||||
} else {
|
||||
const cd = cacheDir();
|
||||
if (cd) {
|
||||
root = join(cd, "deno");
|
||||
} else {
|
||||
const hd = homeDir();
|
||||
if (hd) {
|
||||
root = join(hd, ".deno");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
246
vendor/jsr.io/@denosaurs/plug/1.0.6_meta.json
generated
vendored
Normal file
246
vendor/jsr.io/@denosaurs/plug/1.0.6_meta.json
generated
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
{
|
||||
"manifest": {
|
||||
"/download_test.ts": {
|
||||
"size": 9300,
|
||||
"checksum": "sha256-9dbe825f543096cc20b1f6cc70d1f239fcad6444f25f8e95ccadfb95a421beb0"
|
||||
},
|
||||
"/README.md": {
|
||||
"size": 4633,
|
||||
"checksum": "sha256-2d58d95ce1e2614dd3e74cb9e55566f5f03dfcd621ccaa181557426083fff73a"
|
||||
},
|
||||
"/mod.ts": {
|
||||
"size": 4760,
|
||||
"checksum": "sha256-15c683abe87ed5df6cdccd5ff45ff46438ef68b825729f8463a6c8b605a9d19b"
|
||||
},
|
||||
"/.github/workflows/publish.yml": {
|
||||
"size": 267,
|
||||
"checksum": "sha256-a3f12d6833d9a43bc8453e63c95610a950538191899852bddadd2cf31c071ad7"
|
||||
},
|
||||
"/LICENSE": {
|
||||
"size": 1080,
|
||||
"checksum": "sha256-0546a91da726c46e6d54a352c707ca46e4a47924d13518fa3140c4f71bb4f3e3"
|
||||
},
|
||||
"/.github/FUNDING.yml": {
|
||||
"size": 45,
|
||||
"checksum": "sha256-f7d5bd53b9a6add2d05771a6edeb3192701e92fb60c0725cbd861ebadd5e4181"
|
||||
},
|
||||
"/deno.json": {
|
||||
"size": 417,
|
||||
"checksum": "sha256-79aeb6b285543f6c96f3900359467d80aaeb8d89a1a820aa2e847a8e701dd34e"
|
||||
},
|
||||
"/util.ts": {
|
||||
"size": 3562,
|
||||
"checksum": "sha256-91fb019b500ee81c5cb50754dd598abdab15bc22c80610790d9fe05eed8f948e"
|
||||
},
|
||||
"/.editorconfig": {
|
||||
"size": 99,
|
||||
"checksum": "sha256-561e2d9d8035e8b9861e31b3934557da651481d95dfd8992e12dbbee03c285c2"
|
||||
},
|
||||
"/download.ts": {
|
||||
"size": 8041,
|
||||
"checksum": "sha256-a0dc7084ed428cd95d66840176c9c4318a3a70270fc92a4ada5530adc7f52860"
|
||||
},
|
||||
"/types.ts": {
|
||||
"size": 5585,
|
||||
"checksum": "sha256-944a7abaded38515f0b06a4499d462c99d1c018ced7b33c2ee32607224e4e039"
|
||||
},
|
||||
"/test_import_map.json": {
|
||||
"size": 472,
|
||||
"checksum": "sha256-3db76688daeb0658d136afa66271844953a56b82bac9e786c6337b6ac7e899a2"
|
||||
},
|
||||
"/.github/workflows/checks.yml": {
|
||||
"size": 566,
|
||||
"checksum": "sha256-c9dbd47a446d6756355521e9d98cde8168854e915996b345b4a050605c15a56a"
|
||||
},
|
||||
"/util_test.ts": {
|
||||
"size": 11546,
|
||||
"checksum": "sha256-fcc4302200b7608be814957e147ca4b4fe162551404050939fc5f37cf7fd1753"
|
||||
}
|
||||
},
|
||||
"moduleGraph1": {
|
||||
"/mod.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./download.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
90,
|
||||
25
|
||||
],
|
||||
[
|
||||
90,
|
||||
40
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
91,
|
||||
34
|
||||
],
|
||||
[
|
||||
91,
|
||||
46
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "exportType",
|
||||
"specifier": "./types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
104,
|
||||
7
|
||||
],
|
||||
[
|
||||
104,
|
||||
19
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./download.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
105,
|
||||
25
|
||||
],
|
||||
[
|
||||
105,
|
||||
40
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/download.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^0.221.0",
|
||||
"specifierRange": [
|
||||
[
|
||||
13,
|
||||
7
|
||||
],
|
||||
[
|
||||
13,
|
||||
31
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/fs@^0.221.0",
|
||||
"specifierRange": [
|
||||
[
|
||||
14,
|
||||
26
|
||||
],
|
||||
[
|
||||
14,
|
||||
48
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/fmt@^0.221.0/colors",
|
||||
"specifierRange": [
|
||||
[
|
||||
15,
|
||||
22
|
||||
],
|
||||
[
|
||||
15,
|
||||
52
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
22,
|
||||
7
|
||||
],
|
||||
[
|
||||
22,
|
||||
19
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./util.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
29,
|
||||
7
|
||||
],
|
||||
[
|
||||
29,
|
||||
18
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/util.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^0.221.0",
|
||||
"specifierRange": [
|
||||
[
|
||||
6,
|
||||
64
|
||||
],
|
||||
[
|
||||
6,
|
||||
88
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/encoding@^0.221.0/hex",
|
||||
"specifierRange": [
|
||||
[
|
||||
7,
|
||||
26
|
||||
],
|
||||
[
|
||||
7,
|
||||
58
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/types.ts": {}
|
||||
},
|
||||
"exports": {
|
||||
".": "./mod.ts",
|
||||
"./types": "./types.ts",
|
||||
"./download": "./download.ts",
|
||||
"./util": "./util.ts"
|
||||
}
|
||||
}
|
||||
11
vendor/jsr.io/@denosaurs/plug/meta.json
generated
vendored
Normal file
11
vendor/jsr.io/@denosaurs/plug/meta.json
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"scope": "denosaurs",
|
||||
"name": "plug",
|
||||
"latest": "1.0.6",
|
||||
"versions": {
|
||||
"1.0.4": {},
|
||||
"1.0.5": {},
|
||||
"1.0.6": {},
|
||||
"1.0.3": {}
|
||||
}
|
||||
}
|
||||
131
vendor/jsr.io/@eta-dev/eta/3.5.0/src/compile-string.ts
generated
vendored
Normal file
131
vendor/jsr.io/@eta-dev/eta/3.5.0/src/compile-string.ts
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
/* TYPES */
|
||||
|
||||
import type { Options } from "./config.ts";
|
||||
import type { AstObject } from "./parse.ts";
|
||||
import type { Eta } from "./core.ts";
|
||||
|
||||
/* END TYPES */
|
||||
|
||||
/**
|
||||
* Compiles a template string to a function string. Most often users just use `compile()`, which calls `compileToString` and creates a new function using the result
|
||||
*/
|
||||
|
||||
export function compileToString(
|
||||
this: Eta,
|
||||
str: string,
|
||||
options?: Partial<Options>,
|
||||
): string {
|
||||
const config = this.config;
|
||||
const isAsync = options && options.async;
|
||||
|
||||
const compileBody = this.compileBody;
|
||||
|
||||
const buffer: Array<AstObject> = this.parse.call(this, str);
|
||||
|
||||
// note: when the include function passes through options, the only parameter that matters is the filepath parameter
|
||||
let res = `${config.functionHeader}
|
||||
let include = (template, data) => this.render(template, data, options);
|
||||
let includeAsync = (template, data) => this.renderAsync(template, data, options);
|
||||
|
||||
let __eta = {res: "", e: this.config.escapeFunction, f: this.config.filterFunction${
|
||||
config.debug
|
||||
? ', line: 1, templateStr: "' +
|
||||
str.replace(/\\|"/g, "\\$&").replace(/\r\n|\n|\r/g, "\\n") +
|
||||
'"'
|
||||
: ""
|
||||
}};
|
||||
|
||||
function layout(path, data) {
|
||||
__eta.layout = path;
|
||||
__eta.layoutData = data;
|
||||
}${config.debug ? "try {" : ""}${
|
||||
config.useWith ? "with(" + config.varName + "||{}){" : ""
|
||||
}
|
||||
|
||||
${compileBody.call(this, buffer)}
|
||||
if (__eta.layout) {
|
||||
__eta.res = ${
|
||||
isAsync ? "await includeAsync" : "include"
|
||||
} (__eta.layout, {...${config.varName}, body: __eta.res, ...__eta.layoutData});
|
||||
}
|
||||
${config.useWith ? "}" : ""}${
|
||||
config.debug
|
||||
? "} catch (e) { this.RuntimeErr(e, __eta.templateStr, __eta.line, options.filepath) }"
|
||||
: ""
|
||||
}
|
||||
return __eta.res;
|
||||
`;
|
||||
|
||||
if (config.plugins) {
|
||||
for (let i = 0; i < config.plugins.length; i++) {
|
||||
const plugin = config.plugins[i];
|
||||
if (plugin.processFnString) {
|
||||
res = plugin.processFnString(res, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the AST generated by `parse` and transform each item into JS calls
|
||||
*
|
||||
* **Example**
|
||||
*
|
||||
* ```js
|
||||
* let templateAST = ['Hi ', { val: 'it.name', t: 'i' }]
|
||||
* compileBody.call(Eta, templateAST)
|
||||
* // => "__eta.res+='Hi '\n__eta.res+=__eta.e(it.name)\n"
|
||||
* ```
|
||||
*/
|
||||
|
||||
export function compileBody(this: Eta, buff: Array<AstObject>): string {
|
||||
const config = this.config;
|
||||
|
||||
let i = 0;
|
||||
const buffLength = buff.length;
|
||||
let returnStr = "";
|
||||
|
||||
for (i; i < buffLength; i++) {
|
||||
const currentBlock = buff[i];
|
||||
if (typeof currentBlock === "string") {
|
||||
const str = currentBlock;
|
||||
|
||||
// we know string exists
|
||||
returnStr += "__eta.res+='" + str + "'\n";
|
||||
} else {
|
||||
const type = currentBlock.t; // "r", "e", or "i"
|
||||
let content = currentBlock.val || "";
|
||||
|
||||
if (config.debug) returnStr += "__eta.line=" + currentBlock.lineNo + "\n";
|
||||
|
||||
if (type === "r") {
|
||||
// raw
|
||||
|
||||
if (config.autoFilter) {
|
||||
content = "__eta.f(" + content + ")";
|
||||
}
|
||||
|
||||
returnStr += "__eta.res+=" + content + "\n";
|
||||
} else if (type === "i") {
|
||||
// interpolate
|
||||
|
||||
if (config.autoFilter) {
|
||||
content = "__eta.f(" + content + ")";
|
||||
}
|
||||
|
||||
if (config.autoEscape) {
|
||||
content = "__eta.e(" + content + ")";
|
||||
}
|
||||
|
||||
returnStr += "__eta.res+=" + content + "\n";
|
||||
} else if (type === "e") {
|
||||
// execute
|
||||
returnStr += content + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnStr;
|
||||
}
|
||||
59
vendor/jsr.io/@eta-dev/eta/3.5.0/src/compile.ts
generated
vendored
Normal file
59
vendor/jsr.io/@eta-dev/eta/3.5.0/src/compile.ts
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
import { EtaParseError } from "./err.ts";
|
||||
|
||||
/* TYPES */
|
||||
import type { Eta } from "./core.ts";
|
||||
import type { EtaConfig, Options } from "./config.ts";
|
||||
|
||||
export type TemplateFunction = (
|
||||
this: Eta,
|
||||
data?: object,
|
||||
options?: Partial<Options>,
|
||||
) => string;
|
||||
/* END TYPES */
|
||||
|
||||
/* istanbul ignore next */
|
||||
const AsyncFunction = async function () {}.constructor; // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
|
||||
/**
|
||||
* Takes a template string and returns a template function that can be called with (data, config)
|
||||
*
|
||||
* @param str - The template string
|
||||
* @param config - A custom configuration object (optional)
|
||||
*/
|
||||
|
||||
export function compile(
|
||||
this: Eta,
|
||||
str: string,
|
||||
options?: Partial<Options>,
|
||||
): TemplateFunction {
|
||||
const config: EtaConfig = this.config;
|
||||
|
||||
/* ASYNC HANDLING */
|
||||
// code gratefully taken from https://github.com/mde/ejs and adapted
|
||||
const ctor = options && options.async
|
||||
? (AsyncFunction as FunctionConstructor)
|
||||
: Function;
|
||||
/* END ASYNC HANDLING */
|
||||
|
||||
try {
|
||||
return new ctor(
|
||||
config.varName,
|
||||
"options",
|
||||
this.compileToString.call(this, str, options),
|
||||
) as TemplateFunction; // eslint-disable-line no-new-func
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
throw new EtaParseError(
|
||||
"Bad template syntax\n\n" +
|
||||
e.message +
|
||||
"\n" +
|
||||
Array(e.message.length + 1).join("=") +
|
||||
"\n" +
|
||||
this.compileToString.call(this, str, options) +
|
||||
"\n", // This will put an extra newline before the callstack for extra readability
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
vendor/jsr.io/@eta-dev/eta/3.5.0/src/config.ts
generated
vendored
Normal file
110
vendor/jsr.io/@eta-dev/eta/3.5.0/src/config.ts
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
import { XMLEscape } from "./utils.ts";
|
||||
|
||||
/* TYPES */
|
||||
|
||||
type trimConfig = "nl" | "slurp" | false;
|
||||
|
||||
export interface Options {
|
||||
/** Compile to async function */
|
||||
async?: boolean;
|
||||
|
||||
/** Absolute path to template file */
|
||||
filepath?: string;
|
||||
}
|
||||
|
||||
export interface EtaConfig {
|
||||
/** Whether or not to automatically XML-escape interpolations. Default true */
|
||||
autoEscape: boolean;
|
||||
|
||||
/** Apply a filter function defined on the class to every interpolation or raw interpolation */
|
||||
autoFilter: boolean;
|
||||
|
||||
/** Configure automatic whitespace trimming. Default `[false, 'nl']` */
|
||||
autoTrim: trimConfig | [trimConfig, trimConfig];
|
||||
|
||||
/** Whether or not to cache templates if `name` or `filename` is passed */
|
||||
cache: boolean;
|
||||
|
||||
/** Holds cache of resolved filepaths. Set to `false` to disable. */
|
||||
cacheFilepaths: boolean;
|
||||
|
||||
/** Whether to pretty-format error messages (introduces runtime penalties) */
|
||||
debug: boolean;
|
||||
|
||||
/** Function to XML-sanitize interpolations */
|
||||
escapeFunction: (str: unknown) => string;
|
||||
|
||||
/** Function applied to all interpolations when autoFilter is true */
|
||||
filterFunction: (val: unknown) => string;
|
||||
|
||||
/** Raw JS code inserted in the template function. Useful for declaring global variables for user templates */
|
||||
functionHeader: string;
|
||||
|
||||
/** Parsing options */
|
||||
parse: {
|
||||
/** Which prefix to use for evaluation. Default `""`, does not support `"-"` or `"_"` */
|
||||
exec: string;
|
||||
|
||||
/** Which prefix to use for interpolation. Default `"="`, does not support `"-"` or `"_"` */
|
||||
interpolate: string;
|
||||
|
||||
/** Which prefix to use for raw interpolation. Default `"~"`, does not support `"-"` or `"_"` */
|
||||
raw: string;
|
||||
};
|
||||
|
||||
/** Array of plugins */
|
||||
plugins: Array<
|
||||
{
|
||||
processFnString?: Function;
|
||||
processAST?: Function;
|
||||
processTemplate?: Function;
|
||||
}
|
||||
>;
|
||||
|
||||
/** Remove all safe-to-remove whitespace */
|
||||
rmWhitespace: boolean;
|
||||
|
||||
/** Delimiters: by default `['<%', '%>']` */
|
||||
tags: [string, string];
|
||||
|
||||
/** Make data available on the global object instead of varName */
|
||||
useWith: boolean;
|
||||
|
||||
/** Name of the data object. Default `it` */
|
||||
varName: string;
|
||||
|
||||
/** Directory that contains templates */
|
||||
views?: string;
|
||||
|
||||
/** Control template file extension defaults. Default `.eta` */
|
||||
defaultExtension?: string;
|
||||
}
|
||||
|
||||
/* END TYPES */
|
||||
|
||||
/** Eta's base (global) configuration */
|
||||
const defaultConfig: EtaConfig = {
|
||||
autoEscape: true,
|
||||
autoFilter: false,
|
||||
autoTrim: [false, "nl"],
|
||||
cache: false,
|
||||
cacheFilepaths: true,
|
||||
debug: false,
|
||||
escapeFunction: XMLEscape,
|
||||
// default filter function (not used unless enables) just stringifies the input
|
||||
filterFunction: (val) => String(val),
|
||||
functionHeader: "",
|
||||
parse: {
|
||||
exec: "",
|
||||
interpolate: "=",
|
||||
raw: "~",
|
||||
},
|
||||
plugins: [],
|
||||
rmWhitespace: false,
|
||||
tags: ["<%", "%>"],
|
||||
useWith: false,
|
||||
varName: "it",
|
||||
defaultExtension: ".eta",
|
||||
};
|
||||
|
||||
export { defaultConfig };
|
||||
89
vendor/jsr.io/@eta-dev/eta/3.5.0/src/core.ts
generated
vendored
Normal file
89
vendor/jsr.io/@eta-dev/eta/3.5.0/src/core.ts
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
import { Cacher } from "./storage.ts";
|
||||
import { compile } from "./compile.ts";
|
||||
import { compileBody, compileToString } from "./compile-string.ts";
|
||||
import { defaultConfig } from "./config.ts";
|
||||
import { parse } from "./parse.ts";
|
||||
import {
|
||||
render,
|
||||
renderAsync,
|
||||
renderString,
|
||||
renderStringAsync,
|
||||
} from "./render.ts";
|
||||
import { EtaError, RuntimeErr } from "./err.ts";
|
||||
import { TemplateFunction } from "./compile.ts";
|
||||
|
||||
/* TYPES */
|
||||
import type { EtaConfig, Options } from "./config.ts";
|
||||
/* END TYPES */
|
||||
|
||||
export class Eta {
|
||||
constructor(customConfig?: Partial<EtaConfig>) {
|
||||
if (customConfig) {
|
||||
this.config = { ...defaultConfig, ...customConfig };
|
||||
} else {
|
||||
this.config = { ...defaultConfig };
|
||||
}
|
||||
}
|
||||
|
||||
config: EtaConfig;
|
||||
|
||||
RuntimeErr = RuntimeErr;
|
||||
|
||||
compile = compile;
|
||||
compileToString = compileToString;
|
||||
compileBody = compileBody;
|
||||
parse = parse;
|
||||
render = render;
|
||||
renderAsync = renderAsync;
|
||||
renderString = renderString;
|
||||
renderStringAsync = renderStringAsync;
|
||||
|
||||
filepathCache: Record<string, string> = {};
|
||||
templatesSync: Cacher<TemplateFunction> = new Cacher<TemplateFunction>({});
|
||||
templatesAsync: Cacher<TemplateFunction> = new Cacher<TemplateFunction>({});
|
||||
|
||||
// resolvePath takes a relative path from the "views" directory
|
||||
resolvePath:
|
||||
| null
|
||||
| ((this: Eta, template: string, options?: Partial<Options>) => string) =
|
||||
null;
|
||||
readFile: null | ((this: Eta, path: string) => string) = null;
|
||||
|
||||
// METHODS
|
||||
|
||||
configure(customConfig: Partial<EtaConfig>) {
|
||||
this.config = { ...this.config, ...customConfig };
|
||||
}
|
||||
|
||||
withConfig(customConfig: Partial<EtaConfig>): this & { config: EtaConfig } {
|
||||
return { ...this, config: { ...this.config, ...customConfig } };
|
||||
}
|
||||
|
||||
loadTemplate(
|
||||
name: string,
|
||||
template: string | TemplateFunction, // template string or template function
|
||||
options?: { async: boolean },
|
||||
): void {
|
||||
if (typeof template === "string") {
|
||||
const templates = options && options.async
|
||||
? this.templatesAsync
|
||||
: this.templatesSync;
|
||||
|
||||
templates.define(name, this.compile(template, options));
|
||||
} else {
|
||||
let templates = this.templatesSync;
|
||||
|
||||
if (
|
||||
template.constructor.name === "AsyncFunction" ||
|
||||
(options && options.async)
|
||||
) {
|
||||
templates = this.templatesAsync;
|
||||
}
|
||||
|
||||
templates.define(name, template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for instance checking against thrown errors
|
||||
export { EtaError };
|
||||
91
vendor/jsr.io/@eta-dev/eta/3.5.0/src/err.ts
generated
vendored
Normal file
91
vendor/jsr.io/@eta-dev/eta/3.5.0/src/err.ts
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
export class EtaError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "Eta Error";
|
||||
}
|
||||
}
|
||||
|
||||
export class EtaParseError extends EtaError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "EtaParser Error";
|
||||
}
|
||||
}
|
||||
|
||||
export class EtaRuntimeError extends EtaError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "EtaRuntime Error";
|
||||
}
|
||||
}
|
||||
|
||||
export class EtaFileResolutionError extends EtaError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "EtaFileResolution Error";
|
||||
}
|
||||
}
|
||||
|
||||
export class EtaNameResolutionError extends EtaError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "EtaNameResolution Error";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an EtaError with a nicely formatted error and message showing where in the template the error occurred.
|
||||
*/
|
||||
|
||||
export function ParseErr(message: string, str: string, indx: number): never {
|
||||
const whitespace = str.slice(0, indx).split(/\n/);
|
||||
|
||||
const lineNo = whitespace.length;
|
||||
const colNo = whitespace[lineNo - 1].length + 1;
|
||||
message += " at line " +
|
||||
lineNo +
|
||||
" col " +
|
||||
colNo +
|
||||
":\n\n" +
|
||||
" " +
|
||||
str.split(/\n/)[lineNo - 1] +
|
||||
"\n" +
|
||||
" " +
|
||||
Array(colNo).join(" ") +
|
||||
"^";
|
||||
throw new EtaParseError(message);
|
||||
}
|
||||
|
||||
export function RuntimeErr(
|
||||
originalError: Error,
|
||||
str: string,
|
||||
lineNo: number,
|
||||
path: string,
|
||||
): never {
|
||||
// code gratefully taken from https://github.com/mde/ejs and adapted
|
||||
|
||||
const lines = str.split("\n");
|
||||
const start = Math.max(lineNo - 3, 0);
|
||||
const end = Math.min(lines.length, lineNo + 3);
|
||||
const filename = path;
|
||||
// Error context
|
||||
const context = lines
|
||||
.slice(start, end)
|
||||
.map(function (line, i) {
|
||||
const curr = i + start + 1;
|
||||
return (curr == lineNo ? " >> " : " ") + curr + "| " + line;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
const header = filename
|
||||
? filename + ":" + lineNo + "\n"
|
||||
: "line " + lineNo + "\n";
|
||||
|
||||
const err = new EtaRuntimeError(
|
||||
header + context + "\n\n" + originalError.message,
|
||||
);
|
||||
|
||||
err.name = originalError.name; // the original name (e.g. ReferenceError) may be useful
|
||||
|
||||
throw err;
|
||||
}
|
||||
95
vendor/jsr.io/@eta-dev/eta/3.5.0/src/file-handling.ts
generated
vendored
Normal file
95
vendor/jsr.io/@eta-dev/eta/3.5.0/src/file-handling.ts
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
import { EtaFileResolutionError } from "./err.ts";
|
||||
|
||||
import * as path from "node:path";
|
||||
|
||||
import * as fs from "node:fs";
|
||||
|
||||
/* TYPES */
|
||||
import type { Eta as EtaCore } from "./core.ts";
|
||||
import type { Options } from "./config.ts";
|
||||
/* END TYPES */
|
||||
|
||||
export function readFile(this: EtaCore, path: string): string {
|
||||
let res = "";
|
||||
|
||||
try {
|
||||
res = fs.readFileSync(path, "utf8");
|
||||
// eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
} catch (err: any) {
|
||||
if (err?.code === "ENOENT") {
|
||||
throw new EtaFileResolutionError(`Could not find template: ${path}`);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export function resolvePath(
|
||||
this: EtaCore,
|
||||
templatePath: string,
|
||||
options?: Partial<Options>,
|
||||
): string {
|
||||
let resolvedFilePath = "";
|
||||
|
||||
const views = this.config.views;
|
||||
|
||||
if (!views) {
|
||||
throw new EtaFileResolutionError("Views directory is not defined");
|
||||
}
|
||||
|
||||
const baseFilePath = options && options.filepath;
|
||||
const defaultExtension = this.config.defaultExtension === undefined
|
||||
? ".eta"
|
||||
: this.config.defaultExtension;
|
||||
|
||||
// how we index cached template paths
|
||||
const cacheIndex = JSON.stringify({
|
||||
filename: baseFilePath, // filename of the template which called includeFile()
|
||||
path: templatePath,
|
||||
views: this.config.views,
|
||||
});
|
||||
|
||||
templatePath += path.extname(templatePath) ? "" : defaultExtension;
|
||||
|
||||
// if the file was included from another template
|
||||
if (baseFilePath) {
|
||||
// check the cache
|
||||
|
||||
if (this.config.cacheFilepaths && this.filepathCache[cacheIndex]) {
|
||||
return this.filepathCache[cacheIndex];
|
||||
}
|
||||
|
||||
const absolutePathTest = absolutePathRegExp.exec(templatePath);
|
||||
|
||||
if (absolutePathTest && absolutePathTest.length) {
|
||||
const formattedPath = templatePath.replace(/^\/*|^\\*/, "");
|
||||
resolvedFilePath = path.join(views, formattedPath);
|
||||
} else {
|
||||
resolvedFilePath = path.join(path.dirname(baseFilePath), templatePath);
|
||||
}
|
||||
} else {
|
||||
resolvedFilePath = path.join(views, templatePath);
|
||||
}
|
||||
|
||||
if (dirIsChild(views, resolvedFilePath)) {
|
||||
// add resolved path to the cache
|
||||
if (baseFilePath && this.config.cacheFilepaths) {
|
||||
this.filepathCache[cacheIndex] = resolvedFilePath;
|
||||
}
|
||||
|
||||
return resolvedFilePath;
|
||||
} else {
|
||||
throw new EtaFileResolutionError(
|
||||
`Template '${templatePath}' is not in the views directory`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function dirIsChild(parent: string, dir: string) {
|
||||
const relative = path.relative(parent, dir);
|
||||
return relative && !relative.startsWith("..") && !path.isAbsolute(relative);
|
||||
}
|
||||
|
||||
const absolutePathRegExp = /^\\|^\//;
|
||||
16
vendor/jsr.io/@eta-dev/eta/3.5.0/src/index.ts
generated
vendored
Normal file
16
vendor/jsr.io/@eta-dev/eta/3.5.0/src/index.ts
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import { Eta as EtaCore } from "./core.ts";
|
||||
import { readFile, resolvePath } from "./file-handling.ts";
|
||||
export {
|
||||
EtaError,
|
||||
EtaFileResolutionError,
|
||||
EtaNameResolutionError,
|
||||
EtaParseError,
|
||||
EtaRuntimeError,
|
||||
} from "./err.ts";
|
||||
export { type EtaConfig, type Options } from "./config.ts";
|
||||
|
||||
export class Eta extends EtaCore {
|
||||
readFile = readFile;
|
||||
|
||||
resolvePath = resolvePath;
|
||||
}
|
||||
215
vendor/jsr.io/@eta-dev/eta/3.5.0/src/parse.ts
generated
vendored
Normal file
215
vendor/jsr.io/@eta-dev/eta/3.5.0/src/parse.ts
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
import { ParseErr } from "./err.ts";
|
||||
import { trimWS } from "./utils.ts";
|
||||
|
||||
/* TYPES */
|
||||
|
||||
import type { Eta } from "./core.ts";
|
||||
|
||||
export type TagType = "r" | "e" | "i" | "";
|
||||
|
||||
export interface TemplateObject {
|
||||
t: TagType;
|
||||
val: string;
|
||||
lineNo?: number;
|
||||
}
|
||||
|
||||
export type AstObject = string | TemplateObject;
|
||||
|
||||
/* END TYPES */
|
||||
|
||||
const templateLitReg =
|
||||
/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g;
|
||||
|
||||
const singleQuoteReg = /'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g;
|
||||
|
||||
const doubleQuoteReg = /"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g;
|
||||
|
||||
/** Escape special regular expression characters inside a string */
|
||||
|
||||
function escapeRegExp(string: string) {
|
||||
// From MDN
|
||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
||||
}
|
||||
|
||||
function getLineNo(str: string, index: number) {
|
||||
return str.slice(0, index).split("\n").length;
|
||||
}
|
||||
|
||||
export function parse(this: Eta, str: string): Array<AstObject> {
|
||||
const config = this.config;
|
||||
|
||||
let buffer: Array<AstObject> = [];
|
||||
let trimLeftOfNextStr: string | false = false;
|
||||
let lastIndex = 0;
|
||||
const parseOptions = config.parse;
|
||||
|
||||
if (config.plugins) {
|
||||
for (let i = 0; i < config.plugins.length; i++) {
|
||||
const plugin = config.plugins[i];
|
||||
if (plugin.processTemplate) {
|
||||
str = plugin.processTemplate(str, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding for EJS compatibility */
|
||||
if (config.rmWhitespace) {
|
||||
// Code taken directly from EJS
|
||||
// Have to use two separate replaces here as `^` and `$` operators don't
|
||||
// work well with `\r` and empty lines don't work well with the `m` flag.
|
||||
// Essentially, this replaces the whitespace at the beginning and end of
|
||||
// each line and removes multiple newlines.
|
||||
str = str.replace(/[\r\n]+/g, "\n").replace(/^\s+|\s+$/gm, "");
|
||||
}
|
||||
/* End rmWhitespace option */
|
||||
|
||||
templateLitReg.lastIndex = 0;
|
||||
singleQuoteReg.lastIndex = 0;
|
||||
doubleQuoteReg.lastIndex = 0;
|
||||
|
||||
function pushString(strng: string, shouldTrimRightOfString?: string | false) {
|
||||
if (strng) {
|
||||
// if string is truthy it must be of type 'string'
|
||||
|
||||
strng = trimWS(
|
||||
strng,
|
||||
config,
|
||||
trimLeftOfNextStr, // this will only be false on the first str, the next ones will be null or undefined
|
||||
shouldTrimRightOfString,
|
||||
);
|
||||
|
||||
if (strng) {
|
||||
// replace \ with \\, ' with \'
|
||||
// we're going to convert all CRLF to LF so it doesn't take more than one replace
|
||||
|
||||
strng = strng.replace(/\\|'/g, "\\$&").replace(/\r\n|\n|\r/g, "\\n");
|
||||
|
||||
buffer.push(strng);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const prefixes = [
|
||||
parseOptions.exec,
|
||||
parseOptions.interpolate,
|
||||
parseOptions.raw,
|
||||
].reduce(function (
|
||||
accumulator,
|
||||
prefix,
|
||||
) {
|
||||
if (accumulator && prefix) {
|
||||
return accumulator + "|" + escapeRegExp(prefix);
|
||||
} else if (prefix) {
|
||||
// accumulator is falsy
|
||||
return escapeRegExp(prefix);
|
||||
} else {
|
||||
// prefix and accumulator are both falsy
|
||||
return accumulator;
|
||||
}
|
||||
}, "");
|
||||
|
||||
const parseOpenReg = new RegExp(
|
||||
escapeRegExp(config.tags[0]) + "(-|_)?\\s*(" + prefixes + ")?\\s*",
|
||||
"g",
|
||||
);
|
||||
|
||||
const parseCloseReg = new RegExp(
|
||||
"'|\"|`|\\/\\*|(\\s*(-|_)?" + escapeRegExp(config.tags[1]) + ")",
|
||||
"g",
|
||||
);
|
||||
|
||||
let m;
|
||||
|
||||
while ((m = parseOpenReg.exec(str))) {
|
||||
const precedingString = str.slice(lastIndex, m.index);
|
||||
|
||||
lastIndex = m[0].length + m.index;
|
||||
|
||||
const wsLeft = m[1];
|
||||
const prefix = m[2] || ""; // by default either ~, =, or empty
|
||||
|
||||
pushString(precedingString, wsLeft);
|
||||
|
||||
parseCloseReg.lastIndex = lastIndex;
|
||||
let closeTag;
|
||||
let currentObj: AstObject | false = false;
|
||||
|
||||
while ((closeTag = parseCloseReg.exec(str))) {
|
||||
if (closeTag[1]) {
|
||||
const content = str.slice(lastIndex, closeTag.index);
|
||||
|
||||
parseOpenReg.lastIndex = lastIndex = parseCloseReg.lastIndex;
|
||||
|
||||
trimLeftOfNextStr = closeTag[2];
|
||||
|
||||
const currentType: TagType = prefix === parseOptions.exec
|
||||
? "e"
|
||||
: prefix === parseOptions.raw
|
||||
? "r"
|
||||
: prefix === parseOptions.interpolate
|
||||
? "i"
|
||||
: "";
|
||||
|
||||
currentObj = { t: currentType, val: content };
|
||||
break;
|
||||
} else {
|
||||
const char = closeTag[0];
|
||||
if (char === "/*") {
|
||||
const commentCloseInd = str.indexOf("*/", parseCloseReg.lastIndex);
|
||||
|
||||
if (commentCloseInd === -1) {
|
||||
ParseErr("unclosed comment", str, closeTag.index);
|
||||
}
|
||||
parseCloseReg.lastIndex = commentCloseInd;
|
||||
} else if (char === "'") {
|
||||
singleQuoteReg.lastIndex = closeTag.index;
|
||||
|
||||
const singleQuoteMatch = singleQuoteReg.exec(str);
|
||||
if (singleQuoteMatch) {
|
||||
parseCloseReg.lastIndex = singleQuoteReg.lastIndex;
|
||||
} else {
|
||||
ParseErr("unclosed string", str, closeTag.index);
|
||||
}
|
||||
} else if (char === '"') {
|
||||
doubleQuoteReg.lastIndex = closeTag.index;
|
||||
const doubleQuoteMatch = doubleQuoteReg.exec(str);
|
||||
|
||||
if (doubleQuoteMatch) {
|
||||
parseCloseReg.lastIndex = doubleQuoteReg.lastIndex;
|
||||
} else {
|
||||
ParseErr("unclosed string", str, closeTag.index);
|
||||
}
|
||||
} else if (char === "`") {
|
||||
templateLitReg.lastIndex = closeTag.index;
|
||||
const templateLitMatch = templateLitReg.exec(str);
|
||||
if (templateLitMatch) {
|
||||
parseCloseReg.lastIndex = templateLitReg.lastIndex;
|
||||
} else {
|
||||
ParseErr("unclosed string", str, closeTag.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentObj) {
|
||||
if (config.debug) {
|
||||
currentObj.lineNo = getLineNo(str, m.index);
|
||||
}
|
||||
buffer.push(currentObj);
|
||||
} else {
|
||||
ParseErr("unclosed tag", str, m.index);
|
||||
}
|
||||
}
|
||||
|
||||
pushString(str.slice(lastIndex, str.length), false);
|
||||
|
||||
if (config.plugins) {
|
||||
for (let i = 0; i < config.plugins.length; i++) {
|
||||
const plugin = config.plugins[i];
|
||||
if (plugin.processAST) {
|
||||
buffer = plugin.processAST(buffer, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
114
vendor/jsr.io/@eta-dev/eta/3.5.0/src/render.ts
generated
vendored
Normal file
114
vendor/jsr.io/@eta-dev/eta/3.5.0/src/render.ts
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
import { EtaNameResolutionError } from "./err.ts";
|
||||
|
||||
/* TYPES */
|
||||
import type { Options } from "./config.ts";
|
||||
import type { TemplateFunction } from "./compile.ts";
|
||||
import type { Eta } from "./core.ts";
|
||||
/* END TYPES */
|
||||
|
||||
function handleCache(
|
||||
this: Eta,
|
||||
template: string,
|
||||
options: Partial<Options>,
|
||||
): TemplateFunction {
|
||||
const templateStore = options && options.async
|
||||
? this.templatesAsync
|
||||
: this.templatesSync;
|
||||
|
||||
if (this.resolvePath && this.readFile && !template.startsWith("@")) {
|
||||
const templatePath = options.filepath as string;
|
||||
|
||||
const cachedTemplate = templateStore.get(templatePath);
|
||||
|
||||
if (this.config.cache && cachedTemplate) {
|
||||
return cachedTemplate;
|
||||
} else {
|
||||
const templateString = this.readFile(templatePath);
|
||||
|
||||
const templateFn = this.compile(templateString, options);
|
||||
|
||||
if (this.config.cache) templateStore.define(templatePath, templateFn);
|
||||
|
||||
return templateFn;
|
||||
}
|
||||
} else {
|
||||
const cachedTemplate = templateStore.get(template);
|
||||
|
||||
if (cachedTemplate) {
|
||||
return cachedTemplate;
|
||||
} else {
|
||||
throw new EtaNameResolutionError(
|
||||
"Failed to get template '" + template + "'",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function render<T extends object>(
|
||||
this: Eta,
|
||||
template: string | TemplateFunction, // template name or template function
|
||||
data: T,
|
||||
meta?: { filepath: string },
|
||||
): string {
|
||||
let templateFn: TemplateFunction;
|
||||
const options = { ...meta, async: false };
|
||||
|
||||
if (typeof template === "string") {
|
||||
if (this.resolvePath && this.readFile && !template.startsWith("@")) {
|
||||
options.filepath = this.resolvePath(template, options);
|
||||
}
|
||||
|
||||
templateFn = handleCache.call(this, template, options);
|
||||
} else {
|
||||
templateFn = template;
|
||||
}
|
||||
|
||||
const res = templateFn.call(this, data, options);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export function renderAsync<T extends object>(
|
||||
this: Eta,
|
||||
template: string | TemplateFunction, // template name or template function
|
||||
data: T,
|
||||
meta?: { filepath: string },
|
||||
): Promise<string> {
|
||||
let templateFn: TemplateFunction;
|
||||
const options = { ...meta, async: true };
|
||||
|
||||
if (typeof template === "string") {
|
||||
if (this.resolvePath && this.readFile && !template.startsWith("@")) {
|
||||
options.filepath = this.resolvePath(template, options);
|
||||
}
|
||||
|
||||
templateFn = handleCache.call(this, template, options);
|
||||
} else {
|
||||
templateFn = template;
|
||||
}
|
||||
|
||||
const res = templateFn.call(this, data, options);
|
||||
|
||||
// Return a promise
|
||||
return Promise.resolve(res);
|
||||
}
|
||||
|
||||
export function renderString<T extends object>(
|
||||
this: Eta,
|
||||
template: string,
|
||||
data: T,
|
||||
): string {
|
||||
const templateFn = this.compile(template, { async: false });
|
||||
|
||||
return render.call(this, templateFn, data);
|
||||
}
|
||||
|
||||
export function renderStringAsync<T extends object>(
|
||||
this: Eta,
|
||||
template: string,
|
||||
data: T,
|
||||
): Promise<string> {
|
||||
const templateFn = this.compile(template, { async: true });
|
||||
|
||||
return renderAsync.call(this, templateFn, data);
|
||||
}
|
||||
25
vendor/jsr.io/@eta-dev/eta/3.5.0/src/storage.ts
generated
vendored
Normal file
25
vendor/jsr.io/@eta-dev/eta/3.5.0/src/storage.ts
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Handles storage and accessing of values
|
||||
*
|
||||
* In this case, we use it to store compiled template functions
|
||||
* Indexed by their `name` or `filename`
|
||||
*/
|
||||
|
||||
export class Cacher<T> {
|
||||
constructor(private cache: Record<string, T>) {}
|
||||
define(key: string, val: T): void {
|
||||
this.cache[key] = val;
|
||||
}
|
||||
get(key: string): T {
|
||||
return this.cache[key];
|
||||
}
|
||||
remove(key: string): void {
|
||||
delete this.cache[key];
|
||||
}
|
||||
reset(): void {
|
||||
this.cache = {};
|
||||
}
|
||||
load(cacheObj: Record<string, T>): void {
|
||||
this.cache = { ...this.cache, ...cacheObj };
|
||||
}
|
||||
}
|
||||
91
vendor/jsr.io/@eta-dev/eta/3.5.0/src/utils.ts
generated
vendored
Normal file
91
vendor/jsr.io/@eta-dev/eta/3.5.0/src/utils.ts
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
import type { EtaConfig } from "./config.ts";
|
||||
|
||||
/**
|
||||
* Takes a string within a template and trims it, based on the preceding tag's whitespace control and `config.autoTrim`
|
||||
*/
|
||||
|
||||
export function trimWS(
|
||||
str: string,
|
||||
config: EtaConfig,
|
||||
wsLeft: string | false,
|
||||
wsRight?: string | false,
|
||||
): string {
|
||||
let leftTrim;
|
||||
let rightTrim;
|
||||
|
||||
if (Array.isArray(config.autoTrim)) {
|
||||
// Slightly confusing,
|
||||
// but _}} will trim the left side of the following string
|
||||
leftTrim = config.autoTrim[1];
|
||||
rightTrim = config.autoTrim[0];
|
||||
} else {
|
||||
leftTrim = rightTrim = config.autoTrim;
|
||||
}
|
||||
|
||||
if (wsLeft || wsLeft === false) {
|
||||
leftTrim = wsLeft;
|
||||
}
|
||||
|
||||
if (wsRight || wsRight === false) {
|
||||
rightTrim = wsRight;
|
||||
}
|
||||
|
||||
if (!rightTrim && !leftTrim) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (leftTrim === "slurp" && rightTrim === "slurp") {
|
||||
return str.trim();
|
||||
}
|
||||
|
||||
if (leftTrim === "_" || leftTrim === "slurp") {
|
||||
// full slurp
|
||||
str = str.trimStart();
|
||||
} else if (leftTrim === "-" || leftTrim === "nl") {
|
||||
// nl trim
|
||||
str = str.replace(/^(?:\r\n|\n|\r)/, "");
|
||||
}
|
||||
|
||||
if (rightTrim === "_" || rightTrim === "slurp") {
|
||||
// full slurp
|
||||
str = str.trimEnd();
|
||||
} else if (rightTrim === "-" || rightTrim === "nl") {
|
||||
// nl trim
|
||||
str = str.replace(/(?:\r\n|\n|\r)$/, "");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of special HTML characters to their XML-escaped equivalents
|
||||
*/
|
||||
|
||||
const escMap: { [key: string]: string } = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
};
|
||||
|
||||
function replaceChar(s: string): string {
|
||||
return escMap[s];
|
||||
}
|
||||
|
||||
/**
|
||||
* XML-escapes an input value after converting it to a string
|
||||
*
|
||||
* @param str - Input value (usually a string)
|
||||
* @returns XML-escaped string
|
||||
*/
|
||||
|
||||
export function XMLEscape(str: unknown): string {
|
||||
// To deal with XSS. Based on Escape implementations of Mustache.JS and Marko, then customized.
|
||||
const newStr = String(str);
|
||||
if (/[&<>"']/.test(newStr)) {
|
||||
return newStr.replace(/[&<>"']/g, replaceChar);
|
||||
} else {
|
||||
return newStr;
|
||||
}
|
||||
}
|
||||
602
vendor/jsr.io/@eta-dev/eta/3.5.0_meta.json
generated
vendored
Normal file
602
vendor/jsr.io/@eta-dev/eta/3.5.0_meta.json
generated
vendored
Normal file
@ -0,0 +1,602 @@
|
||||
{
|
||||
"manifest": {
|
||||
"/jsr.json": {
|
||||
"size": 181,
|
||||
"checksum": "sha256-a5fd262244bc73cbd184534361d324caf2c2c823000b2207bfedb363b42a3c1c"
|
||||
},
|
||||
"/src/config.ts": {
|
||||
"size": 2896,
|
||||
"checksum": "sha256-5b13139a94c07a13d9467712d754fb02f6b5245d30c0bab792f79b22277d4da8"
|
||||
},
|
||||
"/src/err.ts": {
|
||||
"size": 2149,
|
||||
"checksum": "sha256-7354a040b6aa49650d564c1f9791d9efe67499c1772632472f1cb91e93eb3af0"
|
||||
},
|
||||
"/README.md": {
|
||||
"size": 10359,
|
||||
"checksum": "sha256-7673f007986cfe047328cbd9dd40f488eb77a681d23b701063f9293a87a53540"
|
||||
},
|
||||
"/src/parse.ts": {
|
||||
"size": 6041,
|
||||
"checksum": "sha256-a029cc6b95e8c1393f1f4d25f107f770e6ab41b8dbb820e2c26f6808b8ef74a5"
|
||||
},
|
||||
"/LICENSE": {
|
||||
"size": 1072,
|
||||
"checksum": "sha256-ffae00b51ffea9ff5ba139166c89119d6ee3810f1e04e427dd6820a728b43915"
|
||||
},
|
||||
"/src/storage.ts": {
|
||||
"size": 565,
|
||||
"checksum": "sha256-c40bd31cdd6f1218c86f70067282709e2f2c7fa7eea67547be950e1ed5d4bd4c"
|
||||
},
|
||||
"/src/file-handling.ts": {
|
||||
"size": 2577,
|
||||
"checksum": "sha256-eeabf27135ec1fa1b513cafc61dc0ef6fbe385b0c10004d250f514e718469b6a"
|
||||
},
|
||||
"/src/render.ts": {
|
||||
"size": 2932,
|
||||
"checksum": "sha256-e63acccd1b3a0dfcf67c712c172f8175e71d30f0d3c6a07f2f7555e52f7b6cf1"
|
||||
},
|
||||
"/src/browser.ts": {
|
||||
"size": 81,
|
||||
"checksum": "sha256-d76f77a2adaa2f0d987c4c65132c65a7fa7b895221b75aee00a52ba48e663bf5"
|
||||
},
|
||||
"/src/index.ts": {
|
||||
"size": 383,
|
||||
"checksum": "sha256-d2bacfd6fc5ab8f41fc2802e2191863b5c630256648b0d2e8a2962412d63b1ac"
|
||||
},
|
||||
"/src/utils.ts": {
|
||||
"size": 2035,
|
||||
"checksum": "sha256-8e651cf1f30dfc90de15242079b7dd1a6f53789c5c8d65e1280cf15381847937"
|
||||
},
|
||||
"/src/compile.ts": {
|
||||
"size": 1600,
|
||||
"checksum": "sha256-6e519d6341664d552da844bb8356e818d3b644b59070fb6a918b8fed0f5e0e6c"
|
||||
},
|
||||
"/src/compile-string.ts": {
|
||||
"size": 3457,
|
||||
"checksum": "sha256-ee1de98e5349dc70652e944316cb7fe1d32fd4065fef323b9e6e78db65d3e20c"
|
||||
},
|
||||
"/src/core.ts": {
|
||||
"size": 2439,
|
||||
"checksum": "sha256-79ca3d073fde31f3d38f09048c9da7519c688563d48e05e014d85db26d9d7402"
|
||||
}
|
||||
},
|
||||
"moduleGraph2": {
|
||||
"/src/file-handling.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
39
|
||||
],
|
||||
[
|
||||
0,
|
||||
49
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "node:path",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
22
|
||||
],
|
||||
[
|
||||
2,
|
||||
33
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "node:fs",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
20
|
||||
],
|
||||
[
|
||||
4,
|
||||
29
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
7,
|
||||
36
|
||||
],
|
||||
[
|
||||
7,
|
||||
47
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
8,
|
||||
29
|
||||
],
|
||||
[
|
||||
8,
|
||||
42
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/core.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./storage.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
23
|
||||
],
|
||||
[
|
||||
0,
|
||||
37
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./compile.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
24
|
||||
],
|
||||
[
|
||||
1,
|
||||
38
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./compile-string.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
45
|
||||
],
|
||||
[
|
||||
2,
|
||||
66
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
30
|
||||
],
|
||||
[
|
||||
3,
|
||||
43
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./parse.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
22
|
||||
],
|
||||
[
|
||||
4,
|
||||
34
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./render.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
10,
|
||||
7
|
||||
],
|
||||
[
|
||||
10,
|
||||
20
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
11,
|
||||
37
|
||||
],
|
||||
[
|
||||
11,
|
||||
47
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./compile.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
12,
|
||||
33
|
||||
],
|
||||
[
|
||||
12,
|
||||
47
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
15,
|
||||
40
|
||||
],
|
||||
[
|
||||
15,
|
||||
53
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/parse.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
25
|
||||
],
|
||||
[
|
||||
0,
|
||||
35
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./utils.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
23
|
||||
],
|
||||
[
|
||||
1,
|
||||
35
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
5,
|
||||
25
|
||||
],
|
||||
[
|
||||
5,
|
||||
36
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/index.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
31
|
||||
],
|
||||
[
|
||||
0,
|
||||
42
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./file-handling.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
38
|
||||
],
|
||||
[
|
||||
1,
|
||||
58
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
8,
|
||||
7
|
||||
],
|
||||
[
|
||||
8,
|
||||
17
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
9,
|
||||
45
|
||||
],
|
||||
[
|
||||
9,
|
||||
58
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/err.ts": {},
|
||||
"/src/config.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./utils.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
26
|
||||
],
|
||||
[
|
||||
0,
|
||||
38
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/compile-string.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
29
|
||||
],
|
||||
[
|
||||
2,
|
||||
42
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./parse.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
31
|
||||
],
|
||||
[
|
||||
3,
|
||||
43
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
25
|
||||
],
|
||||
[
|
||||
4,
|
||||
36
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/render.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
39
|
||||
],
|
||||
[
|
||||
0,
|
||||
49
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
29
|
||||
],
|
||||
[
|
||||
3,
|
||||
42
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./compile.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
38
|
||||
],
|
||||
[
|
||||
4,
|
||||
52
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
5,
|
||||
25
|
||||
],
|
||||
[
|
||||
5,
|
||||
36
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/storage.ts": {},
|
||||
"/src/utils.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
31
|
||||
],
|
||||
[
|
||||
0,
|
||||
44
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/compile.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./err.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
40
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./core.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
25
|
||||
],
|
||||
[
|
||||
3,
|
||||
36
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./config.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
40
|
||||
],
|
||||
[
|
||||
4,
|
||||
53
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
}
|
||||
9
vendor/jsr.io/@eta-dev/eta/meta.json
generated
vendored
Normal file
9
vendor/jsr.io/@eta-dev/eta/meta.json
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"scope": "eta-dev",
|
||||
"name": "eta",
|
||||
"latest": "3.5.0",
|
||||
"versions": {
|
||||
"3.4.0": {},
|
||||
"3.5.0": {}
|
||||
}
|
||||
}
|
||||
89
vendor/jsr.io/@felix/bcrypt/1.0.5/bindings/bindings.ts
generated
vendored
Normal file
89
vendor/jsr.io/@felix/bcrypt/1.0.5/bindings/bindings.ts
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
import { dlopen } from "jsr:@denosaurs/plug@^1.0.6";
|
||||
|
||||
export const VERSION = "1.0.5";
|
||||
|
||||
// Auto-generated with deno_bindgen
|
||||
function encode(v: string | Uint8Array): Uint8Array {
|
||||
if (typeof v !== "string") return v;
|
||||
return new TextEncoder().encode(v);
|
||||
}
|
||||
|
||||
function decode(v: Uint8Array): string {
|
||||
return new TextDecoder().decode(v);
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
function readPointer(v: any): Uint8Array {
|
||||
const ptr = new Deno.UnsafePointerView(v);
|
||||
const lengthBe = new Uint8Array(4);
|
||||
const view = new DataView(lengthBe.buffer);
|
||||
ptr.copyInto(lengthBe, 0);
|
||||
const buf = new Uint8Array(view.getUint32(0));
|
||||
ptr.copyInto(buf, 4);
|
||||
return buf;
|
||||
}
|
||||
|
||||
function getLocalUrl(): string {
|
||||
const url = new URL("../target/release", import.meta.url);
|
||||
|
||||
let uri = url.pathname;
|
||||
if (!uri.endsWith("/")) uri += "/";
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya#parameters
|
||||
if (Deno.build.os === "windows") {
|
||||
uri = uri.replace(/\//g, "\\");
|
||||
// Remove leading slash
|
||||
if (uri.startsWith("\\")) {
|
||||
uri = uri.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
const SYMBOLS = {
|
||||
hash: {
|
||||
parameters: ["buffer", "usize"],
|
||||
result: "buffer",
|
||||
nonblocking: true,
|
||||
},
|
||||
verify: {
|
||||
parameters: ["buffer", "usize", "buffer", "usize"],
|
||||
result: "i8",
|
||||
nonblocking: true,
|
||||
},
|
||||
} as const;
|
||||
|
||||
const LOCAL = Deno.env.get("LOCAL");
|
||||
|
||||
const { symbols } = await dlopen(
|
||||
{
|
||||
name: "deno_bcrypt",
|
||||
url: LOCAL
|
||||
? getLocalUrl()
|
||||
: `https://github.com/felix-schindler/deno-bcrypt/releases/download/v${VERSION}/`,
|
||||
cache: LOCAL ? "reloadAll" : "use",
|
||||
},
|
||||
SYMBOLS,
|
||||
);
|
||||
|
||||
export function hash(a0: string) {
|
||||
const a0_buf = encode(a0);
|
||||
|
||||
const rawResult = symbols.hash(a0_buf, BigInt(a0_buf.byteLength));
|
||||
const result = rawResult.then(readPointer);
|
||||
return result.then(decode);
|
||||
}
|
||||
export function verify(a0: string, a1: string) {
|
||||
const a0_buf = encode(a0);
|
||||
const a1_buf = encode(a1);
|
||||
|
||||
const rawResult = symbols.verify(
|
||||
a0_buf,
|
||||
BigInt(a0_buf.byteLength),
|
||||
a1_buf,
|
||||
BigInt(a1_buf.byteLength),
|
||||
);
|
||||
const result = rawResult;
|
||||
return result;
|
||||
}
|
||||
18
vendor/jsr.io/@felix/bcrypt/1.0.5/helper.ts
generated
vendored
Normal file
18
vendor/jsr.io/@felix/bcrypt/1.0.5/helper.ts
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import * as internal from "./bindings/bindings.ts";
|
||||
|
||||
/**
|
||||
* @param password Clear text password
|
||||
* @returns Hashed password
|
||||
*/
|
||||
export async function hash(password: string): Promise<string> {
|
||||
return await internal.hash(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password Clear text password
|
||||
* @param hash Hashed password
|
||||
* @returns Whether the password matches the hash
|
||||
*/
|
||||
export async function verify(password: string, hash: string): Promise<boolean> {
|
||||
return (await internal.verify(password, hash) === 1);
|
||||
}
|
||||
1
vendor/jsr.io/@felix/bcrypt/1.0.5/mod.ts
generated
vendored
Normal file
1
vendor/jsr.io/@felix/bcrypt/1.0.5/mod.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./helper.ts";
|
||||
94
vendor/jsr.io/@felix/bcrypt/1.0.5_meta.json
generated
vendored
Normal file
94
vendor/jsr.io/@felix/bcrypt/1.0.5_meta.json
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
{
|
||||
"manifest": {
|
||||
"/mod.ts": {
|
||||
"size": 29,
|
||||
"checksum": "sha256-2dc3991ca869eccc6a831a13b7d3488fd139ceead2868263bbf73a97ffcb6fa7"
|
||||
},
|
||||
"/bindings.json": {
|
||||
"size": 216,
|
||||
"checksum": "sha256-334c4ab9ae8029a60ef0d534d49794841e3193b7d082361a795aacceb37e71a0"
|
||||
},
|
||||
"/bindings/bindings.ts": {
|
||||
"size": 2068,
|
||||
"checksum": "sha256-b391e47854e78a54ab044c1c3846a9a4a73330bb953d99658e7c915b72359e1b"
|
||||
},
|
||||
"/helper.ts": {
|
||||
"size": 500,
|
||||
"checksum": "sha256-70a035fd0cebb70a680b28dca6e7f949e91ecc301aa299844374c5706d72a7c3"
|
||||
},
|
||||
"/deno.json": {
|
||||
"size": 802,
|
||||
"checksum": "sha256-cdad19aaf9007e051f72f13def1ac0a18734e6d5d51478feb9d483d9bb25a049"
|
||||
},
|
||||
"/README.md": {
|
||||
"size": 1621,
|
||||
"checksum": "sha256-ee89ab95a010b212cc242cb6bef5c3e596e6312942664a586b2efef8443b4dfd"
|
||||
},
|
||||
"/LICENSE": {
|
||||
"size": 34523,
|
||||
"checksum": "sha256-8486a10c4393cee1c25392769ddd3b2d6c242d6ec7928e1414efff7dfb2f07ef"
|
||||
}
|
||||
},
|
||||
"moduleGraph2": {
|
||||
"/helper.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./bindings/bindings.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
26
|
||||
],
|
||||
[
|
||||
0,
|
||||
50
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/bindings/bindings.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@denosaurs/plug@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
23
|
||||
],
|
||||
[
|
||||
0,
|
||||
51
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/mod.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./helper.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
14
|
||||
],
|
||||
[
|
||||
0,
|
||||
27
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
}
|
||||
}
|
||||
9
vendor/jsr.io/@felix/bcrypt/meta.json
generated
vendored
Normal file
9
vendor/jsr.io/@felix/bcrypt/meta.json
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"scope": "felix",
|
||||
"name": "bcrypt",
|
||||
"latest": "1.0.5",
|
||||
"versions": {
|
||||
"0.3.0": {},
|
||||
"1.0.5": {}
|
||||
}
|
||||
}
|
||||
89
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/mod.ts
generated
vendored
Normal file
89
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/mod.ts
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
import type * as esbuild from "./src/esbuild_types.ts";
|
||||
|
||||
import {
|
||||
denoResolverPlugin,
|
||||
type DenoResolverPluginOptions,
|
||||
} from "./src/plugin_deno_resolver.ts";
|
||||
export { denoResolverPlugin, type DenoResolverPluginOptions };
|
||||
|
||||
import {
|
||||
DEFAULT_LOADER,
|
||||
denoLoaderPlugin,
|
||||
type DenoLoaderPluginOptions,
|
||||
} from "./src/plugin_deno_loader.ts";
|
||||
export { DEFAULT_LOADER, denoLoaderPlugin, type DenoLoaderPluginOptions };
|
||||
|
||||
export {
|
||||
type EsbuildResolution,
|
||||
esbuildResolutionToURL,
|
||||
urlToEsbuildResolution,
|
||||
} from "./src/shared.ts";
|
||||
|
||||
/** Options for the {@link denoPlugins} function. */
|
||||
export interface DenoPluginsOptions {
|
||||
/**
|
||||
* Specify which loader to use. By default this will use the `native` loader,
|
||||
* unless the `--allow-run` permission has not been given.
|
||||
*
|
||||
* See {@link denoLoaderPlugin} for more information on the different loaders.
|
||||
*/
|
||||
loader?: "native" | "portable";
|
||||
|
||||
/**
|
||||
* Specify the path to a deno.json config file to use. This is equivalent to
|
||||
* the `--config` flag to the Deno executable. This path must be absolute.
|
||||
*
|
||||
* If not specified, the plugin will attempt to find the nearest deno.json and
|
||||
* use that. If the deno.json is part of a workspace, the plugin will
|
||||
* automatically find the workspace root.
|
||||
*/
|
||||
configPath?: string;
|
||||
/**
|
||||
* Specify a URL to an import map file to use when resolving import
|
||||
* specifiers. This is equivalent to the `--import-map` flag to the Deno
|
||||
* executable. This URL may be remote or a local file URL.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine what import map to use, if any.
|
||||
*/
|
||||
importMapURL?: string;
|
||||
/**
|
||||
* Specify the path to a deno.lock file to use. This is equivalent to the
|
||||
* `--lock` flag to the Deno executable. This path must be absolute.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine what lock file to use, if any.
|
||||
*
|
||||
* A lockfile must be present to resolve `jsr:` specifiers with the `portable`
|
||||
* loader. When using the `native` loader, a lockfile is not required, but to
|
||||
* ensure dependencies are de-duplicated correctly, it is recommended to use a
|
||||
* lockfile.
|
||||
*/
|
||||
lockPath?: string;
|
||||
/**
|
||||
* Specify how the loader should handle NPM packages. By default and if this
|
||||
* option is set to `none`, the loader will use the global cache to resolve
|
||||
* NPM packages. If this option is set to `manual`, the loader will use a
|
||||
* manually managed `node_modules` directory. If this option is set to `auto`,
|
||||
* the loader will use a local `node_modules` directory.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine which mode to use.
|
||||
*
|
||||
* This option is ignored when using the `portable` loader, as the portable
|
||||
* loader always uses a manual `node_modules` directory (equivalent of
|
||||
* `nodeModulesDir: "manual"`).
|
||||
*/
|
||||
nodeModulesDir?: "auto" | "manual" | "none";
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience function to enable both the Deno resolver plugin, and Deno
|
||||
* loader plugin.
|
||||
*/
|
||||
export function denoPlugins(opts: DenoPluginsOptions = {}): esbuild.Plugin[] {
|
||||
return [
|
||||
denoResolverPlugin(opts),
|
||||
denoLoaderPlugin(opts),
|
||||
];
|
||||
}
|
||||
283
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/deno.ts
generated
vendored
Normal file
283
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/deno.ts
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
export interface RootInfoOutput {
|
||||
denoDir: string;
|
||||
npmCache: string;
|
||||
}
|
||||
|
||||
export async function rootInfo(): Promise<RootInfoOutput> {
|
||||
if (!tmpDir) tmpDir = Deno.makeTempDirSync();
|
||||
const opts = {
|
||||
args: ["info", "--json", "--no-config", "--no-lock"],
|
||||
cwd: tmpDir,
|
||||
env: { DENO_NO_PACKAGE_JSON: "true" } as Record<string, string>,
|
||||
stdout: "piped",
|
||||
stderr: "inherit",
|
||||
};
|
||||
|
||||
const output = await new Deno.Command(
|
||||
Deno.execPath(),
|
||||
opts as Deno.CommandOptions,
|
||||
).output();
|
||||
if (!output.success) {
|
||||
throw new Error(`Failed to call 'deno info'`);
|
||||
}
|
||||
const txt = new TextDecoder().decode(output.stdout);
|
||||
return JSON.parse(txt);
|
||||
}
|
||||
|
||||
// Lifted from https://raw.githubusercontent.com/denoland/deno_graph/89affe43c9d3d5c9165c8089687c107d53ed8fe1/lib/media_type.ts
|
||||
export type MediaType =
|
||||
| "JavaScript"
|
||||
| "Mjs"
|
||||
| "Cjs"
|
||||
| "JSX"
|
||||
| "TypeScript"
|
||||
| "Mts"
|
||||
| "Cts"
|
||||
| "Dts"
|
||||
| "Dmts"
|
||||
| "Dcts"
|
||||
| "TSX"
|
||||
| "Json"
|
||||
| "Wasm"
|
||||
| "TsBuildInfo"
|
||||
| "SourceMap"
|
||||
| "Unknown";
|
||||
|
||||
interface InfoOutput {
|
||||
roots: string[];
|
||||
modules: ModuleEntry[];
|
||||
redirects: Record<string, string>;
|
||||
npmPackages?: Record<string, NpmPackage>;
|
||||
}
|
||||
|
||||
export type ModuleEntry =
|
||||
| ModuleEntryError
|
||||
| ModuleEntryEsm
|
||||
| ModuleEntryJson
|
||||
| ModuleEntryNpm
|
||||
| ModuleEntryNode;
|
||||
|
||||
export interface ModuleEntryBase {
|
||||
specifier: string;
|
||||
}
|
||||
|
||||
export interface ModuleEntryError extends ModuleEntryBase {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface ModuleEntryEsm extends ModuleEntryBase {
|
||||
kind: "esm";
|
||||
local: string | null;
|
||||
emit: string | null;
|
||||
map: string | null;
|
||||
mediaType: MediaType;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface ModuleEntryJson extends ModuleEntryBase {
|
||||
kind: "asserted" | "json";
|
||||
local: string | null;
|
||||
mediaType: MediaType;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface ModuleEntryNpm extends ModuleEntryBase {
|
||||
kind: "npm";
|
||||
npmPackage: string;
|
||||
}
|
||||
|
||||
export interface ModuleEntryNode extends ModuleEntryBase {
|
||||
kind: "node";
|
||||
moduleName: string;
|
||||
}
|
||||
|
||||
export interface NpmPackage {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies: string[];
|
||||
registryUrl?: string;
|
||||
}
|
||||
|
||||
export interface InfoOptions {
|
||||
cwd?: string;
|
||||
config?: string;
|
||||
importMap?: string;
|
||||
lock?: string;
|
||||
nodeModulesDir?: "auto" | "manual" | "none";
|
||||
}
|
||||
|
||||
let tmpDir: string | undefined;
|
||||
|
||||
async function info(
|
||||
specifier: string,
|
||||
options: InfoOptions,
|
||||
): Promise<InfoOutput> {
|
||||
const args = ["info", "--json"];
|
||||
if (!Deno.version.deno.startsWith("1.")) {
|
||||
args.push("--allow-import");
|
||||
}
|
||||
const opts = {
|
||||
args,
|
||||
cwd: undefined as string | undefined,
|
||||
env: { DENO_NO_PACKAGE_JSON: "true" } as Record<string, string>,
|
||||
stdout: "piped",
|
||||
stderr: "inherit",
|
||||
};
|
||||
if (typeof options.config === "string") {
|
||||
opts.args.push("--config", options.config);
|
||||
} else {
|
||||
opts.args.push("--no-config");
|
||||
}
|
||||
if (options.importMap) {
|
||||
opts.args.push("--import-map", options.importMap);
|
||||
}
|
||||
if (typeof options.lock === "string") {
|
||||
opts.args.push("--lock", options.lock);
|
||||
} else if (!options.cwd) {
|
||||
opts.args.push("--no-lock");
|
||||
}
|
||||
if (options.nodeModulesDir !== undefined) {
|
||||
if (Deno.version.deno.startsWith("1.")) {
|
||||
if (options.nodeModulesDir === "auto") {
|
||||
opts.args.push("--node-modules-dir");
|
||||
} else if (options.nodeModulesDir === "manual") {
|
||||
opts.args.push("--unstable-byonm");
|
||||
}
|
||||
} else {
|
||||
opts.args.push(`--node-modules-dir=${options.nodeModulesDir}`);
|
||||
}
|
||||
}
|
||||
if (options.cwd) {
|
||||
opts.cwd = options.cwd;
|
||||
} else {
|
||||
if (!tmpDir) tmpDir = Deno.makeTempDirSync();
|
||||
opts.cwd = tmpDir;
|
||||
}
|
||||
|
||||
opts.args.push(specifier);
|
||||
|
||||
const output = await new Deno.Command(
|
||||
Deno.execPath(),
|
||||
opts as Deno.CommandOptions,
|
||||
).output();
|
||||
if (!output.success) {
|
||||
throw new Error(`Failed to call 'deno info' on '${specifier}'`);
|
||||
}
|
||||
const txt = new TextDecoder().decode(output.stdout);
|
||||
return JSON.parse(txt);
|
||||
}
|
||||
|
||||
export class InfoCache {
|
||||
#options: InfoOptions;
|
||||
|
||||
#pending: { done: Promise<void>; specifiers: Set<string> | null } | null =
|
||||
null;
|
||||
|
||||
#modules: Map<string, ModuleEntry> = new Map();
|
||||
#redirects: Map<string, string> = new Map();
|
||||
#npmPackages: Map<string, NpmPackage> = new Map();
|
||||
|
||||
constructor(options: InfoOptions = {}) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
async get(specifier: string): Promise<ModuleEntry> {
|
||||
let entry = this.#getCached(specifier);
|
||||
if (entry !== undefined) return entry;
|
||||
|
||||
await this.#queueLoad(specifier);
|
||||
|
||||
entry = this.#getCached(specifier);
|
||||
if (entry === undefined) {
|
||||
throw new Error(`Unreachable: '${specifier}' loaded but not reachable`);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
getNpmPackage(id: string): NpmPackage | undefined {
|
||||
return this.#npmPackages.get(id);
|
||||
}
|
||||
|
||||
#resolve(specifier: string): string {
|
||||
const original = specifier;
|
||||
let counter = 0;
|
||||
while (counter++ < 10) {
|
||||
const redirect = this.#redirects.get(specifier);
|
||||
if (redirect === undefined) return specifier;
|
||||
specifier = redirect;
|
||||
}
|
||||
throw new Error(`Too many redirects for '${original}'`);
|
||||
}
|
||||
|
||||
#getCached(specifier: string): ModuleEntry | undefined {
|
||||
specifier = this.#resolve(specifier);
|
||||
return this.#modules.get(specifier);
|
||||
}
|
||||
|
||||
async #queueLoad(specifier: string) {
|
||||
while (true) {
|
||||
if (this.#pending === null) {
|
||||
this.#pending = {
|
||||
specifiers: new Set([specifier]),
|
||||
done: (async () => {
|
||||
await new Promise((r) => setTimeout(r, 5));
|
||||
const specifiers = this.#pending!.specifiers!;
|
||||
this.#pending!.specifiers = null;
|
||||
await this.#load([...specifiers]);
|
||||
this.#pending = null;
|
||||
})(),
|
||||
};
|
||||
await this.#pending.done;
|
||||
return;
|
||||
} else if (this.#pending.specifiers !== null) {
|
||||
this.#pending.specifiers.add(specifier);
|
||||
await this.#pending.done;
|
||||
return;
|
||||
} else {
|
||||
await this.#pending.done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #load(specifiers: string[]): Promise<void> {
|
||||
await this.#populate(specifiers);
|
||||
for (let specifier of specifiers) {
|
||||
specifier = this.#resolve(specifier);
|
||||
const entry = this.#modules.get(specifier);
|
||||
if (entry === undefined && specifier.startsWith("npm:")) {
|
||||
// we hit https://github.com/denoland/deno/issues/18043, so we have to
|
||||
// perform another load to get the actual data of the redirected specifier
|
||||
await this.#populate([specifier]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #populate(specifiers: string[]) {
|
||||
let specifier;
|
||||
if (specifiers.length === 1) {
|
||||
specifier = specifiers[0];
|
||||
} else {
|
||||
specifier = `data:application/javascript,${
|
||||
encodeURIComponent(
|
||||
specifiers.map((s) => `import ${JSON.stringify(s)};`).join(""),
|
||||
)
|
||||
}`;
|
||||
}
|
||||
const { modules, redirects, npmPackages } = await info(
|
||||
specifier,
|
||||
this.#options,
|
||||
);
|
||||
for (const module of modules) {
|
||||
if (specifiers.length !== 1 && module.specifier === specifier) continue;
|
||||
this.#modules.set(module.specifier, module);
|
||||
}
|
||||
for (const [from, to] of Object.entries(redirects)) {
|
||||
this.#redirects.set(from, to);
|
||||
}
|
||||
if (npmPackages !== undefined) {
|
||||
for (const [id, npmPackage] of Object.entries(npmPackages)) {
|
||||
this.#npmPackages.set(id, npmPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/esbuild_types.ts
generated
vendored
Normal file
143
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/esbuild_types.ts
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
* This is a copy of the esbuild types that `deno_esbuild_loader` uses. This is
|
||||
* necessary because the `esbuild` package is not available on JSR yet.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
/** the type of import */
|
||||
export type ImportKind =
|
||||
| "entry-point"
|
||||
// JS
|
||||
| "import-statement"
|
||||
| "require-call"
|
||||
| "dynamic-import"
|
||||
| "require-resolve"
|
||||
// CSS
|
||||
| "import-rule"
|
||||
| "composes-from"
|
||||
| "url-token";
|
||||
|
||||
/** Documentation: https://esbuild.github.io/api/#loader */
|
||||
export type Loader =
|
||||
| "base64"
|
||||
| "binary"
|
||||
| "copy"
|
||||
| "css"
|
||||
| "dataurl"
|
||||
| "default"
|
||||
| "empty"
|
||||
| "file"
|
||||
| "js"
|
||||
| "json"
|
||||
| "jsx"
|
||||
| "local-css"
|
||||
| "text"
|
||||
| "ts"
|
||||
| "tsx";
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins */
|
||||
export interface Plugin {
|
||||
name: string;
|
||||
setup: (build: PluginBuild) => void | Promise<void>;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins */
|
||||
export interface PluginBuild {
|
||||
/** Documentation: https://esbuild.github.io/plugins/#build-options */
|
||||
initialOptions: BuildOptions;
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#resolve */
|
||||
resolve(path: string, options?: ResolveOptions): Promise<ResolveResult>;
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-start */
|
||||
onStart(callback: () => void | Promise<void>): void;
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-resolve */
|
||||
onResolve(
|
||||
options: OnResolveOptions,
|
||||
callback: (args: OnResolveArgs) => Promise<OnResolveResult | undefined>,
|
||||
): void;
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-load */
|
||||
onLoad(
|
||||
options: OnLoadOptions,
|
||||
callback: (
|
||||
args: OnLoadArgs,
|
||||
) => Promise<OnLoadResult | null | undefined> | undefined,
|
||||
): void;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/api */
|
||||
export interface BuildOptions {
|
||||
/** Documentation: https://esbuild.github.io/api/#external */
|
||||
external?: string[];
|
||||
/** Documentation: https://esbuild.github.io/api/#working-directory */
|
||||
absWorkingDir?: string;
|
||||
/** Documentation: https://esbuild.github.io/api/#entry-points */
|
||||
entryPoints?: string[] | Record<string, string> | {
|
||||
in: string;
|
||||
out: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#resolve-options */
|
||||
export interface ResolveOptions {
|
||||
importer?: string;
|
||||
resolveDir?: string;
|
||||
namespace?: string;
|
||||
kind?: ImportKind;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#resolve-results */
|
||||
export interface ResolveResult {
|
||||
path: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-options */
|
||||
export interface OnResolveOptions {
|
||||
filter: RegExp;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-arguments */
|
||||
export interface OnResolveArgs {
|
||||
path: string;
|
||||
importer: string;
|
||||
namespace: string;
|
||||
resolveDir: string;
|
||||
kind: ImportKind;
|
||||
}
|
||||
|
||||
export interface OnResolveResult {
|
||||
path?: string;
|
||||
external?: boolean;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-load-options */
|
||||
export interface OnLoadOptions {
|
||||
filter: RegExp;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-load-arguments */
|
||||
export interface OnLoadArgs {
|
||||
path: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-load-results */
|
||||
export interface OnLoadResult {
|
||||
contents?: string | Uint8Array;
|
||||
resolveDir?: string;
|
||||
loader?: Loader;
|
||||
|
||||
watchFiles?: string[];
|
||||
}
|
||||
|
||||
/** Documentation: https://esbuild.github.io/plugins/#on-start-results */
|
||||
// deno-lint-ignore no-empty-interface
|
||||
export interface OnStartResult {
|
||||
}
|
||||
219
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/loader_native.ts
generated
vendored
Normal file
219
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/loader_native.ts
generated
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
import type * as esbuild from "./esbuild_types.ts";
|
||||
import { dirname, fromFileUrl, join } from "jsr:@std/path@^1.0.6";
|
||||
import { encodeBase32 } from "jsr:/@std/encoding@^1.0.5/base32";
|
||||
import { lastIndexOfNeedle } from "jsr:@std/bytes@^1.0.2";
|
||||
import * as deno from "./deno.ts";
|
||||
import { rootInfo, type RootInfoOutput } from "./deno.ts";
|
||||
import {
|
||||
type Loader,
|
||||
type LoaderResolution,
|
||||
mapContentType,
|
||||
mediaTypeFromSpecifier,
|
||||
mediaTypeToLoader,
|
||||
parseNpmSpecifier,
|
||||
} from "./shared.ts";
|
||||
|
||||
let ROOT_INFO_OUTPUT: Promise<RootInfoOutput> | RootInfoOutput | undefined;
|
||||
|
||||
export const DENO_CACHE_METADATA = new TextEncoder()
|
||||
.encode("\n// denoCacheMetadata=");
|
||||
|
||||
export interface NativeLoaderOptions {
|
||||
infoOptions?: deno.InfoOptions;
|
||||
}
|
||||
|
||||
export class NativeLoader implements Loader {
|
||||
#nodeModulesDirManual: boolean;
|
||||
#infoCache: deno.InfoCache;
|
||||
#linkDirCache: Map<string, string> = new Map(); // mapping from package id -> link dir
|
||||
|
||||
constructor(options: NativeLoaderOptions) {
|
||||
this.#nodeModulesDirManual =
|
||||
options.infoOptions?.nodeModulesDir === "manual";
|
||||
this.#infoCache = new deno.InfoCache(options.infoOptions);
|
||||
}
|
||||
|
||||
async resolve(specifier: URL): Promise<LoaderResolution> {
|
||||
// Workaround for https://github.com/denoland/deno/issues/25903
|
||||
if (this.#nodeModulesDirManual && specifier.protocol === "npm:") {
|
||||
const npmSpecifier = parseNpmSpecifier(specifier);
|
||||
return {
|
||||
kind: "npm",
|
||||
packageId: "",
|
||||
packageName: npmSpecifier.name,
|
||||
path: npmSpecifier.path ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
const entry = await this.#infoCache.get(specifier.href);
|
||||
if ("error" in entry) {
|
||||
if (
|
||||
specifier.protocol === "file:" &&
|
||||
mediaTypeFromSpecifier(specifier) === "Unknown"
|
||||
) {
|
||||
return { kind: "esm", specifier: new URL(entry.specifier) };
|
||||
}
|
||||
throw new Error(entry.error);
|
||||
}
|
||||
|
||||
if (entry.kind === "npm") {
|
||||
// TODO(lucacasonato): remove parsing once https://github.com/denoland/deno/issues/18043 is resolved
|
||||
const parsed = parseNpmSpecifier(new URL(entry.specifier));
|
||||
return {
|
||||
kind: "npm",
|
||||
packageId: entry.npmPackage,
|
||||
packageName: parsed.name,
|
||||
path: parsed.path ?? "",
|
||||
};
|
||||
} else if (entry.kind === "node") {
|
||||
return {
|
||||
kind: "node",
|
||||
path: entry.specifier,
|
||||
};
|
||||
}
|
||||
|
||||
return { kind: "esm", specifier: new URL(entry.specifier) };
|
||||
}
|
||||
|
||||
async loadEsm(specifier: URL): Promise<esbuild.OnLoadResult | undefined> {
|
||||
if (specifier.protocol === "data:") {
|
||||
const resp = await fetch(specifier);
|
||||
const contents = new Uint8Array(await resp.arrayBuffer());
|
||||
const contentType = resp.headers.get("content-type");
|
||||
const mediaType = mapContentType(specifier, contentType);
|
||||
const loader = mediaTypeToLoader(mediaType);
|
||||
if (loader === null) return undefined;
|
||||
return { contents, loader };
|
||||
}
|
||||
const entry = await this.#infoCache.get(specifier.href);
|
||||
if (
|
||||
"error" in entry && specifier.protocol !== "file:" &&
|
||||
mediaTypeFromSpecifier(specifier) !== "Unknown"
|
||||
) throw new Error(entry.error);
|
||||
|
||||
if (!("local" in entry)) {
|
||||
throw new Error("[unreachable] Not an ESM module.");
|
||||
}
|
||||
if (!entry.local) throw new Error("Module not downloaded yet.");
|
||||
const loader = mediaTypeToLoader(entry.mediaType);
|
||||
if (loader === null) return undefined;
|
||||
|
||||
let contents = await Deno.readFile(entry.local);
|
||||
const denoCacheMetadata = lastIndexOfNeedle(contents, DENO_CACHE_METADATA);
|
||||
if (denoCacheMetadata !== -1) {
|
||||
contents = contents.subarray(0, denoCacheMetadata);
|
||||
}
|
||||
const res: esbuild.OnLoadResult = { contents, loader };
|
||||
if (specifier.protocol === "file:") {
|
||||
res.watchFiles = [fromFileUrl(specifier)];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async nodeModulesDirForPackage(npmPackageId: string): Promise<string> {
|
||||
const npmPackage = this.#infoCache.getNpmPackage(npmPackageId);
|
||||
if (!npmPackage) throw new Error("NPM package not found.");
|
||||
|
||||
let linkDir = this.#linkDirCache.get(npmPackageId);
|
||||
if (!linkDir) {
|
||||
linkDir = await this.#nodeModulesDirForPackageInner(
|
||||
npmPackageId,
|
||||
npmPackage,
|
||||
);
|
||||
this.#linkDirCache.set(npmPackageId, linkDir);
|
||||
}
|
||||
return linkDir;
|
||||
}
|
||||
|
||||
async #nodeModulesDirForPackageInner(
|
||||
npmPackageId: string,
|
||||
npmPackage: deno.NpmPackage,
|
||||
): Promise<string> {
|
||||
let name = npmPackage.name;
|
||||
if (name.toLowerCase() !== name) {
|
||||
name = `_${encodeBase32(new TextEncoder().encode(name))}`;
|
||||
}
|
||||
if (ROOT_INFO_OUTPUT === undefined) {
|
||||
ROOT_INFO_OUTPUT = rootInfo();
|
||||
}
|
||||
if (ROOT_INFO_OUTPUT instanceof Promise) {
|
||||
ROOT_INFO_OUTPUT = await ROOT_INFO_OUTPUT;
|
||||
}
|
||||
const { denoDir, npmCache } = ROOT_INFO_OUTPUT;
|
||||
const registryUrl = npmPackage.registryUrl ?? "https://registry.npmjs.org";
|
||||
const registry = new URL(registryUrl);
|
||||
|
||||
const packageDir = join(
|
||||
npmCache,
|
||||
registry.hostname,
|
||||
name,
|
||||
npmPackage.version,
|
||||
);
|
||||
const linkDir = join(
|
||||
denoDir,
|
||||
"deno_esbuild",
|
||||
registry.hostname,
|
||||
npmPackageId,
|
||||
"node_modules",
|
||||
name,
|
||||
);
|
||||
const linkDirParent = dirname(linkDir);
|
||||
const tmpDirParent = join(denoDir, "deno_esbuild_tmp");
|
||||
|
||||
// check if the package is already linked, if so, return the link and skip
|
||||
// a bunch of work
|
||||
try {
|
||||
await Deno.stat(linkDir);
|
||||
this.#linkDirCache.set(npmPackageId, linkDir);
|
||||
return linkDir;
|
||||
} catch {
|
||||
// directory does not yet exist
|
||||
}
|
||||
|
||||
// create a temporary directory, recursively hardlink the package contents
|
||||
// into it, and then rename it to the final location
|
||||
await Deno.mkdir(tmpDirParent, { recursive: true });
|
||||
const tmpDir = await Deno.makeTempDir({ dir: tmpDirParent });
|
||||
await linkRecursive(packageDir, tmpDir);
|
||||
try {
|
||||
await Deno.mkdir(linkDirParent, { recursive: true });
|
||||
await Deno.rename(tmpDir, linkDir);
|
||||
} catch (err) {
|
||||
// the directory may already have been created by someone else - check if so
|
||||
try {
|
||||
await Deno.stat(linkDir);
|
||||
} catch {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return linkDir;
|
||||
}
|
||||
|
||||
packageIdFromNameInPackage(
|
||||
name: string,
|
||||
parentPackageId: string,
|
||||
): string | null {
|
||||
const parentPackage = this.#infoCache.getNpmPackage(parentPackageId);
|
||||
if (!parentPackage) throw new Error("NPM package not found.");
|
||||
if (parentPackage.name === name) return parentPackageId;
|
||||
for (const dep of parentPackage.dependencies) {
|
||||
const depPackage = this.#infoCache.getNpmPackage(dep);
|
||||
if (!depPackage) throw new Error("NPM package not found.");
|
||||
if (depPackage.name === name) return dep;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function linkRecursive(from: string, to: string) {
|
||||
const fromStat = await Deno.stat(from);
|
||||
if (fromStat.isDirectory) {
|
||||
await Deno.mkdir(to, { recursive: true });
|
||||
for await (const entry of Deno.readDir(from)) {
|
||||
await linkRecursive(join(from, entry.name), join(to, entry.name));
|
||||
}
|
||||
} else {
|
||||
await Deno.link(from, to);
|
||||
}
|
||||
}
|
||||
245
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/loader_portable.ts
generated
vendored
Normal file
245
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/loader_portable.ts
generated
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
import type * as esbuild from "./esbuild_types.ts";
|
||||
import { fromFileUrl } from "jsr:@std/path@^1.0.6";
|
||||
import type * as deno from "./deno.ts";
|
||||
import {
|
||||
type Loader,
|
||||
type LoaderResolution,
|
||||
mapContentType,
|
||||
mediaTypeToLoader,
|
||||
parseJsrSpecifier,
|
||||
parseNpmSpecifier,
|
||||
} from "./shared.ts";
|
||||
import { instantiate, type WasmLockfile } from "./wasm/loader.generated.js";
|
||||
|
||||
interface Module {
|
||||
specifier: string;
|
||||
mediaType: deno.MediaType;
|
||||
data: Uint8Array;
|
||||
}
|
||||
|
||||
const JSR_URL = Deno.env.get("JSR_URL") ?? "https://jsr.io";
|
||||
|
||||
async function readLockfile(path: string): Promise<WasmLockfile | null> {
|
||||
try {
|
||||
const data = await Deno.readTextFile(path);
|
||||
const instance = instantiate();
|
||||
return new instance.WasmLockfile(path, data);
|
||||
} catch (err) {
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
interface PortableLoaderOptions {
|
||||
lock?: string;
|
||||
}
|
||||
|
||||
export class PortableLoader implements Loader, Disposable {
|
||||
#options: PortableLoaderOptions;
|
||||
#fetchOngoing = new Map<string, Promise<void>>();
|
||||
#lockfile: Promise<WasmLockfile | null> | WasmLockfile | null | undefined;
|
||||
|
||||
#fetchModules = new Map<string, Module>();
|
||||
#fetchRedirects = new Map<string, string>();
|
||||
|
||||
constructor(options: PortableLoaderOptions) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
if (this.#lockfile != null && "free" in this.#lockfile) {
|
||||
this.#lockfile.free();
|
||||
}
|
||||
}
|
||||
|
||||
async resolve(specifier: URL): Promise<LoaderResolution> {
|
||||
switch (specifier.protocol) {
|
||||
case "file:": {
|
||||
return { kind: "esm", specifier };
|
||||
}
|
||||
case "http:":
|
||||
case "https:":
|
||||
case "data:": {
|
||||
const module = await this.#loadRemote(specifier.href);
|
||||
return { kind: "esm", specifier: new URL(module.specifier) };
|
||||
}
|
||||
case "npm:": {
|
||||
const npmSpecifier = parseNpmSpecifier(specifier);
|
||||
return {
|
||||
kind: "npm",
|
||||
packageId: "",
|
||||
packageName: npmSpecifier.name,
|
||||
path: npmSpecifier.path ?? "",
|
||||
};
|
||||
}
|
||||
case "node:": {
|
||||
return { kind: "node", path: specifier.pathname };
|
||||
}
|
||||
case "jsr:": {
|
||||
const resolvedSpecifier = await this.#resolveJsrSpecifier(specifier);
|
||||
return { kind: "esm", specifier: resolvedSpecifier };
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported scheme: '${specifier.protocol}'`);
|
||||
}
|
||||
}
|
||||
|
||||
async #resolveJsrSpecifier(specifier: URL): Promise<URL> {
|
||||
// parse the JSR specifier.
|
||||
const jsrSpecifier = parseJsrSpecifier(specifier);
|
||||
|
||||
// Attempt to load the lockfile.
|
||||
if (this.#lockfile === undefined) {
|
||||
this.#lockfile = typeof this.#options.lock === "string"
|
||||
? readLockfile(this.#options.lock)
|
||||
: null;
|
||||
}
|
||||
if (this.#lockfile instanceof Promise) {
|
||||
this.#lockfile = await this.#lockfile;
|
||||
}
|
||||
if (this.#lockfile === null) {
|
||||
throw new Error(
|
||||
"jsr: specifiers are not supported in the portable loader without a lockfile",
|
||||
);
|
||||
}
|
||||
const lockfile = this.#lockfile;
|
||||
// Look up the package + constraint in the lockfile.
|
||||
const id = `jsr:${jsrSpecifier.name}${
|
||||
jsrSpecifier.version ? `@${jsrSpecifier.version}` : ""
|
||||
}`;
|
||||
const resolvedVersion = lockfile.package_version(id);
|
||||
if (!resolvedVersion) {
|
||||
throw new Error(`Specifier not found in lockfile: ${id}`);
|
||||
}
|
||||
|
||||
// Load the JSR manifest to find the export path.
|
||||
const manifestUrl = new URL(
|
||||
`./${jsrSpecifier.name}/${resolvedVersion}_meta.json`,
|
||||
JSR_URL,
|
||||
);
|
||||
const manifest = await this.#loadRemote(manifestUrl.href);
|
||||
if (manifest.mediaType !== "Json") {
|
||||
throw new Error(
|
||||
`Expected JSON media type for JSR manifest, got: ${manifest.mediaType}`,
|
||||
);
|
||||
}
|
||||
const manifestData = new TextDecoder().decode(manifest.data);
|
||||
const manifestJson = JSON.parse(manifestData);
|
||||
|
||||
// Look up the export path in the manifest.
|
||||
const exportEntry = `.${jsrSpecifier.path ?? ""}`;
|
||||
const exportPath = manifestJson.exports[exportEntry];
|
||||
if (!exportPath) {
|
||||
throw new Error(
|
||||
`Package 'jsr:${jsrSpecifier.name}@${resolvedVersion}' has no export named '${exportEntry}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Return the resolved URL.
|
||||
return new URL(
|
||||
`./${jsrSpecifier.name}/${resolvedVersion}/${exportPath}`,
|
||||
JSR_URL,
|
||||
);
|
||||
}
|
||||
|
||||
async loadEsm(url: URL): Promise<esbuild.OnLoadResult | undefined> {
|
||||
let module: Module;
|
||||
switch (url.protocol) {
|
||||
case "file:": {
|
||||
module = await this.#loadLocal(url);
|
||||
break;
|
||||
}
|
||||
case "http:":
|
||||
case "https:":
|
||||
case "data:": {
|
||||
module = await this.#loadRemote(url.href);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("[unreachable] unsupported esm scheme " + url.protocol);
|
||||
}
|
||||
|
||||
const loader = mediaTypeToLoader(module.mediaType);
|
||||
if (loader === null) return undefined;
|
||||
|
||||
const res: esbuild.OnLoadResult = { contents: module.data, loader };
|
||||
if (url.protocol === "file:") {
|
||||
res.watchFiles = [fromFileUrl(module.specifier)];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#resolveRemote(specifier: string): string {
|
||||
return this.#fetchRedirects.get(specifier) ?? specifier;
|
||||
}
|
||||
|
||||
async #loadRemote(specifier: string): Promise<Module> {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
specifier = this.#resolveRemote(specifier);
|
||||
const module = this.#fetchModules.get(specifier);
|
||||
if (module) return module;
|
||||
|
||||
let promise = this.#fetchOngoing.get(specifier);
|
||||
if (!promise) {
|
||||
promise = this.#fetch(specifier);
|
||||
this.#fetchOngoing.set(specifier, promise);
|
||||
}
|
||||
|
||||
await promise;
|
||||
}
|
||||
|
||||
throw new Error("Too many redirects. Last one: " + specifier);
|
||||
}
|
||||
|
||||
async #fetch(specifier: string): Promise<void> {
|
||||
const resp = await fetch(specifier, {
|
||||
redirect: "manual",
|
||||
});
|
||||
if (resp.status < 200 && resp.status >= 400) {
|
||||
throw new Error(
|
||||
`Encountered status code ${resp.status} while fetching ${specifier}.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (resp.status >= 300 && resp.status < 400) {
|
||||
await resp.body?.cancel();
|
||||
const location = resp.headers.get("location");
|
||||
if (!location) {
|
||||
throw new Error(
|
||||
`Redirected without location header while fetching ${specifier}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const url = new URL(location, specifier);
|
||||
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
||||
throw new Error(
|
||||
`Redirected to unsupported protocol '${url.protocol}' while fetching ${specifier}.`,
|
||||
);
|
||||
}
|
||||
|
||||
this.#fetchRedirects.set(specifier, url.href);
|
||||
return;
|
||||
}
|
||||
|
||||
const contentType = resp.headers.get("content-type");
|
||||
const mediaType = mapContentType(new URL(specifier), contentType);
|
||||
|
||||
const data = new Uint8Array(await resp.arrayBuffer());
|
||||
this.#fetchModules.set(specifier, {
|
||||
specifier,
|
||||
mediaType,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
async #loadLocal(specifier: URL): Promise<Module> {
|
||||
const path = fromFileUrl(specifier);
|
||||
|
||||
const mediaType = mapContentType(specifier, null);
|
||||
const data = await Deno.readFile(path);
|
||||
|
||||
return { specifier: specifier.href, mediaType, data };
|
||||
}
|
||||
}
|
||||
401
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/plugin_deno_loader.ts
generated
vendored
Normal file
401
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/plugin_deno_loader.ts
generated
vendored
Normal file
@ -0,0 +1,401 @@
|
||||
import type * as esbuild from "./esbuild_types.ts";
|
||||
import { dirname, join } from "jsr:@std/path@^1.0.6";
|
||||
import { NativeLoader } from "./loader_native.ts";
|
||||
import { PortableLoader } from "./loader_portable.ts";
|
||||
import { findWorkspace, isInNodeModules } from "./shared.ts";
|
||||
import {
|
||||
esbuildResolutionToURL,
|
||||
isNodeModulesResolution,
|
||||
type Loader,
|
||||
urlToEsbuildResolution,
|
||||
} from "./shared.ts";
|
||||
|
||||
/** Options for the {@link denoLoaderPlugin}. */
|
||||
export interface DenoLoaderPluginOptions {
|
||||
/**
|
||||
* Specify which loader to use. By default this will use the `native` loader,
|
||||
* unless the `--allow-run` permission has not been given.
|
||||
*
|
||||
* See {@link denoLoaderPlugin} for more information on the different loaders.
|
||||
*/
|
||||
loader?: "native" | "portable";
|
||||
|
||||
/**
|
||||
* Specify the path to a deno.json config file to use. This is equivalent to
|
||||
* the `--config` flag to the Deno executable. This path must be absolute.
|
||||
*
|
||||
* NOTE: Import maps in the config file are not used to inform resolution, as
|
||||
* this has already been done by the `denoResolverPlugin`. This option is only
|
||||
* used when specifying `loader: "native"` to more efficiently load modules
|
||||
* from the cache. When specifying `loader: "native"`, this option must be in
|
||||
* sync with the `configPath` option for `denoResolverPlugin`.
|
||||
*
|
||||
* If not specified, the plugin will attempt to find the nearest deno.json and
|
||||
* use that. If the deno.json is part of a workspace, the plugin will
|
||||
* automatically find the workspace root.
|
||||
*/
|
||||
configPath?: string;
|
||||
/**
|
||||
* Specify a URL to an import map file to use when resolving import
|
||||
* specifiers. This is equivalent to the `--import-map` flag to the Deno
|
||||
* executable. This URL may be remote or a local file URL.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine what import map to use, if any.
|
||||
*
|
||||
* NOTE: Import maps in the config file are not used to inform resolution, as
|
||||
* this has already been done by the `denoResolverPlugin`. This option is only
|
||||
* used when specifying `loader: "native"` to more efficiently load modules
|
||||
* from the cache. When specifying `loader: "native"`, this option must be in
|
||||
* sync with the `importMapURL` option for `denoResolverPlugin`.
|
||||
*/
|
||||
importMapURL?: string;
|
||||
/**
|
||||
* Specify the path to a lock file to use. This is equivalent to the `--lock`
|
||||
* flag to the Deno executable. This path must be absolute.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine what import map to use, if any.
|
||||
*
|
||||
* A lockfile must be present to resolve `jsr:` specifiers with the `portable`
|
||||
* loader. When using the `native` loader, a lockfile is not required, but to
|
||||
* ensure dependencies are de-duplicated correctly, it is recommended to use a
|
||||
* lockfile.
|
||||
*
|
||||
* NOTE: when using `loader: "portable"`, integrity checks are not performed
|
||||
* for ESM modules.
|
||||
*/
|
||||
lockPath?: string;
|
||||
/**
|
||||
* Specify how the loader should handle NPM packages. By default and if this
|
||||
* option is set to `none`, the loader will use the global cache to resolve
|
||||
* NPM packages. If this option is set to `manual`, the loader will use a
|
||||
* manually managed `node_modules` directory. If this option is set to `auto`,
|
||||
* the loader will use a local `node_modules` directory.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine which mode to use. If no config file is present, or the config
|
||||
* file does not specify this option, the default is `none` if no package.json
|
||||
* is present, and `auto` if a package.json is present.
|
||||
*
|
||||
* This option is ignored when using the `portable` loader, as the portable
|
||||
* loader always uses a manual `node_modules` directory (equivalent of
|
||||
* `nodeModulesDir: "manual"`).
|
||||
*/
|
||||
nodeModulesDir?: "auto" | "manual" | "none";
|
||||
}
|
||||
|
||||
const LOADERS = ["native", "portable"] as const;
|
||||
|
||||
/** The default loader to use. */
|
||||
export const DEFAULT_LOADER: "native" | "portable" =
|
||||
await Deno.permissions.query({ name: "run" })
|
||||
.then((res) => res.state !== "granted")
|
||||
? "portable"
|
||||
: "native";
|
||||
|
||||
const BUILTIN_NODE_MODULES = new Set([
|
||||
"assert",
|
||||
"assert/strict",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"dns/promises",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"path/posix",
|
||||
"path/win32",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"repl",
|
||||
"readline",
|
||||
"stream",
|
||||
"stream/consumers",
|
||||
"stream/promises",
|
||||
"stream/web",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"test",
|
||||
"timers",
|
||||
"timers/promises",
|
||||
"tls",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"util/types",
|
||||
"v8",
|
||||
"vm",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
]);
|
||||
|
||||
/**
|
||||
* The Deno loader plugin for esbuild. This plugin will load fully qualified
|
||||
* `file`, `http`, `https`, and `data` URLs.
|
||||
*
|
||||
* **Note** that this plugin does not do relative->absolute specifier
|
||||
* resolution, or import map resolution. You must use the `denoResolverPlugin`
|
||||
* _before_ the `denoLoaderPlugin` to do that.
|
||||
*
|
||||
* This plugin can be backed by two different loaders, the `native` loader and
|
||||
* the `portable` loader.
|
||||
*
|
||||
* ### Native Loader
|
||||
*
|
||||
* The native loader shells out to the Deno executable under the hood to load
|
||||
* files. Requires `--allow-read` and `--allow-run`. In this mode the download
|
||||
* cache is shared with the Deno executable. This mode respects deno.lock,
|
||||
* DENO_DIR, DENO_AUTH_TOKENS, and all similar loading configuration. Files are
|
||||
* cached on disk in the same Deno cache as the Deno executable, and will not be
|
||||
* re-downloaded on subsequent builds.
|
||||
*
|
||||
* NPM specifiers can be used in the native loader without requiring a local
|
||||
* `node_modules` directory. NPM packages are resolved, downloaded, cached, and
|
||||
* loaded in the same way as the Deno executable does.
|
||||
*
|
||||
* JSR specifiers can be used without restrictions in the native loader. To
|
||||
* ensure dependencies are de-duplicated correctly, it is recommended to use a
|
||||
* lockfile.
|
||||
*
|
||||
* ### Portable Loader
|
||||
*
|
||||
* The portable loader does module downloading and caching with only Web APIs.
|
||||
* Requires `--allow-read` and/or `--allow-net`. This mode does not respect
|
||||
* deno.lock, DENO_DIR, DENO_AUTH_TOKENS, or any other loading configuration. It
|
||||
* does not cache downloaded files. It will re-download files on every build.
|
||||
*
|
||||
* NPM specifiers can be used in the portable loader, but require a local
|
||||
* `node_modules` directory. The `node_modules` directory must be created prior
|
||||
* using Deno's `--node-modules-dir` flag.
|
||||
*
|
||||
* JSR specifiers require a lockfile to be present to resolve.
|
||||
*/
|
||||
export function denoLoaderPlugin(
|
||||
options: DenoLoaderPluginOptions = {},
|
||||
): esbuild.Plugin {
|
||||
const loader = options.loader ?? DEFAULT_LOADER;
|
||||
if (LOADERS.indexOf(loader) === -1) {
|
||||
throw new Error(`Invalid loader: ${loader}`);
|
||||
}
|
||||
return {
|
||||
name: "deno-loader",
|
||||
setup(build) {
|
||||
const cwd = build.initialOptions.absWorkingDir ?? Deno.cwd();
|
||||
|
||||
let nodeModulesDir: string | null = null;
|
||||
let loaderImpl: Loader | undefined;
|
||||
|
||||
const packageIdByNodeModules = new Map<string, string>();
|
||||
|
||||
build.onStart(function onStart() {
|
||||
loaderImpl?.[Symbol.dispose]?.();
|
||||
loaderImpl = undefined;
|
||||
packageIdByNodeModules.clear();
|
||||
|
||||
let nodeModulesDirOpt: "auto" | "manual" | "none" | undefined =
|
||||
options.nodeModulesDir;
|
||||
let lockPath: string | undefined = options.lockPath;
|
||||
if (
|
||||
(nodeModulesDirOpt === undefined ||
|
||||
(loader === "portable" && lockPath === undefined))
|
||||
) {
|
||||
const workspace = findWorkspace(
|
||||
cwd,
|
||||
build.initialOptions.entryPoints,
|
||||
options.configPath,
|
||||
);
|
||||
try {
|
||||
if (nodeModulesDirOpt === undefined) {
|
||||
nodeModulesDirOpt = workspace.node_modules_dir() as
|
||||
| "auto"
|
||||
| "manual"
|
||||
| "none";
|
||||
}
|
||||
if (loader === "portable" && lockPath === undefined) {
|
||||
lockPath = workspace.lock_path();
|
||||
}
|
||||
} finally {
|
||||
workspace.free();
|
||||
}
|
||||
}
|
||||
if (
|
||||
nodeModulesDirOpt === "auto" ||
|
||||
nodeModulesDirOpt === "manual"
|
||||
) {
|
||||
nodeModulesDir = join(cwd, "node_modules");
|
||||
}
|
||||
|
||||
switch (loader) {
|
||||
case "native":
|
||||
loaderImpl = new NativeLoader({
|
||||
infoOptions: {
|
||||
cwd,
|
||||
config: options.configPath,
|
||||
importMap: options.importMapURL,
|
||||
lock: options.lockPath,
|
||||
nodeModulesDir: nodeModulesDirOpt,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case "portable": {
|
||||
loaderImpl = new PortableLoader({
|
||||
lock: lockPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function onResolve(
|
||||
args: esbuild.OnResolveArgs,
|
||||
): Promise<esbuild.OnResolveResult | undefined> {
|
||||
if (isNodeModulesResolution(args)) {
|
||||
if (
|
||||
BUILTIN_NODE_MODULES.has(args.path) ||
|
||||
BUILTIN_NODE_MODULES.has("node:" + args.path)
|
||||
) {
|
||||
return {
|
||||
path: args.path,
|
||||
external: true,
|
||||
};
|
||||
}
|
||||
if (nodeModulesDir !== null) {
|
||||
return undefined;
|
||||
} else if (
|
||||
loaderImpl!.nodeModulesDirForPackage &&
|
||||
loaderImpl!.packageIdFromNameInPackage
|
||||
) {
|
||||
let parentPackageId: string | undefined;
|
||||
let path = args.importer;
|
||||
while (true) {
|
||||
const packageId = packageIdByNodeModules.get(path);
|
||||
if (packageId) {
|
||||
parentPackageId = packageId;
|
||||
break;
|
||||
}
|
||||
const pathBefore = path;
|
||||
path = dirname(path);
|
||||
if (path === pathBefore) break;
|
||||
}
|
||||
if (!parentPackageId) {
|
||||
throw new Error(
|
||||
`Could not find package ID for importer: ${args.importer}`,
|
||||
);
|
||||
}
|
||||
if (args.path.startsWith(".")) {
|
||||
return undefined;
|
||||
} else {
|
||||
let packageName: string;
|
||||
let pathParts: string[];
|
||||
if (args.path.startsWith("@")) {
|
||||
const [scope, name, ...rest] = args.path.split("/");
|
||||
packageName = `${scope}/${name}`;
|
||||
pathParts = rest;
|
||||
} else {
|
||||
const [name, ...rest] = args.path.split("/");
|
||||
packageName = name;
|
||||
pathParts = rest;
|
||||
}
|
||||
const packageId = loaderImpl!.packageIdFromNameInPackage(
|
||||
packageName,
|
||||
parentPackageId,
|
||||
);
|
||||
const id = packageId ?? parentPackageId;
|
||||
const resolveDir = await loaderImpl!.nodeModulesDirForPackage(id);
|
||||
packageIdByNodeModules.set(resolveDir, id);
|
||||
const path = [packageName, ...pathParts].join("/");
|
||||
return await build.resolve(path, {
|
||||
kind: args.kind,
|
||||
resolveDir,
|
||||
importer: args.importer,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
`To use "npm:" specifiers, you must specify 'nodeModulesDir: "manual"', or use 'loader: "native"'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const specifier = esbuildResolutionToURL(args);
|
||||
|
||||
// Once we have an absolute path, let the loader resolver figure out
|
||||
// what to do with it.
|
||||
const res = await loaderImpl!.resolve(specifier);
|
||||
|
||||
switch (res.kind) {
|
||||
case "esm": {
|
||||
const { specifier } = res;
|
||||
return urlToEsbuildResolution(specifier);
|
||||
}
|
||||
case "npm": {
|
||||
let resolveDir: string;
|
||||
if (nodeModulesDir !== null) {
|
||||
resolveDir = nodeModulesDir;
|
||||
} else if (loaderImpl!.nodeModulesDirForPackage) {
|
||||
resolveDir = await loaderImpl!.nodeModulesDirForPackage(
|
||||
res.packageId,
|
||||
);
|
||||
packageIdByNodeModules.set(resolveDir, res.packageId);
|
||||
} else {
|
||||
throw new Error(
|
||||
`To use "npm:" specifiers, you must specify 'nodeModulesDir: "manual"', or use 'loader: "native"'.`,
|
||||
);
|
||||
}
|
||||
const path = `${res.packageName}${res.path ?? ""}`;
|
||||
return await build.resolve(path, {
|
||||
kind: args.kind,
|
||||
resolveDir,
|
||||
importer: args.importer,
|
||||
});
|
||||
}
|
||||
case "node": {
|
||||
return {
|
||||
path: res.path,
|
||||
external: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
build.onResolve({ filter: /.*/, namespace: "file" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "http" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "https" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "data" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "npm" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "jsr" }, onResolve);
|
||||
build.onResolve({ filter: /.*/, namespace: "node" }, onResolve);
|
||||
|
||||
function onLoad(
|
||||
args: esbuild.OnLoadArgs,
|
||||
): Promise<esbuild.OnLoadResult | null | undefined> | undefined {
|
||||
if (args.namespace === "file" && isInNodeModules(args.path)) {
|
||||
// inside node_modules, just let esbuild do it's thing
|
||||
return undefined;
|
||||
}
|
||||
const specifier = esbuildResolutionToURL(args);
|
||||
return loaderImpl!.loadEsm(specifier);
|
||||
}
|
||||
// TODO(lucacasonato): once https://github.com/evanw/esbuild/pull/2968 is fixed, remove the catch all "file" handler
|
||||
build.onLoad({ filter: /.*/, namespace: "file" }, onLoad);
|
||||
build.onLoad({ filter: /.*/, namespace: "http" }, onLoad);
|
||||
build.onLoad({ filter: /.*/, namespace: "https" }, onLoad);
|
||||
build.onLoad({ filter: /.*/, namespace: "data" }, onLoad);
|
||||
},
|
||||
};
|
||||
}
|
||||
136
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/plugin_deno_resolver.ts
generated
vendored
Normal file
136
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/plugin_deno_resolver.ts
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
import type * as esbuild from "./esbuild_types.ts";
|
||||
import { toFileUrl } from "jsr:@std/path@^1.0.6";
|
||||
import {
|
||||
findWorkspace,
|
||||
isNodeModulesResolution,
|
||||
urlToEsbuildResolution,
|
||||
} from "./shared.ts";
|
||||
import type { WasmWorkspaceResolver } from "./wasm/loader.generated.js";
|
||||
|
||||
/** Options for the {@link denoResolverPlugin}. */
|
||||
export interface DenoResolverPluginOptions {
|
||||
/**
|
||||
* Specify the path to a deno.json config file to use. This is equivalent to
|
||||
* the `--config` flag to the Deno executable. This path must be absolute.
|
||||
*
|
||||
* If not specified, the plugin will attempt to find the nearest deno.json and
|
||||
* use that. If the deno.json is part of a workspace, the plugin will
|
||||
* automatically find the workspace root.
|
||||
*/
|
||||
configPath?: string;
|
||||
/**
|
||||
* Specify a URL to an import map file to use when resolving import
|
||||
* specifiers. This is equivalent to the `--import-map` flag to the Deno
|
||||
* executable. This URL may be remote or a local file URL.
|
||||
*
|
||||
* If this option is not specified, the deno.json config file is consulted to
|
||||
* determine what import map to use, if any.
|
||||
*/
|
||||
importMapURL?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Deno resolver plugin performs relative->absolute specifier resolution
|
||||
* and import map resolution.
|
||||
*
|
||||
* If using the {@link denoLoaderPlugin}, this plugin must be used before the
|
||||
* loader plugin.
|
||||
*/
|
||||
export function denoResolverPlugin(
|
||||
options: DenoResolverPluginOptions = {},
|
||||
): esbuild.Plugin {
|
||||
return {
|
||||
name: "deno-resolver",
|
||||
setup(build) {
|
||||
let resolver: WasmWorkspaceResolver | null = null;
|
||||
|
||||
const externalRegexps: RegExp[] = (build.initialOptions.external ?? [])
|
||||
.map((external) => {
|
||||
const regexp = new RegExp(
|
||||
"^" + external.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&").replace(
|
||||
/\*/g,
|
||||
".*",
|
||||
) + "$",
|
||||
);
|
||||
return regexp;
|
||||
});
|
||||
|
||||
build.onStart(async function onStart() {
|
||||
const cwd = build.initialOptions.absWorkingDir ?? Deno.cwd();
|
||||
|
||||
const workspace = findWorkspace(
|
||||
cwd,
|
||||
build.initialOptions.entryPoints,
|
||||
options.configPath,
|
||||
);
|
||||
try {
|
||||
const importMapURL: string | undefined = options.importMapURL;
|
||||
let importMapValue: unknown | undefined;
|
||||
if (importMapURL !== undefined) {
|
||||
// If we have an import map URL, fetch it and parse it.
|
||||
const resp = await fetch(importMapURL);
|
||||
importMapValue = await resp.json();
|
||||
}
|
||||
|
||||
resolver?.free();
|
||||
resolver = null;
|
||||
resolver = workspace.resolver(importMapURL, importMapValue);
|
||||
} finally {
|
||||
workspace.free();
|
||||
}
|
||||
});
|
||||
|
||||
build.onResolve({ filter: /.*/ }, async function onResolve(args) {
|
||||
// Pass through any node_modules internal resolution.
|
||||
if (isNodeModulesResolution(args)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// The first pass resolver performs synchronous resolution. This
|
||||
// includes relative to absolute specifier resolution and import map
|
||||
// resolution.
|
||||
|
||||
// We have to first determine the referrer URL to use when resolving
|
||||
// the specifier. This is either the importer URL, or the resolveDir
|
||||
// URL if the importer is not specified (ie if the specifier is at the
|
||||
// root).
|
||||
let referrer: URL;
|
||||
if (args.importer !== "") {
|
||||
if (args.namespace === "") {
|
||||
throw new Error("[assert] namespace is empty");
|
||||
}
|
||||
referrer = new URL(`${args.namespace}:${args.importer}`);
|
||||
} else if (args.resolveDir !== "") {
|
||||
referrer = new URL(`${toFileUrl(args.resolveDir).href}/`);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const externalRegexp of externalRegexps) {
|
||||
if (externalRegexp.test(args.path)) {
|
||||
return {
|
||||
path: args.path,
|
||||
external: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// We can then resolve the specifier relative to the referrer URL, using
|
||||
// the workspace resolver.
|
||||
const resolved = new URL(
|
||||
resolver!.resolve(args.path, referrer.href),
|
||||
);
|
||||
|
||||
// Now pass the resolved specifier back into the resolver, for a second
|
||||
// pass. Now plugins can perform any resolution they want on the fully
|
||||
// resolved specifier.
|
||||
const { path, namespace } = urlToEsbuildResolution(resolved);
|
||||
const res = await build.resolve(path, {
|
||||
namespace,
|
||||
kind: args.kind,
|
||||
});
|
||||
return res;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
387
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/shared.ts
generated
vendored
Normal file
387
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/shared.ts
generated
vendored
Normal file
@ -0,0 +1,387 @@
|
||||
import { dirname, extname, fromFileUrl, SEPARATOR, toFileUrl } from "jsr:@std/path@^1.0.6";
|
||||
import type { MediaType } from "./deno.ts";
|
||||
import type * as esbuild from "./esbuild_types.ts";
|
||||
import { instantiate, WasmWorkspace } from "./wasm/loader.generated.js";
|
||||
import type { BuildOptions } from "./esbuild_types.ts";
|
||||
|
||||
export interface Loader {
|
||||
resolve(specifier: URL): Promise<LoaderResolution>;
|
||||
loadEsm(specifier: URL): Promise<esbuild.OnLoadResult | undefined>;
|
||||
|
||||
packageIdFromNameInPackage?(
|
||||
name: string,
|
||||
parentPackageId: string,
|
||||
): string | null;
|
||||
nodeModulesDirForPackage?(npmPackageId?: string): Promise<string>;
|
||||
|
||||
[Symbol.dispose]?(): void;
|
||||
}
|
||||
|
||||
export function findWorkspace(
|
||||
cwd: string,
|
||||
entryPoints: BuildOptions["entryPoints"],
|
||||
configPath: string | undefined,
|
||||
): WasmWorkspace {
|
||||
const cwdFileUrl = toFileUrl(cwd);
|
||||
if (!cwdFileUrl.pathname.endsWith("/")) {
|
||||
cwdFileUrl.pathname += "/";
|
||||
}
|
||||
|
||||
let entrypoints: Array<string>;
|
||||
let isConfigFile = false;
|
||||
if (configPath !== undefined) {
|
||||
entrypoints = [configPath];
|
||||
isConfigFile = true;
|
||||
} else if (Array.isArray(entryPoints)) {
|
||||
entrypoints = entryPoints.flatMap(
|
||||
(entrypoint) => {
|
||||
let specifier: string;
|
||||
|
||||
if (typeof entrypoint === "string") {
|
||||
specifier = entrypoint;
|
||||
} else {
|
||||
specifier = entrypoint.in;
|
||||
}
|
||||
|
||||
const url = new URL(specifier, cwdFileUrl.href);
|
||||
if (url.protocol === "file:") {
|
||||
return [dirname(fromFileUrl(url.href))];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (typeof entryPoints === "object") {
|
||||
entrypoints = Object.values(entryPoints).flatMap(
|
||||
(entrypoint) => {
|
||||
const url = new URL(entrypoint, cwdFileUrl.href);
|
||||
if (url.protocol === "file:") {
|
||||
return [dirname(fromFileUrl(url.href))];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
entrypoints = [];
|
||||
}
|
||||
if (entrypoints.length === 0) {
|
||||
entrypoints = [cwd];
|
||||
}
|
||||
|
||||
instantiate();
|
||||
return WasmWorkspace.discover(entrypoints, isConfigFile);
|
||||
}
|
||||
|
||||
export type LoaderResolution =
|
||||
| LoaderResolutionEsm
|
||||
| LoaderResolutionNpm
|
||||
| LoaderResolutionNode;
|
||||
|
||||
export interface LoaderResolutionEsm {
|
||||
kind: "esm";
|
||||
specifier: URL;
|
||||
}
|
||||
|
||||
export interface LoaderResolutionNpm {
|
||||
kind: "npm";
|
||||
packageId: string;
|
||||
packageName: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface LoaderResolutionNode {
|
||||
kind: "node";
|
||||
path: string;
|
||||
}
|
||||
|
||||
export function mediaTypeToLoader(mediaType: MediaType): esbuild.Loader | null {
|
||||
switch (mediaType) {
|
||||
case "JavaScript":
|
||||
case "Mjs":
|
||||
return "js";
|
||||
case "JSX":
|
||||
return "jsx";
|
||||
case "TypeScript":
|
||||
case "Mts":
|
||||
return "ts";
|
||||
case "TSX":
|
||||
return "tsx";
|
||||
case "Json":
|
||||
return "json";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Esbuild's representation of a module specifier. */
|
||||
export interface EsbuildResolution {
|
||||
/** The namespace, like `file`, `https`, or `npm`. */
|
||||
namespace: string;
|
||||
/** The path. When the namespace is `file`, this is a file path. Otherwise
|
||||
* this is everything in a URL with the namespace as the scheme, after the
|
||||
* `:` of the scheme. */
|
||||
path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a URL into an {@link EsbuildResolution} by splitting the URL into a
|
||||
* namespace and path.
|
||||
*
|
||||
* For file URLs, the path returned is a file path not a URL path representing a
|
||||
* file.
|
||||
*/
|
||||
export function urlToEsbuildResolution(url: URL): EsbuildResolution {
|
||||
if (url.protocol === "file:") {
|
||||
return { path: fromFileUrl(url), namespace: "file" };
|
||||
}
|
||||
|
||||
const namespace = url.protocol.slice(0, -1);
|
||||
const path = url.href.slice(namespace.length + 1);
|
||||
return { path, namespace };
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn an {@link EsbuildResolution} into a URL by joining the namespace and
|
||||
* path into a URL string.
|
||||
*
|
||||
* For file URLs, the path is interpreted as a file path not as a URL path
|
||||
* representing a file.
|
||||
*/
|
||||
export function esbuildResolutionToURL(specifier: EsbuildResolution): URL {
|
||||
if (specifier.namespace === "file") {
|
||||
return toFileUrl(specifier.path);
|
||||
}
|
||||
|
||||
return new URL(`${specifier.namespace}:${specifier.path}`);
|
||||
}
|
||||
|
||||
export function mapContentType(
|
||||
specifier: URL,
|
||||
contentType: string | null,
|
||||
): MediaType {
|
||||
if (contentType !== null) {
|
||||
const contentTypes = contentType.split(";");
|
||||
const mediaType = contentTypes[0].toLowerCase();
|
||||
switch (mediaType) {
|
||||
case "application/typescript":
|
||||
case "text/typescript":
|
||||
case "video/vnd.dlna.mpeg-tts":
|
||||
case "video/mp2t":
|
||||
case "application/x-typescript":
|
||||
return mapJsLikeExtension(specifier, "TypeScript");
|
||||
case "application/javascript":
|
||||
case "text/javascript":
|
||||
case "application/ecmascript":
|
||||
case "text/ecmascript":
|
||||
case "application/x-javascript":
|
||||
case "application/node":
|
||||
return mapJsLikeExtension(specifier, "JavaScript");
|
||||
case "text/jsx":
|
||||
return "JSX";
|
||||
case "text/tsx":
|
||||
return "TSX";
|
||||
case "application/json":
|
||||
case "text/json":
|
||||
return "Json";
|
||||
case "application/wasm":
|
||||
return "Wasm";
|
||||
case "text/plain":
|
||||
case "application/octet-stream":
|
||||
return mediaTypeFromSpecifier(specifier);
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
} else {
|
||||
return mediaTypeFromSpecifier(specifier);
|
||||
}
|
||||
}
|
||||
|
||||
function mapJsLikeExtension(
|
||||
specifier: URL,
|
||||
defaultType: MediaType,
|
||||
): MediaType {
|
||||
const path = specifier.pathname;
|
||||
switch (extname(path)) {
|
||||
case ".jsx":
|
||||
return "JSX";
|
||||
case ".mjs":
|
||||
return "Mjs";
|
||||
case ".cjs":
|
||||
return "Cjs";
|
||||
case ".tsx":
|
||||
return "TSX";
|
||||
case ".ts":
|
||||
if (path.endsWith(".d.ts")) {
|
||||
return "Dts";
|
||||
} else {
|
||||
return defaultType;
|
||||
}
|
||||
case ".mts": {
|
||||
if (path.endsWith(".d.mts")) {
|
||||
return "Dmts";
|
||||
} else {
|
||||
return defaultType == "JavaScript" ? "Mjs" : "Mts";
|
||||
}
|
||||
}
|
||||
case ".cts": {
|
||||
if (path.endsWith(".d.cts")) {
|
||||
return "Dcts";
|
||||
} else {
|
||||
return defaultType == "JavaScript" ? "Cjs" : "Cts";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return defaultType;
|
||||
}
|
||||
}
|
||||
|
||||
export function mediaTypeFromSpecifier(specifier: URL): MediaType {
|
||||
const path = specifier.pathname;
|
||||
switch (extname(path)) {
|
||||
case "":
|
||||
if (path.endsWith("/.tsbuildinfo")) {
|
||||
return "TsBuildInfo";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
case ".ts":
|
||||
if (path.endsWith(".d.ts")) {
|
||||
return "Dts";
|
||||
} else {
|
||||
return "TypeScript";
|
||||
}
|
||||
case ".mts":
|
||||
if (path.endsWith(".d.mts")) {
|
||||
return "Dmts";
|
||||
} else {
|
||||
return "Mts";
|
||||
}
|
||||
case ".cts":
|
||||
if (path.endsWith(".d.cts")) {
|
||||
return "Dcts";
|
||||
} else {
|
||||
return "Cts";
|
||||
}
|
||||
case ".tsx":
|
||||
return "TSX";
|
||||
case ".js":
|
||||
return "JavaScript";
|
||||
case ".jsx":
|
||||
return "JSX";
|
||||
case ".mjs":
|
||||
return "Mjs";
|
||||
case ".cjs":
|
||||
return "Cjs";
|
||||
case ".json":
|
||||
return "Json";
|
||||
case ".wasm":
|
||||
return "Wasm";
|
||||
case ".tsbuildinfo":
|
||||
return "TsBuildInfo";
|
||||
case ".map":
|
||||
return "SourceMap";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
export interface NpmSpecifier {
|
||||
name: string;
|
||||
version: string | null;
|
||||
path: string | null;
|
||||
}
|
||||
|
||||
export function parseNpmSpecifier(specifier: URL): NpmSpecifier {
|
||||
if (specifier.protocol !== "npm:") throw new Error("Invalid npm specifier");
|
||||
const path = specifier.pathname;
|
||||
const startIndex = path[0] === "/" ? 1 : 0;
|
||||
let pathStartIndex;
|
||||
let versionStartIndex;
|
||||
if (path[startIndex] === "@") {
|
||||
const firstSlash = path.indexOf("/", startIndex);
|
||||
if (firstSlash === -1) {
|
||||
throw new Error(`Invalid npm specifier: ${specifier}`);
|
||||
}
|
||||
pathStartIndex = path.indexOf("/", firstSlash + 1);
|
||||
versionStartIndex = path.indexOf("@", firstSlash + 1);
|
||||
} else {
|
||||
pathStartIndex = path.indexOf("/", startIndex);
|
||||
versionStartIndex = path.indexOf("@", startIndex);
|
||||
}
|
||||
|
||||
if (pathStartIndex === -1) pathStartIndex = path.length;
|
||||
if (versionStartIndex === -1) versionStartIndex = path.length;
|
||||
|
||||
if (versionStartIndex > pathStartIndex) {
|
||||
versionStartIndex = pathStartIndex;
|
||||
}
|
||||
|
||||
if (startIndex === versionStartIndex) {
|
||||
throw new Error(`Invalid npm specifier: ${specifier}`);
|
||||
}
|
||||
|
||||
return {
|
||||
name: path.slice(startIndex, versionStartIndex),
|
||||
version: versionStartIndex === pathStartIndex
|
||||
? null
|
||||
: path.slice(versionStartIndex + 1, pathStartIndex),
|
||||
path: pathStartIndex === path.length ? null : path.slice(pathStartIndex),
|
||||
};
|
||||
}
|
||||
|
||||
export interface JsrSpecifier {
|
||||
name: string;
|
||||
version: string | null;
|
||||
path: string | null;
|
||||
}
|
||||
|
||||
export function parseJsrSpecifier(specifier: URL): JsrSpecifier {
|
||||
if (specifier.protocol !== "jsr:") throw new Error("Invalid jsr specifier");
|
||||
const path = specifier.pathname;
|
||||
const startIndex = path[0] === "/" ? 1 : 0;
|
||||
if (path[startIndex] !== "@") {
|
||||
throw new Error(`Invalid jsr specifier: ${specifier}`);
|
||||
}
|
||||
const firstSlash = path.indexOf("/", startIndex);
|
||||
if (firstSlash === -1) {
|
||||
throw new Error(`Invalid jsr specifier: ${specifier}`);
|
||||
}
|
||||
let pathStartIndex = path.indexOf("/", firstSlash + 1);
|
||||
let versionStartIndex = path.indexOf("@", firstSlash + 1);
|
||||
|
||||
if (pathStartIndex === -1) pathStartIndex = path.length;
|
||||
if (versionStartIndex === -1) versionStartIndex = path.length;
|
||||
|
||||
if (versionStartIndex > pathStartIndex) {
|
||||
versionStartIndex = pathStartIndex;
|
||||
}
|
||||
|
||||
if (startIndex === versionStartIndex) {
|
||||
throw new Error(`Invalid jsr specifier: ${specifier}`);
|
||||
}
|
||||
|
||||
return {
|
||||
name: path.slice(startIndex, versionStartIndex),
|
||||
version: versionStartIndex === pathStartIndex
|
||||
? null
|
||||
: path.slice(versionStartIndex + 1, pathStartIndex),
|
||||
path: pathStartIndex === path.length ? null : path.slice(pathStartIndex),
|
||||
};
|
||||
}
|
||||
|
||||
const SLASH_NODE_MODULES_SLASH = `${SEPARATOR}node_modules${SEPARATOR}`;
|
||||
const SLASH_NODE_MODULES = `${SEPARATOR}node_modules`;
|
||||
|
||||
export function isInNodeModules(path: string): boolean {
|
||||
return path.includes(SLASH_NODE_MODULES_SLASH) ||
|
||||
path.endsWith(SLASH_NODE_MODULES);
|
||||
}
|
||||
|
||||
export function isNodeModulesResolution(args: esbuild.OnResolveArgs) {
|
||||
return (
|
||||
(args.namespace === "" || args.namespace === "file") &&
|
||||
(isInNodeModules(args.resolveDir) || isInNodeModules(args.path) ||
|
||||
isInNodeModules(args.importer))
|
||||
);
|
||||
}
|
||||
77
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/loader.generated.d.ts
generated
vendored
Normal file
77
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/loader.generated.d.ts
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// deno-lint-ignore-file
|
||||
// deno-fmt-ignore-file
|
||||
|
||||
export interface InstantiateResult {
|
||||
instance: WebAssembly.Instance;
|
||||
exports: {
|
||||
WasmLockfile : typeof WasmLockfile ;
|
||||
WasmWorkspace : typeof WasmWorkspace ;
|
||||
WasmWorkspaceResolver : typeof WasmWorkspaceResolver
|
||||
};
|
||||
}
|
||||
|
||||
/** Gets if the Wasm module has been instantiated. */
|
||||
export function isInstantiated(): boolean;
|
||||
|
||||
|
||||
/** Instantiates an instance of the Wasm module returning its functions.
|
||||
* @remarks It is safe to call this multiple times and once successfully
|
||||
* loaded it will always return a reference to the same object. */
|
||||
export function instantiate(): InstantiateResult["exports"];
|
||||
|
||||
/** Instantiates an instance of the Wasm module along with its exports.
|
||||
* @remarks It is safe to call this multiple times and once successfully
|
||||
* loaded it will always return a reference to the same object. */
|
||||
export function instantiateWithInstance(): InstantiateResult;
|
||||
|
||||
/**
|
||||
*/
|
||||
export class WasmLockfile {
|
||||
free(): void;
|
||||
/**
|
||||
* @param {string} file_path
|
||||
* @param {string} content
|
||||
*/
|
||||
constructor(file_path: string, content: string);
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
package_version(specifier: string): string | undefined;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export class WasmWorkspace {
|
||||
free(): void;
|
||||
/**
|
||||
* @param {(string)[]} entrypoints
|
||||
* @param {boolean} is_config_file
|
||||
* @returns {WasmWorkspace}
|
||||
*/
|
||||
static discover(entrypoints: (string)[], is_config_file: boolean): WasmWorkspace;
|
||||
/**
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
lock_path(): string | undefined;
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
node_modules_dir(): string;
|
||||
/**
|
||||
* @param {string | undefined} import_map_url
|
||||
* @param {any} import_map_value
|
||||
* @returns {WasmWorkspaceResolver}
|
||||
*/
|
||||
resolver(import_map_url: string | undefined, import_map_value: any): WasmWorkspaceResolver;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export class WasmWorkspaceResolver {
|
||||
free(): void;
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {string} referrer
|
||||
* @returns {string}
|
||||
*/
|
||||
resolve(specifier: string, referrer: string): string;
|
||||
}
|
||||
29829
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/loader.generated.js
generated
vendored
Normal file
29829
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/loader.generated.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
26
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/snippets/loader-ace679fc3fd6566c/fs.js
generated
vendored
Normal file
26
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1/src/wasm/snippets/loader-ace679fc3fd6566c/fs.js
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/** @param {string} path */
|
||||
export function stat_sync(path) {
|
||||
const stat = Deno.statSync(path);
|
||||
return {
|
||||
is_file: stat.isFile,
|
||||
is_directory: stat.isDirectory,
|
||||
is_symlink: stat.isSymlink,
|
||||
};
|
||||
}
|
||||
|
||||
/** @param {string} path */
|
||||
export function read_to_string_lossy(path) {
|
||||
return Deno.readTextFileSync(path);
|
||||
}
|
||||
|
||||
/** @param {string} path */
|
||||
export function read_dir(path) {
|
||||
return Iterator.from(Deno.readDirSync(path)).map((entry) => {
|
||||
return {
|
||||
name: entry.name,
|
||||
is_file: entry.isFile,
|
||||
is_directory: entry.isDirectory,
|
||||
is_symlink: entry.isSymlink,
|
||||
};
|
||||
}).toArray();
|
||||
}
|
||||
646
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1_meta.json
generated
vendored
Normal file
646
vendor/jsr.io/@luca/esbuild-deno-loader/0.11.1_meta.json
generated
vendored
Normal file
@ -0,0 +1,646 @@
|
||||
{
|
||||
"manifest": {
|
||||
"/src/wasm/fs.js": {
|
||||
"size": 615,
|
||||
"checksum": "sha256-63bedcea54fa2494f106586325ada9dcd5eccf0dcba82caa2fc4a54d9419a14b"
|
||||
},
|
||||
"/src/wasm/src/lib.rs": {
|
||||
"size": 7914,
|
||||
"checksum": "sha256-38e1590caf09b74751963aed2e880faa2bb397ee8ed4b09b5ae525834c1c5ba1"
|
||||
},
|
||||
"/src/wasm/loader.generated.js": {
|
||||
"size": 2343392,
|
||||
"checksum": "sha256-c766177855693201055b3a762929a16b85fd5d5dd8c90d530a928d3e03a1551c"
|
||||
},
|
||||
"/.vscode/settings.json": {
|
||||
"size": 377,
|
||||
"checksum": "sha256-fd130ffd6c737a7e713d5b07a628a7551da177330ff98881b7ce51d4075be47d"
|
||||
},
|
||||
"/examples/custom_scheme_plugin.ts": {
|
||||
"size": 1081,
|
||||
"checksum": "sha256-ff3a9ecb3d9cd4367280e6cf8f0782a1ec5c86ad5b8a521eade12f18accc5930"
|
||||
},
|
||||
"/README.md": {
|
||||
"size": 4470,
|
||||
"checksum": "sha256-31e895507af1a69a840d5ab0655e11aa8ec2c16777e5fa46d63fb6675c73a8eb"
|
||||
},
|
||||
"/LICENSE": {
|
||||
"size": 1070,
|
||||
"checksum": "sha256-75b6120f639f83c46bfaec3a6c97516e015b5ab18053c39bfbaf72f1d76e6c87"
|
||||
},
|
||||
"/src/shared.ts": {
|
||||
"size": 10396,
|
||||
"checksum": "sha256-3237112e33ca33db036cb5d7d5c1064c8bfe65bb3bcbbfb328ecff21629fcd2f"
|
||||
},
|
||||
"/src/wasm/loader.generated.d.ts": {
|
||||
"size": 2005,
|
||||
"checksum": "sha256-5a81527107d6b8fe0ec24477314d3c68ea575d119aa40823cec4ceacd54aede7"
|
||||
},
|
||||
"/src/wasm/snippets/loader-ace679fc3fd6566c/fs.js": {
|
||||
"size": 615,
|
||||
"checksum": "sha256-63bedcea54fa2494f106586325ada9dcd5eccf0dcba82caa2fc4a54d9419a14b"
|
||||
},
|
||||
"/src/plugin_deno_resolver.ts": {
|
||||
"size": 4631,
|
||||
"checksum": "sha256-c0d7d4e4e1cf69313cdf904430824852ff309e628759c3d871b421b40037aa82"
|
||||
},
|
||||
"/src/loader_portable.ts": {
|
||||
"size": 7189,
|
||||
"checksum": "sha256-c600a1e83af419ba72424318d9bb64691fbe8a0155f6577f1aa9ac118babe5ac"
|
||||
},
|
||||
"/.github/workflows/ci.yml": {
|
||||
"size": 1257,
|
||||
"checksum": "sha256-c8bb36bf8002583a645563788905e6e6f2e2a8cfbd2babe9257dc017319dcd92"
|
||||
},
|
||||
"/src/shared_test.ts": {
|
||||
"size": 3926,
|
||||
"checksum": "sha256-b2beb7e9394b1a21d64b57d807d5aa83e5e86ee4eeac755395d6d7ec32bc360d"
|
||||
},
|
||||
"/Cargo.lock": {
|
||||
"size": 17503,
|
||||
"checksum": "sha256-3e2fa77a49a3ac5d2e23a025a64005745ce54c15acb9943b958129d1f146837d"
|
||||
},
|
||||
"/src/esbuild_types.ts": {
|
||||
"size": 3597,
|
||||
"checksum": "sha256-7ecffd69706f9fbe60dcf75a07b94b835b269aedaab270307f2373c246e5fa14"
|
||||
},
|
||||
"/mod.ts": {
|
||||
"size": 3240,
|
||||
"checksum": "sha256-8d0e10d3bd5046246761ae7de21f8087a3d43498cc04aaa34d0b9502956a1c7e"
|
||||
},
|
||||
"/.vscode/launch.json": {
|
||||
"size": 381,
|
||||
"checksum": "sha256-e282e7a86214382bb864dc270b55ef5727bba745506bcc2affa11de235f041cf"
|
||||
},
|
||||
"/examples/bundle.ts": {
|
||||
"size": 307,
|
||||
"checksum": "sha256-df6f7046ef78d8441bb5d77d29735e465900fc5e7741ed84324f42c71323515f"
|
||||
},
|
||||
"/src/deno.ts": {
|
||||
"size": 7321,
|
||||
"checksum": "sha256-11922034c4f35eb98f0787adf5556d07ffb20ba2e743101370a05ee1c9fcc386"
|
||||
},
|
||||
"/rust-toolchain.toml": {
|
||||
"size": 87,
|
||||
"checksum": "sha256-1b36c3d65ba81d090a75fefe18229bf1fd3d4c643973d15dadb271c7f3c38129"
|
||||
},
|
||||
"/deno.json": {
|
||||
"size": 973,
|
||||
"checksum": "sha256-e885193f06c915db9912ec3be459d2d9e79207beaf3c3651108c403dd7907879"
|
||||
},
|
||||
"/Cargo.toml": {
|
||||
"size": 119,
|
||||
"checksum": "sha256-1c3994d06f7d0530b84ae3bed3d5ac92d2d75f8c2a034ec2e67ecb1020a8d8fa"
|
||||
},
|
||||
"/src/loader_native.ts": {
|
||||
"size": 7117,
|
||||
"checksum": "sha256-639560af228e34f165ef69bf4cc3b548e75c5ff4d93a587704a3bdf894e09d5e"
|
||||
},
|
||||
"/src/wasm/Cargo.toml": {
|
||||
"size": 337,
|
||||
"checksum": "sha256-af62a342f0b8d7c002ad57fbcf6edc2ef110ae19c49b7881e166b3a5eaede35b"
|
||||
},
|
||||
"/.rustfmt.toml": {
|
||||
"size": 47,
|
||||
"checksum": "sha256-5c9b47730885a7e03b6afb73eed16e6ccc07ff666e82974559bfc6a7feb61031"
|
||||
},
|
||||
"/src/plugin_deno_loader.ts": {
|
||||
"size": 14302,
|
||||
"checksum": "sha256-df8823e5b3dbe554d8a7d2dafc9af4c564c654dd07ebbb528bb00ce3f38f38f4"
|
||||
}
|
||||
},
|
||||
"moduleGraph2": {
|
||||
"/src/plugin_deno_loader.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
30
|
||||
],
|
||||
[
|
||||
1,
|
||||
52
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./loader_native.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
29
|
||||
],
|
||||
[
|
||||
2,
|
||||
49
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./loader_portable.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
31
|
||||
],
|
||||
[
|
||||
3,
|
||||
53
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
47
|
||||
],
|
||||
[
|
||||
4,
|
||||
60
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
10,
|
||||
7
|
||||
],
|
||||
[
|
||||
10,
|
||||
20
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/loader_native.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
43
|
||||
],
|
||||
[
|
||||
1,
|
||||
65
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:/@std/encoding@^1.0.5/base32",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
29
|
||||
],
|
||||
[
|
||||
2,
|
||||
63
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/bytes@^1.0.2",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
34
|
||||
],
|
||||
[
|
||||
3,
|
||||
57
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./deno.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
22
|
||||
],
|
||||
[
|
||||
4,
|
||||
33
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./deno.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
5,
|
||||
46
|
||||
],
|
||||
[
|
||||
5,
|
||||
57
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
13,
|
||||
7
|
||||
],
|
||||
[
|
||||
13,
|
||||
20
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/wasm/loader.generated.d.ts": {},
|
||||
"/src/wasm/loader.generated.js": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./snippets/loader-ace679fc3fd6566c/fs.js",
|
||||
"specifierRange": [
|
||||
[
|
||||
13,
|
||||
7
|
||||
],
|
||||
[
|
||||
13,
|
||||
49
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"tsReferences": [
|
||||
{
|
||||
"type": "types",
|
||||
"text": "./loader.generated.d.ts",
|
||||
"range": [
|
||||
[
|
||||
4,
|
||||
21
|
||||
],
|
||||
[
|
||||
4,
|
||||
46
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/mod.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./src/esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
54
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./src/plugin_deno_resolver.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
5,
|
||||
7
|
||||
],
|
||||
[
|
||||
5,
|
||||
38
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./src/plugin_deno_loader.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
12,
|
||||
7
|
||||
],
|
||||
[
|
||||
12,
|
||||
36
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "export",
|
||||
"specifier": "./src/shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
19,
|
||||
7
|
||||
],
|
||||
[
|
||||
19,
|
||||
24
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/plugin_deno_resolver.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
26
|
||||
],
|
||||
[
|
||||
1,
|
||||
48
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
6,
|
||||
7
|
||||
],
|
||||
[
|
||||
6,
|
||||
20
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./wasm/loader.generated.js",
|
||||
"specifierRange": [
|
||||
[
|
||||
7,
|
||||
43
|
||||
],
|
||||
[
|
||||
7,
|
||||
71
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/deno.ts": {},
|
||||
"/src/shared.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
68
|
||||
],
|
||||
[
|
||||
0,
|
||||
90
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./deno.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
31
|
||||
],
|
||||
[
|
||||
1,
|
||||
42
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
30
|
||||
],
|
||||
[
|
||||
2,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./wasm/loader.generated.js",
|
||||
"specifierRange": [
|
||||
[
|
||||
3,
|
||||
43
|
||||
],
|
||||
[
|
||||
3,
|
||||
71
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
4,
|
||||
34
|
||||
],
|
||||
[
|
||||
4,
|
||||
54
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/loader_portable.ts": {
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./esbuild_types.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
0,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "jsr:@std/path@^1.0.6",
|
||||
"specifierRange": [
|
||||
[
|
||||
1,
|
||||
28
|
||||
],
|
||||
[
|
||||
1,
|
||||
50
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "importType",
|
||||
"specifier": "./deno.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
2,
|
||||
27
|
||||
],
|
||||
[
|
||||
2,
|
||||
38
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./shared.ts",
|
||||
"specifierRange": [
|
||||
[
|
||||
10,
|
||||
7
|
||||
],
|
||||
[
|
||||
10,
|
||||
20
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"kind": "import",
|
||||
"specifier": "./wasm/loader.generated.js",
|
||||
"specifierRange": [
|
||||
[
|
||||
11,
|
||||
47
|
||||
],
|
||||
[
|
||||
11,
|
||||
75
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"/src/esbuild_types.ts": {},
|
||||
"/src/wasm/snippets/loader-ace679fc3fd6566c/fs.js": {}
|
||||
},
|
||||
"exports": {
|
||||
".": "./mod.ts",
|
||||
"./esbuild_types": "./src/esbuild_types.ts"
|
||||
}
|
||||
}
|
||||
13
vendor/jsr.io/@luca/esbuild-deno-loader/meta.json
generated
vendored
Normal file
13
vendor/jsr.io/@luca/esbuild-deno-loader/meta.json
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"scope": "luca",
|
||||
"name": "esbuild-deno-loader",
|
||||
"latest": "0.11.1",
|
||||
"versions": {
|
||||
"0.10.2": {},
|
||||
"0.11.0-rc.1": {},
|
||||
"0.11.1": {},
|
||||
"0.9.0": {},
|
||||
"0.11.0": {},
|
||||
"0.10.3": {}
|
||||
}
|
||||
}
|
||||
19
vendor/jsr.io/@std/assert/0.217.0/assert.ts
generated
vendored
Normal file
19
vendor/jsr.io/@std/assert/0.217.0/assert.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion, error will be thrown if `expr` does not have truthy value.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assert } from "@std/assert/assert";
|
||||
*
|
||||
* assert("hello".includes("ello")); // Doesn't throw
|
||||
* assert("hello".includes("world")); // Throws
|
||||
* ```
|
||||
*/
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
19
vendor/jsr.io/@std/assert/0.217.0/assertion_error.ts
generated
vendored
Normal file
19
vendor/jsr.io/@std/assert/0.217.0/assertion_error.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/**
|
||||
* Error thrown when an assertion fails.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { AssertionError } from "@std/assert/assertion_error";
|
||||
*
|
||||
* throw new AssertionError("Assertion failed");
|
||||
* ```
|
||||
*/
|
||||
export class AssertionError extends Error {
|
||||
/** Constructs a new instance. */
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "AssertionError";
|
||||
}
|
||||
}
|
||||
2669
vendor/jsr.io/@std/assert/0.217.0_meta.json
generated
vendored
Normal file
2669
vendor/jsr.io/@std/assert/0.217.0_meta.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
vendor/jsr.io/@std/assert/0.221.0/assert.ts
generated
vendored
Normal file
19
vendor/jsr.io/@std/assert/0.221.0/assert.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion, error will be thrown if `expr` does not have truthy value.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assert } from "@std/assert/assert";
|
||||
*
|
||||
* assert("hello".includes("ello")); // Doesn't throw
|
||||
* assert("hello".includes("world")); // Throws
|
||||
* ```
|
||||
*/
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
19
vendor/jsr.io/@std/assert/0.221.0/assertion_error.ts
generated
vendored
Normal file
19
vendor/jsr.io/@std/assert/0.221.0/assertion_error.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/**
|
||||
* Error thrown when an assertion fails.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { AssertionError } from "@std/assert/assertion-error";
|
||||
*
|
||||
* throw new AssertionError("Assertion failed");
|
||||
* ```
|
||||
*/
|
||||
export class AssertionError extends Error {
|
||||
/** Constructs a new instance. */
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "AssertionError";
|
||||
}
|
||||
}
|
||||
1498
vendor/jsr.io/@std/assert/0.221.0_meta.json
generated
vendored
Normal file
1498
vendor/jsr.io/@std/assert/0.221.0_meta.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
55
vendor/jsr.io/@std/assert/1.0.10/almost_equals.ts
generated
vendored
Normal file
55
vendor/jsr.io/@std/assert/1.0.10/almost_equals.ts
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are almost equal numbers
|
||||
* through a given tolerance. It can be used to take into account IEEE-754
|
||||
* double-precision floating-point representation limitations. If the values
|
||||
* are not almost equal then throw.
|
||||
*
|
||||
* The default tolerance is one hundred thousandth of a percent of the
|
||||
* expected value.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertAlmostEquals } from "@std/assert";
|
||||
*
|
||||
* assertAlmostEquals(0.01, 0.02); // Throws
|
||||
* assertAlmostEquals(1e-8, 1e-9); // Throws
|
||||
* assertAlmostEquals(1.000000001e-8, 1.000000002e-8); // Doesn't throw
|
||||
* assertAlmostEquals(0.01, 0.02, 0.1); // Doesn't throw
|
||||
* assertAlmostEquals(0.1 + 0.2, 0.3, 1e-16); // Doesn't throw
|
||||
* assertAlmostEquals(0.1 + 0.2, 0.3, 1e-17); // Throws
|
||||
* ```
|
||||
*
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param tolerance The tolerance to consider the values almost equal. The
|
||||
* default is one hundred thousandth of a percent of the expected value.
|
||||
* @param msg The optional message to include in the error.
|
||||
*/
|
||||
export function assertAlmostEquals(
|
||||
actual: number,
|
||||
expected: number,
|
||||
tolerance?: number,
|
||||
msg?: string,
|
||||
) {
|
||||
if (Object.is(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
const delta = Math.abs(expected - actual);
|
||||
if (tolerance === undefined) {
|
||||
tolerance = isFinite(expected) ? Math.abs(expected * 1e-7) : 1e-7;
|
||||
}
|
||||
if (delta <= tolerance) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
const f = (n: number) => Number.isInteger(n) ? n : n.toExponential();
|
||||
throw new AssertionError(
|
||||
`Expected actual: "${f(actual)}" to be close to "${f(expected)}": \
|
||||
delta "${f(delta)}" is greater than "${f(tolerance)}"${msgSuffix}`,
|
||||
);
|
||||
}
|
||||
57
vendor/jsr.io/@std/assert/1.0.10/array_includes.ts
generated
vendored
Normal file
57
vendor/jsr.io/@std/assert/1.0.10/array_includes.ts
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { equal } from "./equal.ts";
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** An array-like object (`Array`, `Uint8Array`, `NodeList`, etc.) that is not a string */
|
||||
export type ArrayLikeArg<T> = ArrayLike<T> & object;
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` includes the `expected` values. If not then
|
||||
* an error will be thrown.
|
||||
*
|
||||
* Type parameter can be specified to ensure values under comparison have the
|
||||
* same type.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertArrayIncludes } from "@std/assert";
|
||||
*
|
||||
* assertArrayIncludes([1, 2], [2]); // Doesn't throw
|
||||
* assertArrayIncludes([1, 2], [3]); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the elements in the array to compare.
|
||||
* @param actual The array-like object to check for.
|
||||
* @param expected The array-like object to check for.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertArrayIncludes<T>(
|
||||
actual: ArrayLikeArg<T>,
|
||||
expected: ArrayLikeArg<T>,
|
||||
msg?: string,
|
||||
) {
|
||||
const missing: unknown[] = [];
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
let found = false;
|
||||
for (let j = 0; j < actual.length; j++) {
|
||||
if (equal(expected[i], actual[j])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
missing.push(expected[i]);
|
||||
}
|
||||
}
|
||||
if (missing.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg = `Expected actual: "${format(actual)}" to include: "${
|
||||
format(expected)
|
||||
}"${msgSuffix}\nmissing: ${format(missing)}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
23
vendor/jsr.io/@std/assert/1.0.10/assert.ts
generated
vendored
Normal file
23
vendor/jsr.io/@std/assert/1.0.10/assert.ts
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion, error will be thrown if `expr` does not have truthy value.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assert } from "@std/assert";
|
||||
*
|
||||
* assert("hello".includes("ello")); // Doesn't throw
|
||||
* assert("hello".includes("world")); // Throws
|
||||
* ```
|
||||
*
|
||||
* @param expr The expression to test.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
31
vendor/jsr.io/@std/assert/1.0.10/assertion_error.ts
generated
vendored
Normal file
31
vendor/jsr.io/@std/assert/1.0.10/assertion_error.ts
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* Error thrown when an assertion fails.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { AssertionError } from "@std/assert";
|
||||
*
|
||||
* try {
|
||||
* throw new AssertionError("foo", { cause: "bar" });
|
||||
* } catch (error) {
|
||||
* if (error instanceof AssertionError) {
|
||||
* error.message === "foo"; // true
|
||||
* error.cause === "bar"; // true
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class AssertionError extends Error {
|
||||
/** Constructs a new instance.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @param options Additional options. This argument is still unstable. It may change in the future release.
|
||||
*/
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
this.name = "AssertionError";
|
||||
}
|
||||
}
|
||||
208
vendor/jsr.io/@std/assert/1.0.10/equal.ts
generated
vendored
Normal file
208
vendor/jsr.io/@std/assert/1.0.10/equal.ts
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
type KeyedCollection = Set<unknown> | Map<unknown, unknown>;
|
||||
function isKeyedCollection(x: unknown): x is KeyedCollection {
|
||||
return x instanceof Set || x instanceof Map;
|
||||
}
|
||||
|
||||
function prototypesEqual(a: object, b: object) {
|
||||
const pa = Object.getPrototypeOf(a);
|
||||
const pb = Object.getPrototypeOf(b);
|
||||
return pa === pb ||
|
||||
pa === Object.prototype && pb === null ||
|
||||
pa === null && pb === Object.prototype;
|
||||
}
|
||||
|
||||
function isBasicObjectOrArray(obj: object) {
|
||||
const proto = Object.getPrototypeOf(obj);
|
||||
return proto === null || proto === Object.prototype ||
|
||||
proto === Array.prototype;
|
||||
}
|
||||
|
||||
// Slightly faster than Reflect.ownKeys in V8 as of 12.9.202.13-rusty (2024-10-28)
|
||||
function ownKeys(obj: object) {
|
||||
return [
|
||||
...Object.getOwnPropertyNames(obj),
|
||||
...Object.getOwnPropertySymbols(obj),
|
||||
];
|
||||
}
|
||||
|
||||
function getKeysDeep(obj: object) {
|
||||
const keys = new Set<string | symbol>();
|
||||
|
||||
while (obj !== Object.prototype && obj !== Array.prototype && obj != null) {
|
||||
for (const key of ownKeys(obj)) {
|
||||
keys.add(key);
|
||||
}
|
||||
obj = Object.getPrototypeOf(obj);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const Temporal: any = (globalThis as any).Temporal ??
|
||||
new Proxy({}, { get: () => {} });
|
||||
|
||||
/** A non-exhaustive list of prototypes that can be accurately fast-path compared with `String(instance)` */
|
||||
const stringComparablePrototypes = new Set<unknown>(
|
||||
[
|
||||
Intl.Locale,
|
||||
RegExp,
|
||||
Temporal.Duration,
|
||||
Temporal.Instant,
|
||||
Temporal.PlainDate,
|
||||
Temporal.PlainDateTime,
|
||||
Temporal.PlainTime,
|
||||
Temporal.PlainYearMonth,
|
||||
Temporal.PlainMonthDay,
|
||||
Temporal.ZonedDateTime,
|
||||
URL,
|
||||
URLSearchParams,
|
||||
].filter((x) => x != null).map((x) => x.prototype),
|
||||
);
|
||||
|
||||
function isPrimitive(x: unknown) {
|
||||
return typeof x === "string" ||
|
||||
typeof x === "number" ||
|
||||
typeof x === "boolean" ||
|
||||
typeof x === "bigint" ||
|
||||
typeof x === "symbol" ||
|
||||
x == null;
|
||||
}
|
||||
|
||||
type TypedArray = Pick<Uint8Array | BigUint64Array, "length" | number>;
|
||||
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
||||
function compareTypedArrays(a: TypedArray, b: TypedArray) {
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < b.length; i++) {
|
||||
if (!sameValueZero(a[i], b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Check both strict equality (`0 == -0`) and `Object.is` (`NaN == NaN`) */
|
||||
function sameValueZero(a: unknown, b: unknown) {
|
||||
return a === b || Object.is(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep equality comparison used in assertions.
|
||||
*
|
||||
* @param a The actual value
|
||||
* @param b The expected value
|
||||
* @returns `true` if the values are deeply equal, `false` otherwise
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts
|
||||
* import { equal } from "@std/assert/equal";
|
||||
*
|
||||
* equal({ foo: "bar" }, { foo: "bar" }); // Returns `true`
|
||||
* equal({ foo: "bar" }, { foo: "baz" }); // Returns `false`
|
||||
* ```
|
||||
*/
|
||||
export function equal(a: unknown, b: unknown): boolean {
|
||||
const seen = new Map<unknown, unknown>();
|
||||
return (function compare(a: unknown, b: unknown): boolean {
|
||||
if (sameValueZero(a, b)) return true;
|
||||
if (isPrimitive(a) || isPrimitive(b)) return false;
|
||||
|
||||
if (a instanceof Date && b instanceof Date) {
|
||||
return Object.is(a.getTime(), b.getTime());
|
||||
}
|
||||
if (a && typeof a === "object" && b && typeof b === "object") {
|
||||
if (!prototypesEqual(a, b)) {
|
||||
return false;
|
||||
}
|
||||
if (a instanceof TypedArray) {
|
||||
return compareTypedArrays(a as TypedArray, b as TypedArray);
|
||||
}
|
||||
if (a instanceof WeakMap) {
|
||||
throw new TypeError("cannot compare WeakMap instances");
|
||||
}
|
||||
if (a instanceof WeakSet) {
|
||||
throw new TypeError("cannot compare WeakSet instances");
|
||||
}
|
||||
if (a instanceof WeakRef) {
|
||||
return compare(a.deref(), (b as WeakRef<WeakKey>).deref());
|
||||
}
|
||||
if (seen.get(a) === b) {
|
||||
return true;
|
||||
}
|
||||
if (Object.keys(a).length !== Object.keys(b).length) {
|
||||
return false;
|
||||
}
|
||||
seen.set(a, b);
|
||||
if (isKeyedCollection(a) && isKeyedCollection(b)) {
|
||||
if (a.size !== b.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const aKeys = [...a.keys()];
|
||||
const primitiveKeysFastPath = aKeys.every(isPrimitive);
|
||||
if (primitiveKeysFastPath) {
|
||||
if (a instanceof Set) {
|
||||
return a.symmetricDifference(b).size === 0;
|
||||
}
|
||||
|
||||
for (const key of aKeys) {
|
||||
if (
|
||||
!b.has(key) ||
|
||||
!compare(a.get(key), (b as Map<unknown, unknown>).get(key))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let unmatchedEntries = a.size;
|
||||
|
||||
for (const [aKey, aValue] of a.entries()) {
|
||||
for (const [bKey, bValue] of b.entries()) {
|
||||
/* Given that Map keys can be references, we need
|
||||
* to ensure that they are also deeply equal */
|
||||
|
||||
if (!compare(aKey, bKey)) continue;
|
||||
|
||||
if (
|
||||
(aKey === aValue && bKey === bValue) ||
|
||||
(compare(aValue, bValue))
|
||||
) {
|
||||
unmatchedEntries--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unmatchedEntries === 0;
|
||||
}
|
||||
|
||||
let keys: Iterable<string | symbol>;
|
||||
|
||||
if (isBasicObjectOrArray(a)) {
|
||||
// fast path
|
||||
keys = ownKeys({ ...a, ...b });
|
||||
} else if (stringComparablePrototypes.has(Object.getPrototypeOf(a))) {
|
||||
// medium path
|
||||
return String(a) === String(b);
|
||||
} else {
|
||||
// slow path
|
||||
keys = getKeysDeep(a).union(getKeysDeep(b));
|
||||
}
|
||||
|
||||
for (const key of keys) {
|
||||
type Key = keyof typeof a;
|
||||
if (!compare(a[key as Key], b[key as Key])) {
|
||||
return false;
|
||||
}
|
||||
if (((key in a) && (!(key in b))) || ((key in b) && (!(key in a)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})(a, b);
|
||||
}
|
||||
65
vendor/jsr.io/@std/assert/1.0.10/equals.ts
generated
vendored
Normal file
65
vendor/jsr.io/@std/assert/1.0.10/equals.ts
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { equal } from "./equal.ts";
|
||||
import { buildMessage } from "jsr:@std/internal@^1.0.5/build-message";
|
||||
import { diff } from "jsr:@std/internal@^1.0.5/diff";
|
||||
import { diffStr } from "jsr:@std/internal@^1.0.5/diff-str";
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are equal, deeply. If not
|
||||
* deeply equal, then throw.
|
||||
*
|
||||
* Type parameter can be specified to ensure values under comparison have the
|
||||
* same type.
|
||||
*
|
||||
* Note: When comparing `Blob` objects, you should first convert them to
|
||||
* `Uint8Array` using the `Blob.bytes()` method and then compare their
|
||||
* contents.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertEquals } from "@std/assert";
|
||||
*
|
||||
* assertEquals("world", "world"); // Doesn't throw
|
||||
* assertEquals("hello", "world"); // Throws
|
||||
* ```
|
||||
* @example Compare `Blob` objects
|
||||
* ```ts ignore
|
||||
* import { assertEquals } from "@std/assert";
|
||||
*
|
||||
* const bytes1 = await new Blob(["foo"]).bytes();
|
||||
* const bytes2 = await new Blob(["foo"]).bytes();
|
||||
*
|
||||
* assertEquals(bytes1, bytes2);
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the values to compare. This is usually inferred.
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertEquals<T>(
|
||||
actual: T,
|
||||
expected: T,
|
||||
msg?: string,
|
||||
) {
|
||||
if (equal(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
let message = `Values are not equal${msgSuffix}`;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
const stringDiff = (typeof actual === "string") &&
|
||||
(typeof expected === "string");
|
||||
const diffResult = stringDiff
|
||||
? diffStr(actual as string, expected as string)
|
||||
: diff(actualString.split("\n"), expectedString.split("\n"));
|
||||
const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n");
|
||||
message = `${message}\n${diffMsg}`;
|
||||
throw new AssertionError(message);
|
||||
}
|
||||
31
vendor/jsr.io/@std/assert/1.0.10/exists.ts
generated
vendored
Normal file
31
vendor/jsr.io/@std/assert/1.0.10/exists.ts
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that actual is not null or undefined.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertExists } from "@std/assert";
|
||||
*
|
||||
* assertExists("something"); // Doesn't throw
|
||||
* assertExists(undefined); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the actual value.
|
||||
* @param actual The actual value to check.
|
||||
* @param msg The optional message to include in the error if the assertion fails.
|
||||
*/
|
||||
export function assertExists<T>(
|
||||
actual: T,
|
||||
msg?: string,
|
||||
): asserts actual is NonNullable<T> {
|
||||
if (actual === undefined || actual === null) {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg =
|
||||
`Expected actual: "${actual}" to not be null or undefined${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
21
vendor/jsr.io/@std/assert/1.0.10/fail.ts
generated
vendored
Normal file
21
vendor/jsr.io/@std/assert/1.0.10/fail.ts
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Forcefully throws a failed assertion.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { fail } from "@std/assert";
|
||||
*
|
||||
* fail("Deliberately failed!"); // Throws
|
||||
* ```
|
||||
*
|
||||
* @param msg Optional message to include in the error.
|
||||
* @returns Never returns, always throws.
|
||||
*/
|
||||
export function fail(msg?: string): never {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
throw new AssertionError(`Failed assertion${msgSuffix}`);
|
||||
}
|
||||
26
vendor/jsr.io/@std/assert/1.0.10/false.ts
generated
vendored
Normal file
26
vendor/jsr.io/@std/assert/1.0.10/false.ts
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Assertion condition for {@linkcode assertFalse}. */
|
||||
export type Falsy = false | 0 | 0n | "" | null | undefined;
|
||||
|
||||
/**
|
||||
* Make an assertion, error will be thrown if `expr` have truthy value.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertFalse } from "@std/assert";
|
||||
*
|
||||
* assertFalse(false); // Doesn't throw
|
||||
* assertFalse(true); // Throws
|
||||
* ```
|
||||
*
|
||||
* @param expr The expression to test.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertFalse(expr: unknown, msg = ""): asserts expr is Falsy {
|
||||
if (expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
30
vendor/jsr.io/@std/assert/1.0.10/greater.ts
generated
vendored
Normal file
30
vendor/jsr.io/@std/assert/1.0.10/greater.ts
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` is greater than `expected`.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertGreater } from "@std/assert";
|
||||
*
|
||||
* assertGreater(2, 1); // Doesn't throw
|
||||
* assertGreater(1, 1); // Throws
|
||||
* assertGreater(0, 1); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the values to compare.
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertGreater<T>(actual: T, expected: T, msg?: string) {
|
||||
if (actual > expected) return;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
throw new AssertionError(msg ?? `Expect ${actualString} > ${expectedString}`);
|
||||
}
|
||||
36
vendor/jsr.io/@std/assert/1.0.10/greater_or_equal.ts
generated
vendored
Normal file
36
vendor/jsr.io/@std/assert/1.0.10/greater_or_equal.ts
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` is greater than or equal to `expected`.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertGreaterOrEqual } from "@std/assert";
|
||||
*
|
||||
* assertGreaterOrEqual(2, 1); // Doesn't throw
|
||||
* assertGreaterOrEqual(1, 1); // Doesn't throw
|
||||
* assertGreaterOrEqual(0, 1); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the values to compare.
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertGreaterOrEqual<T>(
|
||||
actual: T,
|
||||
expected: T,
|
||||
msg?: string,
|
||||
) {
|
||||
if (actual >= expected) return;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
throw new AssertionError(
|
||||
msg ?? `Expect ${actualString} >= ${expectedString}`,
|
||||
);
|
||||
}
|
||||
64
vendor/jsr.io/@std/assert/1.0.10/instance_of.ts
generated
vendored
Normal file
64
vendor/jsr.io/@std/assert/1.0.10/instance_of.ts
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Any constructor */
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export type AnyConstructor = new (...args: any[]) => any;
|
||||
/** Gets constructor type */
|
||||
export type GetConstructorType<T extends AnyConstructor> = InstanceType<T>;
|
||||
|
||||
/**
|
||||
* Make an assertion that `obj` is an instance of `type`.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertInstanceOf } from "@std/assert";
|
||||
*
|
||||
* assertInstanceOf(new Date(), Date); // Doesn't throw
|
||||
* assertInstanceOf(new Date(), Number); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The expected type of the object.
|
||||
* @param actual The object to check.
|
||||
* @param expectedType The expected class constructor.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertInstanceOf<
|
||||
// deno-lint-ignore no-explicit-any
|
||||
T extends abstract new (...args: any[]) => any,
|
||||
>(
|
||||
actual: unknown,
|
||||
expectedType: T,
|
||||
msg = "",
|
||||
): asserts actual is InstanceType<T> {
|
||||
if (actual instanceof expectedType) return;
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
const expectedTypeStr = expectedType.name;
|
||||
|
||||
let actualTypeStr = "";
|
||||
if (actual === null) {
|
||||
actualTypeStr = "null";
|
||||
} else if (actual === undefined) {
|
||||
actualTypeStr = "undefined";
|
||||
} else if (typeof actual === "object") {
|
||||
actualTypeStr = actual.constructor?.name ?? "Object";
|
||||
} else {
|
||||
actualTypeStr = typeof actual;
|
||||
}
|
||||
|
||||
if (expectedTypeStr === actualTypeStr) {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}"${msgSuffix}`;
|
||||
} else if (actualTypeStr === "function") {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}" but was not an instanced object${msgSuffix}`;
|
||||
} else {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}" but was "${actualTypeStr}"${msgSuffix}`;
|
||||
}
|
||||
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
65
vendor/jsr.io/@std/assert/1.0.10/is_error.ts
generated
vendored
Normal file
65
vendor/jsr.io/@std/assert/1.0.10/is_error.ts
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { stripAnsiCode } from "jsr:@std/internal@^1.0.5/styles";
|
||||
|
||||
/**
|
||||
* Make an assertion that `error` is an `Error`.
|
||||
* If not then an error will be thrown.
|
||||
* An error class and a string that should be included in the
|
||||
* error message can also be asserted.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertIsError } from "@std/assert";
|
||||
*
|
||||
* assertIsError(null); // Throws
|
||||
* assertIsError(new RangeError("Out of range")); // Doesn't throw
|
||||
* assertIsError(new RangeError("Out of range"), SyntaxError); // Throws
|
||||
* assertIsError(new RangeError("Out of range"), SyntaxError, "Out of range"); // Doesn't throw
|
||||
* assertIsError(new RangeError("Out of range"), SyntaxError, "Within range"); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam E The type of the error to assert.
|
||||
* @param error The error to assert.
|
||||
* @param ErrorClass The optional error class to assert.
|
||||
* @param msgMatches The optional string or RegExp to assert in the error message.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertIsError<E extends Error = Error>(
|
||||
error: unknown,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass?: abstract new (...args: any[]) => E,
|
||||
msgMatches?: string | RegExp,
|
||||
msg?: string,
|
||||
): asserts error is E {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
if (!(error instanceof Error)) {
|
||||
throw new AssertionError(
|
||||
`Expected "error" to be an Error object${msgSuffix}`,
|
||||
);
|
||||
}
|
||||
if (ErrorClass && !(error instanceof ErrorClass)) {
|
||||
msg =
|
||||
`Expected error to be instance of "${ErrorClass.name}", but was "${error?.constructor?.name}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
let msgCheck;
|
||||
if (typeof msgMatches === "string") {
|
||||
msgCheck = stripAnsiCode(error.message).includes(
|
||||
stripAnsiCode(msgMatches),
|
||||
);
|
||||
}
|
||||
if (msgMatches instanceof RegExp) {
|
||||
msgCheck = msgMatches.test(stripAnsiCode(error.message));
|
||||
}
|
||||
|
||||
if (msgMatches && !msgCheck) {
|
||||
msg = `Expected error message to include ${
|
||||
msgMatches instanceof RegExp
|
||||
? msgMatches.toString()
|
||||
: JSON.stringify(msgMatches)
|
||||
}, but got ${JSON.stringify(error?.message)}${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
||||
29
vendor/jsr.io/@std/assert/1.0.10/less.ts
generated
vendored
Normal file
29
vendor/jsr.io/@std/assert/1.0.10/less.ts
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` is less than `expected`.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertLess } from "@std/assert";
|
||||
*
|
||||
* assertLess(1, 2); // Doesn't throw
|
||||
* assertLess(2, 1); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the values to compare.
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertLess<T>(actual: T, expected: T, msg?: string) {
|
||||
if (actual < expected) return;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
throw new AssertionError(msg ?? `Expect ${actualString} < ${expectedString}`);
|
||||
}
|
||||
36
vendor/jsr.io/@std/assert/1.0.10/less_or_equal.ts
generated
vendored
Normal file
36
vendor/jsr.io/@std/assert/1.0.10/less_or_equal.ts
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { format } from "jsr:@std/internal@^1.0.5/format";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` is less than or equal to `expected`.
|
||||
* If not then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertLessOrEqual } from "@std/assert";
|
||||
*
|
||||
* assertLessOrEqual(1, 2); // Doesn't throw
|
||||
* assertLessOrEqual(1, 1); // Doesn't throw
|
||||
* assertLessOrEqual(1, 0); // Throws
|
||||
* ```
|
||||
*
|
||||
* @typeParam T The type of the values to compare.
|
||||
* @param actual The actual value to compare.
|
||||
* @param expected The expected value to compare.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertLessOrEqual<T>(
|
||||
actual: T,
|
||||
expected: T,
|
||||
msg?: string,
|
||||
) {
|
||||
if (actual <= expected) return;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
throw new AssertionError(
|
||||
msg ?? `Expect ${actualString} <= ${expectedString}`,
|
||||
);
|
||||
}
|
||||
30
vendor/jsr.io/@std/assert/1.0.10/match.ts
generated
vendored
Normal file
30
vendor/jsr.io/@std/assert/1.0.10/match.ts
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` match RegExp `expected`. If not
|
||||
* then throw.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertMatch } from "@std/assert";
|
||||
*
|
||||
* assertMatch("Raptor", /Raptor/); // Doesn't throw
|
||||
* assertMatch("Denosaurus", /Raptor/); // Throws
|
||||
* ```
|
||||
*
|
||||
* @param actual The actual value to be matched.
|
||||
* @param expected The expected pattern to match.
|
||||
* @param msg The optional message to display if the assertion fails.
|
||||
*/
|
||||
export function assertMatch(
|
||||
actual: string,
|
||||
expected: RegExp,
|
||||
msg?: string,
|
||||
) {
|
||||
if (expected.test(actual)) return;
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg = `Expected actual: "${actual}" to match: "${expected}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user