@dynamic-entity/server 2.5.0 → 3.0.0-rc.2
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/express.d.mts +16 -16
- package/express.d.ts +16 -16
- package/express.js +38 -1072
- package/express.js.map +1 -1
- package/express.mjs +38 -1069
- package/express.mjs.map +1 -1
- package/index.d.mts +55 -140
- package/index.d.ts +55 -140
- package/index.js +50 -813
- package/index.js.map +1 -1
- package/index.mjs +49 -809
- package/index.mjs.map +1 -1
- package/package.json +5 -4
- package/run-import-BUClq6BR.d.mts +187 -0
- package/run-import-BUClq6BR.d.ts +187 -0
- package/write-template-Dqu5b00D.d.mts +0 -355
- package/write-template-Dqu5b00D.d.ts +0 -355
package/index.js
CHANGED
|
@@ -1,840 +1,77 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var node = require('sheet-to-schema/node');
|
|
3
4
|
var core = require('@dynamic-entity/core');
|
|
4
|
-
var zlib = require('zlib');
|
|
5
|
-
var ExcelJS = require('exceljs');
|
|
6
|
-
var stream = require('stream');
|
|
7
|
-
|
|
8
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
-
|
|
10
|
-
var zlib__default = /*#__PURE__*/_interopDefault(zlib);
|
|
11
|
-
var ExcelJS__default = /*#__PURE__*/_interopDefault(ExcelJS);
|
|
12
5
|
|
|
13
6
|
// src/limits.ts
|
|
14
|
-
var DEFAULT_LIMITS =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
totalTimeoutMs: 10 * 6e4
|
|
31
|
-
};
|
|
32
|
-
function resolveLimits(overrides) {
|
|
33
|
-
const out = { ...DEFAULT_LIMITS };
|
|
34
|
-
if (!overrides) return out;
|
|
35
|
-
for (const key of Object.keys(DEFAULT_LIMITS)) {
|
|
36
|
-
const value = overrides[key];
|
|
37
|
-
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
38
|
-
out[key] = Math.floor(value);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return out;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// src/errors.ts
|
|
45
|
-
var STATUS = {
|
|
46
|
-
NO_FILE: 400,
|
|
47
|
-
TOO_MANY_FILES: 400,
|
|
48
|
-
TOO_LARGE: 413,
|
|
49
|
-
UNSUPPORTED_FORMAT: 415,
|
|
50
|
-
MALFORMED_FILE: 400,
|
|
51
|
-
ARCHIVE_REFUSED: 400,
|
|
52
|
-
SHEET_TOO_LARGE: 413,
|
|
53
|
-
UNKNOWN_ENTITY: 404,
|
|
54
|
-
INVALID_PLAN: 400,
|
|
55
|
-
TIMEOUT: 408,
|
|
56
|
-
IMPORT_FAILED: 500,
|
|
57
|
-
INTERNAL: 500
|
|
58
|
-
};
|
|
59
|
-
var ImportError = class extends Error {
|
|
60
|
-
code;
|
|
61
|
-
status;
|
|
62
|
-
details;
|
|
63
|
-
constructor(code, message, options = {}) {
|
|
64
|
-
super(message);
|
|
65
|
-
this.name = "ImportError";
|
|
66
|
-
this.code = code;
|
|
67
|
-
this.status = STATUS[code] ?? 500;
|
|
68
|
-
this.details = options.details;
|
|
69
|
-
if (options.cause !== void 0) this.cause = options.cause;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
function toErrorBody(error) {
|
|
73
|
-
if (error instanceof ImportError) {
|
|
74
|
-
return {
|
|
75
|
-
status: error.status,
|
|
76
|
-
body: {
|
|
77
|
-
error: {
|
|
78
|
-
code: error.code,
|
|
79
|
-
message: error.message,
|
|
80
|
-
...error.details === void 0 ? {} : { details: error.details }
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
status: 500,
|
|
87
|
-
body: { error: { code: "INTERNAL", message: "The import could not be completed." } }
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// src/bytes.ts
|
|
92
|
-
async function* toByteStream(source) {
|
|
93
|
-
if (source instanceof Uint8Array) {
|
|
94
|
-
yield source;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (Symbol.asyncIterator in source) {
|
|
98
|
-
for await (const chunk of source) yield asBytes(chunk);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
for (const chunk of source) yield asBytes(chunk);
|
|
102
|
-
}
|
|
103
|
-
function asBytes(chunk) {
|
|
104
|
-
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
105
|
-
}
|
|
106
|
-
async function* limitBytes(source, maxBytes) {
|
|
107
|
-
let seen = 0;
|
|
108
|
-
for await (const chunk of source) {
|
|
109
|
-
seen += chunk.byteLength;
|
|
110
|
-
if (seen > maxBytes) {
|
|
111
|
-
throw new ImportError("TOO_LARGE", `The file is larger than the ${maxBytes} byte limit.`);
|
|
112
|
-
}
|
|
113
|
-
yield chunk;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async function peek(source, n) {
|
|
117
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
118
|
-
const taken = [];
|
|
119
|
-
let size = 0;
|
|
120
|
-
while (size < n) {
|
|
121
|
-
const next = await iterator.next();
|
|
122
|
-
if (next.done) break;
|
|
123
|
-
taken.push(next.value);
|
|
124
|
-
size += next.value.byteLength;
|
|
125
|
-
}
|
|
126
|
-
const head = Buffer.concat(taken.map((c) => Buffer.from(c.buffer, c.byteOffset, c.byteLength)));
|
|
127
|
-
async function* replay() {
|
|
128
|
-
for (const chunk of taken) yield chunk;
|
|
129
|
-
for (let next = await iterator.next(); !next.done; next = await iterator.next()) {
|
|
130
|
-
yield next.value;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return { head: head.subarray(0, n), stream: replay() };
|
|
134
|
-
}
|
|
135
|
-
function destroySource(source) {
|
|
136
|
-
const candidate = source;
|
|
137
|
-
try {
|
|
138
|
-
if (typeof candidate?.destroy === "function") candidate.destroy();
|
|
139
|
-
else if (typeof candidate?.return === "function") candidate.return();
|
|
140
|
-
} catch {
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
var LOCAL_HEADER = 67324752;
|
|
144
|
-
var CENTRAL_HEADER = 33639248;
|
|
145
|
-
var END_OF_CENTRAL = 101010256;
|
|
146
|
-
var DATA_DESCRIPTOR = 134695760;
|
|
147
|
-
var HEADER_SIZE = 30;
|
|
148
|
-
var HAS_DATA_DESCRIPTOR = 8;
|
|
149
|
-
var ZIP64_SENTINEL = 4294967295;
|
|
150
|
-
var SLICE = 64 * 1024;
|
|
151
|
-
var STORED = 0;
|
|
152
|
-
var DEFLATED = 8;
|
|
153
|
-
var ZIP32_MAX = 4294967295;
|
|
154
|
-
var WANTED = [
|
|
155
|
-
"[Content_Types].xml",
|
|
156
|
-
"_rels/.rels",
|
|
157
|
-
"xl/_rels/workbook.xml.rels",
|
|
158
|
-
"xl/workbook.xml",
|
|
159
|
-
"xl/styles.xml",
|
|
160
|
-
"xl/sharedStrings.xml"
|
|
161
|
-
];
|
|
162
|
-
var WORKSHEET = /^xl\/worksheets\/sheet(\d+)\.xml$/;
|
|
163
|
-
function sheetNumber(name) {
|
|
164
|
-
const match = WORKSHEET.exec(name);
|
|
165
|
-
return match ? Number(match[1]) : null;
|
|
166
|
-
}
|
|
167
|
-
var refuse = (message) => {
|
|
168
|
-
throw new ImportError("ARCHIVE_REFUSED", message);
|
|
169
|
-
};
|
|
170
|
-
var CRC_TABLE = (() => {
|
|
171
|
-
const table = new Int32Array(256);
|
|
172
|
-
for (let i = 0; i < 256; i++) {
|
|
173
|
-
let c = i;
|
|
174
|
-
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
175
|
-
table[i] = c;
|
|
176
|
-
}
|
|
177
|
-
return table;
|
|
178
|
-
})();
|
|
179
|
-
function crc32(current, bytes) {
|
|
180
|
-
let c = ~current;
|
|
181
|
-
for (let i = 0; i < bytes.length; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
182
|
-
return ~c >>> 0;
|
|
183
|
-
}
|
|
184
|
-
var ZipScanner = class {
|
|
185
|
-
constructor(iterator) {
|
|
186
|
-
this.iterator = iterator;
|
|
187
|
-
}
|
|
188
|
-
iterator;
|
|
189
|
-
buffer = Buffer.alloc(0);
|
|
190
|
-
eof = false;
|
|
191
|
-
get available() {
|
|
192
|
-
return this.buffer.length;
|
|
193
|
-
}
|
|
194
|
-
/** Pull until at least `n` bytes are buffered. False means the stream ended first. */
|
|
195
|
-
async need(n) {
|
|
196
|
-
while (this.buffer.length < n && !this.eof) {
|
|
197
|
-
const next = await this.iterator.next();
|
|
198
|
-
if (next.done) {
|
|
199
|
-
this.eof = true;
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
const chunk = Buffer.from(next.value.buffer, next.value.byteOffset, next.value.byteLength);
|
|
203
|
-
this.buffer = this.buffer.length ? Buffer.concat([this.buffer, chunk]) : chunk;
|
|
204
|
-
}
|
|
205
|
-
return this.buffer.length >= n;
|
|
206
|
-
}
|
|
207
|
-
peek(n) {
|
|
208
|
-
return this.buffer.subarray(0, Math.min(n, this.buffer.length));
|
|
209
|
-
}
|
|
210
|
-
take(n) {
|
|
211
|
-
const chunk = this.buffer.subarray(0, n);
|
|
212
|
-
this.buffer = this.buffer.subarray(n);
|
|
213
|
-
return chunk;
|
|
214
|
-
}
|
|
215
|
-
pushBack(bytes) {
|
|
216
|
-
if (bytes.length) this.buffer = Buffer.concat([bytes, this.buffer]);
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
function writeChunk(inflater, chunk) {
|
|
220
|
-
return new Promise((resolve, reject) => {
|
|
221
|
-
const onError = (error) => {
|
|
222
|
-
inflater.removeListener("error", onError);
|
|
223
|
-
reject(error);
|
|
224
|
-
};
|
|
225
|
-
inflater.once("error", onError);
|
|
226
|
-
inflater.write(chunk, (error) => {
|
|
227
|
-
inflater.removeListener("error", onError);
|
|
228
|
-
if (error) reject(error);
|
|
229
|
-
else resolve();
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
var settle = () => new Promise((resolve) => setImmediate(resolve));
|
|
234
|
-
async function readDeflated(scanner, budget, limits, name, declared, keep) {
|
|
235
|
-
const retain = (slice) => {
|
|
236
|
-
budget.retained += slice.length;
|
|
237
|
-
if (budget.retained > limits.maxBytes) {
|
|
238
|
-
refuse(`The workbook is larger than the ${limits.maxBytes} byte limit.`);
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
const inflater = zlib__default.default.createInflateRaw();
|
|
242
|
-
const kept = [];
|
|
243
|
-
let produced = 0;
|
|
244
|
-
let consumed = 0;
|
|
245
|
-
let crc = 0;
|
|
246
|
-
let ended = false;
|
|
247
|
-
let failure = null;
|
|
248
|
-
let breach = null;
|
|
249
|
-
const check = () => {
|
|
250
|
-
if (produced > limits.maxUncompressedBytes || budget.total + produced > limits.maxUncompressedBytes) {
|
|
251
|
-
return new ImportError(
|
|
252
|
-
"ARCHIVE_REFUSED",
|
|
253
|
-
`The workbook inflates to more than the ${limits.maxUncompressedBytes} byte limit.`
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
if (produced > 64 * 1024 && produced / Math.max(consumed, 1) > limits.maxCompressionRatio) {
|
|
257
|
-
return new ImportError(
|
|
258
|
-
"ARCHIVE_REFUSED",
|
|
259
|
-
`An entry in the workbook inflates more than ${limits.maxCompressionRatio} times \u2014 refusing it.`
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
return null;
|
|
263
|
-
};
|
|
264
|
-
inflater.on("data", (chunk) => {
|
|
265
|
-
produced += chunk.length;
|
|
266
|
-
crc = crc32(crc, chunk);
|
|
267
|
-
if (!breach) breach = check();
|
|
268
|
-
});
|
|
269
|
-
inflater.on("end", () => {
|
|
270
|
-
ended = true;
|
|
271
|
-
});
|
|
272
|
-
inflater.on("error", (error) => {
|
|
273
|
-
failure = error;
|
|
274
|
-
});
|
|
275
|
-
try {
|
|
276
|
-
for (; ; ) {
|
|
277
|
-
const remaining = declared === null ? Number.POSITIVE_INFINITY : declared - consumed;
|
|
278
|
-
if (remaining <= 0) break;
|
|
279
|
-
if (ended || failure || breach) break;
|
|
280
|
-
if (!await scanner.need(1)) refuse(`The workbook ends part-way through "${name}".`);
|
|
281
|
-
const slice = Buffer.from(scanner.take(Math.min(SLICE, remaining, scanner.available)));
|
|
282
|
-
consumed += slice.length;
|
|
283
|
-
await writeChunk(inflater, slice);
|
|
284
|
-
if (keep) {
|
|
285
|
-
retain(slice);
|
|
286
|
-
kept.push(slice);
|
|
287
|
-
}
|
|
288
|
-
await settle();
|
|
289
|
-
if (ended && declared === null) {
|
|
290
|
-
const overshoot = consumed - inflater.bytesWritten;
|
|
291
|
-
if (overshoot > 0) {
|
|
292
|
-
scanner.pushBack(slice.subarray(slice.length - overshoot));
|
|
293
|
-
consumed -= overshoot;
|
|
294
|
-
if (keep) {
|
|
295
|
-
kept[kept.length - 1] = slice.subarray(0, slice.length - overshoot);
|
|
296
|
-
budget.retained -= overshoot;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
while (declared !== null && consumed < declared && !breach) {
|
|
302
|
-
if (!await scanner.need(1)) refuse(`The workbook ends part-way through "${name}".`);
|
|
303
|
-
const slice = Buffer.from(scanner.take(Math.min(declared - consumed, SLICE, scanner.available)));
|
|
304
|
-
consumed += slice.length;
|
|
305
|
-
if (keep) {
|
|
306
|
-
retain(slice);
|
|
307
|
-
kept.push(slice);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
} catch (error) {
|
|
311
|
-
if (error instanceof ImportError) throw error;
|
|
312
|
-
throw new ImportError("MALFORMED_FILE", "The workbook could not be read.", { cause: error });
|
|
313
|
-
} finally {
|
|
314
|
-
inflater.destroy();
|
|
315
|
-
}
|
|
316
|
-
if (breach) throw breach;
|
|
317
|
-
if (failure) {
|
|
318
|
-
throw new ImportError("MALFORMED_FILE", "The workbook could not be read.", { cause: failure });
|
|
319
|
-
}
|
|
320
|
-
budget.total += produced;
|
|
321
|
-
return { data: keep ? Buffer.concat(kept) : Buffer.alloc(0), inflated: produced, crc };
|
|
322
|
-
}
|
|
323
|
-
async function readStored(scanner, budget, limits, name, size, keep) {
|
|
324
|
-
const kept = [];
|
|
325
|
-
let crc = 0;
|
|
326
|
-
let left = size;
|
|
327
|
-
while (left > 0) {
|
|
328
|
-
if (!await scanner.need(1)) refuse(`The workbook ends part-way through "${name}".`);
|
|
329
|
-
const slice = Buffer.from(scanner.take(Math.min(left, SLICE, scanner.available)));
|
|
330
|
-
crc = crc32(crc, slice);
|
|
331
|
-
if (keep) {
|
|
332
|
-
budget.retained += slice.length;
|
|
333
|
-
if (budget.retained > limits.maxBytes) {
|
|
334
|
-
refuse(`The workbook is larger than the ${limits.maxBytes} byte limit.`);
|
|
335
|
-
}
|
|
336
|
-
kept.push(slice);
|
|
337
|
-
}
|
|
338
|
-
left -= slice.length;
|
|
339
|
-
budget.total += slice.length;
|
|
340
|
-
if (budget.total > limits.maxUncompressedBytes) {
|
|
341
|
-
refuse(`The workbook inflates to more than the ${limits.maxUncompressedBytes} byte limit.`);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return { data: keep ? Buffer.concat(kept) : Buffer.alloc(0), inflated: size, crc };
|
|
345
|
-
}
|
|
346
|
-
async function skipDescriptor(scanner) {
|
|
347
|
-
if (!await scanner.need(4)) return;
|
|
348
|
-
const signed = scanner.peek(4).readUInt32LE(0) === DATA_DESCRIPTOR;
|
|
349
|
-
const base = signed ? 4 : 0;
|
|
350
|
-
for (const width of [base + 12, base + 20]) {
|
|
351
|
-
if (!await scanner.need(width + 4)) break;
|
|
352
|
-
const next = scanner.peek(width + 4).readUInt32LE(width);
|
|
353
|
-
if (next === LOCAL_HEADER || next === CENTRAL_HEADER) {
|
|
354
|
-
scanner.take(width);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
if (await scanner.need(base + 12)) scanner.take(base + 12);
|
|
359
|
-
}
|
|
360
|
-
function repack(entries) {
|
|
361
|
-
const parts = [];
|
|
362
|
-
const directory = [];
|
|
363
|
-
let offset = 0;
|
|
364
|
-
for (const entry of entries) {
|
|
365
|
-
const name = Buffer.from(entry.name, "utf8");
|
|
366
|
-
const local = Buffer.alloc(HEADER_SIZE);
|
|
367
|
-
local.writeUInt32LE(LOCAL_HEADER, 0);
|
|
368
|
-
local.writeUInt16LE(20, 4);
|
|
369
|
-
local.writeUInt16LE(0, 6);
|
|
370
|
-
local.writeUInt16LE(entry.method, 8);
|
|
371
|
-
local.writeUInt32LE(entry.crc, 14);
|
|
372
|
-
local.writeUInt32LE(entry.data.length, 18);
|
|
373
|
-
local.writeUInt32LE(entry.inflated, 22);
|
|
374
|
-
local.writeUInt16LE(name.length, 26);
|
|
375
|
-
parts.push(local, name, entry.data);
|
|
376
|
-
const central = Buffer.alloc(46);
|
|
377
|
-
central.writeUInt32LE(CENTRAL_HEADER, 0);
|
|
378
|
-
central.writeUInt16LE(20, 4);
|
|
379
|
-
central.writeUInt16LE(20, 6);
|
|
380
|
-
central.writeUInt16LE(entry.method, 10);
|
|
381
|
-
central.writeUInt32LE(entry.crc, 16);
|
|
382
|
-
central.writeUInt32LE(entry.data.length, 20);
|
|
383
|
-
central.writeUInt32LE(entry.inflated, 24);
|
|
384
|
-
central.writeUInt16LE(name.length, 28);
|
|
385
|
-
central.writeUInt32LE(offset, 42);
|
|
386
|
-
directory.push(central, name);
|
|
387
|
-
offset += local.length + name.length + entry.data.length;
|
|
388
|
-
}
|
|
389
|
-
const directoryBytes = Buffer.concat(directory);
|
|
390
|
-
const end = Buffer.alloc(22);
|
|
391
|
-
end.writeUInt32LE(END_OF_CENTRAL, 0);
|
|
392
|
-
end.writeUInt16LE(entries.length, 8);
|
|
393
|
-
end.writeUInt16LE(entries.length, 10);
|
|
394
|
-
end.writeUInt32LE(directoryBytes.length, 12);
|
|
395
|
-
end.writeUInt32LE(offset, 16);
|
|
396
|
-
return Buffer.concat([...parts, directoryBytes, end]);
|
|
397
|
-
}
|
|
398
|
-
async function guardZip(source, limits) {
|
|
399
|
-
const scanner = new ZipScanner(source[Symbol.asyncIterator]());
|
|
400
|
-
const budget = { total: 0, retained: 0, entries: 0 };
|
|
401
|
-
const kept = /* @__PURE__ */ new Map();
|
|
402
|
-
let sheet = null;
|
|
403
|
-
for (; ; ) {
|
|
404
|
-
if (!await scanner.need(4)) break;
|
|
405
|
-
if (scanner.peek(4).readUInt32LE(0) !== LOCAL_HEADER) break;
|
|
406
|
-
if (!await scanner.need(HEADER_SIZE)) {
|
|
407
|
-
refuse("The workbook ends part-way through an entry header.");
|
|
408
|
-
}
|
|
409
|
-
const header = Buffer.from(scanner.peek(HEADER_SIZE));
|
|
410
|
-
const flags = header.readUInt16LE(6);
|
|
411
|
-
const method = header.readUInt16LE(8);
|
|
412
|
-
const declaredCompressed = header.readUInt32LE(18);
|
|
413
|
-
const nameLength = header.readUInt16LE(26);
|
|
414
|
-
const extraLength = header.readUInt16LE(28);
|
|
415
|
-
if (++budget.entries > limits.maxZipEntries) {
|
|
416
|
-
refuse(`The workbook has more than ${limits.maxZipEntries} entries.`);
|
|
417
|
-
}
|
|
418
|
-
if (!await scanner.need(HEADER_SIZE + nameLength + extraLength)) {
|
|
419
|
-
refuse("The workbook ends part-way through an entry header.");
|
|
420
|
-
}
|
|
421
|
-
const name = scanner.peek(HEADER_SIZE + nameLength).subarray(HEADER_SIZE).toString("utf8");
|
|
422
|
-
scanner.take(HEADER_SIZE + nameLength + extraLength);
|
|
423
|
-
const number = sheetNumber(name);
|
|
424
|
-
const keep = number === null ? WANTED.includes(name) && !kept.has(name) : sheet === null || number < sheet.number;
|
|
425
|
-
if (keep && number !== null && sheet) {
|
|
426
|
-
budget.retained -= kept.get(sheet.name)?.data.length ?? 0;
|
|
427
|
-
kept.delete(sheet.name);
|
|
428
|
-
sheet = null;
|
|
429
|
-
}
|
|
430
|
-
const streamed = (flags & HAS_DATA_DESCRIPTOR) !== 0 || declaredCompressed === ZIP64_SENTINEL;
|
|
431
|
-
let read;
|
|
432
|
-
if (method === STORED) {
|
|
433
|
-
if (streamed) {
|
|
434
|
-
refuse(`Entry "${name}" is stored without a declared size.`);
|
|
435
|
-
}
|
|
436
|
-
read = await readStored(scanner, budget, limits, name, declaredCompressed, keep);
|
|
437
|
-
} else if (method === DEFLATED) {
|
|
438
|
-
read = await readDeflated(
|
|
439
|
-
scanner,
|
|
440
|
-
budget,
|
|
441
|
-
limits,
|
|
442
|
-
name,
|
|
443
|
-
streamed ? null : declaredCompressed,
|
|
444
|
-
keep
|
|
445
|
-
);
|
|
446
|
-
if (streamed) await skipDescriptor(scanner);
|
|
447
|
-
} else {
|
|
448
|
-
return refuse(`Entry "${name}" uses compression method ${method}, which is not supported.`);
|
|
449
|
-
}
|
|
450
|
-
if (keep) {
|
|
451
|
-
if (read.data.length > ZIP32_MAX || read.inflated > ZIP32_MAX) {
|
|
452
|
-
refuse(`Entry "${name}" is too large to repack without zip64.`);
|
|
453
|
-
}
|
|
454
|
-
kept.set(name, { name, method, data: read.data, inflated: read.inflated, crc: read.crc });
|
|
455
|
-
if (number !== null) sheet = { name, number };
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
if (!sheet) {
|
|
459
|
-
if (!kept.has("xl/workbook.xml")) {
|
|
460
|
-
throw new ImportError(
|
|
461
|
-
"UNSUPPORTED_FORMAT",
|
|
462
|
-
"This is a zip archive that is not an Excel workbook. Upload an .xlsx or .csv file."
|
|
463
|
-
);
|
|
464
|
-
}
|
|
465
|
-
throw new ImportError("MALFORMED_FILE", "This workbook has no worksheet.");
|
|
466
|
-
}
|
|
467
|
-
const ordered = [...WANTED, sheet.name].map((wanted) => kept.get(wanted)).filter((entry) => entry !== void 0);
|
|
468
|
-
return repack(ordered);
|
|
469
|
-
}
|
|
470
|
-
function cellValue(raw) {
|
|
471
|
-
if (raw === null || raw === void 0) return "";
|
|
472
|
-
if (raw instanceof Date) return raw;
|
|
473
|
-
if (typeof raw !== "object") return raw;
|
|
474
|
-
const cell = raw;
|
|
475
|
-
if (Array.isArray(cell["richText"])) {
|
|
476
|
-
return cell["richText"].map((part) => String(part?.text ?? "")).join("");
|
|
477
|
-
}
|
|
478
|
-
if ("formula" in cell || "sharedFormula" in cell) return cellValue(cell["result"]);
|
|
479
|
-
if ("error" in cell) return String(cell["error"]);
|
|
480
|
-
if ("text" in cell) return String(cell["text"]);
|
|
481
|
-
return "";
|
|
482
|
-
}
|
|
483
|
-
function rowCells(values) {
|
|
484
|
-
if (!Array.isArray(values)) return [];
|
|
485
|
-
const out = [];
|
|
486
|
-
for (let i = 1; i < values.length; i++) out.push(cellValue(values[i]));
|
|
487
|
-
return out;
|
|
488
|
-
}
|
|
489
|
-
async function* xlsxRows(source, limits) {
|
|
490
|
-
const archive = await guardZip(source, limits);
|
|
491
|
-
const guarded = stream.Readable.from([archive]);
|
|
492
|
-
const reader = new ExcelJS__default.default.stream.xlsx.WorkbookReader(guarded, {
|
|
493
|
-
// Nothing decorative is parsed. Each of these is XML this import has no use for, and
|
|
494
|
-
// every part not parsed is a part that cannot be hostile.
|
|
495
|
-
entries: "ignore",
|
|
496
|
-
hyperlinks: "ignore",
|
|
497
|
-
// Cached because a string cell is a reference into this table and an unresolved reference
|
|
498
|
-
// is not a value. See the note at the top about what that costs.
|
|
499
|
-
sharedStrings: "cache",
|
|
500
|
-
// Cached because it is what tells a numeric cell it is a date.
|
|
501
|
-
styles: "cache",
|
|
502
|
-
worksheets: "emit"
|
|
503
|
-
});
|
|
504
|
-
let expected = 1;
|
|
505
|
-
let yielded = false;
|
|
506
|
-
try {
|
|
507
|
-
for await (const worksheet of reader) {
|
|
508
|
-
for await (const row of worksheet) {
|
|
509
|
-
const number = typeof row.number === "number" ? row.number : expected;
|
|
510
|
-
if (number - 1 > limits.maxRows) {
|
|
511
|
-
throw new ImportError("SHEET_TOO_LARGE", `The sheet has more than ${limits.maxRows} rows.`);
|
|
512
|
-
}
|
|
513
|
-
while (expected < number) {
|
|
514
|
-
yield [];
|
|
515
|
-
expected++;
|
|
516
|
-
}
|
|
517
|
-
yield rowCells(row.values);
|
|
518
|
-
yielded = true;
|
|
519
|
-
expected = number + 1;
|
|
520
|
-
}
|
|
521
|
-
break;
|
|
522
|
-
}
|
|
523
|
-
if (!yielded) {
|
|
524
|
-
throw new ImportError("MALFORMED_FILE", "This workbook has no readable rows.");
|
|
525
|
-
}
|
|
526
|
-
} catch (error) {
|
|
527
|
-
if (error instanceof ImportError) throw error;
|
|
528
|
-
throw new ImportError("MALFORMED_FILE", "This is not a readable workbook.", { cause: error });
|
|
529
|
-
} finally {
|
|
530
|
-
guarded.destroy();
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
var MAGIC_BYTES = 8;
|
|
534
|
-
var ZIP = [80, 75];
|
|
535
|
-
var OLE2 = [208, 207, 17, 224];
|
|
536
|
-
var UTF16_LE = [255, 254];
|
|
537
|
-
var UTF16_BE = [254, 255];
|
|
538
|
-
var startsWith = (bytes, signature) => signature.every((byte, i) => bytes[i] === byte);
|
|
539
|
-
function detectFormat(head) {
|
|
540
|
-
if (startsWith(head, ZIP)) return "xlsx";
|
|
541
|
-
if (startsWith(head, OLE2)) {
|
|
542
|
-
throw new ImportError(
|
|
543
|
-
"UNSUPPORTED_FORMAT",
|
|
544
|
-
"This is a pre-2007 Excel file (.xls). Save it as .xlsx or .csv and try again."
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
if (startsWith(head, UTF16_LE) || startsWith(head, UTF16_BE)) {
|
|
548
|
-
throw new ImportError(
|
|
549
|
-
"UNSUPPORTED_FORMAT",
|
|
550
|
-
"This file is UTF-16 encoded. Save it as UTF-8 CSV and try again."
|
|
551
|
-
);
|
|
552
|
-
}
|
|
553
|
-
return "csv";
|
|
554
|
-
}
|
|
555
|
-
async function* csvRows(stream, limits, found, forced) {
|
|
556
|
-
const decoder = new TextDecoder("utf-8");
|
|
557
|
-
const maxHeader = limits.maxCellLength * limits.maxColumns + limits.maxColumns;
|
|
558
|
-
let held = "";
|
|
559
|
-
let reader = null;
|
|
560
|
-
const open = (headerLine) => {
|
|
561
|
-
found.delimiter = forced ?? core.detectDelimiter(headerLine);
|
|
562
|
-
return core.createCsvReader({ delimiter: found.delimiter });
|
|
563
|
-
};
|
|
564
|
-
for await (const chunk of stream) {
|
|
565
|
-
const text = decoder.decode(chunk, { stream: true });
|
|
566
|
-
if (!reader) {
|
|
567
|
-
held += text;
|
|
568
|
-
const line = core.completeFirstLine(held);
|
|
569
|
-
if (line === null) {
|
|
570
|
-
if (held.length > maxHeader) {
|
|
571
|
-
throw new ImportError("SHEET_TOO_LARGE", "The header row is longer than any row may be.");
|
|
572
|
-
}
|
|
573
|
-
continue;
|
|
574
|
-
}
|
|
575
|
-
reader = open(line);
|
|
576
|
-
for (const row of reader.push(held)) yield row;
|
|
577
|
-
held = "";
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
for (const row of reader.push(text)) yield row;
|
|
581
|
-
}
|
|
582
|
-
const rest = held + decoder.decode();
|
|
583
|
-
reader ??= open(core.completeFirstLine(rest) ?? rest);
|
|
584
|
-
for (const row of reader.push(rest)) yield row;
|
|
585
|
-
for (const row of reader.end()) yield row;
|
|
586
|
-
}
|
|
587
|
-
async function* guardRows(rows, width, limits) {
|
|
588
|
-
let seen = 0;
|
|
589
|
-
for await (const row of rows) {
|
|
590
|
-
if (++seen > limits.maxRows) {
|
|
591
|
-
throw new ImportError(
|
|
592
|
-
"SHEET_TOO_LARGE",
|
|
593
|
-
`The sheet has more than ${limits.maxRows} rows.`
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
if (row.length > limits.maxColumns) {
|
|
597
|
-
throw new ImportError(
|
|
598
|
-
"SHEET_TOO_LARGE",
|
|
599
|
-
`Row ${seen + 1} has more than ${limits.maxColumns} columns.`
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
for (const cell of row) {
|
|
603
|
-
if (typeof cell === "string" && cell.length > limits.maxCellLength) {
|
|
604
|
-
throw new ImportError(
|
|
605
|
-
"SHEET_TOO_LARGE",
|
|
606
|
-
`A cell in row ${seen + 1} is longer than ${limits.maxCellLength} characters.`
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
yield core.padRow(row, width);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
async function readSheet(options) {
|
|
614
|
-
const limits = resolveLimits(options.limits);
|
|
615
|
-
try {
|
|
616
|
-
const counted = limitBytes(toByteStream(options.stream), limits.maxBytes);
|
|
617
|
-
const { head, stream } = await peek(counted, MAGIC_BYTES);
|
|
618
|
-
const format = detectFormat(head);
|
|
619
|
-
const found = {};
|
|
620
|
-
const forced = /\.tsv$/i.test(options.filename ?? "") ? " " : void 0;
|
|
621
|
-
const rows = format === "xlsx" ? xlsxRows(stream, limits) : csvRows(stream, limits, found, forced);
|
|
622
|
-
const iterator = rows[Symbol.asyncIterator]();
|
|
623
|
-
const first = await iterator.next();
|
|
624
|
-
const headers = first.done ? [] : first.value.map(core.cellText);
|
|
625
|
-
if (headers.length > limits.maxColumns) {
|
|
626
|
-
throw new ImportError(
|
|
627
|
-
"SHEET_TOO_LARGE",
|
|
628
|
-
`The sheet has more than ${limits.maxColumns} columns.`
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
const remaining = drain(iterator);
|
|
632
|
-
return {
|
|
633
|
-
format,
|
|
634
|
-
headers,
|
|
635
|
-
rows: closing(guardRows(remaining, headers.length, limits), options.stream),
|
|
636
|
-
...found.delimiter ? { delimiter: found.delimiter } : {}
|
|
637
|
-
};
|
|
638
|
-
} catch (error) {
|
|
639
|
-
destroySource(options.stream);
|
|
640
|
-
throw error;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
async function* drain(iterator) {
|
|
644
|
-
for (let next = await iterator.next(); !next.done; next = await iterator.next()) {
|
|
645
|
-
yield next.value;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
async function* closing(rows, source) {
|
|
649
|
-
let drained = false;
|
|
650
|
-
try {
|
|
651
|
-
yield* rows;
|
|
652
|
-
drained = true;
|
|
653
|
-
} finally {
|
|
654
|
-
if (!drained) destroySource(source);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
function checkPlan(plan, config, lang) {
|
|
658
|
-
return core.validateMappingPlan(plan, config, {
|
|
659
|
-
lang,
|
|
660
|
-
// The same derivation `applyMapping` uses, or the two would disagree about which refs
|
|
661
|
-
// exist and the pre-flight would pass a plan the run then rejects.
|
|
662
|
-
includeReadonly: true,
|
|
663
|
-
includeSystemDefault: true
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
async function runImport(options) {
|
|
667
|
-
const limits = resolveLimits(options.limits);
|
|
668
|
-
const { plan, config, onBatch } = options;
|
|
669
|
-
const planProblems = checkPlan(plan, config, options.lang);
|
|
670
|
-
if (planProblems.some((problem) => problem.level === "error")) {
|
|
671
|
-
destroySource(options.stream);
|
|
672
|
-
return {
|
|
673
|
-
imported: 0,
|
|
674
|
-
skipped: 0,
|
|
675
|
-
failed: 0,
|
|
676
|
-
errors: [],
|
|
677
|
-
errorCount: 0,
|
|
678
|
-
truncated: false,
|
|
679
|
-
planProblems,
|
|
680
|
-
rowsRead: 0
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
const sheet = await readSheet({
|
|
7
|
+
var DEFAULT_LIMITS = node.DEFAULT_LIMITS;
|
|
8
|
+
var resolveLimits = node.resolveLimits;
|
|
9
|
+
var toErrorBody = node.toErrorBody;
|
|
10
|
+
var toByteStream = node.toByteStream;
|
|
11
|
+
var limitBytes = node.limitBytes;
|
|
12
|
+
var peek = node.peek;
|
|
13
|
+
var destroySource = node.destroySource;
|
|
14
|
+
var guardZip = node.guardZip;
|
|
15
|
+
var cellValue = node.cellValue;
|
|
16
|
+
var xlsxRows = node.xlsxRows;
|
|
17
|
+
var detectFormat = node.detectFormat;
|
|
18
|
+
var guardRows = node.guardRows;
|
|
19
|
+
var readSheet = node.readSheet;
|
|
20
|
+
function runImport(options) {
|
|
21
|
+
const { config } = options;
|
|
22
|
+
return node.runImport({
|
|
684
23
|
stream: options.stream,
|
|
685
24
|
filename: options.filename,
|
|
686
|
-
|
|
25
|
+
// A 2.x plan that names no entity is read against this config, as 2.x read it.
|
|
26
|
+
plan: core.planForConfig(options.plan, config),
|
|
27
|
+
adapter: core.entityFormConfigAdapter(config, { rules: options.rules, lookups: options.lookups }),
|
|
28
|
+
ctx: { lang: options.lang },
|
|
29
|
+
decimal: options.decimal,
|
|
30
|
+
dateOrder: options.dateOrder,
|
|
31
|
+
onBatch: options.onBatch,
|
|
32
|
+
limits: options.limits
|
|
687
33
|
});
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
let failed = 0;
|
|
694
|
-
let rowsRead = 0;
|
|
695
|
-
let batchIndex = 0;
|
|
696
|
-
let batch = [];
|
|
697
|
-
let firstRow = 2;
|
|
698
|
-
const flush = async () => {
|
|
699
|
-
if (!batch.length) return;
|
|
700
|
-
const rows = batch;
|
|
701
|
-
batch = [];
|
|
702
|
-
const result = core.applyMapping(rows, plan, config, {
|
|
703
|
-
lang: options.lang,
|
|
704
|
-
decimal,
|
|
705
|
-
dateOrder: options.dateOrder,
|
|
706
|
-
rules: options.rules,
|
|
707
|
-
lookups: options.lookups,
|
|
708
|
-
firstRowNumber: firstRow
|
|
709
|
-
});
|
|
710
|
-
skipped += result.skipped;
|
|
711
|
-
errorCount += result.errors.length;
|
|
712
|
-
failed += new Set(result.errors.map((error) => error.row)).size;
|
|
713
|
-
for (const error of result.errors) {
|
|
714
|
-
if (errors.length >= limits.maxReportedErrors) break;
|
|
715
|
-
errors.push(error);
|
|
716
|
-
}
|
|
717
|
-
if (result.records.length && onBatch) {
|
|
718
|
-
const info = { index: batchIndex, firstRow, imported };
|
|
719
|
-
try {
|
|
720
|
-
await onBatch(result.records, info);
|
|
721
|
-
} catch (cause) {
|
|
722
|
-
throw new ImportError(
|
|
723
|
-
"IMPORT_FAILED",
|
|
724
|
-
"The import stopped partway through. Rows before the failure may already have been written \u2014 this import is not transactional.",
|
|
725
|
-
{ cause }
|
|
726
|
-
);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
imported += result.records.length;
|
|
730
|
-
firstRow += rows.length;
|
|
731
|
-
batchIndex++;
|
|
732
|
-
};
|
|
733
|
-
try {
|
|
734
|
-
for await (const row of sheet.rows) {
|
|
735
|
-
rowsRead++;
|
|
736
|
-
batch.push(row);
|
|
737
|
-
if (batch.length >= limits.batchSize) await flush();
|
|
738
|
-
}
|
|
739
|
-
await flush();
|
|
740
|
-
} catch (error) {
|
|
741
|
-
destroySource(options.stream);
|
|
742
|
-
throw error;
|
|
743
|
-
}
|
|
744
|
-
return {
|
|
745
|
-
imported,
|
|
746
|
-
skipped,
|
|
747
|
-
failed,
|
|
748
|
-
errors,
|
|
749
|
-
errorCount,
|
|
750
|
-
truncated: errorCount > errors.length,
|
|
751
|
-
planProblems,
|
|
752
|
-
rowsRead,
|
|
753
|
-
format: sheet.format
|
|
754
|
-
};
|
|
34
|
+
}
|
|
35
|
+
function suggestionFor(headers, config, lang) {
|
|
36
|
+
const arrayBound = core.arrayBoundFor(headers, config, null, lang);
|
|
37
|
+
const { columns } = core.deriveImportColumns(config, { lang, maxArrayRows: arrayBound });
|
|
38
|
+
return { suggestion: core.suggestMapping(headers, columns, config?.entity ?? ""), arrayBound };
|
|
755
39
|
}
|
|
756
40
|
async function previewSheet(options) {
|
|
757
|
-
const
|
|
758
|
-
const sheet = await readSheet({
|
|
41
|
+
const preview = await node.previewSheet({
|
|
759
42
|
stream: options.stream,
|
|
760
43
|
filename: options.filename,
|
|
761
|
-
|
|
44
|
+
adapter: core.entityFormConfigAdapter(options.config, { includeReadonly: false, includeSystemDefault: false }),
|
|
45
|
+
lang: options.lang,
|
|
46
|
+
limits: options.limits
|
|
762
47
|
});
|
|
763
|
-
const sample = [];
|
|
764
|
-
let rowCount = 0;
|
|
765
|
-
try {
|
|
766
|
-
for await (const row of sheet.rows) {
|
|
767
|
-
rowCount++;
|
|
768
|
-
if (sample.length < limits.sampleRows) sample.push(row.map(core.cellText));
|
|
769
|
-
}
|
|
770
|
-
} catch (error) {
|
|
771
|
-
destroySource(options.stream);
|
|
772
|
-
throw error;
|
|
773
|
-
}
|
|
774
|
-
const arrayBound = core.arrayBoundFor(sheet.headers, options.config, null, options.lang);
|
|
775
|
-
const { columns } = core.deriveImportColumns(options.config, { lang: options.lang, maxArrayRows: arrayBound });
|
|
776
48
|
return {
|
|
777
|
-
headers:
|
|
778
|
-
sample,
|
|
779
|
-
rowCount,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
...
|
|
783
|
-
arrayBound
|
|
49
|
+
headers: preview.headers,
|
|
50
|
+
sample: preview.sample,
|
|
51
|
+
rowCount: preview.rowCount,
|
|
52
|
+
format: preview.format,
|
|
53
|
+
...preview.delimiter ? { delimiter: preview.delimiter } : {},
|
|
54
|
+
...suggestionFor(preview.headers, options.config, options.lang)
|
|
784
55
|
};
|
|
785
56
|
}
|
|
786
|
-
var TEMPLATE_EXTENSION =
|
|
787
|
-
var TEMPLATE_MEDIA_TYPE =
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
};
|
|
791
|
-
async function writeTemplate(options) {
|
|
792
|
-
const limits = resolveLimits(options.limits);
|
|
793
|
-
const columns = options.spec.columns;
|
|
794
|
-
if (columns.length > limits.maxColumns) {
|
|
795
|
-
throw new ImportError(
|
|
796
|
-
"SHEET_TOO_LARGE",
|
|
797
|
-
`A template of ${columns.length} columns is past the ${limits.maxColumns} column limit.`
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
if (options.format === "csv") {
|
|
801
|
-
await writeCsv(options.spec, options.out);
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
await writeXlsx(options.spec, options.out);
|
|
57
|
+
var TEMPLATE_EXTENSION = node.TEMPLATE_EXTENSION;
|
|
58
|
+
var TEMPLATE_MEDIA_TYPE = node.TEMPLATE_MEDIA_TYPE;
|
|
59
|
+
function templateSheetOf(spec) {
|
|
60
|
+
return { sheetName: spec.sheetName, headers: spec.columns.map((column) => column.header), notes: spec.notes };
|
|
805
61
|
}
|
|
806
|
-
function
|
|
807
|
-
|
|
808
|
-
return new Promise((resolve, reject) => {
|
|
809
|
-
out.end(csv, () => resolve());
|
|
810
|
-
out.on("error", reject);
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
async function writeXlsx(spec, out) {
|
|
814
|
-
const workbook = new ExcelJS__default.default.stream.xlsx.WorkbookWriter({ stream: out, useStyles: true });
|
|
815
|
-
const sheet = workbook.addWorksheet(sheetName(spec.sheetName));
|
|
816
|
-
const { columns, notes } = spec;
|
|
817
|
-
const row = sheet.addRow(columns.map((column) => core.escapeFormula(column.header)));
|
|
818
|
-
row.eachCell((cell, index) => {
|
|
819
|
-
cell.font = { bold: true };
|
|
820
|
-
const note = notes[index - 1];
|
|
821
|
-
if (note) cell.note = note;
|
|
822
|
-
});
|
|
823
|
-
row.commit();
|
|
824
|
-
sheet.commit();
|
|
825
|
-
await workbook.commit();
|
|
826
|
-
}
|
|
827
|
-
function sheetName(name) {
|
|
828
|
-
const cleaned = String(name).replace(/[[\]:*?/\\]/g, " ").trim();
|
|
829
|
-
return (cleaned || "Import").slice(0, 31);
|
|
62
|
+
function writeTemplate(options) {
|
|
63
|
+
return node.writeTemplate({ sheet: templateSheetOf(options.spec), format: options.format, out: options.out, limits: options.limits });
|
|
830
64
|
}
|
|
831
65
|
|
|
66
|
+
Object.defineProperty(exports, "ImportError", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
get: function () { return node.ImportError; }
|
|
69
|
+
});
|
|
832
70
|
Object.defineProperty(exports, "sampleText", {
|
|
833
71
|
enumerable: true,
|
|
834
72
|
get: function () { return core.cellText; }
|
|
835
73
|
});
|
|
836
74
|
exports.DEFAULT_LIMITS = DEFAULT_LIMITS;
|
|
837
|
-
exports.ImportError = ImportError;
|
|
838
75
|
exports.TEMPLATE_EXTENSION = TEMPLATE_EXTENSION;
|
|
839
76
|
exports.TEMPLATE_MEDIA_TYPE = TEMPLATE_MEDIA_TYPE;
|
|
840
77
|
exports.cellValue = cellValue;
|