@poe-platform/safe-bash 0.1.782 → 0.1.784
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 +40 -0
- package/dist/office-package/zip-sync.d.ts +2 -0
- package/dist/office-package/zip-sync.js +111 -0
- package/dist/safe-bash/chunks/chunk-4FDQJUFW.js +3464 -0
- package/dist/safe-bash/chunks/csvkit-K55OYAQC.js +1564 -0
- package/dist/safe-bash/chunks/ffmpeg-BEFTQ6DZ.js +60 -0
- package/dist/safe-bash/chunks/gh-HQWOWLWE.js +41 -0
- package/dist/safe-bash/chunks/git-UFNPAOYZ.js +52 -0
- package/dist/safe-bash/chunks/imagemagick-53BMHH6D.js +134 -0
- package/dist/safe-bash/chunks/implementation-QUTAAYMT.js +105 -0
- package/dist/safe-bash/chunks/pdfimages-4OYI6FLG.js +73 -0
- package/dist/safe-bash/chunks/pdfinfo-I7U6TQPP.js +153 -0
- package/dist/safe-bash/chunks/pdftk-SUA6FMHI.js +79 -0
- package/dist/safe-bash/chunks/pdftoppm-4C5DGEWX.js +139 -0
- package/dist/safe-bash/chunks/pdftotext-Y4WI225Y.js +118 -0
- package/dist/safe-bash/chunks/qpdf-IORB4RV5.js +68 -0
- package/dist/safe-bash/chunks/sips-WHAMJFEU.js +77 -0
- package/dist/safe-bash/chunks/soffice-SYEK6WJS.js +89 -0
- package/dist/safe-bash/chunks/wkhtmltopdf-ZIICWJLF.js +85 -0
- package/dist/safe-bash/command-chunks/chunk-2LP3VMPA.js +58 -0
- package/dist/safe-bash/command-chunks/{chunk-CG4JSOK2.js → chunk-3HDIDEUJ.js} +1 -1
- package/dist/safe-bash/command-chunks/chunk-4DSJDVBM.js +2897 -0
- package/dist/safe-bash/command-chunks/{chunk-GBHSE6ZO.js → chunk-5GRLAARV.js} +1 -1
- package/dist/safe-bash/command-chunks/chunk-7OKDCM5U.js +112 -0
- package/dist/safe-bash/command-chunks/{chunk-FH3D75FC.js → chunk-ADCGH6A7.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-MTKXVRXL.js → chunk-DREUDEQG.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-ADBFNLLK.js → chunk-FXYWQ6S4.js} +16 -14
- package/dist/safe-bash/command-chunks/{chunk-Y2KHC6TZ.js → chunk-IDKD76KR.js} +5 -3
- package/dist/safe-bash/command-chunks/{chunk-K6KBYLQC.js → chunk-JUDOV5MJ.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-3ZK5F23O.js → chunk-L3MLMXL4.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-E5TEVROY.js → chunk-PFBJR2PY.js} +4 -4
- package/dist/safe-bash/command-chunks/{chunk-YGYOVXTO.js → chunk-UUR2S7AD.js} +9 -5
- package/dist/safe-bash/command-chunks/chunk-VIVYKW7Q.js +101 -0
- package/dist/safe-bash/command-chunks/{chunk-I5GLTNVH.js → chunk-X4P42NYK.js} +2 -27
- package/dist/safe-bash/command-chunks/{chunk-XF6TXYLD.js → chunk-Z57TV6TC.js} +4 -54
- package/dist/safe-bash/command-chunks/{chunk-QDPRSPHQ.js → chunk-Z64BW7CG.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-X3IVPNC3.js → chunk-Z7TYZG3A.js} +5 -3
- package/dist/safe-bash/command-chunks/{chunk-GZXLPWT5.js → chunk-ZF3ZVGQC.js} +259 -258
- package/dist/safe-bash/command-chunks/{pptx-ZL6L7KP2-QVZEYFUV.js → pptx-KY2OJWZW-76LBHCHD.js} +4 -3
- package/dist/safe-bash/commands/csvkit/index.d.ts +1 -8
- package/dist/safe-bash/commands/csvkit/index.js +5 -1639
- package/dist/safe-bash/commands/csvkit/sync.d.ts +9 -0
- package/dist/safe-bash/commands/csvkit/sync.js +1639 -0
- package/dist/safe-bash/commands/pandoc/implementation.d.ts +8 -0
- package/dist/safe-bash/commands/pandoc/implementation.js +92 -0
- package/dist/safe-bash/commands/pandoc/index.d.ts +2 -6
- package/dist/safe-bash/commands/pandoc/index.js +2 -90
- package/dist/safe-bash/core.browser.js +808 -6271
- package/dist/safe-bash/core.d.ts +17 -16
- package/dist/safe-bash/core.js +17 -16
- package/dist/safe-bash/lazy-gh.d.ts +10 -0
- package/dist/safe-bash/lazy-gh.js +30 -0
- package/dist/safe-bash/lazy-optional.d.ts +499 -0
- package/dist/safe-bash/lazy-optional.js +609 -0
- package/dist/safe-bash/plugins/composition.d.ts +1 -1
- package/dist/safe-bash/plugins/composition.js +1 -1
- package/dist/safe-bash/plugins/lazy-command.d.ts +9 -0
- package/dist/safe-bash/plugins/lazy-command.js +57 -0
- package/dist/safe-bash/shell/runtime.js +24 -25
- package/dist/safe-bash-command-csvkit/cli/lexical.d.ts +3 -0
- package/dist/safe-bash-command-csvkit/cli/parser.d.ts +1 -2
- package/dist/safe-bash-command-csvkit/codecs/python.js +3 -2
- package/dist/safe-bash-command-csvkit/codecs/utf8.js +2 -1
- package/dist/safe-bash-command-csvkit/index.js +453 -3270
- package/dist/safe-bash-command-csvkit/sync-support.d.ts +7 -0
- package/dist/safe-bash-command-csvkit/sync-support.js +31 -0
- package/dist/safe-bash-command-gh/index.js +25 -17
- package/dist/safe-bash-command-git/index.js +6 -10
- package/dist/safe-bash-command-imagemagick/index.js +2 -2
- package/dist/safe-bash-command-pandoc/citeproc-filters.js +4 -2
- package/dist/safe-bash-command-pandoc/command.js +8 -6
- package/dist/safe-bash-command-pandoc/index.js +8 -6
- package/dist/safe-bash-command-pandoc/lua-filters.js +3 -2
- package/dist/safe-bash-command-pandoc/options.d.ts +5 -0
- package/dist/safe-bash-command-pandoc/options.js +93 -0
- package/dist/safe-bash-command-sips/index.js +2 -2
- package/dist/safe-bash-command-soffice/index.d.ts +1 -2
- package/dist/safe-bash-command-soffice/index.js +22 -18
- package/dist/safe-bash-command-ssconvert/commands.js +2 -2
- package/dist/safe-bash-command-ssconvert/core.js +2 -2
- package/dist/safe-bash-command-ssconvert/formats/csv.js +2 -2
- package/dist/safe-bash-command-ssconvert/formats/xls.js +3 -3
- package/dist/safe-bash-command-ssconvert/formats/xlsx.js +3 -3
- package/dist/safe-bash-command-timeout/index.js +3 -3
- package/dist/safe-bash-command-yq/index.js +5 -5
- 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 +7 -7
- package/dist/safe-bash-compression-engine/index.js +6 -6
- package/dist/safe-bash-compression-engine/operand.js +7 -7
- package/dist/safe-bash-compression-engine/stream.js +6 -6
- package/dist/safe-bash-compression-engine/zstd-decode.js +5 -5
- 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 +1 -1
- package/dist/safe-bash-contracts/filesystem-output.js +10 -10
- package/dist/safe-bash-contracts/index.js +40 -40
- package/dist/safe-bash-io-engine/commands/search/requirements.js +4 -4
- package/dist/safe-bash-io-engine/commands/text-programs/shared.js +4 -4
- package/dist/safe-bash-io-engine/internal.d.ts +9 -0
- package/dist/safe-bash-io-engine/internal.js +3 -3
- package/dist/safe-bash-query-engine/index.js +6 -6
- package/dist/safe-bash-query-engine/interpreter.js +5 -5
- package/dist/safe-bash-query-engine/query-core.js +6 -6
- package/dist/safe-bash-regex-engine/execution/bounded-provider.js +3 -3
- package/dist/safe-bash-regex-engine/index.js +2 -2
- package/dist/safe-bash-regex-engine/text/regex.js +2 -2
- package/dist/safe-bash-xml-engine/index.js +3 -3
- package/package.json +4 -4
- package/dist/safe-bash/command-chunks/{chunk-DC52GWRK.js → chunk-BUKYQBXO.js} +13 -13
- package/dist/safe-bash/command-chunks/{chunk-QJ3ONEBI.js → chunk-DEH3CMGL.js} +3 -3
- package/dist/safe-bash/command-chunks/{chunk-Y64PA6IA.js → chunk-KHZZ4V3L.js} +3 -3
- package/dist/safe-bash/command-chunks/{chunk-I7PKIGII.js → chunk-QIRUOY2W.js} +3 -3
- package/dist/safe-bash/command-chunks/{chunk-HQG2IBZL.js → chunk-TOSM3T3A.js} +6 -6
- package/dist/safe-bash/command-chunks/{chunk-F4IQCXZG.js → chunk-VBZMCL23.js} +4 -4
- package/dist/safe-bash/command-chunks/{chunk-J2NPH7DO.js → chunk-W2T7JWT3.js} +3 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { builtInDirectContextExecutors } from "../internal.js";
|
|
3
|
-
import { createCsvkitCommands as createRawCsvkitCommands
|
|
1
|
+
import { evalSyncCsvlook, evalSyncCsvjson, evalSyncCsvsort, evalSyncCsvformat, evalSyncCsvstat, evalSyncIn2csv, evalSyncCsvstack, evalSyncCsvjoin } from "./sync.js";
|
|
2
|
+
import { builtInDirectContextExecutors, syncCommandEvaluators } from "../internal.js";
|
|
3
|
+
import { createCsvkitCommands as createRawCsvkitCommands } from "../../../safe-bash-command-csvkit/index.js";
|
|
4
4
|
export * from "../../../safe-bash-command-csvkit/index.js";
|
|
5
|
+
export * from "./sync.js";
|
|
5
6
|
function isDefaultCsvkitOptions(options) {
|
|
6
7
|
if (!options)
|
|
7
8
|
return true;
|
|
@@ -21,6 +22,7 @@ function isDefaultCsvkitOptions(options) {
|
|
|
21
22
|
}
|
|
22
23
|
export function createCsvkitCommands(options = {}) {
|
|
23
24
|
const defs = createRawCsvkitCommands(options);
|
|
25
|
+
Object.assign(syncCommandEvaluators, { evalSyncCsvlook, evalSyncCsvjson, evalSyncCsvsort, evalSyncCsvformat, evalSyncCsvstat, evalSyncIn2csv, evalSyncCsvstack, evalSyncCsvjoin });
|
|
24
26
|
if (isDefaultCsvkitOptions(options)) {
|
|
25
27
|
for (let i = 0; i < defs.length; i++)
|
|
26
28
|
builtInDirectContextExecutors.add(defs[i].execute);
|
|
@@ -47,1640 +49,4 @@ export function csvkitCommands(options = {}) {
|
|
|
47
49
|
},
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
|
-
const syncUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
51
|
-
function parseSyncCsvkitCommon(opArgs, mode) {
|
|
52
|
-
const res = {
|
|
53
|
-
tabs: false,
|
|
54
|
-
noDoublequote: false,
|
|
55
|
-
skipInitialSpace: false,
|
|
56
|
-
noHeaderRow: false,
|
|
57
|
-
skipLines: 0,
|
|
58
|
-
lineNumbers: false,
|
|
59
|
-
addBom: false,
|
|
60
|
-
noInference: false,
|
|
61
|
-
blanks: false,
|
|
62
|
-
noLeadingZeroes: false,
|
|
63
|
-
sniffLimit: 1024,
|
|
64
|
-
noNumberEllipsis: false,
|
|
65
|
-
indent: null,
|
|
66
|
-
key: null,
|
|
67
|
-
streamOutput: false,
|
|
68
|
-
};
|
|
69
|
-
let positionalDone = false;
|
|
70
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
71
|
-
const a = opArgs[i];
|
|
72
|
-
if (!positionalDone && a === "--") {
|
|
73
|
-
positionalDone = true;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (!positionalDone && a.startsWith("-") && a !== "-") {
|
|
77
|
-
if (a === "-t" || a === "--tabs") {
|
|
78
|
-
res.tabs = true;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
if (a === "-b" || a === "--no-doublequote") {
|
|
82
|
-
res.noDoublequote = true;
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (a === "-S" || a === "--skipinitialspace") {
|
|
86
|
-
res.skipInitialSpace = true;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (a === "-H" || a === "--no-header-row") {
|
|
90
|
-
res.noHeaderRow = true;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (a === "-l" || a === "--linenumbers") {
|
|
94
|
-
res.lineNumbers = true;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
if (a === "--add-bom") {
|
|
98
|
-
res.addBom = true;
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (a === "-I" || a === "--no-inference") {
|
|
102
|
-
res.noInference = true;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (a === "--blanks") {
|
|
106
|
-
res.blanks = true;
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (a === "--no-leading-zeroes") {
|
|
110
|
-
res.noLeadingZeroes = true;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
if (a === "-d" || a.startsWith("-d") || a === "--delimiter" || a.startsWith("--delimiter=")) {
|
|
114
|
-
const v = a.startsWith("--delimiter=") ? a.slice(12) : a.startsWith("-d=") ? a.slice(3) : a.length > 2 && a.startsWith("-d") ? a.slice(2) : opArgs[++i];
|
|
115
|
-
if (!v || Array.from(v).length !== 1)
|
|
116
|
-
return undefined;
|
|
117
|
-
res.delimiter = v;
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
if (a === "-q" || a.startsWith("-q") || a === "--quotechar" || a.startsWith("--quotechar=")) {
|
|
121
|
-
const v = a.startsWith("--quotechar=") ? a.slice(12) : a.startsWith("-q=") ? a.slice(3) : a.length > 2 && a.startsWith("-q") ? a.slice(2) : opArgs[++i];
|
|
122
|
-
if (!v || Array.from(v).length !== 1)
|
|
123
|
-
return undefined;
|
|
124
|
-
res.quotechar = v;
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (a === "-p" || a === "--escapechar") {
|
|
128
|
-
const v = opArgs[++i];
|
|
129
|
-
if (!v || Array.from(v).length !== 1)
|
|
130
|
-
return undefined;
|
|
131
|
-
res.escapechar = v;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (a === "-K" || a.startsWith("-K") || a === "--skip-lines" || a.startsWith("--skip-lines=")) {
|
|
135
|
-
const v = a.startsWith("--skip-lines=") ? a.slice(13) : a.startsWith("-K=") ? a.slice(3) : a.length > 2 && a.startsWith("-K") ? a.slice(2) : opArgs[++i];
|
|
136
|
-
if (v === undefined || !/^[0-9]+$/.test(v))
|
|
137
|
-
return undefined;
|
|
138
|
-
res.skipLines = Number(v);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (a === "-y" || a === "--snifflimit") {
|
|
142
|
-
const v = opArgs[++i];
|
|
143
|
-
if (v === undefined || !/^-?[0-9]+$/.test(v))
|
|
144
|
-
return undefined;
|
|
145
|
-
res.sniffLimit = Number(v);
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (mode === "csvlook") {
|
|
149
|
-
if (a === "--no-number-ellipsis") {
|
|
150
|
-
res.noNumberEllipsis = true;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (a === "--max-rows" || a === "--max-columns" || a === "--max-column-width" || a === "--max-precision") {
|
|
154
|
-
const v = opArgs[++i];
|
|
155
|
-
if (v === undefined || !/^[0-9]+$/.test(v))
|
|
156
|
-
return undefined;
|
|
157
|
-
const n = Number(v);
|
|
158
|
-
if (a === "--max-rows")
|
|
159
|
-
res.maxRows = n;
|
|
160
|
-
else if (a === "--max-columns")
|
|
161
|
-
res.maxColumns = n;
|
|
162
|
-
else if (a === "--max-column-width")
|
|
163
|
-
res.maxColumnWidth = n;
|
|
164
|
-
else
|
|
165
|
-
res.maxPrecision = n;
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
if (a === "--stream") {
|
|
171
|
-
res.streamOutput = true;
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
if (a === "-i" || a.startsWith("-i") || a === "--indent" || a.startsWith("--indent=")) {
|
|
175
|
-
const v = a.startsWith("--indent=") ? a.slice(9) : a.startsWith("-i=") ? a.slice(3) : a.length > 2 && a.startsWith("-i") ? a.slice(2) : opArgs[++i];
|
|
176
|
-
if (v === undefined || !/^[0-9]+$/.test(v))
|
|
177
|
-
return undefined;
|
|
178
|
-
res.indent = Number(v);
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
if (a === "-k" || a.startsWith("-k") || a === "--key" || a.startsWith("--key=")) {
|
|
182
|
-
const v = a.startsWith("--key=") ? a.slice(6) : a.startsWith("-k=") ? a.slice(3) : a.length > 2 && a.startsWith("-k") ? a.slice(2) : opArgs[++i];
|
|
183
|
-
if (v === undefined)
|
|
184
|
-
return undefined;
|
|
185
|
-
res.key = v;
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (!a.startsWith("--") && a.length > 2) {
|
|
190
|
-
let ok = true;
|
|
191
|
-
for (let j = 1; j < a.length; j++) {
|
|
192
|
-
const ch = a[j];
|
|
193
|
-
if (ch === "t")
|
|
194
|
-
res.tabs = true;
|
|
195
|
-
else if (ch === "b")
|
|
196
|
-
res.noDoublequote = true;
|
|
197
|
-
else if (ch === "S")
|
|
198
|
-
res.skipInitialSpace = true;
|
|
199
|
-
else if (ch === "H")
|
|
200
|
-
res.noHeaderRow = true;
|
|
201
|
-
else if (ch === "l")
|
|
202
|
-
res.lineNumbers = true;
|
|
203
|
-
else if (ch === "I")
|
|
204
|
-
res.noInference = true;
|
|
205
|
-
else {
|
|
206
|
-
ok = false;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (ok)
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
|
-
if (res.filePath !== undefined)
|
|
216
|
-
return undefined;
|
|
217
|
-
res.filePath = a;
|
|
218
|
-
}
|
|
219
|
-
return res;
|
|
220
|
-
}
|
|
221
|
-
function loadSyncTypedTable(inBytes, opts, readFileSync) {
|
|
222
|
-
let sourceBytes = inBytes;
|
|
223
|
-
if (opts.filePath !== undefined && opts.filePath !== "-") {
|
|
224
|
-
if (!readFileSync)
|
|
225
|
-
return undefined;
|
|
226
|
-
sourceBytes = readFileSync(opts.filePath);
|
|
227
|
-
}
|
|
228
|
-
if (!sourceBytes || sourceBytes.byteLength > 16384)
|
|
229
|
-
return undefined;
|
|
230
|
-
let text;
|
|
231
|
-
try {
|
|
232
|
-
text = syncUtf8Decoder.decode(sourceBytes);
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
return undefined;
|
|
236
|
-
}
|
|
237
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
238
|
-
text = text.slice(1);
|
|
239
|
-
if (opts.skipLines > 0) {
|
|
240
|
-
let linesLeft = opts.skipLines;
|
|
241
|
-
let pos = 0;
|
|
242
|
-
while (pos < text.length && linesLeft > 0) {
|
|
243
|
-
const ch = text[pos++];
|
|
244
|
-
if (ch === "\r") {
|
|
245
|
-
if (text[pos] === "\n")
|
|
246
|
-
pos++;
|
|
247
|
-
linesLeft--;
|
|
248
|
-
}
|
|
249
|
-
else if (ch === "\n") {
|
|
250
|
-
linesLeft--;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
text = text.slice(pos);
|
|
254
|
-
}
|
|
255
|
-
const explicitDelimiter = opts.tabs ? "\t" : opts.delimiter;
|
|
256
|
-
let dialect = {
|
|
257
|
-
...(explicitDelimiter !== undefined ? { delimiter: explicitDelimiter } : {}),
|
|
258
|
-
...(opts.quotechar !== undefined ? { quotechar: opts.quotechar } : {}),
|
|
259
|
-
...(opts.escapechar !== undefined ? { escapechar: opts.escapechar } : {}),
|
|
260
|
-
doublequote: !opts.noDoublequote,
|
|
261
|
-
skipinitialspace: opts.skipInitialSpace,
|
|
262
|
-
};
|
|
263
|
-
if (!opts.tabs &&
|
|
264
|
-
opts.delimiter === undefined &&
|
|
265
|
-
opts.quotechar === undefined &&
|
|
266
|
-
opts.escapechar === undefined &&
|
|
267
|
-
!opts.noDoublequote &&
|
|
268
|
-
!opts.skipInitialSpace &&
|
|
269
|
-
opts.sniffLimit !== 0 &&
|
|
270
|
-
text.length > 0) {
|
|
271
|
-
const sample = opts.sniffLimit > 0 ? text.slice(0, opts.sniffLimit) : text;
|
|
272
|
-
if (sample.includes(",") && !/[\t;|:\x27]/.test(sample)) {
|
|
273
|
-
dialect = { delimiter: ",", quotechar: "\"", doublequote: true, skipinitialspace: false };
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
const sniffed = sniff(sample);
|
|
277
|
-
if (sniffed)
|
|
278
|
-
dialect = sniffed;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
let headers;
|
|
282
|
-
const rows = [];
|
|
283
|
-
const rowLimit = opts.maxRows;
|
|
284
|
-
for (const record of readCsv(text, dialect)) {
|
|
285
|
-
const values = record.cells.map(c => pythonValueText(c));
|
|
286
|
-
const cells = opts.lineNumbers
|
|
287
|
-
? [!opts.noHeaderRow && record.line === 1 ? "line_numbers" : String(record.line - (opts.noHeaderRow ? 0 : 1)), ...values]
|
|
288
|
-
: values;
|
|
289
|
-
if (headers === undefined) {
|
|
290
|
-
headers = opts.noHeaderRow ? defaultHeaders(cells.length) : cells;
|
|
291
|
-
if (headers.some(name => !name) || new Set(headers).size !== headers.length)
|
|
292
|
-
return undefined;
|
|
293
|
-
if (!opts.noHeaderRow) {
|
|
294
|
-
if (rowLimit === 0)
|
|
295
|
-
break;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
rows.push(cells);
|
|
300
|
-
if (rowLimit !== undefined && rows.length >= rowLimit)
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
const inferenceOpts = {
|
|
304
|
-
now: Date.now(),
|
|
305
|
-
timezone: "UTC",
|
|
306
|
-
noInference: opts.noInference,
|
|
307
|
-
numberTextOnly: false,
|
|
308
|
-
blanks: opts.blanks,
|
|
309
|
-
nullValues: [],
|
|
310
|
-
noLeadingZeroes: opts.noLeadingZeroes,
|
|
311
|
-
maxDecimalDigits: Infinity,
|
|
312
|
-
maxDecimalExponent: Infinity,
|
|
313
|
-
};
|
|
314
|
-
return inferTable(headers ?? [], rows, inferenceOpts);
|
|
315
|
-
}
|
|
316
|
-
function syncPrecision(values) {
|
|
317
|
-
let whole = 1;
|
|
318
|
-
let places = 0;
|
|
319
|
-
for (const value of values) {
|
|
320
|
-
if (value === null || typeof value !== "object" || value.kind !== "decimal")
|
|
321
|
-
continue;
|
|
322
|
-
const d = Decimal.parse(value.value).normalized();
|
|
323
|
-
if (d.special || Math.abs(Number(d.toString())) === Infinity)
|
|
324
|
-
continue;
|
|
325
|
-
places = Math.max(places, -d.exponent);
|
|
326
|
-
whole = Math.max(whole, d.coefficient.toString().length + d.exponent);
|
|
327
|
-
}
|
|
328
|
-
return Math.min(places, 28 - whole);
|
|
329
|
-
}
|
|
330
|
-
function syncNumberText(value, places, ellipsis) {
|
|
331
|
-
const d = Decimal.parse(value);
|
|
332
|
-
if (d.special === "Infinity" || Math.abs(Number(d.toString())) === Infinity)
|
|
333
|
-
return value;
|
|
334
|
-
places = Math.max(0, places);
|
|
335
|
-
if (d.special) {
|
|
336
|
-
const digits = "NaN" + d.payload;
|
|
337
|
-
let grouped = "";
|
|
338
|
-
for (let i = 0; i < digits.length; i++) {
|
|
339
|
-
if (i && (digits.length - i) % 3 === 0)
|
|
340
|
-
grouped += ",";
|
|
341
|
-
grouped += digits[i];
|
|
342
|
-
}
|
|
343
|
-
return grouped + (places ? "." + "0".repeat(places) : "") + ellipsis;
|
|
344
|
-
}
|
|
345
|
-
let coefficient = d.coefficient;
|
|
346
|
-
const shift = d.exponent + places;
|
|
347
|
-
if (shift >= 0)
|
|
348
|
-
coefficient *= 10n ** BigInt(shift);
|
|
349
|
-
else {
|
|
350
|
-
const divisor = 10n ** BigInt(-shift);
|
|
351
|
-
const rest = coefficient % divisor;
|
|
352
|
-
coefficient /= divisor;
|
|
353
|
-
if (rest * 2n > divisor || (rest * 2n === divisor && coefficient % 2n !== 0n))
|
|
354
|
-
coefficient++;
|
|
355
|
-
}
|
|
356
|
-
if (coefficient.toString().length > 28)
|
|
357
|
-
throw new Error("InvalidOperation");
|
|
358
|
-
const digits = coefficient.toString().padStart(places + 1, "0");
|
|
359
|
-
const whole = digits.slice(0, digits.length - places);
|
|
360
|
-
let grouped = "";
|
|
361
|
-
for (let i = 0; i < whole.length; i++) {
|
|
362
|
-
if (i && (whole.length - i) % 3 === 0)
|
|
363
|
-
grouped += ",";
|
|
364
|
-
grouped += whole[i];
|
|
365
|
-
}
|
|
366
|
-
return (d.negative ? "-" : "") + grouped + (places ? "." + digits.slice(-places) : "") + ellipsis;
|
|
367
|
-
}
|
|
368
|
-
export function evalSyncCsvlook(inBytes, opArgs, readFileSync) {
|
|
369
|
-
try {
|
|
370
|
-
const opts = parseSyncCsvkitCommon(opArgs, "csvlook");
|
|
371
|
-
if (!opts)
|
|
372
|
-
return undefined;
|
|
373
|
-
const table = loadSyncTypedTable(inBytes, opts, readFileSync);
|
|
374
|
-
if (!table)
|
|
375
|
-
return undefined;
|
|
376
|
-
const maxColumns = opts.maxColumns ?? table.headers.length;
|
|
377
|
-
const width = opts.maxColumnWidth;
|
|
378
|
-
const maxPrecision = opts.maxPrecision ?? 3;
|
|
379
|
-
const cpLen = (v) => Array.from(v).length;
|
|
380
|
-
const truncate = (v) => {
|
|
381
|
-
const chars = Array.from(v);
|
|
382
|
-
return width !== undefined && chars.length > width ? chars.slice(0, width - 3).join("") + "..." : v;
|
|
383
|
-
};
|
|
384
|
-
const names = table.headers.slice(0, maxColumns).map(truncate);
|
|
385
|
-
if (maxColumns < table.headers.length)
|
|
386
|
-
names.push("...");
|
|
387
|
-
const widths = names.map(cpLen);
|
|
388
|
-
const formats = table.columns.map((column, index) => {
|
|
389
|
-
if (index >= maxColumns || column.type !== "Number")
|
|
390
|
-
return undefined;
|
|
391
|
-
const places = syncPrecision(table.rows.map(row => row[index]));
|
|
392
|
-
return { places: Math.min(places, maxPrecision), ellipsis: places > maxPrecision && !opts.noNumberEllipsis ? "…" : "" };
|
|
393
|
-
});
|
|
394
|
-
const renderedRows = table.rows.map(row => {
|
|
395
|
-
const cells = [];
|
|
396
|
-
for (const [j, value] of row.entries()) {
|
|
397
|
-
const format = formats[j];
|
|
398
|
-
let text = j >= maxColumns
|
|
399
|
-
? "..."
|
|
400
|
-
: value === null
|
|
401
|
-
? ""
|
|
402
|
-
: format && typeof value === "object" && value.kind === "decimal"
|
|
403
|
-
? syncNumberText(value.value, format.places, format.ellipsis)
|
|
404
|
-
: pythonValueText(value).replaceAll("\n", "↵");
|
|
405
|
-
text = truncate(text);
|
|
406
|
-
widths[j] = Math.max(widths[j], cpLen(text));
|
|
407
|
-
cells.push(text);
|
|
408
|
-
if (j >= maxColumns)
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
return cells;
|
|
412
|
-
});
|
|
413
|
-
const formatRow = (cells) => {
|
|
414
|
-
const fields = cells.map((cell, j) => {
|
|
415
|
-
const col = table.columns[j];
|
|
416
|
-
if (!col)
|
|
417
|
-
throw new Error("IndexError");
|
|
418
|
-
const spaces = widths[j] - cpLen(cell);
|
|
419
|
-
const padding = " ".repeat(Math.max(0, spaces));
|
|
420
|
-
return col.type === "Text" ? " " + cell + padding + " " : " " + padding + cell + " ";
|
|
421
|
-
});
|
|
422
|
-
return "|" + fields.join("|") + "|\n";
|
|
423
|
-
};
|
|
424
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
425
|
-
out += formatRow(names);
|
|
426
|
-
out += "| " + widths.map(size => "-".repeat(size)).join(" | ") + " |\n";
|
|
427
|
-
for (const row of renderedRows)
|
|
428
|
-
out += formatRow(row);
|
|
429
|
-
return out;
|
|
430
|
-
}
|
|
431
|
-
catch {
|
|
432
|
-
return undefined;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
function syncFloatText(value) {
|
|
436
|
-
if (Number.isNaN(value))
|
|
437
|
-
return "NaN";
|
|
438
|
-
if (!Number.isFinite(value))
|
|
439
|
-
return value < 0 ? "-Infinity" : "Infinity";
|
|
440
|
-
if (Object.is(value, -0))
|
|
441
|
-
return "-0.0";
|
|
442
|
-
const exponent = Number(value.toExponential().split("e")[1]);
|
|
443
|
-
if (value !== 0 && (exponent < -4 || exponent >= 16)) {
|
|
444
|
-
const [digits, power] = value.toExponential().split("e");
|
|
445
|
-
const exp = Number(power);
|
|
446
|
-
return digits + "e" + (exp < 0 ? "-" : "+") + String(Math.abs(exp)).padStart(2, "0");
|
|
447
|
-
}
|
|
448
|
-
return String(value) + (Number.isInteger(value) ? ".0" : "");
|
|
449
|
-
}
|
|
450
|
-
function emitSyncJson(cur, indent, d = 0) {
|
|
451
|
-
if (typeof cur === "number")
|
|
452
|
-
return syncFloatText(cur);
|
|
453
|
-
if (cur === null || typeof cur === "string" || typeof cur === "boolean")
|
|
454
|
-
return JSON.stringify(cur);
|
|
455
|
-
if (cur instanceof Map) {
|
|
456
|
-
let buf = "{";
|
|
457
|
-
let index = 0;
|
|
458
|
-
const childPad = indent !== null ? "\n" + " ".repeat(indent * (d + 1)) : "";
|
|
459
|
-
for (const [key, child] of cur.entries()) {
|
|
460
|
-
if (index++)
|
|
461
|
-
buf += indent === null ? ", " : ",";
|
|
462
|
-
if (indent !== null)
|
|
463
|
-
buf += childPad;
|
|
464
|
-
buf += JSON.stringify(key) + ": " + emitSyncJson(child, indent, d + 1);
|
|
465
|
-
}
|
|
466
|
-
if (cur.size && indent !== null)
|
|
467
|
-
buf += "\n" + " ".repeat(indent * d);
|
|
468
|
-
buf += "}";
|
|
469
|
-
return buf;
|
|
470
|
-
}
|
|
471
|
-
const arr = cur;
|
|
472
|
-
let buf = "[";
|
|
473
|
-
const childPad = indent !== null ? "\n" + " ".repeat(indent * (d + 1)) : "";
|
|
474
|
-
for (let index = 0; index < arr.length; index++) {
|
|
475
|
-
if (index)
|
|
476
|
-
buf += indent === null ? ", " : ",";
|
|
477
|
-
if (indent !== null)
|
|
478
|
-
buf += childPad;
|
|
479
|
-
buf += emitSyncJson(arr[index], indent, d + 1);
|
|
480
|
-
}
|
|
481
|
-
if (arr.length && indent !== null)
|
|
482
|
-
buf += "\n" + " ".repeat(indent * d);
|
|
483
|
-
buf += "]";
|
|
484
|
-
return buf;
|
|
485
|
-
}
|
|
486
|
-
export function evalSyncCsvjson(inBytes, opArgs, readFileSync) {
|
|
487
|
-
try {
|
|
488
|
-
const opts = parseSyncCsvkitCommon(opArgs, "csvjson");
|
|
489
|
-
if (!opts)
|
|
490
|
-
return undefined;
|
|
491
|
-
if (opts.streamOutput && opts.key !== null)
|
|
492
|
-
return undefined;
|
|
493
|
-
if (opts.streamOutput && opts.indent !== null)
|
|
494
|
-
return undefined;
|
|
495
|
-
const table = loadSyncTypedTable(inBytes, opts, readFileSync);
|
|
496
|
-
if (!table)
|
|
497
|
-
return undefined;
|
|
498
|
-
const jsonify = (value) => {
|
|
499
|
-
if (typeof value !== "object" || value === null)
|
|
500
|
-
return value;
|
|
501
|
-
if (value.kind === "decimal")
|
|
502
|
-
return value.value.includes("NaN") ? NaN : Number(value.value);
|
|
503
|
-
if (value.kind === "datetime")
|
|
504
|
-
return value.value.replace(" ", "T");
|
|
505
|
-
return pythonValueText(value);
|
|
506
|
-
};
|
|
507
|
-
const rows = table.rows.map(row => new Map(table.headers.map((name, index) => [name, jsonify(row[index])])));
|
|
508
|
-
let output = rows;
|
|
509
|
-
if (opts.key !== null) {
|
|
510
|
-
const column = table.headers.indexOf(opts.key);
|
|
511
|
-
if (column < 0 && rows.length)
|
|
512
|
-
return undefined;
|
|
513
|
-
const keyed = new Map();
|
|
514
|
-
for (const [index, row] of table.rows.entries()) {
|
|
515
|
-
const cell = row[column];
|
|
516
|
-
const value = cell === null
|
|
517
|
-
? "None"
|
|
518
|
-
: typeof cell === "object" && cell.kind === "decimal"
|
|
519
|
-
? Decimal.parse(cell.value).normalized().toString()
|
|
520
|
-
: pythonValueText(cell);
|
|
521
|
-
if (keyed.has(value))
|
|
522
|
-
return undefined;
|
|
523
|
-
keyed.set(value, rows[index]);
|
|
524
|
-
}
|
|
525
|
-
output = keyed;
|
|
526
|
-
}
|
|
527
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
528
|
-
if (opts.streamOutput) {
|
|
529
|
-
for (const row of rows) {
|
|
530
|
-
out += emitSyncJson(row, opts.indent) + "\n";
|
|
531
|
-
}
|
|
532
|
-
return out;
|
|
533
|
-
}
|
|
534
|
-
out += emitSyncJson(output, opts.indent);
|
|
535
|
-
return out;
|
|
536
|
-
}
|
|
537
|
-
catch {
|
|
538
|
-
return undefined;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
export function evalSyncCsvsort(inBytes, opArgs, readFileSync) {
|
|
542
|
-
try {
|
|
543
|
-
let columnsSpec = null;
|
|
544
|
-
let reverse = false;
|
|
545
|
-
let ignoreCase = false;
|
|
546
|
-
let namesOnly = false;
|
|
547
|
-
let zeroBased = false;
|
|
548
|
-
const filteredArgs = [];
|
|
549
|
-
let posDone = false;
|
|
550
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
551
|
-
const a = opArgs[i];
|
|
552
|
-
if (!posDone && a === "--") {
|
|
553
|
-
posDone = true;
|
|
554
|
-
filteredArgs.push(a);
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
558
|
-
if (a === "-r" || a === "--reverse") {
|
|
559
|
-
reverse = true;
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
if (a === "-i" || a === "--ignore-case") {
|
|
563
|
-
ignoreCase = true;
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
if (a === "-n" || a === "--names") {
|
|
567
|
-
namesOnly = true;
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
if (a === "--zero") {
|
|
571
|
-
zeroBased = true;
|
|
572
|
-
continue;
|
|
573
|
-
}
|
|
574
|
-
if (a === "-ri" || a === "-ir") {
|
|
575
|
-
reverse = true;
|
|
576
|
-
ignoreCase = true;
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
if (a === "-c" || a.startsWith("-c") || a === "--columns" || a.startsWith("--columns=")) {
|
|
580
|
-
const v = a.startsWith("--columns=") ? a.slice(10) : a.startsWith("-c=") ? a.slice(3) : a.length > 2 && a.startsWith("-c") ? a.slice(2) : opArgs[++i];
|
|
581
|
-
if (v === undefined)
|
|
582
|
-
return undefined;
|
|
583
|
-
columnsSpec = v;
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
filteredArgs.push(a);
|
|
588
|
-
}
|
|
589
|
-
const opts = parseSyncCsvkitCommon(filteredArgs, "csvlook");
|
|
590
|
-
if (!opts)
|
|
591
|
-
return undefined;
|
|
592
|
-
const table = loadSyncTypedTable(inBytes, opts, readFileSync);
|
|
593
|
-
if (!table)
|
|
594
|
-
return undefined;
|
|
595
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
596
|
-
if (namesOnly) {
|
|
597
|
-
if (opts.noHeaderRow)
|
|
598
|
-
return undefined;
|
|
599
|
-
for (let i = 0; i < table.headers.length; i++) {
|
|
600
|
-
out += `${String(i + (zeroBased ? 0 : 1)).padStart(3, " ")}: ${table.headers[i]}\n`;
|
|
601
|
-
}
|
|
602
|
-
return out;
|
|
603
|
-
}
|
|
604
|
-
const columns = parseColumnIdentifiers(columnsSpec, table.headers, zeroBased ? 0 : 1, null, () => { }, true);
|
|
605
|
-
const rows = [...table.rows];
|
|
606
|
-
const keyed = rows.map(row => columns.map(idx => {
|
|
607
|
-
const val = row[idx];
|
|
608
|
-
return ignoreCase && typeof val === "string" ? val.toUpperCase() : val;
|
|
609
|
-
}));
|
|
610
|
-
const indices = rows.map((_, i) => i);
|
|
611
|
-
indices.sort((a, b) => {
|
|
612
|
-
for (let c = 0; c < columns.length; c++) {
|
|
613
|
-
const x = keyed[a][c];
|
|
614
|
-
const y = keyed[b][c];
|
|
615
|
-
let order = 0;
|
|
616
|
-
if (x === null || y === null)
|
|
617
|
-
order = x === null ? (y === null ? 0 : 1) : -1;
|
|
618
|
-
else if (typeof x === "string" && typeof y === "string") {
|
|
619
|
-
order = x < y ? -1 : x > y ? 1 : 0;
|
|
620
|
-
}
|
|
621
|
-
else if (typeof x === "boolean" && typeof y === "boolean") {
|
|
622
|
-
order = Number(x) - Number(y);
|
|
623
|
-
}
|
|
624
|
-
else if (typeof x === "object" && typeof y === "object" && x.kind === "decimal" && y.kind === "decimal") {
|
|
625
|
-
if (x.value.includes("NaN") || y.value.includes("NaN"))
|
|
626
|
-
throw new Error("NaN");
|
|
627
|
-
order = Decimal.parse(x.value).compare(Decimal.parse(y.value));
|
|
628
|
-
}
|
|
629
|
-
else if (typeof x === "object" && typeof y === "object" && (x.kind === "date" || x.kind === "datetime") && (y.kind === "date" || y.kind === "datetime") && x.kind === y.kind) {
|
|
630
|
-
order = x.value < y.value ? -1 : x.value > y.value ? 1 : 0;
|
|
631
|
-
}
|
|
632
|
-
else if (typeof x === "object" && typeof y === "object" && x.kind === "timedelta" && y.kind === "timedelta") {
|
|
633
|
-
order = x.microseconds < y.microseconds ? -1 : x.microseconds > y.microseconds ? 1 : 0;
|
|
634
|
-
}
|
|
635
|
-
else {
|
|
636
|
-
throw new Error("unsupported type");
|
|
637
|
-
}
|
|
638
|
-
if (order !== 0)
|
|
639
|
-
return reverse ? -order : order;
|
|
640
|
-
}
|
|
641
|
-
return 0;
|
|
642
|
-
});
|
|
643
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
644
|
-
out += writeCsvRow(table.headers, outDialect);
|
|
645
|
-
for (const idx of indices) {
|
|
646
|
-
const formattedCells = rows[idx].map(v => {
|
|
647
|
-
if (v === null)
|
|
648
|
-
return "";
|
|
649
|
-
if (typeof v === "object" && v.kind === "datetime")
|
|
650
|
-
return v.value.replace(" ", "T");
|
|
651
|
-
return pythonValueText(v);
|
|
652
|
-
});
|
|
653
|
-
out += writeCsvRow(formattedCells, outDialect);
|
|
654
|
-
}
|
|
655
|
-
return out;
|
|
656
|
-
}
|
|
657
|
-
catch {
|
|
658
|
-
return undefined;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
export function evalSyncCsvformat(inBytes, opArgs, readFileSync) {
|
|
662
|
-
try {
|
|
663
|
-
let outDelimiter = ",";
|
|
664
|
-
let outTabs = false;
|
|
665
|
-
let outAsv = false;
|
|
666
|
-
let outQuotechar = "\"";
|
|
667
|
-
let outQuoting = 0;
|
|
668
|
-
let outNoDoublequote = false;
|
|
669
|
-
let outEscapechar;
|
|
670
|
-
let outLineterminator = "\n";
|
|
671
|
-
let skipHeader = false;
|
|
672
|
-
const filteredArgs = [];
|
|
673
|
-
let posDone = false;
|
|
674
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
675
|
-
const a = opArgs[i];
|
|
676
|
-
if (!posDone && a === "--") {
|
|
677
|
-
posDone = true;
|
|
678
|
-
filteredArgs.push(a);
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
682
|
-
if (a === "-E" || a === "--skip-header") {
|
|
683
|
-
skipHeader = true;
|
|
684
|
-
continue;
|
|
685
|
-
}
|
|
686
|
-
if (a === "-T" || a === "--out-tabs") {
|
|
687
|
-
outTabs = true;
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
if (a === "-A" || a === "--out-asv") {
|
|
691
|
-
outAsv = true;
|
|
692
|
-
continue;
|
|
693
|
-
}
|
|
694
|
-
if (a === "-B" || a === "--out-no-doublequote") {
|
|
695
|
-
outNoDoublequote = true;
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
if (a === "-D" || a.startsWith("-D") || a === "--out-delimiter" || a.startsWith("--out-delimiter=")) {
|
|
699
|
-
const v = a.startsWith("--out-delimiter=") ? a.slice(16) : a.startsWith("-D=") ? a.slice(3) : a.length > 2 && a.startsWith("-D") ? a.slice(2) : opArgs[++i];
|
|
700
|
-
if (!v || Array.from(v).length !== 1)
|
|
701
|
-
return undefined;
|
|
702
|
-
outDelimiter = v;
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
if (a === "-Q" || a.startsWith("-Q") || a === "--out-quotechar" || a.startsWith("--out-quotechar=")) {
|
|
706
|
-
const v = a.startsWith("--out-quotechar=") ? a.slice(16) : a.startsWith("-Q=") ? a.slice(3) : a.length > 2 && a.startsWith("-Q") ? a.slice(2) : opArgs[++i];
|
|
707
|
-
if (!v || Array.from(v).length !== 1)
|
|
708
|
-
return undefined;
|
|
709
|
-
outQuotechar = v;
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
|
-
if (a === "-P" || a === "--out-escapechar") {
|
|
713
|
-
const v = opArgs[++i];
|
|
714
|
-
if (!v || Array.from(v).length !== 1)
|
|
715
|
-
return undefined;
|
|
716
|
-
outEscapechar = v;
|
|
717
|
-
continue;
|
|
718
|
-
}
|
|
719
|
-
if (a === "-M" || a.startsWith("-M") || a === "--out-lineterminator" || a.startsWith("--out-lineterminator=")) {
|
|
720
|
-
const v = a.startsWith("--out-lineterminator=") ? a.slice(21) : a.startsWith("-M=") ? a.slice(3) : a.length > 2 && a.startsWith("-M") ? a.slice(2) : opArgs[++i];
|
|
721
|
-
if (v === undefined)
|
|
722
|
-
return undefined;
|
|
723
|
-
outLineterminator = v;
|
|
724
|
-
continue;
|
|
725
|
-
}
|
|
726
|
-
if (a === "-U" || a.startsWith("-U") || a === "--out-quoting" || a.startsWith("--out-quoting=")) {
|
|
727
|
-
const v = a.startsWith("--out-quoting=") ? a.slice(14) : a.startsWith("-U=") ? a.slice(3) : a.length > 2 && a.startsWith("-U") ? a.slice(2) : opArgs[++i];
|
|
728
|
-
if (v === undefined || !/^[0123]$/.test(v))
|
|
729
|
-
return undefined;
|
|
730
|
-
outQuoting = Number(v);
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
filteredArgs.push(a);
|
|
735
|
-
}
|
|
736
|
-
const opts = parseSyncCsvkitCommon(filteredArgs, "csvlook");
|
|
737
|
-
if (!opts)
|
|
738
|
-
return undefined;
|
|
739
|
-
let sourceBytes = inBytes;
|
|
740
|
-
if (opts.filePath !== undefined && opts.filePath !== "-") {
|
|
741
|
-
if (!readFileSync)
|
|
742
|
-
return undefined;
|
|
743
|
-
sourceBytes = readFileSync(opts.filePath);
|
|
744
|
-
}
|
|
745
|
-
if (!sourceBytes || sourceBytes.byteLength > 16384)
|
|
746
|
-
return undefined;
|
|
747
|
-
let text = syncUtf8Decoder.decode(sourceBytes);
|
|
748
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
749
|
-
text = text.slice(1);
|
|
750
|
-
if (opts.skipLines > 0) {
|
|
751
|
-
let linesLeft = opts.skipLines;
|
|
752
|
-
let pos = 0;
|
|
753
|
-
while (pos < text.length && linesLeft > 0) {
|
|
754
|
-
const ch = text[pos++];
|
|
755
|
-
if (ch === "\r") {
|
|
756
|
-
if (text[pos] === "\n")
|
|
757
|
-
pos++;
|
|
758
|
-
linesLeft--;
|
|
759
|
-
}
|
|
760
|
-
else if (ch === "\n")
|
|
761
|
-
linesLeft--;
|
|
762
|
-
}
|
|
763
|
-
text = text.slice(pos);
|
|
764
|
-
}
|
|
765
|
-
const explicitInDelimiter = opts.tabs ? "\t" : opts.delimiter;
|
|
766
|
-
let inDialect = {
|
|
767
|
-
...(explicitInDelimiter !== undefined ? { delimiter: explicitInDelimiter } : {}),
|
|
768
|
-
...(opts.quotechar !== undefined ? { quotechar: opts.quotechar } : {}),
|
|
769
|
-
...(opts.escapechar !== undefined ? { escapechar: opts.escapechar } : {}),
|
|
770
|
-
doublequote: !opts.noDoublequote,
|
|
771
|
-
skipinitialspace: opts.skipInitialSpace,
|
|
772
|
-
};
|
|
773
|
-
if (!opts.tabs &&
|
|
774
|
-
opts.delimiter === undefined &&
|
|
775
|
-
opts.quotechar === undefined &&
|
|
776
|
-
opts.escapechar === undefined &&
|
|
777
|
-
!opts.noDoublequote &&
|
|
778
|
-
!opts.skipInitialSpace &&
|
|
779
|
-
opts.sniffLimit !== 0 &&
|
|
780
|
-
text.length > 0) {
|
|
781
|
-
const sample = opts.sniffLimit > 0 ? text.slice(0, opts.sniffLimit) : text;
|
|
782
|
-
if (sample.includes(",") && !/[\t;|:\x27]/.test(sample)) {
|
|
783
|
-
inDialect = { delimiter: ",", quotechar: "\"", doublequote: true, skipinitialspace: false };
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
const sniffed = sniff(sample);
|
|
787
|
-
if (sniffed)
|
|
788
|
-
inDialect = sniffed;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
const outDialect = {
|
|
792
|
-
delimiter: outAsv ? "\x1f" : outTabs ? "\t" : outDelimiter,
|
|
793
|
-
lineterminator: outAsv ? "\x1e" : outLineterminator,
|
|
794
|
-
quotechar: outQuotechar,
|
|
795
|
-
quoting: outQuoting,
|
|
796
|
-
doublequote: !outNoDoublequote,
|
|
797
|
-
...(outEscapechar !== undefined ? { escapechar: outEscapechar } : {}),
|
|
798
|
-
};
|
|
799
|
-
writeCsvRow([], outDialect);
|
|
800
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
801
|
-
let first = true;
|
|
802
|
-
for (const record of readCsv(text, inDialect)) {
|
|
803
|
-
const values = record.cells.map(c => pythonValueText(c));
|
|
804
|
-
if (first) {
|
|
805
|
-
first = false;
|
|
806
|
-
if (opts.noHeaderRow) {
|
|
807
|
-
if (!skipHeader) {
|
|
808
|
-
const hdr = defaultHeaders(values.length);
|
|
809
|
-
out += writeCsvRow(opts.lineNumbers ? ["line_number", ...hdr] : hdr, outDialect);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
if (!skipHeader) {
|
|
814
|
-
out += writeCsvRow(opts.lineNumbers ? ["line_number", ...values] : values, outDialect);
|
|
815
|
-
}
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
const rowCells = opts.lineNumbers ? [String(record.line - (opts.noHeaderRow ? 0 : 1)), ...values] : values;
|
|
820
|
-
out += writeCsvRow(rowCells, outDialect);
|
|
821
|
-
}
|
|
822
|
-
return out;
|
|
823
|
-
}
|
|
824
|
-
catch {
|
|
825
|
-
return undefined;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
export function evalSyncCsvstat(inBytes, opArgs, readFileSync) {
|
|
829
|
-
try {
|
|
830
|
-
let countOnly = false;
|
|
831
|
-
let namesOnly = false;
|
|
832
|
-
let zeroBased = false;
|
|
833
|
-
let noGrouping = false;
|
|
834
|
-
let columnsSpec = null;
|
|
835
|
-
let metricOp;
|
|
836
|
-
const filteredArgs = [];
|
|
837
|
-
let posDone = false;
|
|
838
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
839
|
-
const a = opArgs[i];
|
|
840
|
-
if (!posDone && a === "--") {
|
|
841
|
-
posDone = true;
|
|
842
|
-
filteredArgs.push(a);
|
|
843
|
-
continue;
|
|
844
|
-
}
|
|
845
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
846
|
-
if (a === "--count") {
|
|
847
|
-
countOnly = true;
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
if (a === "-n" || a === "--names") {
|
|
851
|
-
namesOnly = true;
|
|
852
|
-
continue;
|
|
853
|
-
}
|
|
854
|
-
if (a === "--zero") {
|
|
855
|
-
zeroBased = true;
|
|
856
|
-
continue;
|
|
857
|
-
}
|
|
858
|
-
if (a === "-G" || a === "--no-grouping-separator") {
|
|
859
|
-
noGrouping = true;
|
|
860
|
-
continue;
|
|
861
|
-
}
|
|
862
|
-
if (a === "-c" || a.startsWith("-c") || a === "--columns" || a.startsWith("--columns=")) {
|
|
863
|
-
const v = a.startsWith("--columns=") ? a.slice(10) : a.startsWith("-c=") ? a.slice(3) : a.length > 2 && a.startsWith("-c") ? a.slice(2) : opArgs[++i];
|
|
864
|
-
if (!v)
|
|
865
|
-
return undefined;
|
|
866
|
-
columnsSpec = v;
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
const mMap = {
|
|
870
|
-
"--type": "type", "--nulls": "nulls", "--non-nulls": "nonnulls",
|
|
871
|
-
"--unique": "unique", "--min": "min", "--max": "max",
|
|
872
|
-
"--sum": "sum", "--mean": "mean", "--median": "median",
|
|
873
|
-
"--stdev": "stdev", "--max-precision": "max_precision", "--len": "len",
|
|
874
|
-
};
|
|
875
|
-
if (mMap[a]) {
|
|
876
|
-
if (metricOp !== undefined)
|
|
877
|
-
return undefined;
|
|
878
|
-
metricOp = mMap[a];
|
|
879
|
-
continue;
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
filteredArgs.push(a);
|
|
883
|
-
}
|
|
884
|
-
const modeCount = (countOnly ? 1 : 0) + (namesOnly ? 1 : 0) + (metricOp ? 1 : 0);
|
|
885
|
-
if (modeCount !== 1)
|
|
886
|
-
return undefined;
|
|
887
|
-
const opts = parseSyncCsvkitCommon(filteredArgs, "csvlook");
|
|
888
|
-
if (!opts)
|
|
889
|
-
return undefined;
|
|
890
|
-
const table = loadSyncTypedTable(inBytes, opts, readFileSync);
|
|
891
|
-
if (!table)
|
|
892
|
-
return undefined;
|
|
893
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
894
|
-
if (namesOnly) {
|
|
895
|
-
if (opts.noHeaderRow)
|
|
896
|
-
return undefined;
|
|
897
|
-
for (let i = 0; i < table.headers.length; i++) {
|
|
898
|
-
out += `${String(i + (zeroBased ? 0 : 1)).padStart(3, " ")}: ${table.headers[i]}\n`;
|
|
899
|
-
}
|
|
900
|
-
return out;
|
|
901
|
-
}
|
|
902
|
-
if (countOnly) {
|
|
903
|
-
return out + `${table.rows.length}\n`;
|
|
904
|
-
}
|
|
905
|
-
const ids = parseColumnIdentifiers(columnsSpec, table.headers, zeroBased ? 0 : 1, undefined, () => { }, true);
|
|
906
|
-
const fmtDec = (d) => {
|
|
907
|
-
const num = Number(d.toString());
|
|
908
|
-
if (!Number.isFinite(num))
|
|
909
|
-
return d.toString();
|
|
910
|
-
let s = num.toFixed(3);
|
|
911
|
-
while (s.endsWith("0"))
|
|
912
|
-
s = s.slice(0, -1);
|
|
913
|
-
if (s.endsWith("."))
|
|
914
|
-
s = s.slice(0, -1);
|
|
915
|
-
if (!noGrouping) {
|
|
916
|
-
const [intPart = "", fracPart] = s.split(".");
|
|
917
|
-
const sign = intPart.startsWith("-") ? "-" : "";
|
|
918
|
-
const digits = sign ? intPart.slice(1) : intPart;
|
|
919
|
-
const grouped = digits.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
920
|
-
s = sign + grouped + (fracPart !== undefined ? "." + fracPart : "");
|
|
921
|
-
}
|
|
922
|
-
return s;
|
|
923
|
-
};
|
|
924
|
-
for (const id of ids) {
|
|
925
|
-
const colType = table.columns[id].type;
|
|
926
|
-
const values = table.rows.map(r => r[id]);
|
|
927
|
-
const nonNull = values.filter(v => v !== null);
|
|
928
|
-
let valStr = "None";
|
|
929
|
-
if (metricOp === "type")
|
|
930
|
-
valStr = colType;
|
|
931
|
-
else if (metricOp === "nulls")
|
|
932
|
-
valStr = nonNull.length !== values.length ? "True" : "False";
|
|
933
|
-
else if (metricOp === "nonnulls")
|
|
934
|
-
valStr = String(nonNull.length);
|
|
935
|
-
else if (metricOp === "unique") {
|
|
936
|
-
const seen = new Set(values.map(v => v === null ? "null" : typeof v === "object" && v.kind === "decimal" ? "d:" + Decimal.parse(v.value).normalized().toString() : typeof v + ":" + pythonValueText(v)));
|
|
937
|
-
valStr = String(seen.size);
|
|
938
|
-
}
|
|
939
|
-
else if (metricOp === "len" && colType === "Text") {
|
|
940
|
-
let maxLen = 0;
|
|
941
|
-
for (const v of nonNull)
|
|
942
|
-
maxLen = Math.max(maxLen, Array.from(String(v)).length);
|
|
943
|
-
valStr = fmtDec(Decimal.parse(String(maxLen)));
|
|
944
|
-
}
|
|
945
|
-
else if ((metricOp === "min" || metricOp === "max") && colType !== "Number") {
|
|
946
|
-
if (nonNull.length > 0) {
|
|
947
|
-
const strs = nonNull.map(v => typeof v === "object" && v !== null && "value" in v ? String(v.value) : pythonValueText(v));
|
|
948
|
-
let best = strs[0];
|
|
949
|
-
for (let k = 1; k < strs.length; k++) {
|
|
950
|
-
if (metricOp === "min" ? strs[k] < best : strs[k] > best)
|
|
951
|
-
best = strs[k];
|
|
952
|
-
}
|
|
953
|
-
valStr = best;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
else if ((metricOp === "min" || metricOp === "max" || metricOp === "sum" || metricOp === "mean" || metricOp === "median" || metricOp === "stdev" || metricOp === "max_precision") && colType === "Number") {
|
|
957
|
-
if (nonNull.length > 0) {
|
|
958
|
-
const decs = nonNull.map(v => Decimal.parse(v.value));
|
|
959
|
-
if (metricOp === "min" || metricOp === "max") {
|
|
960
|
-
let best = decs[0];
|
|
961
|
-
for (let k = 1; k < decs.length; k++) {
|
|
962
|
-
if (metricOp === "min" ? decs[k].compare(best) < 0 : decs[k].compare(best) > 0)
|
|
963
|
-
best = decs[k];
|
|
964
|
-
}
|
|
965
|
-
valStr = fmtDec(best);
|
|
966
|
-
}
|
|
967
|
-
else if (metricOp === "max_precision") {
|
|
968
|
-
let maxP = 0;
|
|
969
|
-
for (const d of decs) {
|
|
970
|
-
const norm = d.normalized();
|
|
971
|
-
if (!norm.special && -norm.exponent > maxP)
|
|
972
|
-
maxP = -norm.exponent;
|
|
973
|
-
}
|
|
974
|
-
valStr = fmtDec(Decimal.parse(String(maxP)));
|
|
975
|
-
}
|
|
976
|
-
else if (metricOp === "median") {
|
|
977
|
-
const sorted = [...decs].sort((a, b) => a.compare(b));
|
|
978
|
-
const mid = Math.floor(sorted.length / 2);
|
|
979
|
-
const med = sorted.length % 2 === 1
|
|
980
|
-
? sorted[mid]
|
|
981
|
-
: sorted[mid - 1].add(sorted[mid]).divide(Decimal.parse("2"));
|
|
982
|
-
valStr = fmtDec(med);
|
|
983
|
-
}
|
|
984
|
-
else if (metricOp === "stdev") {
|
|
985
|
-
if (decs.length >= 2) {
|
|
986
|
-
const nums = decs.map(d => Number(d.toString()));
|
|
987
|
-
if (nums.some(n => !Number.isFinite(n)))
|
|
988
|
-
return undefined;
|
|
989
|
-
const mean = nums.reduce((a, b) => a + b, 0) / nums.length;
|
|
990
|
-
const variance = nums.reduce((acc, n) => acc + (n - mean) * (n - mean), 0) / (nums.length - 1);
|
|
991
|
-
valStr = fmtDec(Decimal.parse(String(Math.sqrt(variance))));
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
995
|
-
let sum = Decimal.parse("0");
|
|
996
|
-
for (const d of decs)
|
|
997
|
-
sum = sum.add(d);
|
|
998
|
-
valStr = fmtDec(metricOp === "sum" ? sum : sum.divide(Decimal.parse(String(decs.length))));
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
else {
|
|
1003
|
-
return undefined;
|
|
1004
|
-
}
|
|
1005
|
-
out += (ids.length === 1 ? "" : `${String(id + 1).padStart(3)}. ${table.headers[id]}: `) + valStr + "\n";
|
|
1006
|
-
}
|
|
1007
|
-
return out;
|
|
1008
|
-
}
|
|
1009
|
-
catch {
|
|
1010
|
-
return undefined;
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
export function evalSyncIn2csv(inBytes, opArgs, readFileSync) {
|
|
1014
|
-
try {
|
|
1015
|
-
let formatSpec;
|
|
1016
|
-
let keySpec;
|
|
1017
|
-
let schemaSpec;
|
|
1018
|
-
let sheetSpec;
|
|
1019
|
-
let namesOnly = false;
|
|
1020
|
-
const filteredArgs = [];
|
|
1021
|
-
let posDone = false;
|
|
1022
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
1023
|
-
const a = opArgs[i];
|
|
1024
|
-
if (!posDone && a === "--") {
|
|
1025
|
-
posDone = true;
|
|
1026
|
-
filteredArgs.push(a);
|
|
1027
|
-
continue;
|
|
1028
|
-
}
|
|
1029
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
1030
|
-
if (a === "-n" || a === "--names") {
|
|
1031
|
-
namesOnly = true;
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
if (a === "-f" || a.startsWith("-f") || a === "--format" || a.startsWith("--format=")) {
|
|
1035
|
-
const v = a.startsWith("--format=") ? a.slice(9) : a.startsWith("-f=") ? a.slice(3) : a.length > 2 && a.startsWith("-f") ? a.slice(2) : opArgs[++i];
|
|
1036
|
-
if (!v)
|
|
1037
|
-
return undefined;
|
|
1038
|
-
formatSpec = v.toLowerCase();
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
if (a === "-k" || a.startsWith("-k") || a === "--key" || a.startsWith("--key=")) {
|
|
1042
|
-
const v = a.startsWith("--key=") ? a.slice(6) : a.startsWith("-k=") ? a.slice(3) : a.length > 2 && a.startsWith("-k") ? a.slice(2) : opArgs[++i];
|
|
1043
|
-
if (!v)
|
|
1044
|
-
return undefined;
|
|
1045
|
-
keySpec = v;
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if (a === "--sheet" || a.startsWith("--sheet=")) {
|
|
1049
|
-
const v = a.startsWith("--sheet=") ? a.slice(8) : opArgs[++i];
|
|
1050
|
-
if (!v)
|
|
1051
|
-
return undefined;
|
|
1052
|
-
sheetSpec = v;
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (a === "-s" || a.startsWith("-s") || a === "--schema" || a.startsWith("--schema=")) {
|
|
1056
|
-
const v = a.startsWith("--schema=") ? a.slice(9) : a.startsWith("-s=") ? a.slice(3) : a.length > 2 && a.startsWith("-s") ? a.slice(2) : opArgs[++i];
|
|
1057
|
-
if (!v)
|
|
1058
|
-
return undefined;
|
|
1059
|
-
schemaSpec = v;
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
filteredArgs.push(a);
|
|
1064
|
-
}
|
|
1065
|
-
const opts = parseSyncCsvkitCommon(filteredArgs, "csvlook");
|
|
1066
|
-
if (!opts)
|
|
1067
|
-
return undefined;
|
|
1068
|
-
let sourceBytes = inBytes;
|
|
1069
|
-
if (opts.filePath !== undefined && opts.filePath !== "-") {
|
|
1070
|
-
if (!readFileSync)
|
|
1071
|
-
return undefined;
|
|
1072
|
-
sourceBytes = readFileSync(opts.filePath);
|
|
1073
|
-
}
|
|
1074
|
-
if (!sourceBytes || sourceBytes.byteLength > 16384)
|
|
1075
|
-
return undefined;
|
|
1076
|
-
let fmt = formatSpec;
|
|
1077
|
-
if (!fmt && opts.filePath && opts.filePath !== "-") {
|
|
1078
|
-
const lower = opts.filePath.toLowerCase();
|
|
1079
|
-
if (lower.endsWith(".geojson"))
|
|
1080
|
-
fmt = "geojson";
|
|
1081
|
-
else if (lower.endsWith(".xlsx"))
|
|
1082
|
-
fmt = "xlsx";
|
|
1083
|
-
else if (lower.endsWith(".json") || lower.endsWith(".js"))
|
|
1084
|
-
fmt = "json";
|
|
1085
|
-
else if (lower.endsWith(".ndjson") || lower.endsWith(".jsonl"))
|
|
1086
|
-
fmt = "ndjson";
|
|
1087
|
-
else if (lower.endsWith(".csv") || lower.endsWith(".tsv"))
|
|
1088
|
-
fmt = "csv";
|
|
1089
|
-
}
|
|
1090
|
-
if (!fmt && schemaSpec !== undefined)
|
|
1091
|
-
fmt = "fixed";
|
|
1092
|
-
if (!fmt && keySpec !== undefined)
|
|
1093
|
-
fmt = "json";
|
|
1094
|
-
if (fmt === "geojson") {
|
|
1095
|
-
if (namesOnly)
|
|
1096
|
-
return undefined;
|
|
1097
|
-
let text = syncUtf8Decoder.decode(sourceBytes);
|
|
1098
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
1099
|
-
text = text.slice(1);
|
|
1100
|
-
const doc = JSON.parse(text);
|
|
1101
|
-
if (!doc || typeof doc !== "object" || Array.isArray(doc) || doc.type !== "FeatureCollection" || !Array.isArray(doc.features)) {
|
|
1102
|
-
return undefined;
|
|
1103
|
-
}
|
|
1104
|
-
const propKeys = [];
|
|
1105
|
-
const seenProps = new Set();
|
|
1106
|
-
for (const feat of doc.features) {
|
|
1107
|
-
if (!feat || typeof feat !== "object" || Array.isArray(feat))
|
|
1108
|
-
return undefined;
|
|
1109
|
-
const props = feat.properties && typeof feat.properties === "object" && !Array.isArray(feat.properties) ? feat.properties : {};
|
|
1110
|
-
for (const k of Object.keys(props)) {
|
|
1111
|
-
if (!seenProps.has(k)) {
|
|
1112
|
-
seenProps.add(k);
|
|
1113
|
-
propKeys.push(k);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1118
|
-
let out = writeCsvRow(["id", ...propKeys, "geojson", "type", "longitude", "latitude"], outDialect);
|
|
1119
|
-
for (const feat of doc.features) {
|
|
1120
|
-
const props = feat.properties && typeof feat.properties === "object" && !Array.isArray(feat.properties) ? feat.properties : {};
|
|
1121
|
-
const geom = feat.geometry && typeof feat.geometry === "object" && !Array.isArray(feat.geometry) ? feat.geometry : null;
|
|
1122
|
-
const gType = geom ? String(geom.type ?? "") : "";
|
|
1123
|
-
const coords = gType === "Point" && Array.isArray(geom?.coordinates) && geom.coordinates.length >= 2 ? geom.coordinates : undefined;
|
|
1124
|
-
const fmtVal = (v, isProp = false) => {
|
|
1125
|
-
if (v === undefined || v === null)
|
|
1126
|
-
return "";
|
|
1127
|
-
if (typeof v === "boolean")
|
|
1128
|
-
return v ? "True" : "False";
|
|
1129
|
-
if (typeof v === "object")
|
|
1130
|
-
return isProp ? JSON.stringify(v) : "";
|
|
1131
|
-
return String(v);
|
|
1132
|
-
};
|
|
1133
|
-
const geomJson = JSON.stringify(geom).replace(/":/g, '": ').replace(/,"/g, ', "');
|
|
1134
|
-
const rowCells = [
|
|
1135
|
-
fmtVal(feat.id),
|
|
1136
|
-
...propKeys.map((k) => fmtVal(props[k], true)),
|
|
1137
|
-
geomJson,
|
|
1138
|
-
gType,
|
|
1139
|
-
coords ? fmtVal(coords[0]) : "",
|
|
1140
|
-
coords ? fmtVal(coords[1]) : "",
|
|
1141
|
-
];
|
|
1142
|
-
out += writeCsvRow(rowCells, outDialect);
|
|
1143
|
-
}
|
|
1144
|
-
return out;
|
|
1145
|
-
}
|
|
1146
|
-
if (fmt === "xlsx") {
|
|
1147
|
-
if (sourceBytes[0] !== 80 || sourceBytes[1] !== 75)
|
|
1148
|
-
return undefined;
|
|
1149
|
-
const entries = readZipArchiveEntries(sourceBytes);
|
|
1150
|
-
if (entries.has("EncryptionInfo") || entries.has("EncryptedPackage"))
|
|
1151
|
-
return undefined;
|
|
1152
|
-
const wbXmlBytes = entries.get("xl/workbook.xml");
|
|
1153
|
-
if (!wbXmlBytes)
|
|
1154
|
-
return undefined;
|
|
1155
|
-
const wbXml = syncUtf8Decoder.decode(wbXmlBytes);
|
|
1156
|
-
const sheetNames = [];
|
|
1157
|
-
for (const m of wbXml.matchAll(/<sheet\b[^>]*\bname="([^"]+)"/g)) {
|
|
1158
|
-
sheetNames.push(m[1]);
|
|
1159
|
-
}
|
|
1160
|
-
if (sheetNames.length === 0)
|
|
1161
|
-
return undefined;
|
|
1162
|
-
if (namesOnly) {
|
|
1163
|
-
return sheetNames.map((n) => n + "\n").join("");
|
|
1164
|
-
}
|
|
1165
|
-
const targetIdx = sheetSpec ? sheetNames.indexOf(sheetSpec) : 0;
|
|
1166
|
-
if (targetIdx < 0)
|
|
1167
|
-
return undefined;
|
|
1168
|
-
const sheetBytes = entries.get(`xl/worksheets/sheet${targetIdx + 1}.xml`);
|
|
1169
|
-
if (!sheetBytes)
|
|
1170
|
-
return undefined;
|
|
1171
|
-
const sheetXml = syncUtf8Decoder.decode(sheetBytes);
|
|
1172
|
-
if (/<f(?:\s|>)/u.test(sheetXml))
|
|
1173
|
-
return undefined;
|
|
1174
|
-
const sharedStrings = [];
|
|
1175
|
-
const sstBytes = entries.get("xl/sharedStrings.xml");
|
|
1176
|
-
if (sstBytes) {
|
|
1177
|
-
const sstXml = syncUtf8Decoder.decode(sstBytes);
|
|
1178
|
-
for (const si of sstXml.matchAll(/<si\b[\s\S]*?<\/si>/g)) {
|
|
1179
|
-
const parts = [...si[0].matchAll(/<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/g)].map((t) => (t[1] ?? "").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&"));
|
|
1180
|
-
sharedStrings.push(parts.join(""));
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
const csvRows = [];
|
|
1184
|
-
for (const rm of sheetXml.matchAll(/<row\b[\s\S]*?<\/row>/g)) {
|
|
1185
|
-
const cells = [];
|
|
1186
|
-
for (const cm of rm[0].matchAll(/<c\b([^>]*?)(?:\/>|>([\s\S]*?)<\/c>)/g)) {
|
|
1187
|
-
const attrs = cm[1] ?? "";
|
|
1188
|
-
const body = cm[2] ?? "";
|
|
1189
|
-
const refM = /\br="([A-Z]+)\d+"/i.exec(attrs);
|
|
1190
|
-
if (refM?.[1]) {
|
|
1191
|
-
let col = 0;
|
|
1192
|
-
for (const ch of refM[1].toUpperCase())
|
|
1193
|
-
col = col * 26 + (ch.charCodeAt(0) - 64);
|
|
1194
|
-
col -= 1;
|
|
1195
|
-
while (cells.length < col)
|
|
1196
|
-
cells.push("");
|
|
1197
|
-
}
|
|
1198
|
-
if (cm[2] === undefined) {
|
|
1199
|
-
cells.push("");
|
|
1200
|
-
continue;
|
|
1201
|
-
}
|
|
1202
|
-
const tM = /\bt="([^"]+)"/.exec(attrs);
|
|
1203
|
-
const cType = tM?.[1] ?? "n";
|
|
1204
|
-
if (cType === "inlineStr") {
|
|
1205
|
-
const tv = /<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/.exec(body);
|
|
1206
|
-
cells.push((tv?.[1] ?? "").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&"));
|
|
1207
|
-
}
|
|
1208
|
-
else {
|
|
1209
|
-
const vv = /<v>([\s\S]*?)<\/v>/.exec(body);
|
|
1210
|
-
const raw = (vv?.[1] ?? "").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
1211
|
-
cells.push(cType === "s" ? (sharedStrings[Number.parseInt(raw, 10)] ?? "") : raw);
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
csvRows.push(cells);
|
|
1215
|
-
}
|
|
1216
|
-
const synthDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1217
|
-
const synthCsv = csvRows.map((r) => writeCsvRow(r, synthDialect)).join("");
|
|
1218
|
-
const synthBytes = new TextEncoder().encode(synthCsv);
|
|
1219
|
-
const table = loadSyncTypedTable(synthBytes, { ...opts, filePath: "-" }, undefined);
|
|
1220
|
-
if (!table)
|
|
1221
|
-
return undefined;
|
|
1222
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
1223
|
-
out += writeCsvRow(table.headers, synthDialect);
|
|
1224
|
-
for (const row of table.rows) {
|
|
1225
|
-
out += writeCsvRow(row.map((v) => (v === null ? "" : typeof v === "object" && v.kind === "datetime" ? v.value.replace(" ", "T") : pythonValueText(v))), synthDialect);
|
|
1226
|
-
}
|
|
1227
|
-
return out;
|
|
1228
|
-
}
|
|
1229
|
-
if (fmt === "fixed") {
|
|
1230
|
-
if (!schemaSpec || !readFileSync)
|
|
1231
|
-
return undefined;
|
|
1232
|
-
const schemaBytes = readFileSync(schemaSpec);
|
|
1233
|
-
if (!schemaBytes || schemaBytes.byteLength > 16384)
|
|
1234
|
-
return undefined;
|
|
1235
|
-
let schemaText = syncUtf8Decoder.decode(schemaBytes);
|
|
1236
|
-
if (schemaText.charCodeAt(0) === 0xfeff)
|
|
1237
|
-
schemaText = schemaText.slice(1);
|
|
1238
|
-
const schemaRows = Array.from(readCsv(schemaText, { delimiter: ",", quotechar: "\"", doublequote: true }), record => record.cells);
|
|
1239
|
-
if (schemaRows.length < 2)
|
|
1240
|
-
return undefined;
|
|
1241
|
-
const sHead = schemaRows[0];
|
|
1242
|
-
const colIdx = sHead.indexOf("column");
|
|
1243
|
-
const startIdx = sHead.indexOf("start");
|
|
1244
|
-
const lenIdx = sHead.indexOf("length");
|
|
1245
|
-
if (colIdx < 0 || startIdx < 0 || lenIdx < 0)
|
|
1246
|
-
return undefined;
|
|
1247
|
-
let oneBased;
|
|
1248
|
-
const fields = [];
|
|
1249
|
-
for (let r = 1; r < schemaRows.length; r++) {
|
|
1250
|
-
const row = schemaRows[r];
|
|
1251
|
-
if (row.length === 0 || (row.length === 1 && row[0] === ""))
|
|
1252
|
-
continue;
|
|
1253
|
-
const stNum = Number(row[startIdx]);
|
|
1254
|
-
const lnNum = Number(row[lenIdx]);
|
|
1255
|
-
if (!Number.isSafeInteger(stNum) || !Number.isSafeInteger(lnNum) || stNum < 0 || lnNum < 0)
|
|
1256
|
-
return undefined;
|
|
1257
|
-
oneBased ??= stNum === 1;
|
|
1258
|
-
fields.push({ name: row[colIdx], start: stNum - (oneBased ? 1 : 0), length: lnNum });
|
|
1259
|
-
}
|
|
1260
|
-
let inText = syncUtf8Decoder.decode(sourceBytes);
|
|
1261
|
-
if (inText.charCodeAt(0) === 0xfeff)
|
|
1262
|
-
inText = inText.slice(1);
|
|
1263
|
-
const rawLines = inText.split(/\r?\n/);
|
|
1264
|
-
if (rawLines.length > 0 && rawLines[rawLines.length - 1] === "")
|
|
1265
|
-
rawLines.pop();
|
|
1266
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1267
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
1268
|
-
out += writeCsvRow(fields.map(f => f.name), outDialect);
|
|
1269
|
-
for (let idx = opts.skipLines; idx < rawLines.length; idx++) {
|
|
1270
|
-
const chars = Array.from(rawLines[idx]);
|
|
1271
|
-
const cells = fields.map(f => chars.slice(f.start, f.start + f.length).join("").trim());
|
|
1272
|
-
out += writeCsvRow(cells, outDialect);
|
|
1273
|
-
}
|
|
1274
|
-
return out;
|
|
1275
|
-
}
|
|
1276
|
-
if (namesOnly) {
|
|
1277
|
-
if (fmt !== "json")
|
|
1278
|
-
return undefined;
|
|
1279
|
-
let text = syncUtf8Decoder.decode(sourceBytes);
|
|
1280
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
1281
|
-
text = text.slice(1);
|
|
1282
|
-
const root = JSON.parse(text);
|
|
1283
|
-
if (!root || typeof root !== "object" || Array.isArray(root))
|
|
1284
|
-
return undefined;
|
|
1285
|
-
return Object.keys(root).map(k => k + "\n").join("");
|
|
1286
|
-
}
|
|
1287
|
-
if (fmt === "csv") {
|
|
1288
|
-
const table = loadSyncTypedTable(inBytes, opts, readFileSync);
|
|
1289
|
-
if (!table)
|
|
1290
|
-
return undefined;
|
|
1291
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1292
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
1293
|
-
out += writeCsvRow(table.headers, outDialect);
|
|
1294
|
-
for (const row of table.rows) {
|
|
1295
|
-
out += writeCsvRow(row.map(v => (v === null ? "" : typeof v === "object" && v.kind === "datetime" ? v.value.replace(" ", "T") : pythonValueText(v))), outDialect);
|
|
1296
|
-
}
|
|
1297
|
-
return out;
|
|
1298
|
-
}
|
|
1299
|
-
if (fmt !== "json" && fmt !== "ndjson")
|
|
1300
|
-
return undefined;
|
|
1301
|
-
if (fmt === "ndjson" && keySpec !== undefined)
|
|
1302
|
-
return undefined;
|
|
1303
|
-
let text = syncUtf8Decoder.decode(sourceBytes);
|
|
1304
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
1305
|
-
text = text.slice(1);
|
|
1306
|
-
let parsedItems;
|
|
1307
|
-
if (fmt === "ndjson") {
|
|
1308
|
-
parsedItems = [];
|
|
1309
|
-
for (const line of text.split(/\r?\n/)) {
|
|
1310
|
-
const trimmed = line.trim();
|
|
1311
|
-
if (!trimmed)
|
|
1312
|
-
continue;
|
|
1313
|
-
parsedItems.push(JSON.parse(trimmed));
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
else {
|
|
1317
|
-
let root = JSON.parse(text);
|
|
1318
|
-
if (root && typeof root === "object" && !Array.isArray(root)) {
|
|
1319
|
-
if (!keySpec || !(keySpec in root))
|
|
1320
|
-
return undefined;
|
|
1321
|
-
root = root[keySpec];
|
|
1322
|
-
}
|
|
1323
|
-
if (!Array.isArray(root))
|
|
1324
|
-
return undefined;
|
|
1325
|
-
parsedItems = root;
|
|
1326
|
-
}
|
|
1327
|
-
const headers = [];
|
|
1328
|
-
const known = new Set();
|
|
1329
|
-
const rawMaps = [];
|
|
1330
|
-
const flatten = (val, path, row) => {
|
|
1331
|
-
if (val !== null && typeof val === "object") {
|
|
1332
|
-
if (Array.isArray(val)) {
|
|
1333
|
-
for (let idx = 0; idx < val.length; idx++)
|
|
1334
|
-
flatten(val[idx], path + String(idx) + "/", row);
|
|
1335
|
-
}
|
|
1336
|
-
else {
|
|
1337
|
-
for (const [k, child] of Object.entries(val))
|
|
1338
|
-
flatten(child, path + k + "/", row);
|
|
1339
|
-
}
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
let start = 0;
|
|
1343
|
-
let end = path.length;
|
|
1344
|
-
while (path[start] === "/")
|
|
1345
|
-
start++;
|
|
1346
|
-
while (end > start && path[end - 1] === "/")
|
|
1347
|
-
end--;
|
|
1348
|
-
const name = path.slice(start, end);
|
|
1349
|
-
if (!name)
|
|
1350
|
-
throw new Error("empty header");
|
|
1351
|
-
const cell = val === null || val === undefined ? null : typeof val === "boolean" ? (val ? "True" : "False") : String(val);
|
|
1352
|
-
row.set(name, cell);
|
|
1353
|
-
};
|
|
1354
|
-
for (const item of parsedItems) {
|
|
1355
|
-
if (item === null || typeof item !== "object" || Array.isArray(item))
|
|
1356
|
-
return undefined;
|
|
1357
|
-
const row = new Map();
|
|
1358
|
-
flatten(item, "", row);
|
|
1359
|
-
for (const name of row.keys()) {
|
|
1360
|
-
if (!known.has(name)) {
|
|
1361
|
-
known.add(name);
|
|
1362
|
-
headers.push(name);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
rawMaps.push(row);
|
|
1366
|
-
}
|
|
1367
|
-
if (headers.length === 0)
|
|
1368
|
-
return undefined;
|
|
1369
|
-
const stringRows = rawMaps.map((m, rIdx) => {
|
|
1370
|
-
const cells = headers.map(h => m.get(h) ?? "");
|
|
1371
|
-
return opts.lineNumbers ? [String(rIdx + 1), ...cells] : cells;
|
|
1372
|
-
});
|
|
1373
|
-
const finalHeaders = opts.lineNumbers ? ["line_number", ...headers] : headers;
|
|
1374
|
-
const inferenceOpts = {
|
|
1375
|
-
now: Date.now(),
|
|
1376
|
-
timezone: "UTC",
|
|
1377
|
-
noInference: opts.noInference,
|
|
1378
|
-
numberTextOnly: false,
|
|
1379
|
-
blanks: opts.blanks,
|
|
1380
|
-
nullValues: [],
|
|
1381
|
-
noLeadingZeroes: opts.noLeadingZeroes,
|
|
1382
|
-
maxDecimalDigits: Infinity,
|
|
1383
|
-
maxDecimalExponent: Infinity,
|
|
1384
|
-
};
|
|
1385
|
-
const table = inferTable(finalHeaders, stringRows, inferenceOpts);
|
|
1386
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1387
|
-
let out = opts.addBom ? "\ufeff" : "";
|
|
1388
|
-
out += writeCsvRow(table.headers, outDialect);
|
|
1389
|
-
for (const row of table.rows) {
|
|
1390
|
-
out += writeCsvRow(row.map(v => (v === null ? "" : typeof v === "object" && v.kind === "datetime" ? v.value.replace(" ", "T") : pythonValueText(v))), outDialect);
|
|
1391
|
-
}
|
|
1392
|
-
return out;
|
|
1393
|
-
}
|
|
1394
|
-
catch {
|
|
1395
|
-
return undefined;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
export function evalSyncCsvstack(inBytes, opArgs, readFileSync) {
|
|
1399
|
-
try {
|
|
1400
|
-
let groupsSpec;
|
|
1401
|
-
let groupName = "group";
|
|
1402
|
-
let groupByFilenames = false;
|
|
1403
|
-
let noHeaderRow = false;
|
|
1404
|
-
let lineNumbers = false;
|
|
1405
|
-
let addBom = false;
|
|
1406
|
-
let delimiter = ",";
|
|
1407
|
-
let tabs = false;
|
|
1408
|
-
const files = [];
|
|
1409
|
-
let posDone = false;
|
|
1410
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
1411
|
-
const a = opArgs[i];
|
|
1412
|
-
if (!posDone && a === "--") {
|
|
1413
|
-
posDone = true;
|
|
1414
|
-
continue;
|
|
1415
|
-
}
|
|
1416
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
1417
|
-
if (a === "-H" || a === "--no-header-row") {
|
|
1418
|
-
noHeaderRow = true;
|
|
1419
|
-
continue;
|
|
1420
|
-
}
|
|
1421
|
-
if (a === "-l" || a === "--linenumbers") {
|
|
1422
|
-
lineNumbers = true;
|
|
1423
|
-
continue;
|
|
1424
|
-
}
|
|
1425
|
-
if (a === "--add-bom") {
|
|
1426
|
-
addBom = true;
|
|
1427
|
-
continue;
|
|
1428
|
-
}
|
|
1429
|
-
if (a === "-t" || a === "--tabs") {
|
|
1430
|
-
tabs = true;
|
|
1431
|
-
continue;
|
|
1432
|
-
}
|
|
1433
|
-
if (a === "-d" || a === "--delimiter" || a.startsWith("--delimiter=")) {
|
|
1434
|
-
const v = a.startsWith("--delimiter=") ? a.slice(12) : opArgs[++i];
|
|
1435
|
-
if (!v || Array.from(v).length !== 1)
|
|
1436
|
-
return undefined;
|
|
1437
|
-
delimiter = v;
|
|
1438
|
-
continue;
|
|
1439
|
-
}
|
|
1440
|
-
if (a === "--filenames") {
|
|
1441
|
-
groupByFilenames = true;
|
|
1442
|
-
continue;
|
|
1443
|
-
}
|
|
1444
|
-
if (a === "-g" || a === "--groups") {
|
|
1445
|
-
const v = opArgs[++i];
|
|
1446
|
-
if (v === undefined)
|
|
1447
|
-
return undefined;
|
|
1448
|
-
groupsSpec = v;
|
|
1449
|
-
continue;
|
|
1450
|
-
}
|
|
1451
|
-
if (a === "-n" || a === "--group-name") {
|
|
1452
|
-
const v = opArgs[++i];
|
|
1453
|
-
if (v === undefined)
|
|
1454
|
-
return undefined;
|
|
1455
|
-
groupName = v;
|
|
1456
|
-
continue;
|
|
1457
|
-
}
|
|
1458
|
-
return undefined;
|
|
1459
|
-
}
|
|
1460
|
-
files.push(a);
|
|
1461
|
-
}
|
|
1462
|
-
if (files.length === 0)
|
|
1463
|
-
files.push("-");
|
|
1464
|
-
if (noHeaderRow)
|
|
1465
|
-
return undefined;
|
|
1466
|
-
const groups = groupsSpec !== undefined && !groupByFilenames ? groupsSpec.split(",") : undefined;
|
|
1467
|
-
if (groups && groups.length !== files.length)
|
|
1468
|
-
return undefined;
|
|
1469
|
-
const grouped = groupsSpec !== undefined || groupByFilenames;
|
|
1470
|
-
const parsedFiles = [];
|
|
1471
|
-
const unionHeaders = [];
|
|
1472
|
-
const seen = new Set();
|
|
1473
|
-
for (let idx = 0; idx < files.length; idx++) {
|
|
1474
|
-
const f = files[idx];
|
|
1475
|
-
const bytes = f === "-" ? inBytes : readFileSync ? readFileSync(f) : undefined;
|
|
1476
|
-
if (!bytes || bytes.byteLength > 16384)
|
|
1477
|
-
return undefined;
|
|
1478
|
-
let text = syncUtf8Decoder.decode(bytes);
|
|
1479
|
-
if (text.charCodeAt(0) === 0xfeff)
|
|
1480
|
-
text = text.slice(1);
|
|
1481
|
-
const recs = [...readCsv(text, { delimiter: tabs ? "\t" : delimiter, quotechar: "\"", doublequote: true, skipinitialspace: false })];
|
|
1482
|
-
const hdr = recs[0] ? recs[0].cells.map(c => pythonValueText(c)) : [];
|
|
1483
|
-
for (const h of hdr) {
|
|
1484
|
-
if (!seen.has(h)) {
|
|
1485
|
-
seen.add(h);
|
|
1486
|
-
unionHeaders.push(h);
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
const groupVal = groups ? groups[idx] : f.split("/").at(-1);
|
|
1490
|
-
parsedFiles.push({
|
|
1491
|
-
group: groupVal,
|
|
1492
|
-
headers: hdr,
|
|
1493
|
-
rows: recs.slice(1).map(r => r.cells.map(c => pythonValueText(c))),
|
|
1494
|
-
});
|
|
1495
|
-
}
|
|
1496
|
-
const outHeaders = grouped ? [groupName, ...unionHeaders] : [...unionHeaders];
|
|
1497
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1498
|
-
let out = addBom ? "\ufeff" : "";
|
|
1499
|
-
out += writeCsvRow(lineNumbers ? ["line_number", ...outHeaders] : outHeaders, outDialect);
|
|
1500
|
-
let lineNum = 1;
|
|
1501
|
-
for (const pf of parsedFiles) {
|
|
1502
|
-
for (const r of pf.rows) {
|
|
1503
|
-
const rowMap = new Map();
|
|
1504
|
-
for (let c = 0; c < pf.headers.length; c++)
|
|
1505
|
-
rowMap.set(pf.headers[c], r[c] ?? "");
|
|
1506
|
-
const cells = unionHeaders.map(h => rowMap.get(h) ?? "");
|
|
1507
|
-
if (grouped)
|
|
1508
|
-
cells.unshift(pf.group);
|
|
1509
|
-
if (lineNumbers)
|
|
1510
|
-
cells.unshift(String(lineNum++));
|
|
1511
|
-
out += writeCsvRow(cells, outDialect);
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
return out;
|
|
1515
|
-
}
|
|
1516
|
-
catch {
|
|
1517
|
-
return undefined;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
export function evalSyncCsvjoin(inBytes, opArgs, readFileSync) {
|
|
1521
|
-
try {
|
|
1522
|
-
let columnsSpec;
|
|
1523
|
-
let joinMode = "inner";
|
|
1524
|
-
let noInference = false;
|
|
1525
|
-
let addBom = false;
|
|
1526
|
-
let delimiter;
|
|
1527
|
-
let tabs = false;
|
|
1528
|
-
const files = [];
|
|
1529
|
-
let posDone = false;
|
|
1530
|
-
for (let i = 0; i < opArgs.length; i++) {
|
|
1531
|
-
const a = opArgs[i];
|
|
1532
|
-
if (!posDone && a === "--") {
|
|
1533
|
-
posDone = true;
|
|
1534
|
-
continue;
|
|
1535
|
-
}
|
|
1536
|
-
if (!posDone && a.startsWith("-") && a !== "-") {
|
|
1537
|
-
if (a === "--left") {
|
|
1538
|
-
joinMode = "left";
|
|
1539
|
-
continue;
|
|
1540
|
-
}
|
|
1541
|
-
if (a === "--right") {
|
|
1542
|
-
joinMode = "right";
|
|
1543
|
-
continue;
|
|
1544
|
-
}
|
|
1545
|
-
if (a === "--outer") {
|
|
1546
|
-
joinMode = "outer";
|
|
1547
|
-
continue;
|
|
1548
|
-
}
|
|
1549
|
-
if (a === "-I" || a === "--no-inference") {
|
|
1550
|
-
noInference = true;
|
|
1551
|
-
continue;
|
|
1552
|
-
}
|
|
1553
|
-
if (a === "--add-bom") {
|
|
1554
|
-
addBom = true;
|
|
1555
|
-
continue;
|
|
1556
|
-
}
|
|
1557
|
-
if (a === "-t" || a === "--tabs") {
|
|
1558
|
-
tabs = true;
|
|
1559
|
-
continue;
|
|
1560
|
-
}
|
|
1561
|
-
if (a === "-d" || a === "--delimiter" || a.startsWith("--delimiter=")) {
|
|
1562
|
-
const v = a.startsWith("--delimiter=") ? a.slice(12) : opArgs[++i];
|
|
1563
|
-
if (!v || Array.from(v).length !== 1)
|
|
1564
|
-
return undefined;
|
|
1565
|
-
delimiter = v;
|
|
1566
|
-
continue;
|
|
1567
|
-
}
|
|
1568
|
-
if (a === "-c" || a === "--columns") {
|
|
1569
|
-
const v = opArgs[++i];
|
|
1570
|
-
if (v === undefined)
|
|
1571
|
-
return undefined;
|
|
1572
|
-
columnsSpec = v;
|
|
1573
|
-
continue;
|
|
1574
|
-
}
|
|
1575
|
-
return undefined;
|
|
1576
|
-
}
|
|
1577
|
-
files.push(a);
|
|
1578
|
-
}
|
|
1579
|
-
if (files.length !== 2)
|
|
1580
|
-
return undefined;
|
|
1581
|
-
const leftOpts = {
|
|
1582
|
-
...(delimiter === undefined ? {} : { delimiter }), tabs, noDoublequote: false, skipInitialSpace: false, noHeaderRow: false,
|
|
1583
|
-
skipLines: 0, lineNumbers: false, addBom: false, noInference, blanks: false,
|
|
1584
|
-
noLeadingZeroes: false, sniffLimit: 1024, noNumberEllipsis: false,
|
|
1585
|
-
indent: null, key: null, streamOutput: false, filePath: files[0],
|
|
1586
|
-
};
|
|
1587
|
-
const rightOpts = { ...leftOpts, filePath: files[1] };
|
|
1588
|
-
const leftTable = loadSyncTypedTable(inBytes, leftOpts, readFileSync);
|
|
1589
|
-
const rightTable = loadSyncTypedTable(inBytes, rightOpts, readFileSync);
|
|
1590
|
-
if (!leftTable || !rightTable)
|
|
1591
|
-
return undefined;
|
|
1592
|
-
if (!columnsSpec) {
|
|
1593
|
-
if (joinMode !== "inner")
|
|
1594
|
-
return undefined;
|
|
1595
|
-
const outHeaders = [
|
|
1596
|
-
...leftTable.headers,
|
|
1597
|
-
...rightTable.headers.map(h => (leftTable.headers.includes(h) ? h + "2" : h)),
|
|
1598
|
-
];
|
|
1599
|
-
if (new Set(outHeaders).size !== outHeaders.length)
|
|
1600
|
-
return undefined;
|
|
1601
|
-
const maxRows = Math.max(leftTable.rows.length, rightTable.rows.length);
|
|
1602
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1603
|
-
let out = addBom ? "\ufeff" : "";
|
|
1604
|
-
out += writeCsvRow(outHeaders, outDialect);
|
|
1605
|
-
for (let r = 0; r < maxRows; r++) {
|
|
1606
|
-
const lRow = leftTable.rows[r] ?? leftTable.headers.map(() => null);
|
|
1607
|
-
const rRow = rightTable.rows[r] ?? rightTable.headers.map(() => null);
|
|
1608
|
-
out += writeCsvRow([...lRow, ...rRow].map(v => (v === null ? "" : typeof v === "object" && v.kind === "datetime" ? v.value.replace(" ", "T") : pythonValueText(v))), outDialect);
|
|
1609
|
-
}
|
|
1610
|
-
return out;
|
|
1611
|
-
}
|
|
1612
|
-
const colParts = columnsSpec.split(",");
|
|
1613
|
-
if (colParts.length !== 1 && colParts.length !== 2)
|
|
1614
|
-
return undefined;
|
|
1615
|
-
const leftKey = matchColumnIdentifier(leftTable.headers, colParts[0], 1);
|
|
1616
|
-
const rightKey = matchColumnIdentifier(rightTable.headers, colParts[1] ?? colParts[0], 1);
|
|
1617
|
-
const full = joinMode === "outer" || joinMode === "right";
|
|
1618
|
-
const inner = joinMode === "inner";
|
|
1619
|
-
const keyVal = (v) => {
|
|
1620
|
-
if (v === null)
|
|
1621
|
-
return "null";
|
|
1622
|
-
if (typeof v === "string")
|
|
1623
|
-
return "text:" + v;
|
|
1624
|
-
if (typeof v === "boolean")
|
|
1625
|
-
return v ? "number:1:0" : "number:0";
|
|
1626
|
-
if (v.kind === "decimal") {
|
|
1627
|
-
const d = Decimal.parse(v.value).normalized();
|
|
1628
|
-
return "number:" + d.toString();
|
|
1629
|
-
}
|
|
1630
|
-
return "other:" + pythonValueText(v);
|
|
1631
|
-
};
|
|
1632
|
-
const includedRight = rightTable.headers.map((_, idx) => idx).filter(idx => full || idx !== rightKey);
|
|
1633
|
-
const outHeaders = [
|
|
1634
|
-
...leftTable.headers,
|
|
1635
|
-
...includedRight.map(idx => (leftTable.headers.includes(rightTable.headers[idx]) ? rightTable.headers[idx] + "2" : rightTable.headers[idx])),
|
|
1636
|
-
];
|
|
1637
|
-
if (new Set(outHeaders).size !== outHeaders.length)
|
|
1638
|
-
return undefined;
|
|
1639
|
-
const rightHash = new Map();
|
|
1640
|
-
const rightKeys = [];
|
|
1641
|
-
for (const row of rightTable.rows) {
|
|
1642
|
-
const k = keyVal(row[rightKey]);
|
|
1643
|
-
rightKeys.push(k);
|
|
1644
|
-
const list = rightHash.get(k);
|
|
1645
|
-
if (list)
|
|
1646
|
-
list.push(row);
|
|
1647
|
-
else
|
|
1648
|
-
rightHash.set(k, [row]);
|
|
1649
|
-
}
|
|
1650
|
-
const joinedRows = [];
|
|
1651
|
-
const seenKeys = new Set();
|
|
1652
|
-
for (const lRow of leftTable.rows) {
|
|
1653
|
-
const k = keyVal(lRow[leftKey]);
|
|
1654
|
-
const matches = k === "null" ? undefined : rightHash.get(k);
|
|
1655
|
-
if (matches) {
|
|
1656
|
-
seenKeys.add(k);
|
|
1657
|
-
for (const rRow of matches) {
|
|
1658
|
-
joinedRows.push([...lRow, ...includedRight.map(idx => rRow[idx])]);
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
else if (!inner && joinMode !== "right") {
|
|
1662
|
-
joinedRows.push([...lRow, ...includedRight.map(() => null)]);
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
if (full) {
|
|
1666
|
-
for (let i = 0; i < rightTable.rows.length; i++) {
|
|
1667
|
-
const k = rightKeys[i];
|
|
1668
|
-
if (k === "null" || !seenKeys.has(k)) {
|
|
1669
|
-
const rRow = rightTable.rows[i];
|
|
1670
|
-
joinedRows.push([...leftTable.headers.map(() => null), ...includedRight.map(idx => rRow[idx])]);
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
const outDialect = { delimiter: ",", quotechar: "\"", doublequote: true, lineterminator: "\n" };
|
|
1675
|
-
let out = addBom ? "\ufeff" : "";
|
|
1676
|
-
out += writeCsvRow(outHeaders, outDialect);
|
|
1677
|
-
for (const row of joinedRows) {
|
|
1678
|
-
out += writeCsvRow(row.map(v => (v === null ? "" : typeof v === "object" && v.kind === "datetime" ? v.value.replace(" ", "T") : pythonValueText(v))), outDialect);
|
|
1679
|
-
}
|
|
1680
|
-
return out;
|
|
1681
|
-
}
|
|
1682
|
-
catch {
|
|
1683
|
-
return undefined;
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
52
|
//# sourceMappingURL=index.js.map
|