@noy-db/as-xlsx 0.2.0-pre.30 → 0.2.0-pre.31
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/package.json +9 -16
- package/dist/index.cjs +0 -1170
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -538
package/dist/index.cjs
DELETED
|
@@ -1,1170 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
XlsxDictAmbiguityError: () => XlsxDictAmbiguityError,
|
|
34
|
-
colLetter: () => colLetter,
|
|
35
|
-
download: () => download,
|
|
36
|
-
formula: () => formula,
|
|
37
|
-
fromBytes: () => fromBytes,
|
|
38
|
-
inferSchema: () => inferSchema,
|
|
39
|
-
readXlsx: () => readXlsx,
|
|
40
|
-
styled: () => styled,
|
|
41
|
-
toBytes: () => toBytes,
|
|
42
|
-
toBytesFromCollection: () => toBytesFromCollection,
|
|
43
|
-
toBytesMultiVault: () => toBytesMultiVault,
|
|
44
|
-
write: () => write,
|
|
45
|
-
writeXlsx: () => writeXlsx,
|
|
46
|
-
zodSourceFor: () => zodSourceFor
|
|
47
|
-
});
|
|
48
|
-
module.exports = __toCommonJS(index_exports);
|
|
49
|
-
|
|
50
|
-
// src/xlsx.ts
|
|
51
|
-
var import_as_zip = require("@noy-db/as-zip");
|
|
52
|
-
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
|
|
53
|
-
var ENCODER = new TextEncoder();
|
|
54
|
-
function formula(f, cachedValue) {
|
|
55
|
-
return cachedValue === void 0 ? { __xlsxFormula: f } : { __xlsxFormula: f, v: cachedValue };
|
|
56
|
-
}
|
|
57
|
-
function isFormulaCell(v) {
|
|
58
|
-
return typeof v === "object" && v !== null && typeof v.__xlsxFormula === "string";
|
|
59
|
-
}
|
|
60
|
-
function styled(value, numberFormat) {
|
|
61
|
-
return { __xlsxStyle: numberFormat, v: value };
|
|
62
|
-
}
|
|
63
|
-
function isStyledCell(v) {
|
|
64
|
-
return typeof v === "object" && v !== null && typeof v.__xlsxStyle === "string";
|
|
65
|
-
}
|
|
66
|
-
async function writeXlsx(sheets, options = {}) {
|
|
67
|
-
if (sheets.length === 0) {
|
|
68
|
-
throw new Error("writeXlsx: at least one sheet is required");
|
|
69
|
-
}
|
|
70
|
-
const seen = /* @__PURE__ */ new Set();
|
|
71
|
-
const safeSheets = sheets.map((s, i) => {
|
|
72
|
-
let name = truncateSheetName(s.name || `Sheet${i + 1}`);
|
|
73
|
-
let n = 1;
|
|
74
|
-
while (seen.has(name)) {
|
|
75
|
-
const suffix = `(${n++})`;
|
|
76
|
-
name = truncateSheetName(name.slice(0, 31 - suffix.length) + suffix);
|
|
77
|
-
}
|
|
78
|
-
seen.add(name);
|
|
79
|
-
return { ...s, name };
|
|
80
|
-
});
|
|
81
|
-
const sharedStrings = [];
|
|
82
|
-
const stringIndex = /* @__PURE__ */ new Map();
|
|
83
|
-
const internString = (s) => {
|
|
84
|
-
const existing = stringIndex.get(s);
|
|
85
|
-
if (existing !== void 0) return existing;
|
|
86
|
-
const idx = sharedStrings.length;
|
|
87
|
-
sharedStrings.push(s);
|
|
88
|
-
stringIndex.set(s, idx);
|
|
89
|
-
return idx;
|
|
90
|
-
};
|
|
91
|
-
const numFmtCodes = [];
|
|
92
|
-
const styleIndexByCode = /* @__PURE__ */ new Map();
|
|
93
|
-
const internStyle = (code) => {
|
|
94
|
-
const existing = styleIndexByCode.get(code);
|
|
95
|
-
if (existing !== void 0) return existing;
|
|
96
|
-
const idx = numFmtCodes.length + 1;
|
|
97
|
-
numFmtCodes.push(code);
|
|
98
|
-
styleIndexByCode.set(code, idx);
|
|
99
|
-
return idx;
|
|
100
|
-
};
|
|
101
|
-
const sheetXmls = safeSheets.map((sheet) => {
|
|
102
|
-
const lines = [
|
|
103
|
-
XML_HEADER,
|
|
104
|
-
'<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
|
|
105
|
-
];
|
|
106
|
-
if (sheet.widths && sheet.widths.length > 0) {
|
|
107
|
-
const colLines = [];
|
|
108
|
-
for (let i = 0; i < sheet.widths.length; i++) {
|
|
109
|
-
const w = sheet.widths[i];
|
|
110
|
-
if (typeof w !== "number" || !Number.isFinite(w) || w <= 0) continue;
|
|
111
|
-
const n = i + 1;
|
|
112
|
-
colLines.push(`<col min="${n}" max="${n}" width="${w}" customWidth="1"/>`);
|
|
113
|
-
}
|
|
114
|
-
if (colLines.length > 0) {
|
|
115
|
-
lines.push("<cols>", ...colLines, "</cols>");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
lines.push("<sheetData>");
|
|
119
|
-
let rowNum = 0;
|
|
120
|
-
if (sheet.header && sheet.header.length > 0) {
|
|
121
|
-
rowNum++;
|
|
122
|
-
const cells = sheet.header.map((h, i) => {
|
|
123
|
-
const idx = internString(String(h));
|
|
124
|
-
return `<c r="${colLetter(i + 1)}${rowNum}" t="s"><v>${idx}</v></c>`;
|
|
125
|
-
}).join("");
|
|
126
|
-
lines.push(`<row r="${rowNum}">${cells}</row>`);
|
|
127
|
-
}
|
|
128
|
-
for (const row of sheet.rows) {
|
|
129
|
-
rowNum++;
|
|
130
|
-
const cells = row.map((value, i) => cellXml(value, i + 1, rowNum, internString, internStyle)).join("");
|
|
131
|
-
lines.push(`<row r="${rowNum}">${cells}</row>`);
|
|
132
|
-
}
|
|
133
|
-
lines.push("</sheetData>");
|
|
134
|
-
if (sheet.validations && sheet.validations.length > 0) {
|
|
135
|
-
lines.push(`<dataValidations count="${sheet.validations.length}">`);
|
|
136
|
-
for (const dv of sheet.validations) {
|
|
137
|
-
const f1 = dv.formula1 ?? `"${(dv.values ?? []).join(",")}"`;
|
|
138
|
-
lines.push(
|
|
139
|
-
`<dataValidation type="list" allowBlank="1" showInputMessage="1" showErrorMessage="1" sqref="${escapeXmlAttr(dv.sqref)}"><formula1>${escapeXmlText(f1)}</formula1></dataValidation>`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
lines.push("</dataValidations>");
|
|
143
|
-
}
|
|
144
|
-
lines.push("</worksheet>");
|
|
145
|
-
return lines.join("");
|
|
146
|
-
});
|
|
147
|
-
const hasStyles = numFmtCodes.length > 0;
|
|
148
|
-
const stylesXml = hasStyles ? [
|
|
149
|
-
XML_HEADER,
|
|
150
|
-
'<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">',
|
|
151
|
-
`<numFmts count="${numFmtCodes.length}">`,
|
|
152
|
-
...numFmtCodes.map((code, i) => `<numFmt numFmtId="${164 + i}" formatCode="${escapeXmlAttr(code)}"/>`),
|
|
153
|
-
"</numFmts>",
|
|
154
|
-
'<fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts>',
|
|
155
|
-
'<fills count="1"><fill><patternFill patternType="none"/></fill></fills>',
|
|
156
|
-
'<borders count="1"><border/></borders>',
|
|
157
|
-
'<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>',
|
|
158
|
-
`<cellXfs count="${numFmtCodes.length + 1}">`,
|
|
159
|
-
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>',
|
|
160
|
-
...numFmtCodes.map(
|
|
161
|
-
(_, i) => `<xf numFmtId="${164 + i}" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>`
|
|
162
|
-
),
|
|
163
|
-
"</cellXfs>",
|
|
164
|
-
"</styleSheet>"
|
|
165
|
-
].join("") : "";
|
|
166
|
-
const sheetEntries = safeSheets.map((s, i) => ({
|
|
167
|
-
index: i + 1,
|
|
168
|
-
id: `rId${i + 1}`,
|
|
169
|
-
name: s.name,
|
|
170
|
-
path: `xl/worksheets/sheet${i + 1}.xml`
|
|
171
|
-
}));
|
|
172
|
-
const contentTypes = [
|
|
173
|
-
XML_HEADER,
|
|
174
|
-
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">',
|
|
175
|
-
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>',
|
|
176
|
-
'<Default Extension="xml" ContentType="application/xml"/>',
|
|
177
|
-
'<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>',
|
|
178
|
-
...sheetEntries.map(
|
|
179
|
-
(s) => `<Override PartName="/${s.path}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`
|
|
180
|
-
),
|
|
181
|
-
'<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>',
|
|
182
|
-
...hasStyles ? ['<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>'] : [],
|
|
183
|
-
"</Types>"
|
|
184
|
-
].join("");
|
|
185
|
-
const rootRels = XML_HEADER + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>';
|
|
186
|
-
const workbookXml = [
|
|
187
|
-
XML_HEADER,
|
|
188
|
-
'<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">',
|
|
189
|
-
"<sheets>",
|
|
190
|
-
...sheetEntries.map(
|
|
191
|
-
(s) => `<sheet name="${escapeXmlAttr(s.name)}" sheetId="${s.index}" r:id="${s.id}"/>`
|
|
192
|
-
),
|
|
193
|
-
"</sheets>",
|
|
194
|
-
...options.definedNames && options.definedNames.length > 0 ? [
|
|
195
|
-
"<definedNames>",
|
|
196
|
-
...options.definedNames.map(
|
|
197
|
-
(d) => `<definedName name="${escapeXmlAttr(d.name)}">${escapeXmlText(d.ref)}</definedName>`
|
|
198
|
-
),
|
|
199
|
-
"</definedNames>"
|
|
200
|
-
] : [],
|
|
201
|
-
"</workbook>"
|
|
202
|
-
].join("");
|
|
203
|
-
const workbookRels = [
|
|
204
|
-
XML_HEADER,
|
|
205
|
-
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">',
|
|
206
|
-
...sheetEntries.map(
|
|
207
|
-
(s) => `<Relationship Id="${s.id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${s.index}.xml"/>`
|
|
208
|
-
),
|
|
209
|
-
`<Relationship Id="rIdSharedStrings" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`,
|
|
210
|
-
...hasStyles ? [`<Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>`] : [],
|
|
211
|
-
"</Relationships>"
|
|
212
|
-
].join("");
|
|
213
|
-
const sharedStringsXml = [
|
|
214
|
-
XML_HEADER,
|
|
215
|
-
`<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${sharedStrings.length}" uniqueCount="${sharedStrings.length}">`,
|
|
216
|
-
...sharedStrings.map((s) => `<si><t xml:space="preserve">${escapeXmlText(s)}</t></si>`),
|
|
217
|
-
"</sst>"
|
|
218
|
-
].join("");
|
|
219
|
-
const entries = [
|
|
220
|
-
{ path: "[Content_Types].xml", bytes: ENCODER.encode(contentTypes) },
|
|
221
|
-
{ path: "_rels/.rels", bytes: ENCODER.encode(rootRels) },
|
|
222
|
-
{ path: "xl/workbook.xml", bytes: ENCODER.encode(workbookXml) },
|
|
223
|
-
{ path: "xl/_rels/workbook.xml.rels", bytes: ENCODER.encode(workbookRels) },
|
|
224
|
-
{ path: "xl/sharedStrings.xml", bytes: ENCODER.encode(sharedStringsXml) },
|
|
225
|
-
...hasStyles ? [{ path: "xl/styles.xml", bytes: ENCODER.encode(stylesXml) }] : [],
|
|
226
|
-
...sheetEntries.map((s, i) => ({ path: s.path, bytes: ENCODER.encode(sheetXmls[i] ?? "") }))
|
|
227
|
-
];
|
|
228
|
-
return await (0, import_as_zip.writeZip)(entries);
|
|
229
|
-
}
|
|
230
|
-
function cellXml(value, colIdx, rowNum, intern, internStyle) {
|
|
231
|
-
const ref = `${colLetter(colIdx)}${rowNum}`;
|
|
232
|
-
if (isStyledCell(value)) {
|
|
233
|
-
const s2 = internStyle(value.__xlsxStyle);
|
|
234
|
-
const v = value.v;
|
|
235
|
-
if (v === null || v === void 0 || v === "") return `<c r="${ref}" s="${s2}"/>`;
|
|
236
|
-
if (typeof v === "number" && Number.isFinite(v)) return `<c r="${ref}" s="${s2}"><v>${v}</v></c>`;
|
|
237
|
-
if (typeof v === "boolean") return `<c r="${ref}" s="${s2}" t="b"><v>${v ? 1 : 0}</v></c>`;
|
|
238
|
-
return `<c r="${ref}" s="${s2}" t="s"><v>${intern(typeof v === "string" ? v : String(v))}</v></c>`;
|
|
239
|
-
}
|
|
240
|
-
if (isFormulaCell(value)) {
|
|
241
|
-
const f = escapeXmlText(value.__xlsxFormula);
|
|
242
|
-
if (value.v === void 0) return `<c r="${ref}"><f>${f}</f></c>`;
|
|
243
|
-
if (typeof value.v === "number" && Number.isFinite(value.v)) return `<c r="${ref}"><f>${f}</f><v>${value.v}</v></c>`;
|
|
244
|
-
if (typeof value.v === "boolean") return `<c r="${ref}" t="b"><f>${f}</f><v>${value.v ? 1 : 0}</v></c>`;
|
|
245
|
-
return `<c r="${ref}" t="str"><f>${f}</f><v>${escapeXmlText(String(value.v))}</v></c>`;
|
|
246
|
-
}
|
|
247
|
-
if (value === null || value === void 0 || value === "") return `<c r="${ref}"/>`;
|
|
248
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
249
|
-
return `<c r="${ref}"><v>${value}</v></c>`;
|
|
250
|
-
}
|
|
251
|
-
if (typeof value === "boolean") {
|
|
252
|
-
return `<c r="${ref}" t="b"><v>${value ? 1 : 0}</v></c>`;
|
|
253
|
-
}
|
|
254
|
-
const s = value instanceof Date ? value.toISOString() : typeof value === "string" ? value : JSON.stringify(value);
|
|
255
|
-
const idx = intern(s);
|
|
256
|
-
return `<c r="${ref}" t="s"><v>${idx}</v></c>`;
|
|
257
|
-
}
|
|
258
|
-
function colLetter(n) {
|
|
259
|
-
let s = "";
|
|
260
|
-
let x = n;
|
|
261
|
-
while (x > 0) {
|
|
262
|
-
const r = (x - 1) % 26;
|
|
263
|
-
s = String.fromCharCode(65 + r) + s;
|
|
264
|
-
x = Math.floor((x - 1) / 26);
|
|
265
|
-
}
|
|
266
|
-
return s;
|
|
267
|
-
}
|
|
268
|
-
function truncateSheetName(name) {
|
|
269
|
-
const cleaned = name.replace(/[:/\\?*[\]]/g, "_");
|
|
270
|
-
if (cleaned.length <= 31) return cleaned;
|
|
271
|
-
return cleaned.slice(0, 30) + "\u2026";
|
|
272
|
-
}
|
|
273
|
-
function escapeXmlText(s) {
|
|
274
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\r/g, " ");
|
|
275
|
-
}
|
|
276
|
-
function escapeXmlAttr(s) {
|
|
277
|
-
return escapeXmlText(s).replace(/"/g, """);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// src/read.ts
|
|
281
|
-
var import_as_zip2 = require("@noy-db/as-zip");
|
|
282
|
-
var import_fast_xml_parser = require("fast-xml-parser");
|
|
283
|
-
var PARSER = new import_fast_xml_parser.XMLParser({
|
|
284
|
-
ignoreAttributes: false,
|
|
285
|
-
attributeNamePrefix: "@_",
|
|
286
|
-
parseTagValue: false,
|
|
287
|
-
parseAttributeValue: false,
|
|
288
|
-
trimValues: false,
|
|
289
|
-
isArray: (name) => name === "sheet" || name === "row" || name === "c" || name === "si" || name === "Relationship"
|
|
290
|
-
});
|
|
291
|
-
async function readXlsx(bytes) {
|
|
292
|
-
const entries = await (0, import_as_zip2.readZip)(bytes);
|
|
293
|
-
const partByPath = /* @__PURE__ */ new Map();
|
|
294
|
-
for (const e of entries) partByPath.set(e.path, e.bytes);
|
|
295
|
-
const sharedStrings = readSharedStrings(partByPath.get("xl/sharedStrings.xml"));
|
|
296
|
-
const sheetMeta = readWorkbook(partByPath.get("xl/workbook.xml"));
|
|
297
|
-
const rels = readWorkbookRels(partByPath.get("xl/_rels/workbook.xml.rels"));
|
|
298
|
-
const sheets = [];
|
|
299
|
-
for (const meta of sheetMeta) {
|
|
300
|
-
const target = rels.get(meta.rId);
|
|
301
|
-
if (target === void 0) {
|
|
302
|
-
throw new Error(
|
|
303
|
-
`as-xlsx.readXlsx: workbook references rId="${meta.rId}" but the rels file has no matching target`
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
const sheetPath = `xl/${target}`;
|
|
307
|
-
const sheetBytes = partByPath.get(sheetPath);
|
|
308
|
-
if (sheetBytes === void 0) {
|
|
309
|
-
throw new Error(`as-xlsx.readXlsx: missing sheet part ${sheetPath}`);
|
|
310
|
-
}
|
|
311
|
-
sheets.push({
|
|
312
|
-
name: meta.name,
|
|
313
|
-
rows: readSheet(sheetBytes, sharedStrings)
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
return { sheets };
|
|
317
|
-
}
|
|
318
|
-
function decodeXml(bytes) {
|
|
319
|
-
return new TextDecoder().decode(bytes);
|
|
320
|
-
}
|
|
321
|
-
function parseStrict(xml, where) {
|
|
322
|
-
const validation = import_fast_xml_parser.XMLValidator.validate(xml);
|
|
323
|
-
if (validation !== true) {
|
|
324
|
-
const err = validation.err;
|
|
325
|
-
throw new Error(
|
|
326
|
-
`as-xlsx.readXlsx: ${where} is not valid XML (${err.code} at line ${err.line}: ${err.msg})`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
try {
|
|
330
|
-
return PARSER.parse(xml);
|
|
331
|
-
} catch (err) {
|
|
332
|
-
throw new Error(`as-xlsx.readXlsx: failed to parse ${where} (${err.message})`);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function readSharedStrings(bytes) {
|
|
336
|
-
if (bytes === void 0) return [];
|
|
337
|
-
const parsed = parseStrict(decodeXml(bytes), "xl/sharedStrings.xml");
|
|
338
|
-
const sst = parsed.sst;
|
|
339
|
-
if (sst === null || sst === void 0 || typeof sst !== "object") return [];
|
|
340
|
-
const items = sst.si ?? [];
|
|
341
|
-
if (!Array.isArray(items)) return [];
|
|
342
|
-
return items.map((si) => {
|
|
343
|
-
if (si === null || typeof si !== "object") return "";
|
|
344
|
-
const t = si.t;
|
|
345
|
-
return textValue(t);
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
function readWorkbook(bytes) {
|
|
349
|
-
if (bytes === void 0) {
|
|
350
|
-
throw new Error("as-xlsx.readXlsx: missing xl/workbook.xml");
|
|
351
|
-
}
|
|
352
|
-
const parsed = parseStrict(decodeXml(bytes), "xl/workbook.xml");
|
|
353
|
-
const workbook = parsed.workbook;
|
|
354
|
-
if (workbook === null || workbook === void 0 || typeof workbook !== "object") {
|
|
355
|
-
throw new Error("as-xlsx.readXlsx: xl/workbook.xml has no <workbook> root");
|
|
356
|
-
}
|
|
357
|
-
const sheetsObj = workbook.sheets;
|
|
358
|
-
if (sheetsObj === null || sheetsObj === void 0 || typeof sheetsObj !== "object") {
|
|
359
|
-
return [];
|
|
360
|
-
}
|
|
361
|
-
const sheetEntries = sheetsObj.sheet ?? [];
|
|
362
|
-
if (!Array.isArray(sheetEntries)) return [];
|
|
363
|
-
return sheetEntries.map((s) => {
|
|
364
|
-
const obj = s;
|
|
365
|
-
return {
|
|
366
|
-
name: stringAttr(obj["@_name"]),
|
|
367
|
-
sheetId: stringAttr(obj["@_sheetId"]),
|
|
368
|
-
rId: stringAttr(obj["@_r:id"]) || stringAttr(obj["@_id"])
|
|
369
|
-
};
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
function readWorkbookRels(bytes) {
|
|
373
|
-
if (bytes === void 0) {
|
|
374
|
-
throw new Error("as-xlsx.readXlsx: missing xl/_rels/workbook.xml.rels");
|
|
375
|
-
}
|
|
376
|
-
const parsed = parseStrict(decodeXml(bytes), "xl/_rels/workbook.xml.rels");
|
|
377
|
-
const root = parsed.Relationships;
|
|
378
|
-
if (root === null || root === void 0 || typeof root !== "object") {
|
|
379
|
-
return /* @__PURE__ */ new Map();
|
|
380
|
-
}
|
|
381
|
-
const rels = root.Relationship ?? [];
|
|
382
|
-
if (!Array.isArray(rels)) return /* @__PURE__ */ new Map();
|
|
383
|
-
const map = /* @__PURE__ */ new Map();
|
|
384
|
-
for (const r of rels) {
|
|
385
|
-
const obj = r;
|
|
386
|
-
const id = stringAttr(obj["@_Id"]);
|
|
387
|
-
const target = stringAttr(obj["@_Target"]);
|
|
388
|
-
if (id) map.set(id, target);
|
|
389
|
-
}
|
|
390
|
-
return map;
|
|
391
|
-
}
|
|
392
|
-
function readSheet(bytes, sharedStrings) {
|
|
393
|
-
const parsed = parseStrict(decodeXml(bytes), "sheet");
|
|
394
|
-
const ws = parsed.worksheet;
|
|
395
|
-
if (ws === null || ws === void 0 || typeof ws !== "object") return [];
|
|
396
|
-
const sheetData = ws.sheetData;
|
|
397
|
-
if (sheetData === null || sheetData === void 0 || typeof sheetData !== "object") return [];
|
|
398
|
-
const rowEntries = sheetData.row ?? [];
|
|
399
|
-
if (!Array.isArray(rowEntries)) return [];
|
|
400
|
-
const rows = [];
|
|
401
|
-
for (const row of rowEntries) {
|
|
402
|
-
if (row === null || typeof row !== "object") {
|
|
403
|
-
rows.push({});
|
|
404
|
-
continue;
|
|
405
|
-
}
|
|
406
|
-
const cells = row.c ?? [];
|
|
407
|
-
if (!Array.isArray(cells)) {
|
|
408
|
-
rows.push({});
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
const out = {};
|
|
412
|
-
for (const c of cells) {
|
|
413
|
-
if (c === null || typeof c !== "object") continue;
|
|
414
|
-
const cellObj = c;
|
|
415
|
-
const ref = stringAttr(cellObj["@_r"]);
|
|
416
|
-
if (!ref) continue;
|
|
417
|
-
const col = letterFromRef(ref);
|
|
418
|
-
const t = cellObj["@_t"];
|
|
419
|
-
const v = cellObj["v"];
|
|
420
|
-
const text = textValue(v);
|
|
421
|
-
if (text === "") {
|
|
422
|
-
if (t === "s") {
|
|
423
|
-
out[col] = "";
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
if (t === "s") {
|
|
429
|
-
const idx = Number(text);
|
|
430
|
-
if (!Number.isInteger(idx) || idx < 0 || idx >= sharedStrings.length) {
|
|
431
|
-
throw new Error(
|
|
432
|
-
`as-xlsx.readXlsx: shared-string reference ${idx} out of range (table has ${sharedStrings.length} entries)`
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
out[col] = sharedStrings[idx];
|
|
436
|
-
} else if (t === "b") {
|
|
437
|
-
out[col] = text === "1";
|
|
438
|
-
} else if (t === "str" || t === "inlineStr") {
|
|
439
|
-
out[col] = text;
|
|
440
|
-
} else {
|
|
441
|
-
const n = Number(text);
|
|
442
|
-
out[col] = Number.isFinite(n) ? n : text;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
rows.push(out);
|
|
446
|
-
}
|
|
447
|
-
return rows;
|
|
448
|
-
}
|
|
449
|
-
function letterFromRef(ref) {
|
|
450
|
-
let i = 0;
|
|
451
|
-
while (i < ref.length && /[A-Z]/.test(ref[i])) i++;
|
|
452
|
-
return ref.slice(0, i);
|
|
453
|
-
}
|
|
454
|
-
function textValue(raw) {
|
|
455
|
-
if (raw === null || raw === void 0) return "";
|
|
456
|
-
if (typeof raw === "string") return raw;
|
|
457
|
-
if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
|
|
458
|
-
if (typeof raw === "object") {
|
|
459
|
-
const txt = raw["#text"];
|
|
460
|
-
if (txt !== void 0) return textValue(txt);
|
|
461
|
-
}
|
|
462
|
-
return "";
|
|
463
|
-
}
|
|
464
|
-
function stringAttr(raw) {
|
|
465
|
-
if (raw === void 0 || raw === null) return "";
|
|
466
|
-
if (typeof raw === "string") return raw;
|
|
467
|
-
if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
|
|
468
|
-
return "";
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// src/infer.ts
|
|
472
|
-
var ISO_DATE = /^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2})?/;
|
|
473
|
-
function inferType(vals) {
|
|
474
|
-
if (vals.length === 0) return "string";
|
|
475
|
-
if (vals.every((v) => typeof v === "boolean")) return "boolean";
|
|
476
|
-
if (vals.every((v) => typeof v === "number")) return "number";
|
|
477
|
-
if (vals.every((v) => typeof v === "string" && ISO_DATE.test(v))) return "date";
|
|
478
|
-
return "string";
|
|
479
|
-
}
|
|
480
|
-
async function inferSchema(bytes, options = {}) {
|
|
481
|
-
const skip = new Set(options.skipSheets ?? []);
|
|
482
|
-
const decoded = await readXlsx(bytes);
|
|
483
|
-
const sheets = [];
|
|
484
|
-
for (const sh of decoded.sheets) {
|
|
485
|
-
if (sh.name.startsWith("_") || skip.has(sh.name)) continue;
|
|
486
|
-
const headerRow = sh.rows[0] ?? {};
|
|
487
|
-
const colToField = /* @__PURE__ */ new Map();
|
|
488
|
-
const fields = [];
|
|
489
|
-
for (const [letter, val] of Object.entries(headerRow)) {
|
|
490
|
-
const name = typeof val === "string" ? val.trim() : typeof val === "number" || typeof val === "boolean" ? String(val) : "";
|
|
491
|
-
if (!name) continue;
|
|
492
|
-
colToField.set(letter, name);
|
|
493
|
-
fields.push(name);
|
|
494
|
-
}
|
|
495
|
-
const records = sh.rows.slice(1).map((row) => {
|
|
496
|
-
const rec = {};
|
|
497
|
-
for (const [letter, val] of Object.entries(row)) {
|
|
498
|
-
const f = colToField.get(letter);
|
|
499
|
-
if (f !== void 0) rec[f] = val;
|
|
500
|
-
}
|
|
501
|
-
return rec;
|
|
502
|
-
});
|
|
503
|
-
sheets.push({ name: sh.name, fields, records });
|
|
504
|
-
}
|
|
505
|
-
const valuesOf = (s, f) => s.records.map((r) => r[f]).filter((v) => v != null && v !== "");
|
|
506
|
-
const idFieldOf = (s) => {
|
|
507
|
-
if (s.fields.includes("id")) return "id";
|
|
508
|
-
for (const f of s.fields) {
|
|
509
|
-
const vals = valuesOf(s, f);
|
|
510
|
-
if (vals.length > 0 && new Set(vals.map((v) => String(v))).size === vals.length) return f;
|
|
511
|
-
}
|
|
512
|
-
return s.fields[0] ?? "id";
|
|
513
|
-
};
|
|
514
|
-
const meta = sheets.map((s) => ({ s, idField: idFieldOf(s) }));
|
|
515
|
-
const idValuesByName = /* @__PURE__ */ new Map();
|
|
516
|
-
for (const { s, idField } of meta) {
|
|
517
|
-
idValuesByName.set(s.name, new Set(valuesOf(s, idField).map((v) => String(v))));
|
|
518
|
-
}
|
|
519
|
-
const collections = {};
|
|
520
|
-
for (const { s, idField } of meta) {
|
|
521
|
-
const fields = {};
|
|
522
|
-
for (const f of s.fields) {
|
|
523
|
-
const vals = valuesOf(s, f);
|
|
524
|
-
const type = inferType(vals);
|
|
525
|
-
let references;
|
|
526
|
-
if (f !== idField && type === "string" && vals.length > 0) {
|
|
527
|
-
const distinct = new Set(vals.map((v) => String(v)));
|
|
528
|
-
for (const { s: other } of meta) {
|
|
529
|
-
if (other.name === s.name) continue;
|
|
530
|
-
const ids = idValuesByName.get(other.name);
|
|
531
|
-
if (ids && ids.size > 0 && [...distinct].every((v) => ids.has(v))) {
|
|
532
|
-
references = other.name;
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
fields[f] = references ? { type, references } : { type };
|
|
538
|
-
}
|
|
539
|
-
collections[s.name] = { idField, fields };
|
|
540
|
-
}
|
|
541
|
-
return { collections };
|
|
542
|
-
}
|
|
543
|
-
function zodSourceFor(schema) {
|
|
544
|
-
const zType = (t) => t === "number" ? "z.number()" : t === "boolean" ? "z.boolean()" : t === "date" ? "z.string().datetime()" : "z.string()";
|
|
545
|
-
const blocks = [`import { z } from 'zod'`];
|
|
546
|
-
for (const [name, c] of Object.entries(schema.collections)) {
|
|
547
|
-
const lines = Object.entries(c.fields).map(
|
|
548
|
-
([f, d]) => ` ${f}: ${zType(d.type)},${d.references ? ` // \u2192 ${d.references}` : ""}`
|
|
549
|
-
);
|
|
550
|
-
blocks.push(`export const ${name}Schema = z.object({
|
|
551
|
-
${lines.join("\n")}
|
|
552
|
-
})`);
|
|
553
|
-
}
|
|
554
|
-
return blocks.join("\n\n");
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// src/index.ts
|
|
558
|
-
var import_hub = require("@noy-db/hub");
|
|
559
|
-
async function toBytesFromCollection(vault, collectionName) {
|
|
560
|
-
return toBytes(vault, {
|
|
561
|
-
sheets: [{ name: collectionName, collection: collectionName }]
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
async function toBytes(vault, options) {
|
|
565
|
-
vault.assertCanExport("plaintext", "xlsx");
|
|
566
|
-
if (options.sheets.length === 0) {
|
|
567
|
-
throw new Error("as-xlsx: at least one sheet is required");
|
|
568
|
-
}
|
|
569
|
-
if (options.smart) {
|
|
570
|
-
const { sheets, definedNames } = await buildSmartSheets(vault, options);
|
|
571
|
-
return writeXlsx(sheets, { definedNames });
|
|
572
|
-
}
|
|
573
|
-
const materialisedSheets = [];
|
|
574
|
-
for (const sheetOpt of options.sheets) {
|
|
575
|
-
const collection = vault.collection(sheetOpt.collection);
|
|
576
|
-
const list = await collection.list();
|
|
577
|
-
const records = [];
|
|
578
|
-
for (const item of list) {
|
|
579
|
-
const r = item;
|
|
580
|
-
if (sheetOpt.filter && !sheetOpt.filter(r)) continue;
|
|
581
|
-
records.push(r);
|
|
582
|
-
}
|
|
583
|
-
const columns = sheetOpt.columns ?? inferColumns(records);
|
|
584
|
-
materialisedSheets.push({
|
|
585
|
-
name: sheetOpt.name,
|
|
586
|
-
header: columns,
|
|
587
|
-
rows: records.map((r) => columns.map((c) => r[c] ?? null)),
|
|
588
|
-
...sheetOpt.widths !== void 0 ? { widths: sheetOpt.widths } : {}
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
return writeXlsx(materialisedSheets);
|
|
592
|
-
}
|
|
593
|
-
async function download(vault, options) {
|
|
594
|
-
const bytes = await toBytes(vault, options);
|
|
595
|
-
const filename = options.filename ?? "export.xlsx";
|
|
596
|
-
const blob = new Blob([bytes], {
|
|
597
|
-
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
598
|
-
});
|
|
599
|
-
const url = URL.createObjectURL(blob);
|
|
600
|
-
const a = document.createElement("a");
|
|
601
|
-
a.href = url;
|
|
602
|
-
a.download = filename;
|
|
603
|
-
a.click();
|
|
604
|
-
URL.revokeObjectURL(url);
|
|
605
|
-
}
|
|
606
|
-
async function write(vault, path, options) {
|
|
607
|
-
if (options.acknowledgeRisks !== true) {
|
|
608
|
-
throw new Error(
|
|
609
|
-
`as-xlsx.write: acknowledgeRisks: true is required for on-disk plaintext output. This call creates a persistent plaintext xlsx outside noy-db's encrypted storage \u2014 see docs/patterns/as-exports.md \xA7"The three tiers of \\"plaintext out\\""`
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
const bytes = await toBytes(vault, options);
|
|
613
|
-
const { writeFile } = await import("fs/promises");
|
|
614
|
-
await writeFile(path, bytes);
|
|
615
|
-
}
|
|
616
|
-
async function toBytesMultiVault(entries, options = {}) {
|
|
617
|
-
const sep = options.sheetSeparator ?? "_";
|
|
618
|
-
for (const entry of entries) {
|
|
619
|
-
entry.vault.assertCanExport("plaintext", "xlsx");
|
|
620
|
-
}
|
|
621
|
-
const loaded = [];
|
|
622
|
-
const denormIndex = /* @__PURE__ */ new Map();
|
|
623
|
-
for (const entry of entries) {
|
|
624
|
-
const prefix = entry.label ?? entry.vault.name;
|
|
625
|
-
for (const s of entry.sheets) {
|
|
626
|
-
const all = await entry.vault.collection(s.collection).list();
|
|
627
|
-
const records = [];
|
|
628
|
-
for (const item of all) {
|
|
629
|
-
const r = item;
|
|
630
|
-
const allow = entry.closure?.get(s.collection);
|
|
631
|
-
if (allow && !allow.has(String(r.id))) continue;
|
|
632
|
-
if (s.filter && !s.filter(r)) continue;
|
|
633
|
-
records.push(r);
|
|
634
|
-
}
|
|
635
|
-
loaded.push({ entry, prefix, sheetOpt: s, records });
|
|
636
|
-
const indexKey = `${prefix}/${s.collection}`;
|
|
637
|
-
const collectionIndex = denormIndex.get(indexKey) ?? /* @__PURE__ */ new Map();
|
|
638
|
-
denormIndex.set(indexKey, collectionIndex);
|
|
639
|
-
for (const r of records) {
|
|
640
|
-
const idVal = r.id;
|
|
641
|
-
if (idVal != null) collectionIndex.set(safeStringify(idVal), r);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
for (const ls of loaded) {
|
|
646
|
-
for (const d of ls.sheetOpt.denormalize ?? []) {
|
|
647
|
-
if (d.from.keyField === "id") continue;
|
|
648
|
-
const indexKey = `${d.from.label}/${d.from.collection}`;
|
|
649
|
-
const idx = denormIndex.get(indexKey);
|
|
650
|
-
if (!idx) continue;
|
|
651
|
-
const srcLoaded = loaded.find(
|
|
652
|
-
(l) => l.prefix === d.from.label && l.sheetOpt.collection === d.from.collection
|
|
653
|
-
);
|
|
654
|
-
if (!srcLoaded) continue;
|
|
655
|
-
for (const r of srcLoaded.records) {
|
|
656
|
-
const kv = r[d.from.keyField];
|
|
657
|
-
if (kv != null) idx.set(safeStringify(kv), r);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
const allSheets = [];
|
|
662
|
-
const manifestRows = [];
|
|
663
|
-
for (const { prefix, sheetOpt: s, records } of loaded) {
|
|
664
|
-
const baseColumns = s.columns ?? inferColumns(records);
|
|
665
|
-
const denormDefs = s.denormalize ?? [];
|
|
666
|
-
if (denormDefs.length === 0) {
|
|
667
|
-
const sheetName2 = `${prefix}${sep}${s.name}`;
|
|
668
|
-
allSheets.push(buildFlatSheet(sheetName2, baseColumns, records));
|
|
669
|
-
manifestRows.push([prefix, s.collection, records.length]);
|
|
670
|
-
continue;
|
|
671
|
-
}
|
|
672
|
-
const allColumns = [...baseColumns, ...denormDefs.map((d) => d.column)];
|
|
673
|
-
const sheetName = `${prefix}${sep}${s.name}`;
|
|
674
|
-
const rows = records.map((r) => {
|
|
675
|
-
const baseCells = baseColumns.map((c) => r[c] ?? null);
|
|
676
|
-
const denormCells = denormDefs.map((d) => {
|
|
677
|
-
const idxKey = `${d.from.label}/${d.from.collection}`;
|
|
678
|
-
const idx = denormIndex.get(idxKey);
|
|
679
|
-
if (!idx) return "";
|
|
680
|
-
const fkVal = r[d.localField];
|
|
681
|
-
if (fkVal == null) return "";
|
|
682
|
-
const supporting = idx.get(safeStringify(fkVal));
|
|
683
|
-
if (!supporting) return "";
|
|
684
|
-
return supporting[d.from.pick] ?? "";
|
|
685
|
-
});
|
|
686
|
-
return [...baseCells, ...denormCells];
|
|
687
|
-
});
|
|
688
|
-
allSheets.push({ name: sheetName, header: allColumns, rows });
|
|
689
|
-
manifestRows.push([prefix, s.collection, records.length]);
|
|
690
|
-
}
|
|
691
|
-
allSheets.unshift({
|
|
692
|
-
name: "_manifest",
|
|
693
|
-
header: ["Vault", "Collection", "Records"],
|
|
694
|
-
rows: manifestRows
|
|
695
|
-
});
|
|
696
|
-
return writeXlsx(allSheets);
|
|
697
|
-
}
|
|
698
|
-
function buildFlatSheet(name, columns, records) {
|
|
699
|
-
return {
|
|
700
|
-
name,
|
|
701
|
-
header: [...columns],
|
|
702
|
-
rows: records.map((r) => columns.map((c) => r[c] ?? null))
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
function safeStringify(v) {
|
|
706
|
-
if (typeof v === "string") return v;
|
|
707
|
-
if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
|
|
708
|
-
if (v == null) return "";
|
|
709
|
-
try {
|
|
710
|
-
return JSON.stringify(v) ?? "";
|
|
711
|
-
} catch {
|
|
712
|
-
return "";
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
function asCached(v) {
|
|
716
|
-
if (typeof v === "number" || typeof v === "boolean" || typeof v === "string") return v;
|
|
717
|
-
return safeStringify(v);
|
|
718
|
-
}
|
|
719
|
-
async function buildSmartSheets(vault, options) {
|
|
720
|
-
const snapshot = await vault.dumpSchema();
|
|
721
|
-
const sheetNameByCollection = /* @__PURE__ */ new Map();
|
|
722
|
-
for (const s of options.sheets) sheetNameByCollection.set(s.collection, s.name);
|
|
723
|
-
const mats = [];
|
|
724
|
-
const localeSet = /* @__PURE__ */ new Set();
|
|
725
|
-
for (const sheetOpt of options.sheets) {
|
|
726
|
-
const collection = vault.collection(sheetOpt.collection);
|
|
727
|
-
const list = await collection.list();
|
|
728
|
-
const records = [];
|
|
729
|
-
for (const item of list) {
|
|
730
|
-
const r = item;
|
|
731
|
-
if (sheetOpt.filter && !sheetOpt.filter(r)) continue;
|
|
732
|
-
records.push(r);
|
|
733
|
-
}
|
|
734
|
-
const base = sheetOpt.columns ?? inferColumns(records);
|
|
735
|
-
const cols = ["id", ...base.filter((c) => c !== "id")];
|
|
736
|
-
const labelCol = cols.find((c) => c !== "id");
|
|
737
|
-
const labelMap = /* @__PURE__ */ new Map();
|
|
738
|
-
if (labelCol) {
|
|
739
|
-
for (const r of records) if (r.id != null) labelMap.set(safeStringify(r.id), r[labelCol]);
|
|
740
|
-
}
|
|
741
|
-
const i18nFields = (sheetOpt.i18nFields ?? []).filter((f) => cols.includes(f));
|
|
742
|
-
for (const f of i18nFields) {
|
|
743
|
-
for (const r of records) {
|
|
744
|
-
const v = r[f];
|
|
745
|
-
if (v && typeof v === "object") for (const loc of Object.keys(v)) localeSet.add(loc);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
mats.push({ opt: sheetOpt, records, cols, labelMap, i18nFields });
|
|
749
|
-
}
|
|
750
|
-
const matByCollection = new Map(mats.map((m) => [m.opt.collection, m]));
|
|
751
|
-
const dictEntries = /* @__PURE__ */ new Map();
|
|
752
|
-
for (const m of mats) {
|
|
753
|
-
for (const [field, dictName] of Object.entries(m.opt.dictFields ?? {})) {
|
|
754
|
-
if (!m.cols.includes(field) || dictEntries.has(dictName)) continue;
|
|
755
|
-
dictEntries.set(dictName, await vault.dictionary(dictName).list());
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
for (const entries of dictEntries.values()) {
|
|
759
|
-
for (const e of entries) for (const loc of Object.keys(e.labels)) localeSet.add(loc);
|
|
760
|
-
}
|
|
761
|
-
const locales = [...localeSet].sort();
|
|
762
|
-
const hasLang = locales.length > 0;
|
|
763
|
-
const defaultLocale = locales.includes("en") ? "en" : locales[0] ?? "en";
|
|
764
|
-
const ifChain = (refOf) => {
|
|
765
|
-
if (locales.length === 0) return '""';
|
|
766
|
-
let expr = refOf(locales[0]);
|
|
767
|
-
for (let k = locales.length - 1; k >= 0; k--) {
|
|
768
|
-
expr = `IF(LANG="${locales[k]}",${refOf(locales[k])},${expr})`;
|
|
769
|
-
}
|
|
770
|
-
return expr;
|
|
771
|
-
};
|
|
772
|
-
const sheetMeta = /* @__PURE__ */ new Map();
|
|
773
|
-
const dataSheets = mats.map((m) => {
|
|
774
|
-
const refs = snapshot.collections[m.opt.collection]?.refs ?? {};
|
|
775
|
-
const fields = snapshot.collections[m.opt.collection]?.fields ?? {};
|
|
776
|
-
const i18nSet = new Set(m.i18nFields);
|
|
777
|
-
const refFields = Object.keys(refs).filter((f) => m.cols.includes(f) && matByCollection.has(refs[f].target));
|
|
778
|
-
const baseCols = m.cols.filter((c) => !i18nSet.has(c));
|
|
779
|
-
const i18nFlat = m.i18nFields.flatMap((f) => [f, ...locales.map((l) => `${f}__${l}`)]);
|
|
780
|
-
const dictPairs = Object.entries(m.opt.dictFields ?? {}).filter(([f]) => m.cols.includes(f));
|
|
781
|
-
const header = [
|
|
782
|
-
...baseCols,
|
|
783
|
-
...i18nFlat,
|
|
784
|
-
...dictPairs.map(([f]) => `${f}__label`),
|
|
785
|
-
...refFields.map((f) => `${f}__label`)
|
|
786
|
-
];
|
|
787
|
-
const colIndex = /* @__PURE__ */ new Map();
|
|
788
|
-
header.forEach((h, i) => colIndex.set(h, i + 1));
|
|
789
|
-
sheetMeta.set(m.opt.collection, { name: m.opt.name, colIndex });
|
|
790
|
-
const lastRow = Math.max(m.records.length + 1, 2);
|
|
791
|
-
const validations = [];
|
|
792
|
-
for (const field of baseCols) {
|
|
793
|
-
const colL = colLetter(colIndex.get(field));
|
|
794
|
-
const sqref = `${colL}2:${colL}${lastRow}`;
|
|
795
|
-
const explicit = m.opt.dropdowns?.[field];
|
|
796
|
-
if (explicit && explicit.length > 0) {
|
|
797
|
-
validations.push({ sqref, values: explicit });
|
|
798
|
-
continue;
|
|
799
|
-
}
|
|
800
|
-
const rf = refs[field];
|
|
801
|
-
if (rf && matByCollection.has(rf.target)) {
|
|
802
|
-
const targetSheet = sheetNameByCollection.get(rf.target);
|
|
803
|
-
const targetRows = Math.max(matByCollection.get(rf.target).records.length + 1, 2);
|
|
804
|
-
validations.push({ sqref, formula1: `'${targetSheet}'!$A$2:$A$${targetRows}` });
|
|
805
|
-
continue;
|
|
806
|
-
}
|
|
807
|
-
const enumVals = fields[field]?.constraints?.["values"];
|
|
808
|
-
if (Array.isArray(enumVals) && enumVals.length > 0) validations.push({ sqref, values: enumVals.map((v) => safeStringify(v)) });
|
|
809
|
-
}
|
|
810
|
-
const rows = m.records.map((r, i) => {
|
|
811
|
-
const rowNum = i + 2;
|
|
812
|
-
const baseCells = baseCols.map((c) => {
|
|
813
|
-
const raw = c === "id" ? r.id ?? null : r[c] ?? null;
|
|
814
|
-
const fmt = m.opt.numberFormats?.[c];
|
|
815
|
-
if (fmt === void 0) return raw;
|
|
816
|
-
const num = typeof raw === "string" && raw.trim() !== "" && Number.isFinite(Number(raw)) ? Number(raw) : raw;
|
|
817
|
-
return styled(num, fmt);
|
|
818
|
-
});
|
|
819
|
-
const i18nCells = m.i18nFields.flatMap((f) => {
|
|
820
|
-
const rawMap = r[f] && typeof r[f] === "object" ? r[f] : {};
|
|
821
|
-
const display = formula(
|
|
822
|
-
ifChain((l) => `${colLetter(colIndex.get(`${f}__${l}`))}${rowNum}`),
|
|
823
|
-
asCached(rawMap[defaultLocale] ?? "")
|
|
824
|
-
);
|
|
825
|
-
return [display, ...locales.map((l) => rawMap[l] ?? null)];
|
|
826
|
-
});
|
|
827
|
-
const dictCells = dictPairs.map(([f, dn]) => {
|
|
828
|
-
const codeRef = `${colLetter(colIndex.get(f))}${rowNum}`;
|
|
829
|
-
const lk = `_Lookups_${dn}`;
|
|
830
|
-
const f1 = `IFERROR(VLOOKUP(${codeRef},'${lk}'!$A:$ZZ,MATCH(LANG,'${lk}'!$1:$1,0),FALSE),${codeRef})`;
|
|
831
|
-
const code = r[f];
|
|
832
|
-
const entry = code == null ? void 0 : dictEntries.get(dn)?.find((e) => e.key === safeStringify(code));
|
|
833
|
-
return formula(f1, asCached(entry?.labels[defaultLocale] ?? (code ?? "")));
|
|
834
|
-
});
|
|
835
|
-
const refCells = refFields.map((f) => {
|
|
836
|
-
const target = refs[f].target;
|
|
837
|
-
const targetSheet = sheetNameByCollection.get(target);
|
|
838
|
-
const targetMat = matByCollection.get(target);
|
|
839
|
-
const codeRef = `${colLetter(colIndex.get(f))}${rowNum}`;
|
|
840
|
-
const f1 = `IFERROR(VLOOKUP(${codeRef},'${targetSheet}'!$A:$ZZ,2,FALSE),"")`;
|
|
841
|
-
const code = r[f];
|
|
842
|
-
const cached = code == null ? "" : asCached(targetMat.labelMap.get(safeStringify(code)));
|
|
843
|
-
return formula(f1, cached);
|
|
844
|
-
});
|
|
845
|
-
return [...baseCells, ...i18nCells, ...dictCells, ...refCells];
|
|
846
|
-
});
|
|
847
|
-
return {
|
|
848
|
-
name: m.opt.name,
|
|
849
|
-
header,
|
|
850
|
-
rows,
|
|
851
|
-
...validations.length > 0 ? { validations } : {},
|
|
852
|
-
...m.opt.widths !== void 0 ? { widths: m.opt.widths } : {}
|
|
853
|
-
};
|
|
854
|
-
});
|
|
855
|
-
const manifest = {
|
|
856
|
-
name: "_manifest",
|
|
857
|
-
header: ["Collection", "Records", "Refs"],
|
|
858
|
-
rows: mats.map((m) => {
|
|
859
|
-
const refs = snapshot.collections[m.opt.collection]?.refs ?? {};
|
|
860
|
-
return [m.opt.name, m.records.length, Object.entries(refs).map(([f, r]) => `${f}\u2192${r.target}`).join(", ")];
|
|
861
|
-
})
|
|
862
|
-
};
|
|
863
|
-
const dialect = options.dialect ?? "excel";
|
|
864
|
-
const summarySheets = [];
|
|
865
|
-
for (const spec of options.summaries ?? []) {
|
|
866
|
-
const src = sheetMeta.get(spec.from);
|
|
867
|
-
const srcMat = matByCollection.get(spec.from);
|
|
868
|
-
const gCol = src?.colIndex.get(spec.groupBy);
|
|
869
|
-
if (!src || !srcMat || gCol === void 0) continue;
|
|
870
|
-
const gLetter = colLetter(gCol);
|
|
871
|
-
if (dialect === "sheets") {
|
|
872
|
-
const selects = [];
|
|
873
|
-
const labels = [];
|
|
874
|
-
for (const a of spec.aggregates) {
|
|
875
|
-
if (a.op === "count") {
|
|
876
|
-
selects.push(`COUNT(${gLetter})`);
|
|
877
|
-
labels.push(`COUNT(${gLetter}) '${a.label}'`);
|
|
878
|
-
continue;
|
|
879
|
-
}
|
|
880
|
-
const vIdx = a.field ? src.colIndex.get(a.field) : void 0;
|
|
881
|
-
if (vIdx === void 0) continue;
|
|
882
|
-
const vL = colLetter(vIdx);
|
|
883
|
-
const fn = a.op === "sum" ? "SUM" : "AVG";
|
|
884
|
-
selects.push(`${fn}(${vL})`);
|
|
885
|
-
labels.push(`${fn}(${vL}) '${a.label}'`);
|
|
886
|
-
}
|
|
887
|
-
const q = `QUERY('${src.name}'!A:ZZ, "SELECT ${gLetter}, ${selects.join(", ")} GROUP BY ${gLetter} LABEL ${labels.join(", ")}", 1)`;
|
|
888
|
-
summarySheets.push({ name: spec.name, rows: [[formula(q)]] });
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
const seen = /* @__PURE__ */ new Set();
|
|
892
|
-
const groups = [];
|
|
893
|
-
for (const r of srcMat.records) {
|
|
894
|
-
const k = safeStringify(r[spec.groupBy]);
|
|
895
|
-
if (!seen.has(k)) {
|
|
896
|
-
seen.add(k);
|
|
897
|
-
groups.push(r[spec.groupBy]);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
const header = [spec.groupBy, ...spec.aggregates.map((a) => a.label)];
|
|
901
|
-
const rows = groups.map((g, i) => {
|
|
902
|
-
const rowNum = i + 2;
|
|
903
|
-
const groupRecs = srcMat.records.filter((r) => safeStringify(r[spec.groupBy]) === safeStringify(g));
|
|
904
|
-
const cells = [g];
|
|
905
|
-
for (const a of spec.aggregates) {
|
|
906
|
-
if (a.op === "count") {
|
|
907
|
-
cells.push(formula(`COUNTIFS('${src.name}'!$${gLetter}:$${gLetter},$A${rowNum})`, groupRecs.length));
|
|
908
|
-
continue;
|
|
909
|
-
}
|
|
910
|
-
const vIdx = a.field ? src.colIndex.get(a.field) : void 0;
|
|
911
|
-
if (vIdx === void 0) {
|
|
912
|
-
cells.push(null);
|
|
913
|
-
continue;
|
|
914
|
-
}
|
|
915
|
-
const vLetter = colLetter(vIdx);
|
|
916
|
-
const nums = groupRecs.map((r) => Number(r[a.field])).filter((n) => Number.isFinite(n));
|
|
917
|
-
const sum = nums.reduce((s, n) => s + n, 0);
|
|
918
|
-
const cached = a.op === "sum" ? sum : nums.length ? sum / nums.length : 0;
|
|
919
|
-
const fn = a.op === "sum" ? "SUMIFS" : "AVERAGEIFS";
|
|
920
|
-
cells.push(
|
|
921
|
-
formula(`${fn}('${src.name}'!$${vLetter}:$${vLetter},'${src.name}'!$${gLetter}:$${gLetter},$A${rowNum})`, cached)
|
|
922
|
-
);
|
|
923
|
-
}
|
|
924
|
-
return cells;
|
|
925
|
-
});
|
|
926
|
-
summarySheets.push({ name: spec.name, header, rows });
|
|
927
|
-
}
|
|
928
|
-
const lookupSheets = [...dictEntries.entries()].map(([dn, entries]) => ({
|
|
929
|
-
name: `_Lookups_${dn}`,
|
|
930
|
-
header: ["Code", ...locales],
|
|
931
|
-
rows: entries.map((e) => [e.key, ...locales.map((l) => e.labels[l] ?? "")])
|
|
932
|
-
}));
|
|
933
|
-
const settingsSheets = [];
|
|
934
|
-
const definedNames = [];
|
|
935
|
-
if (hasLang) {
|
|
936
|
-
settingsSheets.push({
|
|
937
|
-
name: "_settings",
|
|
938
|
-
header: ["Setting", "Value"],
|
|
939
|
-
rows: [["Language", defaultLocale]],
|
|
940
|
-
validations: [{ sqref: "B2:B2", values: locales }]
|
|
941
|
-
});
|
|
942
|
-
definedNames.push({ name: "LANG", ref: `'_settings'!$B$2` });
|
|
943
|
-
}
|
|
944
|
-
return {
|
|
945
|
-
sheets: [...settingsSheets, ...lookupSheets, manifest, ...summarySheets, ...dataSheets],
|
|
946
|
-
definedNames
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
function inferColumns(records) {
|
|
950
|
-
const seen = /* @__PURE__ */ new Set();
|
|
951
|
-
const out = [];
|
|
952
|
-
for (const r of records) {
|
|
953
|
-
for (const key of Object.keys(r)) {
|
|
954
|
-
if (!seen.has(key)) {
|
|
955
|
-
seen.add(key);
|
|
956
|
-
out.push(key);
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
return out;
|
|
961
|
-
}
|
|
962
|
-
var XlsxDictAmbiguityError = class extends Error {
|
|
963
|
-
constructor(column, label) {
|
|
964
|
-
super(
|
|
965
|
-
`as-xlsx.fromBytes: dict for column "${column}" has ambiguous label "${label}" \u2014 it maps to more than one key across locales. Supply a stricter dict or resolve the label conflict before importing.`
|
|
966
|
-
);
|
|
967
|
-
this.column = column;
|
|
968
|
-
this.label = label;
|
|
969
|
-
this.name = "XlsxDictAmbiguityError";
|
|
970
|
-
}
|
|
971
|
-
column;
|
|
972
|
-
label;
|
|
973
|
-
};
|
|
974
|
-
async function fromBytes(vault, bytes, options) {
|
|
975
|
-
vault.assertCanImport("plaintext", "xlsx");
|
|
976
|
-
const policy = options.policy ?? "merge";
|
|
977
|
-
const idKey = options.idKey ?? "id";
|
|
978
|
-
const types = options.fieldTypes ?? {};
|
|
979
|
-
const headerRowIdx = (options.headerRow ?? 1) - 1;
|
|
980
|
-
if (headerRowIdx < 0) {
|
|
981
|
-
throw new Error("as-xlsx.fromBytes: headerRow must be 1-based and >= 1");
|
|
982
|
-
}
|
|
983
|
-
const decoded = await readXlsx(bytes);
|
|
984
|
-
if (decoded.sheets.length === 0) {
|
|
985
|
-
return emptyXlsxPlan(vault, options.collection, policy, idKey);
|
|
986
|
-
}
|
|
987
|
-
const sheet = options.sheet === void 0 ? decoded.sheets[0] : decoded.sheets.find((s) => s.name === options.sheet);
|
|
988
|
-
if (sheet === void 0) {
|
|
989
|
-
throw new Error(
|
|
990
|
-
`as-xlsx.fromBytes: workbook has no sheet named "${options.sheet}". Available: ${decoded.sheets.map((s) => `"${s.name}"`).join(", ")}`
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
|
-
const allRows = sheet.rows;
|
|
994
|
-
if (allRows.length <= headerRowIdx) {
|
|
995
|
-
return emptyXlsxPlan(vault, options.collection, policy, idKey);
|
|
996
|
-
}
|
|
997
|
-
const headerRow = allRows[headerRowIdx];
|
|
998
|
-
const colToField = /* @__PURE__ */ new Map();
|
|
999
|
-
for (const [col, value] of Object.entries(headerRow)) {
|
|
1000
|
-
const fieldName = headerCellToField(value);
|
|
1001
|
-
if (fieldName === "") continue;
|
|
1002
|
-
colToField.set(col, fieldName);
|
|
1003
|
-
}
|
|
1004
|
-
const invertMaps = /* @__PURE__ */ new Map();
|
|
1005
|
-
const allFields = new Set(colToField.values());
|
|
1006
|
-
for (const field of allFields) {
|
|
1007
|
-
const explicitEntries = options.dicts?.[field];
|
|
1008
|
-
if (explicitEntries !== void 0 && explicitEntries.length > 0) {
|
|
1009
|
-
invertMaps.set(field, buildInversionMap(field, explicitEntries));
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
try {
|
|
1013
|
-
const vaultEntries = await vault.dictionary(field).list();
|
|
1014
|
-
if (vaultEntries.length > 0) {
|
|
1015
|
-
invertMaps.set(field, buildInversionMap(field, vaultEntries));
|
|
1016
|
-
}
|
|
1017
|
-
} catch {
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
const i18nBases = /* @__PURE__ */ new Set();
|
|
1021
|
-
if (options.smart) {
|
|
1022
|
-
for (const field of colToField.values()) {
|
|
1023
|
-
const m = /^(.+)__(.+)$/.exec(field);
|
|
1024
|
-
if (m && m[2] !== "label") i18nBases.add(m[1]);
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
const records = [];
|
|
1028
|
-
for (let i = headerRowIdx + 1; i < allRows.length; i++) {
|
|
1029
|
-
const row = allRows[i];
|
|
1030
|
-
const record = {};
|
|
1031
|
-
let hasAny = false;
|
|
1032
|
-
for (const [col, value] of Object.entries(row)) {
|
|
1033
|
-
const field = colToField.get(col);
|
|
1034
|
-
if (field === void 0) continue;
|
|
1035
|
-
if (options.smart) {
|
|
1036
|
-
if (field.endsWith("__label")) continue;
|
|
1037
|
-
const lm = /^(.+)__(.+)$/.exec(field);
|
|
1038
|
-
if (lm && lm[2] !== "label" && i18nBases.has(lm[1])) {
|
|
1039
|
-
const base = lm[1];
|
|
1040
|
-
const coerced2 = coerceXlsxCell(value, types[base]);
|
|
1041
|
-
if (coerced2 !== void 0 && coerced2 !== "") {
|
|
1042
|
-
const map = record[base] ?? {};
|
|
1043
|
-
map[lm[2]] = coerced2;
|
|
1044
|
-
record[base] = map;
|
|
1045
|
-
hasAny = true;
|
|
1046
|
-
}
|
|
1047
|
-
continue;
|
|
1048
|
-
}
|
|
1049
|
-
if (i18nBases.has(field)) continue;
|
|
1050
|
-
}
|
|
1051
|
-
const coerced = coerceXlsxCell(value, types[field]);
|
|
1052
|
-
if (coerced !== void 0) {
|
|
1053
|
-
const invMap = invertMaps.get(field);
|
|
1054
|
-
if (invMap !== void 0 && typeof coerced === "string") {
|
|
1055
|
-
record[field] = invMap.get(coerced) ?? coerced;
|
|
1056
|
-
} else {
|
|
1057
|
-
record[field] = coerced;
|
|
1058
|
-
}
|
|
1059
|
-
hasAny = true;
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
if (hasAny) records.push(record);
|
|
1063
|
-
}
|
|
1064
|
-
const plan = await (0, import_hub.diffVault)(vault, { [options.collection]: records }, {
|
|
1065
|
-
collections: [options.collection],
|
|
1066
|
-
idKey
|
|
1067
|
-
});
|
|
1068
|
-
return {
|
|
1069
|
-
plan,
|
|
1070
|
-
policy,
|
|
1071
|
-
async apply() {
|
|
1072
|
-
await vault.noydb.transaction((tx) => {
|
|
1073
|
-
const txVault = tx.vault(vault.name);
|
|
1074
|
-
for (const entry of plan.added) {
|
|
1075
|
-
txVault.collection(entry.collection).put(entry.id, entry.record, { reason: "import:xlsx" });
|
|
1076
|
-
}
|
|
1077
|
-
if (policy !== "insert-only") {
|
|
1078
|
-
for (const entry of plan.modified) {
|
|
1079
|
-
txVault.collection(entry.collection).put(entry.id, entry.record, { reason: "import:xlsx" });
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
if (policy === "replace") {
|
|
1083
|
-
for (const entry of plan.deleted) {
|
|
1084
|
-
txVault.collection(entry.collection).delete(entry.id);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
async function emptyXlsxPlan(vault, collection, policy, idKey) {
|
|
1092
|
-
const plan = await (0, import_hub.diffVault)(vault, { [collection]: [] }, { collections: [collection], idKey });
|
|
1093
|
-
return { plan, policy, async apply() {
|
|
1094
|
-
} };
|
|
1095
|
-
}
|
|
1096
|
-
function buildInversionMap(column, entries) {
|
|
1097
|
-
const map = /* @__PURE__ */ new Map();
|
|
1098
|
-
for (const entry of entries) {
|
|
1099
|
-
for (const label of Object.values(entry.labels)) {
|
|
1100
|
-
if (label === "") continue;
|
|
1101
|
-
const existing = map.get(label);
|
|
1102
|
-
if (existing !== void 0 && existing !== entry.key) {
|
|
1103
|
-
throw new XlsxDictAmbiguityError(column, label);
|
|
1104
|
-
}
|
|
1105
|
-
map.set(label, entry.key);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
return map;
|
|
1109
|
-
}
|
|
1110
|
-
function headerCellToField(value) {
|
|
1111
|
-
if (typeof value === "string") return value;
|
|
1112
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1113
|
-
return "";
|
|
1114
|
-
}
|
|
1115
|
-
function coerceXlsxCell(value, type) {
|
|
1116
|
-
if (value === void 0 || value === null) return void 0;
|
|
1117
|
-
if (type === void 0) return value;
|
|
1118
|
-
if (type === "string") {
|
|
1119
|
-
if (typeof value === "string") return value;
|
|
1120
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1121
|
-
return void 0;
|
|
1122
|
-
}
|
|
1123
|
-
if (type === "number") {
|
|
1124
|
-
if (typeof value === "number") return value;
|
|
1125
|
-
const n = Number(value);
|
|
1126
|
-
return Number.isFinite(n) ? n : void 0;
|
|
1127
|
-
}
|
|
1128
|
-
if (type === "boolean") {
|
|
1129
|
-
if (typeof value === "boolean") return value;
|
|
1130
|
-
if (value === "true" || value === 1) return true;
|
|
1131
|
-
if (value === "false" || value === 0) return false;
|
|
1132
|
-
return void 0;
|
|
1133
|
-
}
|
|
1134
|
-
if (type === "date") {
|
|
1135
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1136
|
-
const ms = excelSerialToMs(value);
|
|
1137
|
-
const d = new Date(ms);
|
|
1138
|
-
return d.toISOString();
|
|
1139
|
-
}
|
|
1140
|
-
if (typeof value === "string") {
|
|
1141
|
-
const d = new Date(value);
|
|
1142
|
-
if (!Number.isNaN(d.getTime())) return d.toISOString();
|
|
1143
|
-
}
|
|
1144
|
-
return void 0;
|
|
1145
|
-
}
|
|
1146
|
-
return value;
|
|
1147
|
-
}
|
|
1148
|
-
function excelSerialToMs(serial) {
|
|
1149
|
-
const EPOCH_OFFSET_DAYS = 25569;
|
|
1150
|
-
const MS_PER_DAY = 864e5;
|
|
1151
|
-
return Math.round((serial - EPOCH_OFFSET_DAYS) * MS_PER_DAY);
|
|
1152
|
-
}
|
|
1153
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1154
|
-
0 && (module.exports = {
|
|
1155
|
-
XlsxDictAmbiguityError,
|
|
1156
|
-
colLetter,
|
|
1157
|
-
download,
|
|
1158
|
-
formula,
|
|
1159
|
-
fromBytes,
|
|
1160
|
-
inferSchema,
|
|
1161
|
-
readXlsx,
|
|
1162
|
-
styled,
|
|
1163
|
-
toBytes,
|
|
1164
|
-
toBytesFromCollection,
|
|
1165
|
-
toBytesMultiVault,
|
|
1166
|
-
write,
|
|
1167
|
-
writeXlsx,
|
|
1168
|
-
zodSourceFor
|
|
1169
|
-
});
|
|
1170
|
-
//# sourceMappingURL=index.cjs.map
|