@poe-platform/safe-bash 0.1.788 → 0.1.789
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/safe-bash/chunks/{chunk-WHURJBET.js → chunk-2MUJ7RLZ.js} +1 -1
- package/dist/safe-bash/chunks/{chunk-PYTLIUST.js → chunk-CTUHLNJM.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-Z3HX3ZBA.js → chunk-D4PHJK4T.js} +1 -1
- package/dist/safe-bash/chunks/{chunk-O6356Z27.js → chunk-H7MMJS26.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-Q3E6C3DX.js → chunk-KHJGUF2W.js} +14 -0
- package/dist/safe-bash/chunks/{chunk-FJZNUUOQ.js → chunk-VUVKC6HV.js} +1 -1
- package/dist/safe-bash/chunks/{chunk-ZMYVCRAF.js → chunk-X5ZCECM6.js} +2 -2
- package/dist/safe-bash/chunks/{git-UFNPAOYZ.js → git-HO7WDPHZ.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-PFBJR2PY.js → chunk-2KRKKW5S.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-4DSJDVBM.js → chunk-32F3RBUW.js} +10 -749
- package/dist/safe-bash/command-chunks/{chunk-L3MLMXL4.js → chunk-3ZK5F23O.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-4QX6XCDD.js → chunk-4RNIZ3RT.js} +79 -0
- package/dist/safe-bash/command-chunks/{chunk-D7TADAYG.js → chunk-64LG3EVJ.js} +17 -0
- package/dist/safe-bash/command-chunks/{chunk-JUDOV5MJ.js → chunk-6F7QJMJ3.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-IJ3FXP4Q.js → chunk-A3ZX6SCY.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-YNT4ZJHW.js → chunk-AT6ZSOE6.js} +3 -3
- package/dist/safe-bash/command-chunks/{chunk-KSIGF4AG.js → chunk-BK4CMEE6.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-XGMWWUHV.js → chunk-CZ5DAK4K.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-Z57TV6TC.js → chunk-EZ2DTOLI.js} +4 -2
- package/dist/safe-bash/command-chunks/{chunk-ADCGH6A7.js → chunk-FH3D75FC.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-WYJTWJZ5.js → chunk-G3G6W5ZE.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-3HDIDEUJ.js → chunk-GF54KE2M.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-Z7TYZG3A.js → chunk-IHHTTQX6.js} +5 -3
- package/dist/safe-bash/command-chunks/{chunk-INDIFLBW.js → chunk-JTAGNROA.js} +4 -0
- package/dist/safe-bash/command-chunks/chunk-PGEYORBZ.js +25 -0
- package/dist/safe-bash/command-chunks/chunk-QM4UZF3C.js +753 -0
- package/dist/safe-bash/command-chunks/{chunk-TOSM3T3A.js → chunk-UJOO6DKY.js} +20 -9
- package/dist/safe-bash/command-chunks/{chunk-2LP3VMPA.js → chunk-WFDW4XXD.js} +1 -17
- package/dist/safe-bash/command-chunks/chunk-WR37IS4O.js +318 -0
- package/dist/safe-bash/command-chunks/{chunk-Y5IHIAY3.js → chunk-XNHSCU6I.js} +7 -3
- package/dist/safe-bash/commands/basic.js +148 -48
- package/dist/safe-bash/commands/bytes/compression/index.js +5 -6
- package/dist/safe-bash/commands/cmp.d.ts +2 -3
- package/dist/safe-bash/commands/cmp.js +2 -689
- package/dist/safe-bash/commands/docx/index.browser.js +3 -46
- package/dist/safe-bash/commands/docx/index.d.ts +2 -24
- package/dist/safe-bash/commands/docx/index.js +2 -41
- package/dist/safe-bash/commands/docx/io.d.ts +1 -14
- package/dist/safe-bash/commands/docx/io.js +1 -15
- package/dist/safe-bash/commands/llm/index.browser.js +3 -3
- package/dist/safe-bash/commands/network/index.browser.js +3 -3
- package/dist/safe-bash/commands/node/index.browser.js +3 -3
- package/dist/safe-bash/commands/pptx/index.d.ts +2 -28
- package/dist/safe-bash/commands/pptx/index.js +2 -152
- package/dist/safe-bash/commands/printf-float.d.ts +1 -0
- package/dist/safe-bash/commands/printf-float.js +48 -38
- package/dist/safe-bash/commands/printf-format.js +9 -6
- package/dist/safe-bash/commands/printf-quote.d.ts +3 -0
- package/dist/safe-bash/commands/printf-quote.js +62 -0
- package/dist/safe-bash/commands/printf-wide.d.ts +5 -0
- package/dist/safe-bash/commands/printf-wide.js +41 -0
- package/dist/safe-bash/commands/python/index.browser.js +2 -2
- package/dist/safe-bash/commands/truncate.d.ts +2 -3
- package/dist/safe-bash/commands/truncate.js +2 -686
- package/dist/safe-bash/contracts/diagnostics.d.ts +2 -0
- package/dist/safe-bash/contracts/diagnostics.js +2 -0
- package/dist/safe-bash/contracts/runtime-control.d.ts +2 -0
- package/dist/safe-bash/contracts/runtime-control.js +2 -0
- package/dist/safe-bash/core.browser.d.ts +1 -1
- package/dist/safe-bash/core.browser.js +2651 -4871
- package/dist/safe-bash/core.d.ts +10 -0
- package/dist/safe-bash/opt-in/commands/cmp/index.d.ts +6 -2
- package/dist/safe-bash/opt-in/commands/cmp/index.js +776 -79
- package/dist/safe-bash/opt-in/commands/cmp/options.d.ts +0 -12
- package/dist/safe-bash/opt-in/commands/cmp/options.js +0 -153
- package/dist/safe-bash/opt-in/commands/truncate/index.d.ts +8 -3
- package/dist/safe-bash/opt-in/commands/truncate/index.js +790 -272
- package/dist/safe-bash/opt-in/commands/truncate/sync.d.ts +1 -0
- package/dist/safe-bash/opt-in/commands/truncate/sync.js +60 -0
- package/dist/safe-bash/optional-host.browser.js +9 -1
- package/dist/safe-bash/optional-host.d.ts +3 -1
- package/dist/safe-bash/optional-host.js +3 -1
- package/dist/safe-bash/shell/runtime.js +10 -6
- package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
- package/dist/safe-bash-checksum-engine/index.js +14 -2
- package/dist/safe-bash-command-bzip2/index.js +2 -1
- package/dist/safe-bash-command-cmp/index.d.ts +10 -0
- package/dist/safe-bash-command-cmp/index.js +796 -0
- package/dist/safe-bash-command-cmp/options.d.ts +12 -0
- package/dist/safe-bash-command-cmp/options.js +42 -0
- package/dist/safe-bash-command-csvcut/index.js +11 -8
- package/dist/safe-bash-command-csvgrep/index.js +35 -7
- package/dist/safe-bash-command-csvkit/codecs/python.js +4 -3
- package/dist/safe-bash-command-csvkit/codecs/utf8.js +3 -2
- package/dist/safe-bash-command-csvkit/index.js +80 -324
- package/dist/safe-bash-command-csvkit/python-regex.d.ts +5 -0
- package/dist/safe-bash-command-csvkit/python-regex.js +14 -0
- package/dist/safe-bash-command-csvkit/runtime.d.ts +1 -0
- package/dist/safe-bash-command-csvkit/sync-support.js +4 -2
- package/dist/safe-bash-command-diff3/index.js +3 -0
- package/dist/safe-bash-command-docx/LICENSE +21 -0
- package/dist/safe-bash-command-docx/index.d.ts +30 -0
- package/dist/safe-bash-command-docx/index.js +67 -0
- package/dist/safe-bash-command-docx/io.d.ts +14 -0
- package/dist/safe-bash-command-docx/io.js +26 -0
- package/dist/safe-bash-command-envsubst/index.js +34 -3
- package/dist/safe-bash-command-exiftool/index.js +3 -0
- package/dist/safe-bash-command-ffmpeg/index.js +1102 -1088
- package/dist/safe-bash-command-fold/family.js +1 -1
- package/dist/safe-bash-command-fold/index.js +1 -1
- package/dist/safe-bash-command-htmlq/index.js +5 -0
- package/dist/safe-bash-command-imagemagick/index.d.ts +25 -21
- package/dist/safe-bash-command-imagemagick/index.js +669 -271
- package/dist/safe-bash-command-mmdc/index.js +48 -10
- package/dist/safe-bash-command-mmdc/svg.d.ts +1 -0
- package/dist/safe-bash-command-op/index.js +19 -14
- package/dist/safe-bash-command-pandoc/command.js +1 -1
- package/dist/safe-bash-command-pandoc/index.js +1 -1
- package/dist/safe-bash-command-pdfimages/index.d.ts +7 -1
- package/dist/safe-bash-command-pdfimages/index.js +63 -33
- package/dist/safe-bash-command-pdfinfo/index.d.ts +24 -20
- package/dist/safe-bash-command-pdfinfo/index.js +370 -161
- package/dist/safe-bash-command-pdftk/index.d.ts +7 -3
- package/dist/safe-bash-command-pdftk/index.js +114 -45
- package/dist/safe-bash-command-pdftoppm/index.d.ts +15 -7
- package/dist/safe-bash-command-pdftoppm/index.js +179 -109
- package/dist/safe-bash-command-pdftotext/index.d.ts +9 -5
- package/dist/safe-bash-command-pdftotext/index.js +90 -27
- package/dist/safe-bash-command-pptx/LICENSE +21 -0
- package/dist/safe-bash-command-pptx/index.d.ts +33 -0
- package/dist/safe-bash-command-pptx/index.js +168 -0
- package/dist/safe-bash-command-qpdf/index.d.ts +9 -3
- package/dist/safe-bash-command-qpdf/index.js +80 -29
- package/dist/safe-bash-command-sha512sum/index.js +12 -475
- package/dist/safe-bash-command-sips/index.d.ts +9 -5
- package/dist/safe-bash-command-sips/index.js +63 -44
- package/dist/safe-bash-command-soffice/index.d.ts +9 -3
- package/dist/safe-bash-command-soffice/index.js +65 -24
- package/dist/safe-bash-command-sqlite3/engine.d.ts +9 -0
- package/dist/safe-bash-command-sqlite3/index.d.ts +1 -0
- package/dist/safe-bash-command-sqlite3/index.js +851 -352
- package/dist/safe-bash-command-ssconvert/formats/xls.js +3 -3
- package/dist/safe-bash-command-timeout/index.js +3 -3
- package/dist/safe-bash-command-truncate/index.d.ts +8 -3
- package/dist/safe-bash-command-truncate/index.js +790 -272
- package/dist/safe-bash-command-truncate/sync.d.ts +1 -0
- package/dist/safe-bash-command-truncate/sync.js +60 -0
- package/dist/safe-bash-command-wkhtmltopdf/index.js +92 -38
- package/dist/safe-bash-command-wkhtmltopdf/pdf-renderer.d.ts +1 -1
- package/dist/safe-bash-command-xxd/index.js +78 -20
- package/dist/safe-bash-command-xz/command.d.ts +4 -0
- package/dist/safe-bash-command-xz/index.d.ts +1 -1
- package/dist/safe-bash-command-xz/index.js +1 -1
- package/dist/safe-bash-compression-engine/bounded-codec.js +3 -3
- package/dist/safe-bash-compression-engine/codec-loader.js +2 -2
- package/dist/safe-bash-compression-engine/files.js +6 -6
- package/dist/safe-bash-compression-engine/index.js +5 -5
- package/dist/safe-bash-compression-engine/operand.js +6 -6
- package/dist/safe-bash-compression-engine/stream.js +5 -5
- package/dist/safe-bash-compression-engine/zstd-decode.js +4 -4
- package/dist/safe-bash-contracts/command.js +3 -3
- package/dist/safe-bash-contracts/diagnostics.js +3 -3
- package/dist/safe-bash-contracts/escaping.js +9 -9
- package/dist/safe-bash-contracts/filesystem-descriptor.js +3 -3
- package/dist/safe-bash-contracts/filesystem-output.js +8 -8
- package/dist/safe-bash-contracts/index.js +21 -19
- package/dist/safe-bash-contracts/io.d.ts +12 -0
- package/dist/safe-bash-contracts/io.js +4 -1
- package/dist/safe-bash-contracts/output.js +3 -2
- package/dist/safe-bash-contracts/runtime-control.js +2 -2
- package/dist/safe-bash-contracts/signals.js +1 -1
- package/dist/safe-bash-contracts/yield.d.ts +1 -0
- package/dist/safe-bash-contracts/yield.js +3 -1
- package/dist/safe-bash-csv-engine/index.d.ts +10 -1
- package/dist/safe-bash-csv-engine/index.js +78 -6
- package/dist/safe-bash-io-engine/commands/search/requirements.js +3 -3
- package/dist/safe-bash-io-engine/commands/text-programs/shared.js +3 -3
- package/dist/safe-bash-io-engine/gnu-information.js +1 -1
- package/dist/safe-bash-io-engine/internal.d.ts +1 -1
- package/dist/safe-bash-io-engine/internal.js +2 -2
- package/dist/safe-bash-query-engine/index.js +4 -4
- package/dist/safe-bash-query-engine/interpreter.js +2 -2
- package/dist/safe-bash-query-engine/query-core.js +4 -4
- package/package.json +2 -2
- package/dist/safe-bash/opt-in/commands/cmp/compare.js +0 -95
- package/dist/safe-bash/opt-in/commands/cmp/io.js +0 -218
- package/dist/safe-bash/command-chunks/{chunk-FXYWQ6S4.js → chunk-2VTMZTV3.js} +0 -0
- package/dist/safe-bash/command-chunks/{chunk-RTOJNFFL.js → chunk-BJ6DGYJA.js} +4 -4
- package/dist/safe-bash/command-chunks/{chunk-DEH3CMGL.js → chunk-QJ3ONEBI.js} +3 -3
|
@@ -1,315 +1,833 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { creationUmask } from "../safe-bash-contracts/runtime-control.js";
|
|
2
2
|
import { commandRuntimeIdentity, FsError, dirname, getCommandArguments, writeBytes } from "../safe-bash-contracts/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { createOutputOperation } from "../safe-bash-contracts/output.js";
|
|
4
|
+
import { shellValueByteLength } from "../safe-bash-contracts/value.js";
|
|
4
5
|
import { yieldTurn } from "../safe-bash-contracts/yield.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
import { PublicDiagnostic, publicDiagnosticMessage } from "../safe-bash-contracts/diagnostics.js";
|
|
7
|
+
import { registerDefaultExecutor, pathOf, codeOf } from "../safe-bash-io-engine/internal.js";
|
|
8
|
+
import { parseArguments, TruncateError, helpText as portableHelp, quote as portableQuote } from "./arguments.js";
|
|
9
|
+
function settings(options) {
|
|
10
|
+
const limits = { maxArgumentBytes: Infinity, maxArguments: Infinity, maxOutputBytes: Infinity, maxEntries: Infinity, ...options.limits };
|
|
11
|
+
for (const [name, value] of Object.entries(limits))
|
|
12
|
+
if (value !== Infinity && (!Number.isSafeInteger(value) || value < (name === "maxDepth" ? 0 : 1)))
|
|
13
|
+
throw new RangeError(`Invalid truncate limit: ${name}`);
|
|
14
|
+
const umask = options.umask ?? 0o022;
|
|
15
|
+
if (!Number.isInteger(umask) || umask < 0 || umask > 0o777)
|
|
16
|
+
throw new RangeError("Invalid truncate umask");
|
|
17
|
+
return { limits, umask };
|
|
18
|
+
}
|
|
19
|
+
const signedMaximum = (1n << 63n) - 1n;
|
|
20
|
+
const signedMinimum = -signedMaximum - 1n;
|
|
21
|
+
const helpText = "Usage: truncate OPTION... FILE...\nShrink or extend the size of each FILE to the specified size\n\nA FILE argument that does not exist is created.\n\nIf a FILE is larger than the specified size, the extra data is lost.\nIf a FILE is shorter, it is extended and the extended part (hole)\nreads as zero bytes.\n\nMandatory arguments to long options are mandatory for short options too.\n -c, --no-create do not create any files\n -o, --io-blocks treat SIZE as number of IO blocks instead of bytes\n -r, --reference=RFILE base size on RFILE\n -s, --size=SIZE set or adjust the file size by SIZE bytes\n --help display this help and exit\n --version output version information and exit\n\nThe SIZE argument is an integer and optional unit (example: 10K is 10*1024).\nUnits are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000).\n\nSIZE may also be prefixed by one of the following modifying characters:\n'+' extend by, '-' reduce by, '<' at most, '>' at least,\n'/' round down to multiple of, '%' round up to multiple of.\n\nGNU coreutils online help: <https://www.gnu.org/software/coreutils/>\nReport truncate translation bugs to <https://translationproject.org/team/>\nFull documentation at: <https://www.gnu.org/software/coreutils/truncate>\nor available locally via: info '(coreutils) truncate invocation'\n";
|
|
22
|
+
const glibc231PrintableRanges = [
|
|
23
|
+
0x20, 0x7e, 0xa0, 0x377, 0x37a, 0x37f, 0x384, 0x38a, 0x38c, 0x38c, 0x38e, 0x3a1, 0x3a3, 0x52f, 0x531, 0x556,
|
|
24
|
+
0x559, 0x55f, 0x561, 0x587, 0x589, 0x58a, 0x58d, 0x58f, 0x591, 0x5c7, 0x5d0, 0x5ea, 0x5f0, 0x5f4, 0x600, 0x61c,
|
|
25
|
+
0x61e, 0x70d, 0x70f, 0x74a, 0x74d, 0x7b1, 0x7c0, 0x7fa, 0x800, 0x82d, 0x830, 0x83e, 0x840, 0x85b, 0x85e, 0x85e,
|
|
26
|
+
0x8a0, 0x8b4, 0x8b6, 0x8bd, 0x8d4, 0x983, 0x985, 0x98c, 0x98f, 0x990, 0x993, 0x9a8, 0x9aa, 0x9b0, 0x9b2, 0x9b2,
|
|
27
|
+
0x9b6, 0x9b9, 0x9bc, 0x9c4, 0x9c7, 0x9c8, 0x9cb, 0x9ce, 0x9d7, 0x9d7, 0x9dc, 0x9dd, 0x9df, 0x9e3, 0x9e6, 0x9fb,
|
|
28
|
+
0xa01, 0xa03, 0xa05, 0xa0a, 0xa0f, 0xa10, 0xa13, 0xa28, 0xa2a, 0xa30, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38, 0xa39,
|
|
29
|
+
0xa3c, 0xa3c, 0xa3e, 0xa42, 0xa47, 0xa48, 0xa4b, 0xa4d, 0xa51, 0xa51, 0xa59, 0xa5c, 0xa5e, 0xa5e, 0xa66, 0xa75,
|
|
30
|
+
0xa81, 0xa83, 0xa85, 0xa8d, 0xa8f, 0xa91, 0xa93, 0xaa8, 0xaaa, 0xab0, 0xab2, 0xab3, 0xab5, 0xab9, 0xabc, 0xac5,
|
|
31
|
+
0xac7, 0xac9, 0xacb, 0xacd, 0xad0, 0xad0, 0xae0, 0xae3, 0xae6, 0xaf1, 0xaf9, 0xaf9, 0xb01, 0xb03, 0xb05, 0xb0c,
|
|
32
|
+
0xb0f, 0xb10, 0xb13, 0xb28, 0xb2a, 0xb30, 0xb32, 0xb33, 0xb35, 0xb39, 0xb3c, 0xb44, 0xb47, 0xb48, 0xb4b, 0xb4d,
|
|
33
|
+
0xb56, 0xb57, 0xb5c, 0xb5d, 0xb5f, 0xb63, 0xb66, 0xb77, 0xb82, 0xb83, 0xb85, 0xb8a, 0xb8e, 0xb90, 0xb92, 0xb95,
|
|
34
|
+
0xb99, 0xb9a, 0xb9c, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4, 0xba8, 0xbaa, 0xbae, 0xbb9, 0xbbe, 0xbc2, 0xbc6, 0xbc8,
|
|
35
|
+
0xbca, 0xbcd, 0xbd0, 0xbd0, 0xbd7, 0xbd7, 0xbe6, 0xbfa, 0xc00, 0xc03, 0xc05, 0xc0c, 0xc0e, 0xc10, 0xc12, 0xc28,
|
|
36
|
+
0xc2a, 0xc39, 0xc3d, 0xc44, 0xc46, 0xc48, 0xc4a, 0xc4d, 0xc55, 0xc56, 0xc58, 0xc5a, 0xc60, 0xc63, 0xc66, 0xc6f,
|
|
37
|
+
0xc78, 0xc83, 0xc85, 0xc8c, 0xc8e, 0xc90, 0xc92, 0xca8, 0xcaa, 0xcb3, 0xcb5, 0xcb9, 0xcbc, 0xcc4, 0xcc6, 0xcc8,
|
|
38
|
+
0xcca, 0xccd, 0xcd5, 0xcd6, 0xcde, 0xcde, 0xce0, 0xce3, 0xce6, 0xcef, 0xcf1, 0xcf2, 0xd01, 0xd03, 0xd05, 0xd0c,
|
|
39
|
+
0xd0e, 0xd10, 0xd12, 0xd3a, 0xd3d, 0xd44, 0xd46, 0xd48, 0xd4a, 0xd4f, 0xd54, 0xd63, 0xd66, 0xd7f, 0xd82, 0xd83,
|
|
40
|
+
0xd85, 0xd96, 0xd9a, 0xdb1, 0xdb3, 0xdbb, 0xdbd, 0xdbd, 0xdc0, 0xdc6, 0xdca, 0xdca, 0xdcf, 0xdd4, 0xdd6, 0xdd6,
|
|
41
|
+
0xdd8, 0xddf, 0xde6, 0xdef, 0xdf2, 0xdf4, 0xe01, 0xe3a, 0xe3f, 0xe5b, 0xe81, 0xe82, 0xe84, 0xe84, 0xe87, 0xe88,
|
|
42
|
+
0xe8a, 0xe8a, 0xe8d, 0xe8d, 0xe94, 0xe97, 0xe99, 0xe9f, 0xea1, 0xea3, 0xea5, 0xea5, 0xea7, 0xea7, 0xeaa, 0xeab,
|
|
43
|
+
0xead, 0xeb9, 0xebb, 0xebd, 0xec0, 0xec4, 0xec6, 0xec6, 0xec8, 0xecd, 0xed0, 0xed9, 0xedc, 0xedf, 0xf00, 0xf47,
|
|
44
|
+
0xf49, 0xf6c, 0xf71, 0xf97, 0xf99, 0xfbc, 0xfbe, 0xfcc, 0xfce, 0xfda, 0x1000, 0x10c5, 0x10c7, 0x10c7, 0x10cd, 0x10cd,
|
|
45
|
+
0x10d0, 0x1248, 0x124a, 0x124d, 0x1250, 0x1256, 0x1258, 0x1258, 0x125a, 0x125d, 0x1260, 0x1288, 0x128a, 0x128d, 0x1290, 0x12b0,
|
|
46
|
+
0x12b2, 0x12b5, 0x12b8, 0x12be, 0x12c0, 0x12c0, 0x12c2, 0x12c5, 0x12c8, 0x12d6, 0x12d8, 0x1310, 0x1312, 0x1315, 0x1318, 0x135a,
|
|
47
|
+
0x135d, 0x137c, 0x1380, 0x1399, 0x13a0, 0x13f5, 0x13f8, 0x13fd, 0x1400, 0x169c, 0x16a0, 0x16f8, 0x1700, 0x170c, 0x170e, 0x1714,
|
|
48
|
+
0x1720, 0x1736, 0x1740, 0x1753, 0x1760, 0x176c, 0x176e, 0x1770, 0x1772, 0x1773, 0x1780, 0x17dd, 0x17e0, 0x17e9, 0x17f0, 0x17f9,
|
|
49
|
+
0x1800, 0x180e, 0x1810, 0x1819, 0x1820, 0x1877, 0x1880, 0x18aa, 0x18b0, 0x18f5, 0x1900, 0x191e, 0x1920, 0x192b, 0x1930, 0x193b,
|
|
50
|
+
0x1940, 0x1940, 0x1944, 0x196d, 0x1970, 0x1974, 0x1980, 0x19ab, 0x19b0, 0x19c9, 0x19d0, 0x19da, 0x19de, 0x1a1b, 0x1a1e, 0x1a5e,
|
|
51
|
+
0x1a60, 0x1a7c, 0x1a7f, 0x1a89, 0x1a90, 0x1a99, 0x1aa0, 0x1aad, 0x1ab0, 0x1abe, 0x1b00, 0x1b4b, 0x1b50, 0x1b7c, 0x1b80, 0x1bf3,
|
|
52
|
+
0x1bfc, 0x1c37, 0x1c3b, 0x1c49, 0x1c4d, 0x1c88, 0x1cc0, 0x1cc7, 0x1cd0, 0x1cf6, 0x1cf8, 0x1cf9, 0x1d00, 0x1df5, 0x1dfb, 0x1f15,
|
|
53
|
+
0x1f18, 0x1f1d, 0x1f20, 0x1f45, 0x1f48, 0x1f4d, 0x1f50, 0x1f57, 0x1f59, 0x1f59, 0x1f5b, 0x1f5b, 0x1f5d, 0x1f5d, 0x1f5f, 0x1f7d,
|
|
54
|
+
0x1f80, 0x1fb4, 0x1fb6, 0x1fc4, 0x1fc6, 0x1fd3, 0x1fd6, 0x1fdb, 0x1fdd, 0x1fef, 0x1ff2, 0x1ff4, 0x1ff6, 0x1ffe, 0x2000, 0x2027,
|
|
55
|
+
0x202a, 0x2064, 0x2066, 0x2071, 0x2074, 0x208e, 0x2090, 0x209c, 0x20a0, 0x20be, 0x20d0, 0x20f0, 0x2100, 0x218b, 0x2190, 0x23fe,
|
|
56
|
+
0x2400, 0x2426, 0x2440, 0x244a, 0x2460, 0x2b73, 0x2b76, 0x2b95, 0x2b98, 0x2bb9, 0x2bbd, 0x2bc8, 0x2bca, 0x2bd1, 0x2bec, 0x2bef,
|
|
57
|
+
0x2c00, 0x2c2e, 0x2c30, 0x2c5e, 0x2c60, 0x2cf3, 0x2cf9, 0x2d25, 0x2d27, 0x2d27, 0x2d2d, 0x2d2d, 0x2d30, 0x2d67, 0x2d6f, 0x2d70,
|
|
58
|
+
0x2d7f, 0x2d96, 0x2da0, 0x2da6, 0x2da8, 0x2dae, 0x2db0, 0x2db6, 0x2db8, 0x2dbe, 0x2dc0, 0x2dc6, 0x2dc8, 0x2dce, 0x2dd0, 0x2dd6,
|
|
59
|
+
0x2dd8, 0x2dde, 0x2de0, 0x2e44, 0x2e80, 0x2e99, 0x2e9b, 0x2ef3, 0x2f00, 0x2fd5, 0x2ff0, 0x2ffb, 0x3000, 0x303f, 0x3041, 0x3096,
|
|
60
|
+
0x3099, 0x30ff, 0x3105, 0x312d, 0x3131, 0x318e, 0x3190, 0x31ba, 0x31c0, 0x31e3, 0x31f0, 0x321e, 0x3220, 0x32fe, 0x3300, 0x4db5,
|
|
61
|
+
0x4dc0, 0x9fd5, 0xa000, 0xa48c, 0xa490, 0xa4c6, 0xa4d0, 0xa62b, 0xa640, 0xa6f7, 0xa700, 0xa7ae, 0xa7b0, 0xa7b7, 0xa7f7, 0xa82b,
|
|
62
|
+
0xa830, 0xa839, 0xa840, 0xa877, 0xa880, 0xa8c5, 0xa8ce, 0xa8d9, 0xa8e0, 0xa8fd, 0xa900, 0xa953, 0xa95f, 0xa97c, 0xa980, 0xa9cd,
|
|
63
|
+
0xa9cf, 0xa9d9, 0xa9de, 0xa9fe, 0xaa00, 0xaa36, 0xaa40, 0xaa4d, 0xaa50, 0xaa59, 0xaa5c, 0xaac2, 0xaadb, 0xaaf6, 0xab01, 0xab06,
|
|
64
|
+
0xab09, 0xab0e, 0xab11, 0xab16, 0xab20, 0xab26, 0xab28, 0xab2e, 0xab30, 0xab65, 0xab70, 0xabed, 0xabf0, 0xabf9, 0xac00, 0xd7a3,
|
|
65
|
+
0xd7b0, 0xd7c6, 0xd7cb, 0xd7fb, 0xe000, 0xfa6d, 0xfa70, 0xfad9, 0xfb00, 0xfb06, 0xfb13, 0xfb17, 0xfb1d, 0xfb36, 0xfb38, 0xfb3c,
|
|
66
|
+
0xfb3e, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfbc1, 0xfbd3, 0xfd3f, 0xfd50, 0xfd8f, 0xfd92, 0xfdc7, 0xfdf0, 0xfdfd,
|
|
67
|
+
0xfe00, 0xfe19, 0xfe20, 0xfe52, 0xfe54, 0xfe66, 0xfe68, 0xfe6b, 0xfe70, 0xfe74, 0xfe76, 0xfefc, 0xfeff, 0xfeff, 0xff01, 0xffbe,
|
|
68
|
+
0xffc2, 0xffc7, 0xffca, 0xffcf, 0xffd2, 0xffd7, 0xffda, 0xffdc, 0xffe0, 0xffe6, 0xffe8, 0xffee, 0xfff9, 0xfffd, 0x10000, 0x1000b,
|
|
69
|
+
0x1000d, 0x10026, 0x10028, 0x1003a, 0x1003c, 0x1003d, 0x1003f, 0x1004d, 0x10050, 0x1005d, 0x10080, 0x100fa, 0x10100, 0x10102, 0x10107, 0x10133,
|
|
70
|
+
0x10137, 0x1018e, 0x10190, 0x1019b, 0x101a0, 0x101a0, 0x101d0, 0x101fd, 0x10280, 0x1029c, 0x102a0, 0x102d0, 0x102e0, 0x102fb, 0x10300, 0x10323,
|
|
71
|
+
0x10330, 0x1034a, 0x10350, 0x1037a, 0x10380, 0x1039d, 0x1039f, 0x103c3, 0x103c8, 0x103d5, 0x10400, 0x1049d, 0x104a0, 0x104a9, 0x104b0, 0x104d3,
|
|
72
|
+
0x104d8, 0x104fb, 0x10500, 0x10527, 0x10530, 0x10563, 0x1056f, 0x1056f, 0x10600, 0x10736, 0x10740, 0x10755, 0x10760, 0x10767, 0x10800, 0x10805,
|
|
73
|
+
0x10808, 0x10808, 0x1080a, 0x10835, 0x10837, 0x10838, 0x1083c, 0x1083c, 0x1083f, 0x10855, 0x10857, 0x1089e, 0x108a7, 0x108af, 0x108e0, 0x108f2,
|
|
74
|
+
0x108f4, 0x108f5, 0x108fb, 0x1091b, 0x1091f, 0x10939, 0x1093f, 0x1093f, 0x10980, 0x109b7, 0x109bc, 0x109cf, 0x109d2, 0x10a03, 0x10a05, 0x10a06,
|
|
75
|
+
0x10a0c, 0x10a13, 0x10a15, 0x10a17, 0x10a19, 0x10a33, 0x10a38, 0x10a3a, 0x10a3f, 0x10a47, 0x10a50, 0x10a58, 0x10a60, 0x10a9f, 0x10ac0, 0x10ae6,
|
|
76
|
+
0x10aeb, 0x10af6, 0x10b00, 0x10b35, 0x10b39, 0x10b55, 0x10b58, 0x10b72, 0x10b78, 0x10b91, 0x10b99, 0x10b9c, 0x10ba9, 0x10baf, 0x10c00, 0x10c48,
|
|
77
|
+
0x10c80, 0x10cb2, 0x10cc0, 0x10cf2, 0x10cfa, 0x10cff, 0x10e60, 0x10e7e, 0x11000, 0x1104d, 0x11052, 0x1106f, 0x1107f, 0x110c1, 0x110d0, 0x110e8,
|
|
78
|
+
0x110f0, 0x110f9, 0x11100, 0x11134, 0x11136, 0x11143, 0x11150, 0x11176, 0x11180, 0x111cd, 0x111d0, 0x111df, 0x111e1, 0x111f4, 0x11200, 0x11211,
|
|
79
|
+
0x11213, 0x1123e, 0x11280, 0x11286, 0x11288, 0x11288, 0x1128a, 0x1128d, 0x1128f, 0x1129d, 0x1129f, 0x112a9, 0x112b0, 0x112ea, 0x112f0, 0x112f9,
|
|
80
|
+
0x11300, 0x11303, 0x11305, 0x1130c, 0x1130f, 0x11310, 0x11313, 0x11328, 0x1132a, 0x11330, 0x11332, 0x11333, 0x11335, 0x11339, 0x1133c, 0x11344,
|
|
81
|
+
0x11347, 0x11348, 0x1134b, 0x1134d, 0x11350, 0x11350, 0x11357, 0x11357, 0x1135d, 0x11363, 0x11366, 0x1136c, 0x11370, 0x11374, 0x11400, 0x11459,
|
|
82
|
+
0x1145b, 0x1145b, 0x1145d, 0x1145d, 0x11480, 0x114c7, 0x114d0, 0x114d9, 0x11580, 0x115b5, 0x115b8, 0x115dd, 0x11600, 0x11644, 0x11650, 0x11659,
|
|
83
|
+
0x11660, 0x1166c, 0x11680, 0x116b7, 0x116c0, 0x116c9, 0x11700, 0x11719, 0x1171d, 0x1172b, 0x11730, 0x1173f, 0x118a0, 0x118f2, 0x118ff, 0x118ff,
|
|
84
|
+
0x11ac0, 0x11af8, 0x11c00, 0x11c08, 0x11c0a, 0x11c36, 0x11c38, 0x11c45, 0x11c50, 0x11c6c, 0x11c70, 0x11c8f, 0x11c92, 0x11ca7, 0x11ca9, 0x11cb6,
|
|
85
|
+
0x12000, 0x12399, 0x12400, 0x1246e, 0x12470, 0x12474, 0x12480, 0x12543, 0x13000, 0x1342e, 0x14400, 0x14646, 0x16800, 0x16a38, 0x16a40, 0x16a5e,
|
|
86
|
+
0x16a60, 0x16a69, 0x16a6e, 0x16a6f, 0x16ad0, 0x16aed, 0x16af0, 0x16af5, 0x16b00, 0x16b45, 0x16b50, 0x16b59, 0x16b5b, 0x16b61, 0x16b63, 0x16b77,
|
|
87
|
+
0x16b7d, 0x16b8f, 0x16f00, 0x16f44, 0x16f50, 0x16f7e, 0x16f8f, 0x16f9f, 0x16fe0, 0x16fe0, 0x17000, 0x187ec, 0x18800, 0x18af2, 0x1b000, 0x1b001,
|
|
88
|
+
0x1bc00, 0x1bc6a, 0x1bc70, 0x1bc7c, 0x1bc80, 0x1bc88, 0x1bc90, 0x1bc99, 0x1bc9c, 0x1bca3, 0x1d000, 0x1d0f5, 0x1d100, 0x1d126, 0x1d129, 0x1d1e8,
|
|
89
|
+
0x1d200, 0x1d245, 0x1d300, 0x1d356, 0x1d360, 0x1d371, 0x1d400, 0x1d454, 0x1d456, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6,
|
|
90
|
+
0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c3, 0x1d4c5, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c,
|
|
91
|
+
0x1d51e, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546, 0x1d54a, 0x1d550, 0x1d552, 0x1d6a5, 0x1d6a8, 0x1d7cb, 0x1d7ce, 0x1da8b,
|
|
92
|
+
0x1da9b, 0x1da9f, 0x1daa1, 0x1daaf, 0x1e000, 0x1e006, 0x1e008, 0x1e018, 0x1e01b, 0x1e021, 0x1e023, 0x1e024, 0x1e026, 0x1e02a, 0x1e800, 0x1e8c4,
|
|
93
|
+
0x1e8c7, 0x1e8d6, 0x1e900, 0x1e94a, 0x1e950, 0x1e959, 0x1e95e, 0x1e95f, 0x1ee00, 0x1ee03, 0x1ee05, 0x1ee1f, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee24,
|
|
94
|
+
0x1ee27, 0x1ee27, 0x1ee29, 0x1ee32, 0x1ee34, 0x1ee37, 0x1ee39, 0x1ee39, 0x1ee3b, 0x1ee3b, 0x1ee42, 0x1ee42, 0x1ee47, 0x1ee47, 0x1ee49, 0x1ee49,
|
|
95
|
+
0x1ee4b, 0x1ee4b, 0x1ee4d, 0x1ee4f, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee54, 0x1ee57, 0x1ee57, 0x1ee59, 0x1ee59, 0x1ee5b, 0x1ee5b, 0x1ee5d, 0x1ee5d,
|
|
96
|
+
0x1ee5f, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee64, 0x1ee67, 0x1ee6a, 0x1ee6c, 0x1ee72, 0x1ee74, 0x1ee77, 0x1ee79, 0x1ee7c, 0x1ee7e, 0x1ee7e,
|
|
97
|
+
0x1ee80, 0x1ee89, 0x1ee8b, 0x1ee9b, 0x1eea1, 0x1eea3, 0x1eea5, 0x1eea9, 0x1eeab, 0x1eebb, 0x1eef0, 0x1eef1, 0x1f000, 0x1f02b, 0x1f030, 0x1f093,
|
|
98
|
+
0x1f0a0, 0x1f0ae, 0x1f0b1, 0x1f0bf, 0x1f0c1, 0x1f0cf, 0x1f0d1, 0x1f0f5, 0x1f100, 0x1f10c, 0x1f110, 0x1f12e, 0x1f130, 0x1f16b, 0x1f170, 0x1f1ac,
|
|
99
|
+
0x1f1e6, 0x1f202, 0x1f210, 0x1f23b, 0x1f240, 0x1f248, 0x1f250, 0x1f251, 0x1f300, 0x1f6d2, 0x1f6e0, 0x1f6ec, 0x1f6f0, 0x1f6f6, 0x1f700, 0x1f773,
|
|
100
|
+
0x1f780, 0x1f7d4, 0x1f800, 0x1f80b, 0x1f810, 0x1f847, 0x1f850, 0x1f859, 0x1f860, 0x1f887, 0x1f890, 0x1f8ad, 0x1f910, 0x1f91e, 0x1f920, 0x1f927,
|
|
101
|
+
0x1f930, 0x1f930, 0x1f933, 0x1f93e, 0x1f940, 0x1f94b, 0x1f950, 0x1f95e, 0x1f980, 0x1f991, 0x1f9c0, 0x1f9c0, 0x20000, 0x2a6d6, 0x2a700, 0x2b734,
|
|
102
|
+
0x2b740, 0x2b81d, 0x2b820, 0x2cea1, 0x2f800, 0x2fa1d, 0xe0001, 0xe0001, 0xe0020, 0xe007f, 0xe0100, 0xe01ef, 0xf0000, 0xffffd, 0x100000, 0x10fffd,
|
|
103
|
+
];
|
|
104
|
+
class TruncateDiagnostic extends Error {
|
|
105
|
+
detail;
|
|
106
|
+
usage;
|
|
107
|
+
constructor(detail, usage = false) {
|
|
108
|
+
super(detail);
|
|
109
|
+
this.detail = detail;
|
|
110
|
+
this.usage = usage;
|
|
13
111
|
}
|
|
14
|
-
return pathOf(context, name);
|
|
15
112
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
EROFS: "Read-only file system", ENOSPC: "No space left on device", EFBIG: "File too large",
|
|
20
|
-
EINVAL: "Invalid argument", EIO: "Input/output error", ENAMETOOLONG: "File name too long",
|
|
21
|
-
ENOTSUP: "Operation not supported", EOPNOTSUPP: "Operation not supported", ENOSYS: "Function not implemented",
|
|
22
|
-
};
|
|
23
|
-
function failure(operation, error) {
|
|
24
|
-
const code = codeOf(error);
|
|
25
|
-
return new TruncateError(`${operation}: ${code && errors[code] || (error instanceof Error ? error.message : String(error))}`);
|
|
113
|
+
function unicodeLocale(context) {
|
|
114
|
+
const locale = (context.env.LC_ALL || context.env.LC_CTYPE || context.env.LANG || "C").toLowerCase();
|
|
115
|
+
return locale.endsWith("utf-8") || locale.endsWith("utf8");
|
|
26
116
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
117
|
+
function quote(text, filename = false, unicode = false) {
|
|
118
|
+
const controls = { "\u0007": "\\a", "\b": "\\b", "\t": "\\t", "\n": "\\n", "\v": "\\v", "\f": "\\f", "\r": "\\r" };
|
|
119
|
+
const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
120
|
+
const units = [];
|
|
121
|
+
for (let offset = 0; offset < text.length;) {
|
|
122
|
+
const first = text.charCodeAt(offset);
|
|
123
|
+
let length = 1;
|
|
124
|
+
let point = first;
|
|
125
|
+
let valid = first < 128;
|
|
126
|
+
if (unicode && first >= 0xc2 && first <= 0xf4) {
|
|
127
|
+
const size = first < 0xe0 ? 2 : first < 0xf0 ? 3 : 4;
|
|
128
|
+
try {
|
|
129
|
+
point = decoder.decode(Uint8Array.from(text.slice(offset, offset + size), character => character.charCodeAt(0))).codePointAt(0);
|
|
130
|
+
length = size;
|
|
131
|
+
valid = true;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
valid = false;
|
|
135
|
+
}
|
|
36
136
|
}
|
|
37
|
-
|
|
38
|
-
|
|
137
|
+
let printable = valid && point >= 32 && point < 127;
|
|
138
|
+
if (valid && point >= 128) {
|
|
139
|
+
let low = 0, high = glibc231PrintableRanges.length / 2;
|
|
140
|
+
while (low < high) {
|
|
141
|
+
const middle = Math.floor((low + high) / 2);
|
|
142
|
+
if (point < glibc231PrintableRanges[middle * 2])
|
|
143
|
+
high = middle;
|
|
144
|
+
else if (point > glibc231PrintableRanges[middle * 2 + 1])
|
|
145
|
+
low = middle + 1;
|
|
146
|
+
else {
|
|
147
|
+
printable = true;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
39
151
|
}
|
|
152
|
+
const unit = text.slice(offset, offset + length);
|
|
153
|
+
const shellSpecial = '!"$&()*;<=>?[\\^`|'.includes(unit);
|
|
154
|
+
const positional = "#~".includes(unit) ? offset === 0 : "{}".includes(unit) && text.length === 1;
|
|
155
|
+
units.push({ text: unit, printable, shellSpecial: shellSpecial || positional,
|
|
156
|
+
cAndShellCompatible: printable && !shellSpecial && (!"#~{}".includes(unit) || positional) });
|
|
157
|
+
offset += length;
|
|
40
158
|
}
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
while (true) {
|
|
58
|
-
context.signal.throwIfAborted();
|
|
59
|
-
try {
|
|
60
|
-
const capabilities = await context.fs.capabilitiesFor(candidate, { signal: context.signal });
|
|
61
|
-
context.signal.throwIfAborted();
|
|
62
|
-
check(capabilities);
|
|
63
|
-
return;
|
|
159
|
+
if (filename && text.includes("'") && units.every(unit => unit.cAndShellCompatible))
|
|
160
|
+
return `"${text}"`;
|
|
161
|
+
const left = !filename && unicode ? "\xe2\x80\x98" : "'";
|
|
162
|
+
const right = !filename && unicode ? "\xe2\x80\x99" : "'";
|
|
163
|
+
let result = left;
|
|
164
|
+
let escaping = filename && text.includes("'") && units.length > 0 && !units[units.length - 1].printable;
|
|
165
|
+
for (const unit of units) {
|
|
166
|
+
if (filename && unit.text === "'") {
|
|
167
|
+
result += "'\\''";
|
|
168
|
+
escaping = false;
|
|
169
|
+
}
|
|
170
|
+
else if (!unit.printable) {
|
|
171
|
+
if (filename && !escaping)
|
|
172
|
+
result += "'$'";
|
|
173
|
+
escaping = true;
|
|
174
|
+
result += controls[unit.text] ?? Array.from(unit.text, character => `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}`).join("");
|
|
64
175
|
}
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
176
|
+
else {
|
|
177
|
+
if (filename && escaping)
|
|
178
|
+
result += "''";
|
|
179
|
+
escaping = false;
|
|
180
|
+
if (!filename && (unit.text === right || unit.text === "\\"))
|
|
181
|
+
result += "\\";
|
|
182
|
+
result += unit.text;
|
|
69
183
|
}
|
|
70
184
|
}
|
|
185
|
+
return result + right;
|
|
71
186
|
}
|
|
72
|
-
|
|
73
|
-
let
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
187
|
+
function number(text, unicode) {
|
|
188
|
+
let offset = 0;
|
|
189
|
+
const negative = text[0] === "-";
|
|
190
|
+
if (negative || text[0] === "+")
|
|
191
|
+
offset++;
|
|
192
|
+
const start = offset;
|
|
193
|
+
let value = 0n;
|
|
194
|
+
while (text.charCodeAt(offset) >= 48 && text.charCodeAt(offset) <= 57) {
|
|
195
|
+
value = value > -signedMinimum ? -signedMinimum + 1n : value * 10n + BigInt(text.charCodeAt(offset) - 48);
|
|
196
|
+
offset++;
|
|
197
|
+
}
|
|
198
|
+
const powers = { E: 6, g: 3, G: 3, k: 1, K: 1, m: 2, M: 2, P: 5, Q: 10, R: 9, t: 4, T: 4, Y: 8, Z: 7 };
|
|
199
|
+
let invalid = false;
|
|
200
|
+
if (offset === start) {
|
|
201
|
+
if (offset === 0 && Object.hasOwn(powers, text[0] ?? ""))
|
|
202
|
+
value = 1n;
|
|
203
|
+
else
|
|
204
|
+
invalid = true;
|
|
205
|
+
}
|
|
206
|
+
if (negative)
|
|
207
|
+
value = -value;
|
|
208
|
+
let overflow = value < signedMinimum || value > signedMaximum;
|
|
209
|
+
if (offset < text.length) {
|
|
210
|
+
const power = powers[text[offset]];
|
|
211
|
+
if (power === undefined)
|
|
212
|
+
invalid = true;
|
|
213
|
+
else {
|
|
214
|
+
offset++;
|
|
215
|
+
let base = 1024n;
|
|
216
|
+
if (text.slice(offset, offset + 2) === "iB")
|
|
217
|
+
offset += 2;
|
|
218
|
+
else if (text[offset] === "B" || text[offset] === "D") {
|
|
219
|
+
base = 1000n;
|
|
220
|
+
offset++;
|
|
221
|
+
}
|
|
222
|
+
value *= base ** BigInt(power);
|
|
223
|
+
overflow ||= value < signedMinimum || value > signedMaximum;
|
|
224
|
+
invalid ||= offset !== text.length;
|
|
82
225
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
226
|
+
}
|
|
227
|
+
if (invalid || overflow)
|
|
228
|
+
throw new TruncateDiagnostic(`Invalid number: ${quote(text, false, unicode)}${overflow && !invalid ? ": Value too large for defined data type" : ""}`);
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
function parse(context, argumentLimit, maximumArguments) {
|
|
232
|
+
if (context.args.length > maximumArguments)
|
|
233
|
+
throw new PublicDiagnostic("argument limit exceeded");
|
|
234
|
+
let total = 0;
|
|
235
|
+
for (const argument of context.args) {
|
|
236
|
+
if (context.argumentValues !== undefined) {
|
|
237
|
+
total += argument.length;
|
|
238
|
+
if (total > argumentLimit)
|
|
239
|
+
throw new PublicDiagnostic("argument limit exceeded");
|
|
240
|
+
continue;
|
|
86
241
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
await admit(context, path, existing === undefined);
|
|
93
|
-
context.signal.throwIfAborted();
|
|
94
|
-
if (existing === undefined) {
|
|
95
|
-
await context.fs.writeFile(path, new Uint8Array(), { ...fsOptions, flag: "a", mode: 0o666 });
|
|
96
|
-
context.signal.throwIfAborted();
|
|
97
|
-
existing = await context.fs.stat(path, fsOptions);
|
|
98
|
-
context.signal.throwIfAborted();
|
|
242
|
+
for (const character of argument) {
|
|
243
|
+
const point = character.codePointAt(0);
|
|
244
|
+
total += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
|
|
245
|
+
if (total > argumentLimit)
|
|
246
|
+
throw new PublicDiagnostic("argument limit exceeded");
|
|
99
247
|
}
|
|
100
|
-
stat = existing;
|
|
101
248
|
}
|
|
102
|
-
|
|
103
|
-
|
|
249
|
+
const carrier = getCommandArguments(context);
|
|
250
|
+
total = 0;
|
|
251
|
+
for (const value of carrier.values) {
|
|
252
|
+
total += shellValueByteLength(value);
|
|
253
|
+
if (total > argumentLimit)
|
|
254
|
+
throw new PublicDiagnostic("argument limit exceeded");
|
|
104
255
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
256
|
+
const args = context.args.map((_argument, index) => Array.from(carrier.bytes(index), byte => String.fromCharCode(byte)).join(""));
|
|
257
|
+
const settings = { modifier: "absolute", blocks: false, noCreate: false, operands: [] };
|
|
258
|
+
const unicode = unicodeLocale(context);
|
|
259
|
+
const long = { "no-create": "c", "io-blocks": "o", reference: "r", size: "s", help: "help", version: "version" };
|
|
260
|
+
const apply = (key, value = "") => {
|
|
261
|
+
if (key === "c")
|
|
262
|
+
settings.noCreate = true;
|
|
263
|
+
else if (key === "o")
|
|
264
|
+
settings.blocks = true;
|
|
265
|
+
else if (key === "r")
|
|
266
|
+
settings.reference = value;
|
|
267
|
+
else if (key === "help" || key === "version")
|
|
268
|
+
settings.information = key;
|
|
269
|
+
else {
|
|
270
|
+
let offset = 0;
|
|
271
|
+
while (value.charCodeAt(offset) === 32 || value.charCodeAt(offset) >= 9 && value.charCodeAt(offset) <= 13)
|
|
272
|
+
offset++;
|
|
273
|
+
const modifiers = { "<": "maximum", ">": "minimum", "/": "down", "%": "up" };
|
|
274
|
+
if (Object.hasOwn(modifiers, value[offset] ?? ""))
|
|
275
|
+
settings.modifier = modifiers[value[offset++]];
|
|
276
|
+
while (value.charCodeAt(offset) === 32 || value.charCodeAt(offset) >= 9 && value.charCodeAt(offset) <= 13)
|
|
277
|
+
offset++;
|
|
278
|
+
if (value[offset] === "+" || value[offset] === "-") {
|
|
279
|
+
if (settings.modifier !== "absolute")
|
|
280
|
+
throw new TruncateDiagnostic("multiple relative modifiers specified", true);
|
|
281
|
+
settings.modifier = "relative";
|
|
116
282
|
}
|
|
283
|
+
settings.size = number(value.slice(offset), unicode);
|
|
284
|
+
if ((settings.modifier === "down" || settings.modifier === "up") && settings.size === 0n)
|
|
285
|
+
throw new TruncateDiagnostic("division by zero");
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
let stopped = false;
|
|
289
|
+
for (let index = 0; index < args.length; index++) {
|
|
290
|
+
const argument = args[index];
|
|
291
|
+
if (stopped || argument === "-" || !argument.startsWith("-")) {
|
|
292
|
+
settings.operands.push(argument);
|
|
293
|
+
if (context.env.POSIXLY_CORRECT !== undefined)
|
|
294
|
+
stopped = true;
|
|
295
|
+
}
|
|
296
|
+
else if (argument === "--")
|
|
297
|
+
stopped = true;
|
|
298
|
+
else if (argument.startsWith("--")) {
|
|
299
|
+
const equals = argument.indexOf("=");
|
|
300
|
+
const name = argument.slice(2, equals < 0 ? undefined : equals);
|
|
301
|
+
const matches = Object.keys(long).filter(candidate => candidate.startsWith(name));
|
|
302
|
+
const selected = Object.hasOwn(long, name) ? name : matches.length === 1 ? matches[0] : undefined;
|
|
303
|
+
if (!selected)
|
|
304
|
+
throw new TruncateDiagnostic(matches.length > 1 ? `option '${argument}' is ambiguous; possibilities: ${matches.map(candidate => `'--${candidate}'`).join(" ")}` : `unrecognized option '${argument}'`, true);
|
|
305
|
+
const key = long[selected];
|
|
306
|
+
const required = key === "s" || key === "r";
|
|
307
|
+
if (!required && equals >= 0)
|
|
308
|
+
throw new TruncateDiagnostic(`option '--${selected}' doesn't allow an argument`, true);
|
|
309
|
+
const value = required ? equals < 0 ? args[++index] : argument.slice(equals + 1) : "";
|
|
310
|
+
if (value === undefined)
|
|
311
|
+
throw new TruncateDiagnostic(`option '--${selected}' requires an argument`, true);
|
|
312
|
+
apply(key, value);
|
|
117
313
|
}
|
|
118
|
-
if (blockSize === undefined)
|
|
119
|
-
throw new TruncateError(`cannot truncate ${quote(operand)}: Operation not supported (I/O block size is unavailable)`);
|
|
120
|
-
if (typeof blockSize !== "number" || !Number.isSafeInteger(blockSize) || blockSize <= 0)
|
|
121
|
-
throw new TruncateError(`cannot truncate ${quote(operand)}: Operation not supported (invalid I/O block size)`);
|
|
122
|
-
const scaled = size * BigInt(blockSize);
|
|
123
|
-
if (scaled > maximumSize || scaled < minimumSize)
|
|
124
|
-
throw new TruncateError(`overflow in ${size} * ${blockSize} byte blocks for file ${quote(operand)}`);
|
|
125
|
-
size = scaled;
|
|
126
|
-
}
|
|
127
|
-
if (args.mode !== "absolute") {
|
|
128
|
-
const base = reference ?? await measuredSize(context, path, stat, operand, options);
|
|
129
|
-
if (args.mode === "<")
|
|
130
|
-
size = base < size ? base : size;
|
|
131
|
-
else if (args.mode === ">")
|
|
132
|
-
size = base > size ? base : size;
|
|
133
|
-
else if (args.mode === "/")
|
|
134
|
-
size = base - base % size;
|
|
135
314
|
else {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
315
|
+
for (let position = 1; position < argument.length; position++) {
|
|
316
|
+
const key = argument[position];
|
|
317
|
+
if (!"cors".includes(key))
|
|
318
|
+
throw new TruncateDiagnostic(`invalid option -- '${key}'`, true);
|
|
319
|
+
let value = "";
|
|
320
|
+
if (key === "r" || key === "s") {
|
|
321
|
+
const supplied = argument.slice(position + 1) || args[++index];
|
|
322
|
+
if (supplied === undefined)
|
|
323
|
+
throw new TruncateDiagnostic(`option requires an argument -- '${key}'`, true);
|
|
324
|
+
value = supplied;
|
|
325
|
+
position = argument.length;
|
|
326
|
+
}
|
|
327
|
+
apply(key, value);
|
|
328
|
+
}
|
|
141
329
|
}
|
|
330
|
+
if (settings.information)
|
|
331
|
+
return settings;
|
|
142
332
|
}
|
|
143
|
-
if (size
|
|
144
|
-
size
|
|
145
|
-
if (size
|
|
146
|
-
throw new
|
|
333
|
+
if (settings.reference === undefined && settings.size === undefined)
|
|
334
|
+
throw new TruncateDiagnostic(`you must specify either ${quote("--size", false, unicode)} or ${quote("--reference", false, unicode)}`, true);
|
|
335
|
+
if (settings.reference !== undefined && settings.size !== undefined && settings.modifier === "absolute")
|
|
336
|
+
throw new TruncateDiagnostic(`you must specify a relative ${quote("--size", false, unicode)} with ${quote("--reference", false, unicode)}`, true);
|
|
337
|
+
if (settings.blocks && settings.size === undefined)
|
|
338
|
+
throw new TruncateDiagnostic(`${quote("--io-blocks", false, unicode)} was specified but ${quote("--size", false, unicode)} was not`, true);
|
|
339
|
+
if (!settings.operands.length)
|
|
340
|
+
throw new TruncateDiagnostic("missing file operand", true);
|
|
341
|
+
return settings;
|
|
342
|
+
}
|
|
343
|
+
function filePath(context, name) {
|
|
344
|
+
let decoded;
|
|
147
345
|
try {
|
|
148
|
-
|
|
149
|
-
await context.fs.truncate(path, Number(size), fsOptions);
|
|
150
|
-
context.signal.throwIfAborted();
|
|
346
|
+
decoded = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(Uint8Array.from(name, character => character.charCodeAt(0)));
|
|
151
347
|
}
|
|
152
348
|
catch (error) {
|
|
153
|
-
|
|
349
|
+
if (error instanceof TypeError)
|
|
350
|
+
throw new FsError("ENOTSUP");
|
|
351
|
+
throw error;
|
|
154
352
|
}
|
|
353
|
+
return pathOf(context, decoded);
|
|
155
354
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
355
|
+
function ioError(error, label, retained) {
|
|
356
|
+
const code = error instanceof FsError ? error.code : retained ? undefined : codeOf(error);
|
|
357
|
+
if (!code)
|
|
358
|
+
return error;
|
|
359
|
+
const descriptions = {
|
|
360
|
+
ENOENT: "No such file or directory", EACCES: "Permission denied", EPERM: "Operation not permitted", EISDIR: "Is a directory",
|
|
361
|
+
ENOTDIR: "Not a directory", EBADF: "Bad file descriptor", EIO: "Input/output error", ENOSPC: "No space left on device",
|
|
362
|
+
EPIPE: "Broken pipe", ESPIPE: "Illegal seek", ELOOP: "Too many levels of symbolic links", ENAMETOOLONG: "File name too long", ENOTSUP: "Operation not supported",
|
|
363
|
+
EFBIG: "File too large", EINVAL: "Invalid argument", EROFS: "Read-only file system", EMFILE: "Too many open files",
|
|
163
364
|
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
if (
|
|
172
|
-
|
|
365
|
+
return descriptions[code] ? new TruncateDiagnostic(`${label}: ${descriptions[code]}`) : error;
|
|
366
|
+
}
|
|
367
|
+
function interrupt(pending, signal) {
|
|
368
|
+
return new Promise((resolve, reject) => {
|
|
369
|
+
const abort = () => { signal.removeEventListener("abort", abort); reject(signal.reason); };
|
|
370
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
371
|
+
pending.then(value => { signal.removeEventListener("abort", abort); resolve(value); }, error => { signal.removeEventListener("abort", abort); reject(error); });
|
|
372
|
+
if (signal.aborted)
|
|
373
|
+
abort();
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
function observedSize(stat, label) {
|
|
377
|
+
if (stat.type !== "file")
|
|
378
|
+
throw new TruncateDiagnostic(`cannot get the size of ${label}: Operation not supported`);
|
|
379
|
+
if (!Number.isSafeInteger(stat.size))
|
|
380
|
+
throw new PublicDiagnostic("file size is not a safe integer");
|
|
381
|
+
if (stat.size < 0)
|
|
382
|
+
throw new TruncateDiagnostic(`${label} has unusable, apparently negative size`);
|
|
383
|
+
return BigInt(stat.size);
|
|
384
|
+
}
|
|
385
|
+
function createDefinition(retained, options = {}) {
|
|
386
|
+
const configured = settings(options);
|
|
387
|
+
const configuredUmask = options.umask === undefined ? undefined : configured.umask;
|
|
388
|
+
const creationMode = (context) => {
|
|
389
|
+
const umask = configuredUmask ?? Reflect.get(context.fs, creationUmask);
|
|
390
|
+
return 0o666 & ~(typeof umask === "number" ? umask : configured.umask);
|
|
391
|
+
};
|
|
392
|
+
const argumentLimit = configured.limits.maxArgumentBytes;
|
|
393
|
+
const outputMaximum = configured.limits.maxOutputBytes;
|
|
394
|
+
const definition = { name: "truncate", runtimeIdentity: commandRuntimeIdentity, filesystemRequirements: retained ? [{ id: "resize", description: "Resize writable VFS entries through retained handles or atomic operations", capabilities: [], anyOf: [["retainedResize"], ["atomicResize"]], mutates: true }] : [{ id: "resize", description: "Resize existing files", capabilities: ["stat", "truncate"], mutates: true }, { id: "create", description: "Create missing files without replacing existing bytes", capabilities: ["stat", "truncate", "append"], mutates: true }], async execute(context) {
|
|
395
|
+
context.signal.throwIfAborted();
|
|
396
|
+
const retirementController = new AbortController();
|
|
397
|
+
const invocationSignal = retained || !context.registerCleanup ? context.signal : AbortSignal.any([context.signal, retirementController.signal]);
|
|
398
|
+
const root = createOutputOperation({ signal: invocationSignal, registerCleanup(cleanup) {
|
|
399
|
+
let retirement;
|
|
400
|
+
context.registerCleanup?.(() => {
|
|
401
|
+
if (!retained)
|
|
402
|
+
retirementController.abort(new Error("truncate invocation is closed"));
|
|
403
|
+
return retirement ??= Promise.resolve(cleanup()).catch(() => { });
|
|
404
|
+
});
|
|
405
|
+
} }, { async write() { throw new Error("resource scope has no output destination"); } });
|
|
406
|
+
const signal = root.signal;
|
|
407
|
+
const stdout = root.child(context.stdout), stderr = root.child(context.stderr);
|
|
408
|
+
const closures = new WeakMap();
|
|
409
|
+
const active = new WeakMap();
|
|
410
|
+
const closeHandle = (handle) => {
|
|
411
|
+
let closing = closures.get(handle);
|
|
412
|
+
if (!closing) {
|
|
413
|
+
closing = Promise.resolve().then(async () => { await active.get(handle); await handle.close(); });
|
|
414
|
+
closures.set(handle, closing);
|
|
415
|
+
}
|
|
416
|
+
return closing;
|
|
417
|
+
};
|
|
418
|
+
const closeReference = async (handle) => {
|
|
419
|
+
try {
|
|
420
|
+
await closeHandle(handle);
|
|
421
|
+
}
|
|
422
|
+
catch { /* Reference close failures are nonfatal GNU compatibility behavior. */ }
|
|
423
|
+
};
|
|
424
|
+
const useHandle = (handle, start) => root.acquire(signal => {
|
|
425
|
+
let finish;
|
|
426
|
+
active.set(handle, new Promise(resolve => { finish = resolve; }));
|
|
427
|
+
try {
|
|
428
|
+
return Promise.resolve(start(signal)).finally(finish);
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
finish();
|
|
432
|
+
throw error;
|
|
433
|
+
}
|
|
434
|
+
}, () => { });
|
|
435
|
+
const seekSize = async (handle, label) => {
|
|
436
|
+
try {
|
|
437
|
+
const end = await useHandle(handle, signal => {
|
|
438
|
+
const seekEnd = handle.seekEnd;
|
|
439
|
+
signal.throwIfAborted();
|
|
440
|
+
if (typeof seekEnd !== "function")
|
|
441
|
+
throw new FsError("ENOTSUP");
|
|
442
|
+
return Reflect.apply(seekEnd, handle, [{ signal }]);
|
|
443
|
+
});
|
|
444
|
+
if (typeof end !== "bigint" || end < 0n || end > signedMaximum)
|
|
445
|
+
throw new PublicDiagnostic("invalid retained end-seek offset");
|
|
446
|
+
return end;
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
signal.throwIfAborted();
|
|
450
|
+
throw ioError(error, `cannot get the size of ${label}`, retained);
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
const openPortable = async (path, label, noCreate) => {
|
|
454
|
+
const fs = context.fs;
|
|
455
|
+
let stat;
|
|
456
|
+
try {
|
|
457
|
+
stat = await root.acquire(signal => fs.stat(path, { signal }), () => { });
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
signal.throwIfAborted();
|
|
461
|
+
if (!(error instanceof FsError) || error.code !== "ENOENT")
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
464
|
+
if (stat === undefined && noCreate)
|
|
465
|
+
throw new FsError("ENOENT");
|
|
466
|
+
if (stat?.type === "directory")
|
|
467
|
+
throw new FsError("EISDIR");
|
|
468
|
+
const check = (capabilities) => {
|
|
469
|
+
if (capabilities.readOnly)
|
|
470
|
+
throw new FsError("EROFS");
|
|
471
|
+
if (capabilities.truncate === false || typeof fs.truncate !== "function" || capabilities.stat === false || stat === undefined && capabilities.append === false)
|
|
472
|
+
throw new FsError("ENOTSUP");
|
|
473
|
+
};
|
|
474
|
+
check(fs.capabilities);
|
|
475
|
+
if (fs.capabilitiesFor) {
|
|
476
|
+
let candidate = path;
|
|
477
|
+
while (true) {
|
|
478
|
+
try {
|
|
479
|
+
check(await root.acquire(signal => fs.capabilitiesFor(candidate, { signal }), () => { }));
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
signal.throwIfAborted();
|
|
484
|
+
if (!(error instanceof FsError) || error.code !== "ENOENT" || candidate === "/")
|
|
485
|
+
throw error;
|
|
486
|
+
candidate = dirname(candidate);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (stat === undefined) {
|
|
491
|
+
await root.acquire(signal => fs.writeFile(path, new Uint8Array(), { flag: "a", mode: creationMode(context), signal }), () => { });
|
|
492
|
+
stat = await root.acquire(signal => fs.stat(path, { signal }), () => { });
|
|
493
|
+
}
|
|
494
|
+
const observed = stat;
|
|
495
|
+
return { stat: async () => observed,
|
|
496
|
+
async truncate(length, options) { await fs.truncate(path, length, !context.registerCleanup ? { ...options, signal: context.signal } : options); },
|
|
497
|
+
async seekEnd() {
|
|
498
|
+
if (!options.seekEnd)
|
|
499
|
+
throw new TruncateDiagnostic(`cannot get the size of ${label}: Operation not supported (seek-end measurement is unavailable)`);
|
|
500
|
+
const measured = await options.seekEnd(path, observed, { ...context, signal });
|
|
501
|
+
if (!Number.isSafeInteger(measured) || measured < 0)
|
|
502
|
+
throw new TruncateDiagnostic(`${label} has unusable size: Operation not supported`);
|
|
503
|
+
return BigInt(measured);
|
|
504
|
+
},
|
|
505
|
+
async close() { }, };
|
|
506
|
+
};
|
|
507
|
+
let outputBytes = 0;
|
|
508
|
+
const outputLimit = new PublicDiagnostic("truncate output limit exceeded");
|
|
509
|
+
const emit = async (text, error = true, utf8 = false) => {
|
|
510
|
+
const used = outputBytes;
|
|
511
|
+
if (text.length > outputMaximum - used)
|
|
512
|
+
throw outputLimit;
|
|
513
|
+
let length = text.length;
|
|
514
|
+
if (utf8) {
|
|
515
|
+
length = 0;
|
|
516
|
+
let scanned = 0;
|
|
517
|
+
for (const character of text) {
|
|
518
|
+
if (++scanned % 65536 === 0)
|
|
519
|
+
await yieldTurn(signal);
|
|
520
|
+
const point = character.codePointAt(0);
|
|
521
|
+
length += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
|
|
522
|
+
if (length > outputMaximum - used)
|
|
523
|
+
throw outputLimit;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
outputBytes += length;
|
|
527
|
+
const encoder = new TextEncoder();
|
|
528
|
+
for (let offset = 0; offset < text.length;) {
|
|
529
|
+
let end = Math.min(text.length, offset + (utf8 ? 16384 : 65536));
|
|
530
|
+
if (utf8 && end < text.length && text.charCodeAt(end - 1) >= 0xd800 && text.charCodeAt(end - 1) <= 0xdbff)
|
|
531
|
+
end--;
|
|
532
|
+
const chunk = text.slice(offset, end);
|
|
533
|
+
await writeBytes(error ? stderr.output : stdout.output, utf8 ? encoder.encode(chunk) : Uint8Array.from(chunk, character => character.charCodeAt(0)), signal);
|
|
534
|
+
offset = end;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
const report = async (error) => {
|
|
538
|
+
signal.throwIfAborted();
|
|
539
|
+
if (error instanceof TruncateError) {
|
|
540
|
+
await emit(`truncate: ${error.message}\n${error.usage ? "Try 'truncate --help' for more information.\n" : ""}`, true, !error.raw);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (!(error instanceof TruncateDiagnostic))
|
|
544
|
+
throw error;
|
|
545
|
+
await emit(`truncate: ${error.detail}\n${error.usage ? "Try 'truncate --help' for more information.\n" : ""}`);
|
|
546
|
+
};
|
|
547
|
+
let outcome;
|
|
173
548
|
try {
|
|
174
|
-
|
|
549
|
+
let settings;
|
|
550
|
+
if (retained)
|
|
551
|
+
settings = parse(context, argumentLimit, configured.limits.maxArguments);
|
|
552
|
+
else {
|
|
553
|
+
const values = getCommandArguments(context);
|
|
554
|
+
let total = 0;
|
|
555
|
+
for (const value of values.values) {
|
|
556
|
+
total += shellValueByteLength(value);
|
|
557
|
+
if (total > argumentLimit)
|
|
558
|
+
throw new FsError("EFBIG", { message: "argument byte limit exceeded" });
|
|
559
|
+
}
|
|
560
|
+
if (values.values.length > configured.limits.maxArguments)
|
|
561
|
+
throw new PublicDiagnostic("argument count limit exceeded");
|
|
562
|
+
const parsed = parseArguments(context.args, Object.hasOwn(context.env, "POSIXLY_CORRECT"), values);
|
|
563
|
+
const modifiers = { absolute: "absolute", relative: "relative", "<": "maximum", ">": "minimum", "/": "down", "%": "up" };
|
|
564
|
+
settings = { size: parsed.size, reference: parsed.reference, modifier: modifiers[parsed.mode], blocks: parsed.ioBlocks, noCreate: parsed.noCreate, operands: [...parsed.files], information: parsed.display };
|
|
565
|
+
}
|
|
566
|
+
const unicode = unicodeLocale(context);
|
|
567
|
+
if (settings.information) {
|
|
568
|
+
await emit(settings.information === "help" ? retained ? helpText : portableHelp : retained ? "truncate (virtual-bash)\n" : "truncate (safe-bash; GNU coreutils 9.7 semantics)\n", false);
|
|
569
|
+
outcome = { exitCode: 0 };
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
let reference;
|
|
573
|
+
if (settings.reference !== undefined) {
|
|
574
|
+
const label = retained ? quote(settings.reference, true, unicode) : portableQuote(settings.reference);
|
|
575
|
+
let stat;
|
|
576
|
+
try {
|
|
577
|
+
const filesystem = context.fs;
|
|
578
|
+
const path = filePath(context, settings.reference);
|
|
579
|
+
const referenceStat = filesystem.stat;
|
|
580
|
+
signal.throwIfAborted();
|
|
581
|
+
stat = retained ? await interrupt(Promise.resolve(Reflect.apply(referenceStat, filesystem, [path, { signal }])), signal) : await root.acquire(signal => Reflect.apply(referenceStat, filesystem, [path, { signal }]), () => { });
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
signal.throwIfAborted();
|
|
585
|
+
throw ioError(error, `cannot stat ${label}`, retained);
|
|
586
|
+
}
|
|
587
|
+
if (stat.type === "file" || !retained && stat.type === "symlink")
|
|
588
|
+
reference = observedSize({ ...stat, type: "file" }, label);
|
|
589
|
+
else if (options.seekEnd) {
|
|
590
|
+
signal.throwIfAborted();
|
|
591
|
+
try {
|
|
592
|
+
const measured = await root.acquire(signal => options.seekEnd(filePath(context, settings.reference), stat, { ...context, signal }), () => { });
|
|
593
|
+
signal.throwIfAborted();
|
|
594
|
+
if (!Number.isSafeInteger(measured) || measured < 0)
|
|
595
|
+
throw new FsError("EINVAL");
|
|
596
|
+
reference = BigInt(measured);
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
signal.throwIfAborted();
|
|
600
|
+
throw ioError(error, `cannot get the size of ${label}`, retained);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
else if (!retained) {
|
|
604
|
+
throw new TruncateDiagnostic(`cannot get the size of ${label}: Operation not supported (seek-end measurement is unavailable)`);
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
let handle;
|
|
608
|
+
try {
|
|
609
|
+
const filesystem = context.fs;
|
|
610
|
+
const path = filePath(context, settings.reference);
|
|
611
|
+
const capabilitiesFor = filesystem.capabilitiesFor;
|
|
612
|
+
signal.throwIfAborted();
|
|
613
|
+
const capabilities = await interrupt(Promise.resolve((capabilitiesFor == null ? undefined : Reflect.apply(capabilitiesFor, filesystem, [path, { allowDirectory: true, signal }])) ?? filesystem.capabilities), signal);
|
|
614
|
+
signal.throwIfAborted();
|
|
615
|
+
const retainedRead = capabilities.retainedRead;
|
|
616
|
+
signal.throwIfAborted();
|
|
617
|
+
if (retainedRead !== true)
|
|
618
|
+
throw new FsError("ENOTSUP");
|
|
619
|
+
const openReadFile = filesystem.openReadFile;
|
|
620
|
+
signal.throwIfAborted();
|
|
621
|
+
if (typeof openReadFile !== "function")
|
|
622
|
+
throw new FsError("ENOTSUP");
|
|
623
|
+
handle = await root.acquire(signal => Reflect.apply(openReadFile, filesystem, [path, { allowDirectory: true, signal }]), closeReference);
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
signal.throwIfAborted();
|
|
627
|
+
throw ioError(error, `cannot get the size of ${label}`, retained);
|
|
628
|
+
}
|
|
629
|
+
try {
|
|
630
|
+
reference = await seekSize(handle, label);
|
|
631
|
+
}
|
|
632
|
+
finally {
|
|
633
|
+
await closeReference(handle);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
let exitCode = 0;
|
|
638
|
+
for (let index = 0; index < settings.operands.length; index++) {
|
|
639
|
+
if (index % 64 === 0)
|
|
640
|
+
await yieldTurn(signal);
|
|
641
|
+
signal.throwIfAborted();
|
|
642
|
+
if (index >= configured.limits.maxEntries)
|
|
643
|
+
throw new PublicDiagnostic("entry limit exceeded");
|
|
644
|
+
const name = settings.operands[index];
|
|
645
|
+
const label = retained ? quote(name, true, unicode) : portableQuote(name);
|
|
646
|
+
let handle;
|
|
647
|
+
try {
|
|
648
|
+
const path = filePath(context, name);
|
|
649
|
+
const filesystem = context.fs;
|
|
650
|
+
if (!retained) {
|
|
651
|
+
handle = await openPortable(path, label, settings.noCreate);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
const capabilitiesFor = filesystem.capabilitiesFor;
|
|
655
|
+
signal.throwIfAborted();
|
|
656
|
+
const capabilities = await interrupt(Promise.resolve((capabilitiesFor == null ? undefined : Reflect.apply(capabilitiesFor, filesystem, [path, { create: !settings.noCreate, signal }])) ?? filesystem.capabilities), signal);
|
|
657
|
+
signal.throwIfAborted();
|
|
658
|
+
const readOnly = capabilities.readOnly;
|
|
659
|
+
signal.throwIfAborted();
|
|
660
|
+
if (readOnly === true)
|
|
661
|
+
throw new FsError("EROFS");
|
|
662
|
+
const retainedResize = capabilities.retainedResize;
|
|
663
|
+
signal.throwIfAborted();
|
|
664
|
+
if (retainedResize !== true && capabilities.atomicResize === true) {
|
|
665
|
+
signal.throwIfAborted();
|
|
666
|
+
const resize = filesystem.resizeFile;
|
|
667
|
+
signal.throwIfAborted();
|
|
668
|
+
if (typeof resize !== "function")
|
|
669
|
+
throw new FsError("ENOTSUP");
|
|
670
|
+
const operation = { size: settings.size ?? reference, modifier: settings.modifier,
|
|
671
|
+
...(reference === undefined ? {} : { referenceSize: reference }), ioBlocks: settings.blocks };
|
|
672
|
+
await root.acquire(signal => Reflect.apply(resize, filesystem, [path, operation,
|
|
673
|
+
{ create: !settings.noCreate, mode: creationMode(context), signal }]), () => { });
|
|
674
|
+
signal.throwIfAborted();
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
if (retainedResize !== true)
|
|
678
|
+
throw new FsError("ENOTSUP");
|
|
679
|
+
const openResizeFile = filesystem.openResizeFile;
|
|
680
|
+
signal.throwIfAborted();
|
|
681
|
+
if (typeof openResizeFile !== "function")
|
|
682
|
+
throw new FsError("ENOTSUP");
|
|
683
|
+
handle = await root.acquire(signal => Reflect.apply(openResizeFile, filesystem, [path, { create: !settings.noCreate, mode: creationMode(context), signal }]), closeHandle);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
catch (error) {
|
|
687
|
+
signal.throwIfAborted();
|
|
688
|
+
if (settings.noCreate && error instanceof FsError && error.code === "ENOENT")
|
|
689
|
+
continue;
|
|
690
|
+
await report(ioError(error, `cannot open ${label} for writing`, retained));
|
|
691
|
+
exitCode = 1;
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
let size = settings.size ?? reference;
|
|
696
|
+
let stat;
|
|
697
|
+
if (!retained || settings.blocks || settings.modifier !== "absolute" && reference === undefined) {
|
|
698
|
+
try {
|
|
699
|
+
stat = await useHandle(handle, signal => {
|
|
700
|
+
const stat = handle.stat;
|
|
701
|
+
signal.throwIfAborted();
|
|
702
|
+
return Reflect.apply(stat, handle, [{ signal }]);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
catch (error) {
|
|
706
|
+
signal.throwIfAborted();
|
|
707
|
+
throw ioError(error, `cannot fstat ${label}`, retained);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (settings.blocks) {
|
|
711
|
+
let hint;
|
|
712
|
+
try {
|
|
713
|
+
hint = stat.ioBlockSize ?? (retained ? stat.preferredIoBlockSize : undefined) ?? await root.acquire(signal => options.ioBlockSize?.(filePath(context, name), stat, { ...context, signal }), () => { });
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
signal.throwIfAborted();
|
|
717
|
+
throw ioError(error, `cannot get the I/O block size of ${label}`, retained);
|
|
718
|
+
}
|
|
719
|
+
signal.throwIfAborted();
|
|
720
|
+
if (!retained && hint === undefined)
|
|
721
|
+
throw new TruncateDiagnostic(`cannot truncate ${label}: Operation not supported (I/O block size is unavailable)`);
|
|
722
|
+
if (!retained && (!Number.isSafeInteger(hint) || hint <= 0))
|
|
723
|
+
throw new TruncateDiagnostic(`cannot truncate ${label}: Operation not supported (invalid I/O block size)`);
|
|
724
|
+
if (hint === undefined || !Number.isSafeInteger(hint) || hint <= 0)
|
|
725
|
+
throw new TruncateDiagnostic(`cannot get the I/O block size of ${label}: Operation not supported`);
|
|
726
|
+
const block = BigInt(hint);
|
|
727
|
+
if (size < signedMinimum / block || size > signedMaximum / block)
|
|
728
|
+
throw new TruncateDiagnostic(`overflow in ${size} * ${block} byte blocks for file ${label}`);
|
|
729
|
+
size *= block;
|
|
730
|
+
}
|
|
731
|
+
if (settings.modifier !== "absolute") {
|
|
732
|
+
const base = reference ?? (stat.type === "file" ? observedSize(stat, label) : await seekSize(handle, label));
|
|
733
|
+
if (settings.modifier === "minimum")
|
|
734
|
+
size = base > size ? base : size;
|
|
735
|
+
else if (settings.modifier === "maximum")
|
|
736
|
+
size = base < size ? base : size;
|
|
737
|
+
else if (settings.modifier === "down")
|
|
738
|
+
size = base / size * size;
|
|
739
|
+
else if (settings.modifier === "up") {
|
|
740
|
+
size = (base + size - 1n) / size * size;
|
|
741
|
+
if (size > signedMaximum)
|
|
742
|
+
throw new TruncateDiagnostic(retained ? `overflow rounding up size of file ${label}` : `overflow extending size of file ${label}`);
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
if (size > signedMaximum - base)
|
|
746
|
+
throw new TruncateDiagnostic(`overflow extending size of file ${label}`);
|
|
747
|
+
size += base;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (size < 0n)
|
|
751
|
+
size = 0n;
|
|
752
|
+
try {
|
|
753
|
+
if (size > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
754
|
+
if (!retained)
|
|
755
|
+
throw new TruncateDiagnostic(`failed to truncate ${label} at ${size} bytes: Operation not supported (size exceeds exact filesystem integer range)`);
|
|
756
|
+
throw new FsError("EFBIG");
|
|
757
|
+
}
|
|
758
|
+
await useHandle(handle, signal => {
|
|
759
|
+
const truncate = handle.truncate;
|
|
760
|
+
signal.throwIfAborted();
|
|
761
|
+
return Reflect.apply(truncate, handle, [Number(size), { signal }]);
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
signal.throwIfAborted();
|
|
766
|
+
throw ioError(error, `failed to truncate ${label} at ${size} bytes`, retained);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
catch (error) {
|
|
770
|
+
await report(error);
|
|
771
|
+
exitCode = 1;
|
|
772
|
+
}
|
|
773
|
+
try {
|
|
774
|
+
await closeHandle(handle);
|
|
775
|
+
}
|
|
776
|
+
catch (error) {
|
|
777
|
+
await report(ioError(error, `failed to close ${label}`, retained));
|
|
778
|
+
exitCode = 1;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
outcome = { exitCode };
|
|
782
|
+
}
|
|
175
783
|
}
|
|
176
784
|
catch (error) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
exitCode = 1;
|
|
196
|
-
}
|
|
197
|
-
if (++completed % 64 === 0)
|
|
198
|
-
await yieldTurn(context.signal);
|
|
199
|
-
}
|
|
200
|
-
return { exitCode };
|
|
201
|
-
}
|
|
202
|
-
export function evalSyncTruncate(opArgs, readFileSync, writeFileSync) {
|
|
203
|
-
try {
|
|
204
|
-
const args = parseArguments(opArgs, false);
|
|
205
|
-
if (args.display === "help")
|
|
206
|
-
return helpText;
|
|
207
|
-
if (args.display === "version")
|
|
208
|
-
return "truncate (safe-bash; GNU coreutils 9.7 semantics)\n";
|
|
209
|
-
if (!writeFileSync || args.files.length === 0)
|
|
210
|
-
return undefined;
|
|
211
|
-
const blockFactor = args.ioBlocks ? 4096n : 1n;
|
|
212
|
-
let refSize;
|
|
213
|
-
if (args.reference !== undefined) {
|
|
214
|
-
const refBytes = readFileSync?.(args.reference);
|
|
215
|
-
if (!refBytes)
|
|
216
|
-
return undefined;
|
|
217
|
-
refSize = BigInt(refBytes.length);
|
|
218
|
-
}
|
|
219
|
-
for (const file of args.files) {
|
|
220
|
-
const existing = readFileSync?.(file);
|
|
221
|
-
if (!existing && args.noCreate)
|
|
222
|
-
continue;
|
|
223
|
-
const curSize = BigInt(existing?.length ?? 0);
|
|
224
|
-
const base = refSize ?? curSize;
|
|
225
|
-
const scaledSize = args.size === undefined ? undefined : args.size * blockFactor;
|
|
226
|
-
let target;
|
|
227
|
-
if (scaledSize === undefined)
|
|
228
|
-
target = refSize;
|
|
229
|
-
else if (args.mode === "absolute")
|
|
230
|
-
target = scaledSize;
|
|
231
|
-
else if (args.mode === "relative")
|
|
232
|
-
target = base + scaledSize;
|
|
233
|
-
else if (args.mode === "<")
|
|
234
|
-
target = base < scaledSize ? base : scaledSize;
|
|
235
|
-
else if (args.mode === ">")
|
|
236
|
-
target = base > scaledSize ? base : scaledSize;
|
|
237
|
-
else if (args.mode === "/")
|
|
238
|
-
target = (base / scaledSize) * scaledSize;
|
|
239
|
-
else
|
|
240
|
-
target = ((base + scaledSize - 1n) / scaledSize) * scaledSize;
|
|
241
|
-
if (target < 0n)
|
|
242
|
-
target = 0n;
|
|
243
|
-
if (target > 1048576n)
|
|
244
|
-
return undefined;
|
|
245
|
-
const n = Number(target);
|
|
246
|
-
const out = new Uint8Array(n);
|
|
247
|
-
if (existing && existing.length > 0) {
|
|
248
|
-
out.set(existing.subarray(0, Math.min(existing.length, n)));
|
|
249
|
-
}
|
|
250
|
-
if (!writeFileSync(file, out))
|
|
251
|
-
return undefined;
|
|
252
|
-
}
|
|
253
|
-
return "";
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
return undefined;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
syncCommandEvaluators.evalSyncTruncate = evalSyncTruncate;
|
|
260
|
-
export function createTruncateCommand(options = {}) {
|
|
261
|
-
const maximum = options.limits?.maxArgumentBytes ?? Infinity;
|
|
262
|
-
if (maximum !== Infinity && (!Number.isSafeInteger(maximum) || maximum < 1))
|
|
263
|
-
throw new RangeError("maxArgumentBytes must be positive");
|
|
264
|
-
const settings = { ...options };
|
|
265
|
-
const def = {
|
|
266
|
-
name: "truncate",
|
|
267
|
-
runtimeIdentity: commandRuntimeIdentity,
|
|
268
|
-
filesystemRequirements: [
|
|
269
|
-
{ id: "resize", description: "Resize existing files", capabilities: ["stat", "truncate"], mutates: true },
|
|
270
|
-
{ id: "create", description: "Create missing files without replacing existing bytes", capabilities: ["stat", "truncate", "append"], mutates: true },
|
|
271
|
-
],
|
|
272
|
-
async execute(context) {
|
|
273
|
-
let total = 0;
|
|
274
|
-
for (const value of getCommandArguments(context).values) {
|
|
275
|
-
total += shellValueByteLength(value);
|
|
276
|
-
if (total > maximum)
|
|
277
|
-
throw new FsError("EFBIG", { message: "argument byte limit exceeded" });
|
|
785
|
+
try {
|
|
786
|
+
signal.throwIfAborted();
|
|
787
|
+
if (error === outputLimit)
|
|
788
|
+
outcome = { exitCode: 1 };
|
|
789
|
+
else if (error instanceof TruncateDiagnostic || error instanceof TruncateError) {
|
|
790
|
+
await report(error);
|
|
791
|
+
outcome = { exitCode: 1 };
|
|
792
|
+
}
|
|
793
|
+
else if (error instanceof PublicDiagnostic) {
|
|
794
|
+
await emit(`truncate: ${publicDiagnosticMessage(error, context.onInternalError)}\n`, true, true);
|
|
795
|
+
outcome = { exitCode: 1 };
|
|
796
|
+
}
|
|
797
|
+
else
|
|
798
|
+
outcome = { error };
|
|
799
|
+
}
|
|
800
|
+
catch (failure) {
|
|
801
|
+
outcome = failure === outputLimit ? { exitCode: 1 } : { error: failure };
|
|
802
|
+
}
|
|
278
803
|
}
|
|
279
|
-
const controller = new AbortController();
|
|
280
|
-
let pending;
|
|
281
|
-
let cleanup;
|
|
282
|
-
const close = () => {
|
|
283
|
-
controller.abort(new Error("truncate invocation is closed"));
|
|
284
|
-
return cleanup ??= (async () => { await pending?.catch(() => { }); })();
|
|
285
|
-
};
|
|
286
|
-
context.registerCleanup?.(close);
|
|
287
|
-
const invocation = context.registerCleanup ? { ...context, signal: AbortSignal.any([context.signal, controller.signal]) } : context;
|
|
288
804
|
try {
|
|
289
|
-
|
|
290
|
-
return await pending;
|
|
805
|
+
await root.close();
|
|
291
806
|
}
|
|
292
|
-
|
|
293
|
-
|
|
807
|
+
catch (error) {
|
|
808
|
+
if (!("error" in outcome) && outcome.exitCode === 0)
|
|
809
|
+
outcome = { error };
|
|
294
810
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
export function createTruncateCommands(options = {}) {
|
|
302
|
-
return [createTruncateCommand(options)];
|
|
811
|
+
context.signal.throwIfAborted();
|
|
812
|
+
if ("error" in outcome)
|
|
813
|
+
throw outcome.error;
|
|
814
|
+
return outcome;
|
|
815
|
+
} };
|
|
816
|
+
return registerDefaultExecutor(definition, options);
|
|
303
817
|
}
|
|
818
|
+
// Portable callers retain the path-based filesystem contract; shell defaults require retained identity.
|
|
819
|
+
export const createTruncateCommand = createDefinition.bind(undefined, false);
|
|
820
|
+
export const truncateCommand = createDefinition.bind(undefined, true);
|
|
821
|
+
export { evalSyncTruncate } from "./sync.js";
|
|
822
|
+
export function createTruncateCommands(options = {}) { return [createTruncateCommand(options)]; }
|
|
304
823
|
export function truncateCommands(options = {}) {
|
|
305
|
-
const commands = createTruncateCommands(options)
|
|
824
|
+
const commands = createTruncateCommands(options);
|
|
306
825
|
return { name: "truncate-commands", setup(host) {
|
|
307
|
-
if (!replace)
|
|
308
|
-
for (const command of commands)
|
|
826
|
+
if (!options.replace)
|
|
827
|
+
for (const command of commands)
|
|
309
828
|
if (host.commands.has(command.name))
|
|
310
829
|
throw new Error(`Command already registered: ${command.name}`);
|
|
311
|
-
}
|
|
312
830
|
for (const command of commands)
|
|
313
|
-
host.commands.register(command, { replace });
|
|
831
|
+
host.commands.register(command, { replace: options.replace ?? false });
|
|
314
832
|
} };
|
|
315
833
|
}
|