token-goat 2.9.13 → 2.9.15
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 +28 -1
- package/dist/token-goat-chunk-2X2EBBC6.mjs +277 -0
- package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
- package/dist/token-goat-chunk-3NSDDTGL.mjs +34 -0
- package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
- package/dist/token-goat-chunk-5V7DAC7V.mjs +123 -0
- package/dist/token-goat-chunk-6DLVZDB6.mjs +34 -0
- package/dist/token-goat-chunk-7ZYK25AO.mjs +24 -0
- package/dist/token-goat-chunk-A4JYKD5H.mjs +144 -0
- package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
- package/dist/token-goat-chunk-ASYEPR3S.mjs +212 -0
- package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-ATIFTMRC.mjs} +31 -13
- package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-BL5LNGBG.mjs} +3935 -11949
- package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-C5JIO6HK.mjs} +8 -4
- package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-DQ4J5AFF.mjs} +50 -18
- package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
- package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-GIIHUSZX.mjs} +142 -21
- package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
- package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-GMQQA7E4.mjs} +12576 -12326
- package/dist/token-goat-chunk-IVUQLQWN.mjs +2046 -0
- package/dist/token-goat-chunk-K7F2BFIK.mjs +2430 -0
- package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-LCZBPOIN.mjs} +10197 -9717
- package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
- package/dist/token-goat-chunk-LT7JRU6K.mjs +22 -0
- package/dist/token-goat-chunk-MZDIJJ3R.mjs +420 -0
- package/dist/token-goat-chunk-NDPO7GAH.mjs +177 -0
- package/dist/token-goat-chunk-NDRP4KJQ.mjs +4371 -0
- package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
- package/dist/token-goat-chunk-NU7TLMQK.mjs +585 -0
- package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
- package/dist/token-goat-chunk-OUGNPMDA.mjs +959 -0
- package/dist/token-goat-chunk-PM76YS22.mjs +1341 -0
- package/dist/token-goat-chunk-S4XRY446.mjs +2637 -0
- package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-SFAS46RE.mjs} +5 -3
- package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-SZWYESBS.mjs} +793 -650
- package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-XEPXYDPI.mjs} +3 -2
- package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
- package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
- package/dist/token-goat-chunk-YKG35VHC.mjs +228 -0
- package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-YQ7WI2CO.mjs} +990 -106
- package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-YZX7EFG4.mjs} +1 -1
- package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
- package/dist/token-goat-hook.mjs +16 -8
- package/dist/token-goat.core.mjs +27 -10
- package/docs/cli.md +9 -6
- package/package.json +4 -2
- package/dist/token-goat-chunk-FQCNJV4V.mjs +0 -693
- package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
- package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
- package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
- package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
- package/dist/token-goat-chunk-UMXJN7DI.mjs +0 -5521
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
GENERIC_CLAUSE,
|
|
4
5
|
lastContentLine,
|
|
5
6
|
makeLineSymbol,
|
|
6
7
|
matchGroovySlashy,
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
stripMultilineStringSpan,
|
|
10
11
|
stripNestedBlockCommentSpan,
|
|
11
12
|
stripStringLiterals
|
|
12
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-K7F2BFIK.mjs";
|
|
13
14
|
import {
|
|
14
15
|
init_define_import_meta_env
|
|
15
16
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -22,7 +23,7 @@ var IDENT = `(?:\`[^\`]+\`|[${IDENT_START}][${IDENT_CONT}]*)`;
|
|
|
22
23
|
function unquoteIdent(name) {
|
|
23
24
|
return name.startsWith("`") && name.endsWith("`") ? name.slice(1, -1) : name;
|
|
24
25
|
}
|
|
25
|
-
var GENERIC = "(
|
|
26
|
+
var GENERIC = "(?:" + GENERIC_CLAUSE + ")?";
|
|
26
27
|
var LEADING_ATTRIBUTE_RE = /^\s*(?:@[A-Za-z_][A-Za-z0-9_.]*(?:\((?:[^()]|\([^()]*\))*\))?\s+)+/;
|
|
27
28
|
function stripLeadingAttributes(s) {
|
|
28
29
|
return s.replace(LEADING_ATTRIBUTE_RE, "");
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
DocumentRefusedError
|
|
5
|
+
} from "./token-goat-chunk-Y4AFKTHK.mjs";
|
|
6
|
+
import {
|
|
7
|
+
init_define_import_meta_env
|
|
8
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
9
|
+
|
|
10
|
+
// src/zip_bounds.ts
|
|
11
|
+
init_define_import_meta_env();
|
|
12
|
+
var MAX_ZIP_INPUT_BYTES = 50 * 1024 * 1024;
|
|
13
|
+
var MAX_ZIP_OUTPUT_BYTES = 500 * 1024 * 1024;
|
|
14
|
+
var STREAM_CHUNK_BYTES = 64 * 1024;
|
|
15
|
+
var ZipOutputTooLargeError = class extends DocumentRefusedError {
|
|
16
|
+
constructor(entryName, limitBytes, decompressedSoFarBytes) {
|
|
17
|
+
super(
|
|
18
|
+
`zip entry '${entryName}' is over the ${Math.round(limitBytes / (1024 * 1024))}MB decompressed-size limit (over ${Math.round(decompressedSoFarBytes / (1024 * 1024))}MB decompressed so far)`,
|
|
19
|
+
"ZipOutputTooLargeError"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var ZipInputTooLargeError = class extends DocumentRefusedError {
|
|
24
|
+
constructor(filePath, sizeBytes, limitBytes) {
|
|
25
|
+
super(
|
|
26
|
+
`${filePath} is ${Math.round(sizeBytes / (1024 * 1024))}MB, over the ${Math.round(limitBytes / (1024 * 1024))}MB limit for zip-format archives`,
|
|
27
|
+
"ZipInputTooLargeError"
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function concatChunks(chunks, total) {
|
|
32
|
+
const out = new Uint8Array(total);
|
|
33
|
+
let offset = 0;
|
|
34
|
+
for (const chunk of chunks) {
|
|
35
|
+
out.set(chunk, offset);
|
|
36
|
+
offset += chunk.length;
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
function unzipBounded(mod, data, opts) {
|
|
41
|
+
mod.unzipSync(data, { filter: () => false });
|
|
42
|
+
const results = {};
|
|
43
|
+
let firstError;
|
|
44
|
+
let totalDecompressed = 0;
|
|
45
|
+
const unzip = new mod.Unzip((file) => {
|
|
46
|
+
if (firstError !== void 0 || !opts.shouldExtract(file.name)) return;
|
|
47
|
+
if (typeof file.originalSize === "number" && totalDecompressed + file.originalSize > opts.limitBytes) {
|
|
48
|
+
firstError = new ZipOutputTooLargeError(file.name, opts.limitBytes, totalDecompressed + file.originalSize);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const chunks = [];
|
|
52
|
+
let entryTotal = 0;
|
|
53
|
+
file.ondata = (err, chunk, final) => {
|
|
54
|
+
if (firstError !== void 0) return;
|
|
55
|
+
if (err) {
|
|
56
|
+
firstError = err instanceof Error ? err : new Error(String(err));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
entryTotal += chunk.length;
|
|
60
|
+
totalDecompressed += chunk.length;
|
|
61
|
+
if (totalDecompressed > opts.limitBytes) {
|
|
62
|
+
firstError = new ZipOutputTooLargeError(file.name, opts.limitBytes, totalDecompressed);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
chunks.push(chunk);
|
|
66
|
+
if (final) results[file.name] = concatChunks(chunks, entryTotal);
|
|
67
|
+
};
|
|
68
|
+
file.start();
|
|
69
|
+
});
|
|
70
|
+
unzip.register(mod.UnzipInflate);
|
|
71
|
+
let offset = 0;
|
|
72
|
+
for (; ; ) {
|
|
73
|
+
const end = Math.min(offset + STREAM_CHUNK_BYTES, data.length);
|
|
74
|
+
const isFinal = end >= data.length;
|
|
75
|
+
unzip.push(data.subarray(offset, end), isFinal);
|
|
76
|
+
offset = end;
|
|
77
|
+
if (firstError !== void 0 || isFinal) break;
|
|
78
|
+
}
|
|
79
|
+
if (firstError !== void 0) throw firstError;
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
MAX_ZIP_INPUT_BYTES,
|
|
85
|
+
MAX_ZIP_OUTPUT_BYTES,
|
|
86
|
+
ZipOutputTooLargeError,
|
|
87
|
+
ZipInputTooLargeError,
|
|
88
|
+
unzipBounded
|
|
89
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
init_define_import_meta_env
|
|
5
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
6
|
+
|
|
7
|
+
// src/document_refusal.ts
|
|
8
|
+
init_define_import_meta_env();
|
|
9
|
+
var MAX_DOCUMENT_WORK_MILLIS = 6e4;
|
|
10
|
+
var DocumentRefusedError = class extends Error {
|
|
11
|
+
transient;
|
|
12
|
+
constructor(message, name, transient = false) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.transient = transient;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
MAX_DOCUMENT_WORK_MILLIS,
|
|
21
|
+
DocumentRefusedError
|
|
22
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
parse
|
|
5
|
+
} from "./token-goat-chunk-3BTK54F3.mjs";
|
|
6
|
+
import {
|
|
7
|
+
filtersFilteredToEmptyNotice
|
|
8
|
+
} from "./token-goat-chunk-PM76YS22.mjs";
|
|
9
|
+
import {
|
|
10
|
+
displaySafeText
|
|
11
|
+
} from "./token-goat-chunk-ERTXEKB6.mjs";
|
|
12
|
+
import {
|
|
13
|
+
compileGuardedRegexCached
|
|
14
|
+
} from "./token-goat-chunk-GMOUBOX4.mjs";
|
|
15
|
+
import {
|
|
16
|
+
init_define_import_meta_env
|
|
17
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
18
|
+
|
|
19
|
+
// src/csv_query.ts
|
|
20
|
+
init_define_import_meta_env();
|
|
21
|
+
var DELIMITER_CANDIDATES = [",", " ", ";", "|"];
|
|
22
|
+
var DELIMITER_SAMPLE_ROWS = 5;
|
|
23
|
+
function detectDelimiter(content) {
|
|
24
|
+
const slice = content.slice(0, 1e4);
|
|
25
|
+
if (slice.trim() === "") return ",";
|
|
26
|
+
for (const cand of DELIMITER_CANDIDATES) {
|
|
27
|
+
let rows;
|
|
28
|
+
try {
|
|
29
|
+
rows = parse(slice, { columns: false, skip_empty_lines: true, trim: true, delimiter: cand, bom: true, relax_quotes: true, to: DELIMITER_SAMPLE_ROWS });
|
|
30
|
+
} catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if ((rows[0]?.length ?? 0) < 2) continue;
|
|
34
|
+
return cand;
|
|
35
|
+
}
|
|
36
|
+
return ",";
|
|
37
|
+
}
|
|
38
|
+
function parseRecords(content, opts) {
|
|
39
|
+
const delimiter = opts.delimiter ?? detectDelimiter(content);
|
|
40
|
+
if (opts.noHeader === true) {
|
|
41
|
+
const rows = parse(content, { columns: false, skip_empty_lines: true, trim: true, delimiter, bom: true, relax_column_count: true, relax_quotes: true });
|
|
42
|
+
return rows.map((row) => Object.fromEntries(row.map((cell, i) => [`col${i + 1}`, cell])));
|
|
43
|
+
}
|
|
44
|
+
const header = csvHeader(content, { ...opts, delimiter });
|
|
45
|
+
const dupes = header.filter((name, i) => name !== "" && header.indexOf(name) !== i);
|
|
46
|
+
if (dupes.length > 0) {
|
|
47
|
+
const unique = [...new Set(dupes)];
|
|
48
|
+
throw new Error(
|
|
49
|
+
`duplicate column ${unique.length === 1 ? "name" : "names"} in header: ${unique.join(", ")} \u2014 rename the duplicates or pass --no-header to address columns positionally as col1, col2, \u2026`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return parse(content, { columns: true, skip_empty_lines: true, trim: true, delimiter, bom: true, relax_column_count: true, relax_quotes: true });
|
|
53
|
+
}
|
|
54
|
+
function csvHeader(content, opts) {
|
|
55
|
+
if (opts.noHeader === true) return [];
|
|
56
|
+
const delimiter = opts.delimiter ?? detectDelimiter(content);
|
|
57
|
+
try {
|
|
58
|
+
const rows = parse(content, { columns: false, skip_empty_lines: true, trim: true, delimiter, bom: true, to: 1, relax_quotes: true });
|
|
59
|
+
return rows[0] ?? [];
|
|
60
|
+
} catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var WHERE_SPEC_RE = /^((?:[^=<>~!]|!(?!=)|~(?!=))+)(!=|~=|>=|<=|=|>|<)(.*)$/;
|
|
65
|
+
function parseWhereSpecs(specs) {
|
|
66
|
+
if (specs === void 0 || specs.length === 0) return void 0;
|
|
67
|
+
return specs.map((spec) => {
|
|
68
|
+
const m = WHERE_SPEC_RE.exec(spec);
|
|
69
|
+
if (!m) throw new Error(`invalid --where spec: ${spec} (expected col=value, col!=value, col>value, col<value, col>=value, or col<=value, or col~=regex)`);
|
|
70
|
+
const op = m[2];
|
|
71
|
+
const value = m[3];
|
|
72
|
+
if ((op === ">" || op === "<" || op === ">=" || op === "<=") && value.trim() === "") {
|
|
73
|
+
throw new Error(`invalid --where spec: ${spec} (missing comparison value after '${op}')`);
|
|
74
|
+
}
|
|
75
|
+
if (op === "~=") {
|
|
76
|
+
const guarded = compileGuardedRegexCached(value);
|
|
77
|
+
if (!guarded.ok) throw new Error(`invalid --where spec: ${spec} (the pattern ${guarded.reason})`);
|
|
78
|
+
}
|
|
79
|
+
return { column: m[1].trim(), op, value };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function resolveWhereColumn(where, allColumns) {
|
|
83
|
+
const rawSpec = where.column + where.op + where.value;
|
|
84
|
+
let best = where;
|
|
85
|
+
for (const col of allColumns) {
|
|
86
|
+
if (col.length <= best.column.length) continue;
|
|
87
|
+
if (!rawSpec.startsWith(col)) continue;
|
|
88
|
+
const rest = rawSpec.slice(col.length);
|
|
89
|
+
const m = /^(!=|~=|>=|<=|=|>|<)(.*)$/.exec(rest);
|
|
90
|
+
if (m) {
|
|
91
|
+
best = { column: col, op: m[1], value: m[2] };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return best;
|
|
95
|
+
}
|
|
96
|
+
function matchesWhere(row, where) {
|
|
97
|
+
const cell = row[where.column] ?? "";
|
|
98
|
+
switch (where.op) {
|
|
99
|
+
case "=":
|
|
100
|
+
return cell === where.value;
|
|
101
|
+
case "!=":
|
|
102
|
+
return cell !== where.value;
|
|
103
|
+
case "~=": {
|
|
104
|
+
const guarded = compileGuardedRegexCached(where.value);
|
|
105
|
+
return guarded.ok && guarded.re.test(cell);
|
|
106
|
+
}
|
|
107
|
+
case ">":
|
|
108
|
+
case "<":
|
|
109
|
+
case ">=":
|
|
110
|
+
case "<=": {
|
|
111
|
+
if (cell.trim() === "") return false;
|
|
112
|
+
const cellNum = Number(cell);
|
|
113
|
+
const valNum = Number(where.value);
|
|
114
|
+
const useNum = !Number.isNaN(cellNum) && !Number.isNaN(valNum);
|
|
115
|
+
const lhs = useNum ? cellNum : cell;
|
|
116
|
+
const rhs = useNum ? valNum : where.value;
|
|
117
|
+
switch (where.op) {
|
|
118
|
+
case ">":
|
|
119
|
+
return lhs > rhs;
|
|
120
|
+
case "<":
|
|
121
|
+
return lhs < rhs;
|
|
122
|
+
case ">=":
|
|
123
|
+
return lhs >= rhs;
|
|
124
|
+
case "<=":
|
|
125
|
+
return lhs <= rhs;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function queryCsv(content, opts) {
|
|
131
|
+
const records = parseRecords(content, opts);
|
|
132
|
+
const allColumns = records.length > 0 ? Object.keys(records[0]) : [];
|
|
133
|
+
const realHeader = records.length > 0 ? allColumns : csvHeader(content, opts);
|
|
134
|
+
const columns = opts.columns && opts.columns.length > 0 ? opts.columns : allColumns;
|
|
135
|
+
for (const c of columns) {
|
|
136
|
+
if (!realHeader.includes(c)) {
|
|
137
|
+
throw new Error(`unknown column: ${c} (available: ${realHeader.join(", ")})`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const wheres = (opts.wheres ?? []).map((w) => resolveWhereColumn(w, realHeader));
|
|
141
|
+
for (const w of wheres) {
|
|
142
|
+
if (!realHeader.includes(w.column)) {
|
|
143
|
+
throw new Error(`unknown column: ${w.column} (available: ${realHeader.join(", ")})`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
let filtered = records;
|
|
147
|
+
if (wheres.length > 0) {
|
|
148
|
+
filtered = records.filter((r) => wheres.every((w) => matchesWhere(r, w)));
|
|
149
|
+
}
|
|
150
|
+
const totalRows = filtered.length;
|
|
151
|
+
const limited = opts.head !== void 0 ? filtered.slice(0, opts.head) : filtered;
|
|
152
|
+
const rows = limited.map((r) => columns.map((c) => r[c] ?? ""));
|
|
153
|
+
return { header: columns, rows, totalRows, preFilterRows: records.length };
|
|
154
|
+
}
|
|
155
|
+
function quoteCsvCell(cell) {
|
|
156
|
+
if (cell.includes(",") || cell.includes('"') || cell.includes("\n") || cell.includes("\r")) {
|
|
157
|
+
return `"${cell.replace(/"/g, '""')}"`;
|
|
158
|
+
}
|
|
159
|
+
return cell;
|
|
160
|
+
}
|
|
161
|
+
function formatCsvTable(result, activeFilters = []) {
|
|
162
|
+
const lines = [
|
|
163
|
+
result.header.map(quoteCsvCell).join(","),
|
|
164
|
+
...result.rows.map((r) => r.map(quoteCsvCell).join(","))
|
|
165
|
+
];
|
|
166
|
+
if (result.totalRows > result.rows.length) {
|
|
167
|
+
lines.push(`...(${result.totalRows - result.rows.length} more rows elided; use --head to see more)`);
|
|
168
|
+
}
|
|
169
|
+
if (result.totalRows === 0 && result.preFilterRows > 0) {
|
|
170
|
+
lines.push(filtersFilteredToEmptyNotice(result.preFilterRows, activeFilters, "data row", "data rows"));
|
|
171
|
+
}
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
function profileCsv(content, opts = {}) {
|
|
175
|
+
const records = parseRecords(content, opts);
|
|
176
|
+
const columns = records.length > 0 ? Object.keys(records[0]) : [];
|
|
177
|
+
return columns.map((col) => {
|
|
178
|
+
const values = records.map((r) => r[col] ?? "");
|
|
179
|
+
const nullCount = values.filter((v) => v.trim() === "").length;
|
|
180
|
+
const nonEmpty = values.filter((v) => v.trim() !== "");
|
|
181
|
+
const distinct = new Set(nonEmpty);
|
|
182
|
+
const isNumber = nonEmpty.length > 0 && nonEmpty.every((v) => v.trim() !== "" && !Number.isNaN(Number(v)));
|
|
183
|
+
const isDate = !isNumber && nonEmpty.length > 0 && nonEmpty.every((v) => !Number.isNaN(Date.parse(v)));
|
|
184
|
+
const inferredType = isNumber ? "number" : isDate ? "date" : "string";
|
|
185
|
+
const profile = { name: col, inferredType, nullCount, distinctCount: distinct.size };
|
|
186
|
+
if (nonEmpty.length > 0) {
|
|
187
|
+
if (isNumber) {
|
|
188
|
+
const nums = nonEmpty.map(Number);
|
|
189
|
+
profile.min = String(nums.reduce((a, b) => Math.min(a, b)));
|
|
190
|
+
profile.max = String(nums.reduce((a, b) => Math.max(a, b)));
|
|
191
|
+
} else if (isDate) {
|
|
192
|
+
const sorted = [...nonEmpty].sort((a, b) => Date.parse(a) - Date.parse(b));
|
|
193
|
+
profile.min = sorted[0];
|
|
194
|
+
profile.max = sorted[sorted.length - 1];
|
|
195
|
+
} else {
|
|
196
|
+
const sorted = [...nonEmpty].sort();
|
|
197
|
+
profile.min = sorted[0];
|
|
198
|
+
profile.max = sorted[sorted.length - 1];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (distinct.size > 0 && distinct.size <= 10) {
|
|
202
|
+
const counts = /* @__PURE__ */ new Map();
|
|
203
|
+
for (const v of nonEmpty) counts.set(v, (counts.get(v) ?? 0) + 1);
|
|
204
|
+
profile.topValues = [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([value, count]) => ({ value, count }));
|
|
205
|
+
}
|
|
206
|
+
return profile;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function formatCsvProfile(profiles) {
|
|
210
|
+
return profiles.map((p) => {
|
|
211
|
+
const lines = [
|
|
212
|
+
`${displaySafeText(p.name)} (${p.inferredType})`,
|
|
213
|
+
` nulls: ${p.nullCount} distinct: ${p.distinctCount}`
|
|
214
|
+
];
|
|
215
|
+
if (p.min !== void 0) lines.push(` range: ${displaySafeText(p.min)} .. ${displaySafeText(p.max ?? "")}`);
|
|
216
|
+
if (p.topValues !== void 0) lines.push(` values: ${p.topValues.map((t) => `${displaySafeText(t.value)} (${t.count})`).join(", ")}`);
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}).join("\n\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export {
|
|
222
|
+
parseWhereSpecs,
|
|
223
|
+
queryCsv,
|
|
224
|
+
quoteCsvCell,
|
|
225
|
+
formatCsvTable,
|
|
226
|
+
profileCsv,
|
|
227
|
+
formatCsvProfile
|
|
228
|
+
};
|