@ai-matrx/records-ui 0.93.69 → 0.93.72

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.
@@ -0,0 +1,554 @@
1
+ "use client";
2
+
3
+ // src/kindValues.ts
4
+ import { tryDecodeDirective } from "@ai-matrx/content-ir/directives";
5
+ var KIND_KEY = "__kind";
6
+ var WHOLE_FENCE = /^\s*```(?:matrx|json)?[ \t]*\r?\n?([\s\S]*?)\r?\n?[ \t]*```\s*$/;
7
+ function asObject(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
9
+ }
10
+ function parseJsonObject(text) {
11
+ const trimmed = text.trim();
12
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
13
+ try {
14
+ return asObject(JSON.parse(trimmed));
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ function fromObject(obj) {
20
+ const directive = tryDecodeDirective(obj);
21
+ if (directive) return { value: obj, kind: directive.slug, directive: true, items: [...directive.items] };
22
+ const named = obj[KIND_KEY];
23
+ if (typeof named === "string" && named.trim() !== "") {
24
+ const items = Array.isArray(obj.items) ? obj.items.filter((i) => asObject(i) !== null) : [];
25
+ return { value: obj, kind: named.trim(), directive: false, items };
26
+ }
27
+ return null;
28
+ }
29
+ function kindValueOf(value) {
30
+ const obj = asObject(value);
31
+ if (obj) return fromObject(obj);
32
+ if (typeof value !== "string" || value.length > 2e5) return null;
33
+ const fenced = WHOLE_FENCE.exec(value);
34
+ const parsed = parseJsonObject(fenced ? fenced[1] : value);
35
+ return parsed ? fromObject(parsed) : null;
36
+ }
37
+
38
+ // src/names.ts
39
+ function humanize(token) {
40
+ const words = token.replace(/[_\-.]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim();
41
+ if (words === "") return token;
42
+ return words.charAt(0).toUpperCase() + words.slice(1);
43
+ }
44
+
45
+ // src/tableShape.ts
46
+ var FEWEST_LIST_ITEMS = 2;
47
+ var FEWEST_KEY_VALUE_PAIRS = 2;
48
+ var LONGEST_TEXT_READ = 2e6;
49
+ function cellWords(raw) {
50
+ return raw.replace(/<br\s*\/?>/gi, "\n").replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\(([^)]*)\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/(^|[^\w*])\*([^*\n]+)\*(?=[^\w*]|$)/g, "$1$2").replace(/(^|[^\w_])_([^_\n]+)_(?=[^\w_]|$)/g, "$1$2").replace(/~~([^~]+)~~/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\\\|/g, "|").trim();
51
+ }
52
+ function uniqueLabels(raw) {
53
+ const seen = /* @__PURE__ */ new Map();
54
+ return raw.map((label, index) => {
55
+ const base = label.trim() || `Column ${index + 1}`;
56
+ const key = base.toLowerCase();
57
+ const count = (seen.get(key) ?? 0) + 1;
58
+ seen.set(key, count);
59
+ return count === 1 ? base : `${base} ${count}`;
60
+ });
61
+ }
62
+ function rowsOf(headers, matrix) {
63
+ return matrix.filter((cells) => cells.some((c) => c.trim() !== "")).map((cells) => {
64
+ const row = {};
65
+ headers.forEach((h, i) => {
66
+ row[h] = (cells[i] ?? "").trim();
67
+ });
68
+ return row;
69
+ });
70
+ }
71
+ function plural(n, one, many) {
72
+ return `${n} ${n === 1 ? one : many}`;
73
+ }
74
+ function sizeWords(rows, columns) {
75
+ return `${plural(rows, "row", "rows")} and ${plural(columns, "column", "columns")}`;
76
+ }
77
+ var HEADING = /^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/;
78
+ var BOLD_LINE = /^\s*\*\*([^*]+)\*\*:?\s*$/;
79
+ var LEAD_IN = /^\s*([^|\-*+#>`].{1,80}?):\s*$/;
80
+ function nameAbove(lines, lineIndex) {
81
+ let looked = 0;
82
+ for (let i = lineIndex - 1; i >= 0 && looked < 4; i -= 1) {
83
+ const line = lines[i] ?? "";
84
+ if (line.trim() === "") continue;
85
+ looked += 1;
86
+ const m = HEADING.exec(line) ?? (looked === 1 ? BOLD_LINE.exec(line) ?? LEAD_IN.exec(line) : null);
87
+ if (m) return cellWords(m[1]).replace(/:$/, "").trim() || null;
88
+ }
89
+ return null;
90
+ }
91
+ var SEPARATOR = /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/;
92
+ function splitPipes(line) {
93
+ let text = line.trim();
94
+ if (text.startsWith("|")) text = text.slice(1);
95
+ if (text.endsWith("|") && !text.endsWith("\\|")) text = text.slice(0, -1);
96
+ const cells = [];
97
+ let cell = "";
98
+ for (let i = 0; i < text.length; i += 1) {
99
+ const ch = text[i];
100
+ if (ch === "\\" && text[i + 1] === "|") {
101
+ cell += "\\|";
102
+ i += 1;
103
+ } else if (ch === "|") {
104
+ cells.push(cell);
105
+ cell = "";
106
+ } else cell += ch;
107
+ }
108
+ cells.push(cell);
109
+ return cells.map(cellWords);
110
+ }
111
+ var LIST_ITEM = /^(\s*)(?:[-*+•]|\d{1,3}[.)])\s+(?:\[[ xX]\]\s+)?(.*)$/;
112
+ var KEY_VALUE = /^\s*(?:\*\*|__)?([^:*_|]{1,40}?)(?::(?:\*\*|__)|(?:\*\*|__):|:)\s+(.+)$/;
113
+ function keyValueOf(text) {
114
+ const m = KEY_VALUE.exec(text);
115
+ if (!m) return null;
116
+ const key = cellWords(m[1]);
117
+ const value = cellWords(m[2]);
118
+ if (!key || !value) return null;
119
+ if (key.split(/\s+/).length > 5 || /^\d+$/.test(key) || /https?$/i.test(key)) return null;
120
+ return { key, value };
121
+ }
122
+ function recordsFromPairs(pairs) {
123
+ const records = [];
124
+ let current = /* @__PURE__ */ new Map();
125
+ const first = pairs[0]?.key.toLowerCase();
126
+ for (const pair of pairs) {
127
+ const k = pair.key.toLowerCase();
128
+ if (current.size > 0 && (k === first || [...current.keys()].some((c) => c.toLowerCase() === k))) {
129
+ records.push(current);
130
+ current = /* @__PURE__ */ new Map();
131
+ }
132
+ current.set(pair.key, pair.value);
133
+ }
134
+ if (current.size > 0) records.push(current);
135
+ return records;
136
+ }
137
+ function shapeFromRecords(records, base, from) {
138
+ const order = [];
139
+ for (const r of records) for (const k of r.keys()) if (!order.some((o) => o.toLowerCase() === k.toLowerCase())) order.push(k);
140
+ const headers = uniqueLabels(order);
141
+ const rows = records.map((r) => {
142
+ const row = {};
143
+ order.forEach((k, i) => {
144
+ const hit = [...r.entries()].find(([rk]) => rk.toLowerCase() === k.toLowerCase());
145
+ row[headers[i]] = hit ? hit[1] : "";
146
+ });
147
+ return row;
148
+ });
149
+ return {
150
+ ...base,
151
+ kind: "key_value",
152
+ headers,
153
+ rows,
154
+ splits: [],
155
+ said: rows.length === 1 ? `One record with ${plural(headers.length, "value", "values")} from ${from}` : `${sizeWords(rows.length, headers.length)} from ${from}`
156
+ };
157
+ }
158
+ var SPLITS = [
159
+ { delimiter: " \u2014 ", label: "Split at the dash" },
160
+ { delimiter: " \u2013 ", label: "Split at the dash" },
161
+ { delimiter: " - ", label: "Split at the hyphen" },
162
+ { delimiter: ": ", label: "Split at the colon" },
163
+ { delimiter: " | ", label: "Split at the bar" },
164
+ { delimiter: " ", label: "Split at the tab" },
165
+ { delimiter: ", ", label: "Split at each comma" }
166
+ ];
167
+ function listSplits(items) {
168
+ const out = [];
169
+ for (const { delimiter, label } of SPLITS) {
170
+ if (!items.every((t) => t.includes(delimiter))) continue;
171
+ if (out.some((s) => s.label === label)) continue;
172
+ const every = delimiter === ", ";
173
+ const parts = items.map((t) => every ? t.split(delimiter) : [t.slice(0, t.indexOf(delimiter)), t.slice(t.indexOf(delimiter) + delimiter.length)]);
174
+ const width = Math.max(...parts.map((p) => p.length));
175
+ const headers = uniqueLabels(width === 2 ? ["Item", "Detail"] : Array.from({ length: width }, (_, i) => i === 0 ? "Item" : `Detail ${i}`));
176
+ out.push({ delimiter, label, headers, rows: rowsOf(headers, parts.map((p) => p.map((c) => cellWords(c)))) });
177
+ }
178
+ return out;
179
+ }
180
+ function shapeFromList(items, name, at) {
181
+ const top = items.filter((i) => i.depth === 0);
182
+ if (top.length === 0) return null;
183
+ const withChildren = top.filter((i) => i.children.length > 0);
184
+ if (withChildren.length === top.length && top.length >= 1) {
185
+ const childPairs = top.map((i) => i.children.map(keyValueOf));
186
+ if (childPairs.every((ps) => ps.length > 0 && ps.every((p) => p !== null))) {
187
+ const lead = "Name";
188
+ const records = top.map((item, idx) => {
189
+ const r = /* @__PURE__ */ new Map();
190
+ r.set(lead, cellWords(item.text).replace(/:$/, ""));
191
+ for (const p of childPairs[idx]) r.set(p.key, p.value);
192
+ return r;
193
+ });
194
+ return shapeFromRecords(records, { name, at }, "a list");
195
+ }
196
+ }
197
+ const pairs = top.map((i) => keyValueOf(i.text));
198
+ if (pairs.length >= FEWEST_KEY_VALUE_PAIRS && pairs.every((p) => p !== null)) {
199
+ const records = recordsFromPairs(pairs);
200
+ const sameKeys = records.every((r) => r.size === records[0].size);
201
+ if (records.length === 1 || sameKeys && records[0].size >= 2) return shapeFromRecords(records, { name, at }, "a list");
202
+ }
203
+ if (top.length < FEWEST_LIST_ITEMS) return null;
204
+ const texts = top.map((i) => cellWords(i.text));
205
+ const anyChildren = top.some((i) => i.children.length > 0);
206
+ const headers = anyChildren ? ["Item", "Details"] : ["Item"];
207
+ const rows = top.map((item, idx) => {
208
+ const row = { Item: texts[idx] };
209
+ if (anyChildren) row.Details = item.children.map(cellWords).join("; ");
210
+ return row;
211
+ });
212
+ return {
213
+ kind: "list",
214
+ headers,
215
+ rows,
216
+ name,
217
+ at,
218
+ splits: anyChildren ? [] : listSplits(texts),
219
+ said: `${plural(rows.length, "item", "items")} from a list`
220
+ };
221
+ }
222
+ function parseDelimited(text, delimiter) {
223
+ const rows = [];
224
+ let row = [];
225
+ let cell = "";
226
+ let quoted = false;
227
+ for (let i = 0; i < text.length; i += 1) {
228
+ const ch = text[i];
229
+ if (quoted) {
230
+ if (ch === '"') {
231
+ if (text[i + 1] === '"') {
232
+ cell += '"';
233
+ i += 1;
234
+ } else quoted = false;
235
+ } else cell += ch;
236
+ continue;
237
+ }
238
+ if (ch === '"' && cell.trim() === "") quoted = true;
239
+ else if (ch === delimiter) {
240
+ row.push(cell);
241
+ cell = "";
242
+ } else if (ch === "\n" || ch === "\r") {
243
+ if (ch === "\r" && text[i + 1] === "\n") i += 1;
244
+ row.push(cell);
245
+ rows.push(row);
246
+ row = [];
247
+ cell = "";
248
+ } else cell += ch;
249
+ }
250
+ if (cell.length > 0 || row.length > 0) {
251
+ row.push(cell);
252
+ rows.push(row);
253
+ }
254
+ return rows.filter((r) => r.some((c) => c.trim() !== ""));
255
+ }
256
+ function delimitedShape(text, delimiter, fenced, at, name) {
257
+ const matrix = parseDelimited(text.trim(), delimiter);
258
+ if (matrix.length < 2) return null;
259
+ const width = matrix[0].length;
260
+ if (width < 2) return null;
261
+ const same = matrix.filter((r) => r.length === width).length;
262
+ if (same / matrix.length < 0.9) return null;
263
+ if (!fenced) {
264
+ const cells = matrix.flat();
265
+ const long = cells.filter((c) => c.trim().length > 80).length;
266
+ if (delimiter === "," && (long / cells.length > 0.2 || matrix.length < 2)) return null;
267
+ }
268
+ const headers = uniqueLabels(matrix[0].map((c) => c.trim()));
269
+ const rows = rowsOf(headers, matrix.slice(1));
270
+ if (rows.length === 0) return null;
271
+ const kind = delimiter === " " ? "tsv" : "csv";
272
+ return {
273
+ kind,
274
+ headers,
275
+ rows,
276
+ name,
277
+ at,
278
+ splits: [],
279
+ said: `${sizeWords(rows.length, headers.length)} from ${kind === "tsv" ? "pasted spreadsheet cells" : "CSV"}`
280
+ };
281
+ }
282
+ function cellOf(value) {
283
+ if (value === null || value === void 0) return "";
284
+ if (typeof value === "string") return value;
285
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
286
+ if (Array.isArray(value) && value.every((v) => typeof v !== "object" || v === null)) return value.map(cellOf).join(", ");
287
+ return JSON.stringify(value);
288
+ }
289
+ function isPlainObject(v) {
290
+ return typeof v === "object" && v !== null && !Array.isArray(v);
291
+ }
292
+ function labelOfKey(key) {
293
+ return /[\s]/.test(key) || /^[A-Z]/.test(key) ? key : humanize(key);
294
+ }
295
+ function shapeFromObjects(objects, kind, from, name) {
296
+ if (objects.length === 0) return null;
297
+ const keys = [];
298
+ for (const o of objects) for (const k of Object.keys(o)) if (k !== "__kind" && !keys.includes(k)) keys.push(k);
299
+ if (keys.length === 0) return null;
300
+ const headers = uniqueLabels(keys.map(labelOfKey));
301
+ const rows = objects.map((o) => {
302
+ const row = {};
303
+ keys.forEach((k, i) => {
304
+ row[headers[i]] = cellOf(o[k]);
305
+ });
306
+ return row;
307
+ });
308
+ return { kind, headers, rows, name, at: null, splits: [], said: `${sizeWords(rows.length, headers.length)} from ${from}` };
309
+ }
310
+ function shapeOfValue(value, name = null) {
311
+ let v = value;
312
+ if (typeof v === "string") {
313
+ const t = v.trim();
314
+ const fence = /^```(?:json|matrx)?\s*\n?([\s\S]*?)\n?```$/.exec(t);
315
+ const body = fence ? fence[1].trim() : t;
316
+ if (!(body.startsWith("{") || body.startsWith("["))) return null;
317
+ try {
318
+ v = JSON.parse(body);
319
+ } catch {
320
+ return null;
321
+ }
322
+ }
323
+ if (Array.isArray(v)) {
324
+ const objects = v.filter(isPlainObject);
325
+ if (objects.length === 0 || objects.length < v.length) return null;
326
+ return shapeFromObjects(objects, "rows", "JSON rows", name);
327
+ }
328
+ if (!isPlainObject(v)) return null;
329
+ const kv = kindValueOf(v);
330
+ if (kv) {
331
+ const label = kv.kind.replace(/^directive_v\d+_/, "").replace(/_/g, " ");
332
+ if (kv.items.length > 0) return shapeFromObjects(kv.items, "kind", `a ${label}`, name);
333
+ const scalars = Object.fromEntries(Object.entries(v).filter(([k, x]) => k !== "__kind" && (typeof x !== "object" || x === null)));
334
+ const shape = shapeFromObjects([scalars], "kind", `a ${label}`, name);
335
+ if (shape) return shape;
336
+ }
337
+ let best = null;
338
+ for (const [key, member] of Object.entries(v)) {
339
+ if (Array.isArray(member) && member.length > 0 && member.every(isPlainObject)) {
340
+ if (!best || member.length > best.items.length) best = { key, items: member };
341
+ }
342
+ }
343
+ if (best) return shapeFromObjects(best.items, kv ? "kind" : "rows", "JSON rows", name ?? labelOfKey(best.key));
344
+ return null;
345
+ }
346
+ function readTableShapes(text) {
347
+ if (typeof text !== "string" || text.trim() === "" || text.length > LONGEST_TEXT_READ) return [];
348
+ const whole = text.trim();
349
+ if (whole.startsWith("{") || whole.startsWith("[") || /^```(?:json|matrx)/.test(whole)) {
350
+ const s = shapeOfValue(whole);
351
+ if (s) return [{ ...s, at: { start: 0, end: text.length } }];
352
+ }
353
+ if (!/^\s*[|#>*-]/m.test(whole)) {
354
+ if (whole.includes(" ")) {
355
+ const s2 = delimitedShape(whole, " ", false, { start: 0, end: text.length }, null);
356
+ if (s2) return [s2];
357
+ }
358
+ const s = delimitedShape(whole, ",", false, { start: 0, end: text.length }, null);
359
+ if (s) return [s];
360
+ }
361
+ const lines = text.split(/\r?\n/);
362
+ const offsets = [];
363
+ let pos = 0;
364
+ for (const line of lines) {
365
+ offsets.push(pos);
366
+ pos += line.length + 1;
367
+ }
368
+ const endOf = (i2) => (offsets[i2] ?? 0) + (lines[i2]?.length ?? 0);
369
+ const shapes = [];
370
+ let i = 0;
371
+ while (i < lines.length) {
372
+ const line = lines[i] ?? "";
373
+ const fence = /^\s*```\s*([\w-]*)\s*$/.exec(line);
374
+ if (fence) {
375
+ let j = i + 1;
376
+ while (j < lines.length && !/^\s*```\s*$/.test(lines[j] ?? "")) j += 1;
377
+ const body = lines.slice(i + 1, j).join("\n");
378
+ const lang = fence[1].toLowerCase();
379
+ const at = { start: offsets[i], end: endOf(Math.min(j, lines.length - 1)) };
380
+ const name = nameAbove(lines, i);
381
+ let s = null;
382
+ if (lang === "csv") s = delimitedShape(body, ",", true, at, name);
383
+ else if (lang === "tsv") s = delimitedShape(body, " ", true, at, name);
384
+ else if (lang === "json" || lang === "matrx") s = shapeOfValue(body, name);
385
+ if (s) shapes.push({ ...s, at });
386
+ i = j + 1;
387
+ continue;
388
+ }
389
+ if (line.includes("|") && SEPARATOR.test(lines[i + 1] ?? "") && !SEPARATOR.test(line)) {
390
+ const headers = uniqueLabels(splitPipes(line));
391
+ let j = i + 2;
392
+ const matrix = [];
393
+ while (j < lines.length && (lines[j] ?? "").includes("|") && (lines[j] ?? "").trim() !== "") {
394
+ matrix.push(splitPipes(lines[j]));
395
+ j += 1;
396
+ }
397
+ const rows = rowsOf(headers, matrix);
398
+ if (headers.length >= 1 && rows.length >= 1) {
399
+ shapes.push({
400
+ kind: "table",
401
+ headers,
402
+ rows,
403
+ name: nameAbove(lines, i),
404
+ at: { start: offsets[i], end: endOf(j - 1) },
405
+ splits: [],
406
+ said: `${sizeWords(rows.length, headers.length)} from a table`
407
+ });
408
+ }
409
+ i = j;
410
+ continue;
411
+ }
412
+ const item = LIST_ITEM.exec(line);
413
+ if (item) {
414
+ const baseIndent = item[1].length;
415
+ const items = [];
416
+ let j = i;
417
+ while (j < lines.length) {
418
+ const l = lines[j] ?? "";
419
+ const m = LIST_ITEM.exec(l);
420
+ if (m) {
421
+ const depth = m[1].length > baseIndent ? 1 : 0;
422
+ if (depth === 0) items.push({ depth: 0, text: m[2], children: [] });
423
+ else if (items.length > 0) items[items.length - 1].children.push(m[2]);
424
+ j += 1;
425
+ continue;
426
+ }
427
+ if (l.trim() === "" && LIST_ITEM.test(lines[j + 1] ?? "")) {
428
+ j += 1;
429
+ continue;
430
+ }
431
+ if (l.trim() !== "" && /^\s{2,}\S/.test(l) && items.length > 0) {
432
+ items[items.length - 1].text += ` ${l.trim()}`;
433
+ j += 1;
434
+ continue;
435
+ }
436
+ break;
437
+ }
438
+ const s = shapeFromList(items, nameAbove(lines, i), { start: offsets[i], end: endOf(j - 1) });
439
+ if (s) shapes.push(s);
440
+ i = j;
441
+ continue;
442
+ }
443
+ if (keyValueOf(line)) {
444
+ let j = i;
445
+ const pairs = [];
446
+ while (j < lines.length) {
447
+ const l = lines[j] ?? "";
448
+ const p = keyValueOf(l);
449
+ if (p) {
450
+ pairs.push(p);
451
+ j += 1;
452
+ continue;
453
+ }
454
+ if (l.trim() === "" && keyValueOf(lines[j + 1] ?? "")) {
455
+ j += 1;
456
+ continue;
457
+ }
458
+ break;
459
+ }
460
+ if (pairs.length >= FEWEST_KEY_VALUE_PAIRS) {
461
+ const records = recordsFromPairs(pairs);
462
+ const sameKeys = records.every((r) => r.size === records[0].size);
463
+ if (records.length === 1 || sameKeys && records[0].size >= 2) {
464
+ shapes.push(shapeFromRecords(records, { name: nameAbove(lines, i), at: { start: offsets[i], end: endOf(j - 1) } }, "key and value lines"));
465
+ } else {
466
+ const headers = ["Name", "Text"];
467
+ shapes.push({
468
+ kind: "key_value",
469
+ headers,
470
+ rows: pairs.map((p) => ({ Name: p.key, Text: p.value })),
471
+ name: nameAbove(lines, i),
472
+ at: { start: offsets[i], end: endOf(j - 1) },
473
+ splits: [],
474
+ said: `${plural(pairs.length, "line", "lines")}, each a name and what was said`
475
+ });
476
+ }
477
+ }
478
+ i = Math.max(j, i + 1);
479
+ continue;
480
+ }
481
+ i += 1;
482
+ }
483
+ return shapes;
484
+ }
485
+ function readTableShape(text) {
486
+ return readTableShapes(text)[0] ?? null;
487
+ }
488
+ function hasTableShape(text) {
489
+ return readTableShapes(text).length > 0;
490
+ }
491
+ function shapeOfGrid(headers, cells, name = null) {
492
+ const labels = uniqueLabels(headers.map((h) => cellWords(String(h ?? ""))));
493
+ const rows = rowsOf(labels, cells.map((r) => r.map((c) => cellWords(String(c ?? "")))));
494
+ if (labels.length === 0 || rows.length === 0) return null;
495
+ return { kind: "table", headers: labels, rows, name, at: null, splits: [], said: `${sizeWords(rows.length, labels.length)} from a table` };
496
+ }
497
+ var MOST_GUESSED_CHOICES = 12;
498
+ var NUMBER = /^[+-]?(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?$/;
499
+ var MONEY = /^([$€£¥])\s?([+-]?(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?)$/;
500
+ var PERCENT = /^[+-]?\d+(?:\.\d+)?\s?%$/;
501
+ var ISO_DATE = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
502
+ var SLASH_DATE = /^\d{1,2}\/\d{1,2}\/\d{2,4}$/;
503
+ var WORD_DATE = /^(?:\d{1,2}\s+)?(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\.?\s+\d{1,2}(?:st|nd|rd|th)?,?\s+\d{4}$|^\d{1,2}\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\.?\s+\d{4}$/i;
504
+ var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
505
+ var URL_WORD = /^https?:\/\/\S+$/i;
506
+ var PHONE = /^\+?[\d\s().-]{7,20}$/;
507
+ var YES = /* @__PURE__ */ new Set(["yes", "true", "y", "\u2713", "\u2714", "checked", "done"]);
508
+ var NO = /* @__PURE__ */ new Set(["no", "false", "n", "\u2717", "\u2718", "unchecked", ""]);
509
+ function isDate(v) {
510
+ return ISO_DATE.test(v) || SLASH_DATE.test(v) || WORD_DATE.test(v);
511
+ }
512
+ function guessColumn(values) {
513
+ const filled = values.map((v) => String(v ?? "").trim()).filter((v) => v !== "");
514
+ if (filled.length === 0) return { type: "text" };
515
+ const every = (test) => filled.every(test);
516
+ if (every((v) => YES.has(v.toLowerCase()) || NO.has(v.toLowerCase())) && filled.some((v) => YES.has(v.toLowerCase())) && filled.some((v) => !/^\d+$/.test(v))) {
517
+ return { type: "checkbox" };
518
+ }
519
+ if (every((v) => NUMBER.test(v))) return { type: "number" };
520
+ if (every((v) => MONEY.test(v))) {
521
+ const symbols = new Set(filled.map((v) => MONEY.exec(v)[1]));
522
+ if (symbols.size === 1) return { type: "currency", unit: [...symbols][0] };
523
+ }
524
+ if (every((v) => PERCENT.test(v))) return { type: "percent" };
525
+ if (every(isDate)) return { type: "datetime", kind: every((v) => !/\d:\d/.test(v)) ? "date" : "datetime" };
526
+ if (every((v) => EMAIL.test(v))) return { type: "email" };
527
+ if (every((v) => URL_WORD.test(v))) return { type: "url" };
528
+ if (every((v) => PHONE.test(v) && (v.match(/\d/g)?.length ?? 0) >= 7)) return { type: "phone" };
529
+ if (filled.some((v) => v.length > 120 || v.includes("\n"))) return { type: "long_text" };
530
+ const distinct = [];
531
+ for (const v of filled) if (!distinct.some((d) => d.toLowerCase() === v.toLowerCase())) distinct.push(v);
532
+ const short = every((v) => v.length <= 40 && v.split(/\s+/).length <= 5);
533
+ const words = filled.filter((v) => !/\d/.test(v)).length >= filled.length / 2;
534
+ if (filled.length >= 3 && short && words && distinct.length < filled.length && distinct.length <= MOST_GUESSED_CHOICES) {
535
+ return { type: "select", options: distinct };
536
+ }
537
+ return { type: "text" };
538
+ }
539
+ export {
540
+ FEWEST_KEY_VALUE_PAIRS,
541
+ FEWEST_LIST_ITEMS,
542
+ LONGEST_TEXT_READ,
543
+ MOST_GUESSED_CHOICES,
544
+ cellWords,
545
+ guessColumn,
546
+ hasTableShape,
547
+ parseDelimited,
548
+ readTableShape,
549
+ readTableShapes,
550
+ shapeOfGrid,
551
+ shapeOfValue,
552
+ uniqueLabels
553
+ };
554
+ //# sourceMappingURL=table-shape.js.map