juxscript 1.1.161 → 1.1.162
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.
|
@@ -17,6 +17,7 @@ export interface ParseOptions {
|
|
|
17
17
|
maxRows?: number;
|
|
18
18
|
skipRows?: number;
|
|
19
19
|
columns?: string[];
|
|
20
|
+
sheet?: string | number;
|
|
20
21
|
}
|
|
21
22
|
export declare class TabularDriver {
|
|
22
23
|
private _dbName;
|
|
@@ -29,9 +30,18 @@ export declare class TabularDriver {
|
|
|
29
30
|
*/
|
|
30
31
|
parseCSV(text: string, options?: ParseOptions): DataFrame;
|
|
31
32
|
/**
|
|
32
|
-
* Stream-parse a File into a DataFrame, with progress callback
|
|
33
|
+
* Stream-parse a File into a DataFrame, with progress callback.
|
|
34
|
+
* Auto-detects XLSX/XLS and routes accordingly.
|
|
33
35
|
*/
|
|
34
36
|
streamFile(file: File, options?: ParseOptions): Promise<DataFrame>;
|
|
37
|
+
/**
|
|
38
|
+
* Parse an XLSX/XLS file into a DataFrame using SheetJS
|
|
39
|
+
*/
|
|
40
|
+
private _parseXLSX;
|
|
41
|
+
/**
|
|
42
|
+
* Get sheet names from an XLSX file (useful for UI)
|
|
43
|
+
*/
|
|
44
|
+
getSheetNames(file: File): Promise<string[]>;
|
|
35
45
|
/**
|
|
36
46
|
* Store a DataFrame to IndexedDB
|
|
37
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabularDriver.d.ts","sourceRoot":"","sources":["TabularDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"TabularDriver.d.ts","sourceRoot":"","sources":["TabularDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,GAAG,CAA4B;gBAE3B,MAAM,GAAE,MAAsB,EAAE,SAAS,GAAE,MAAiB;IAKlE,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IA4BlC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,SAAS;IA6C7D;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IAoG5E;;OAEG;YACW,UAAU;IAuExB;;OAEG;IACG,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBlD;;OAEG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzF;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAwBjD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA4BzD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAqBlH;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IA8ExE,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAmClB,OAAO,CAAC,SAAS;IAYjB,KAAK,IAAI,IAAI;CAMhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAEhF"}
|
|
@@ -63,9 +63,14 @@ export class TabularDriver {
|
|
|
63
63
|
return df;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
* Stream-parse a File into a DataFrame, with progress callback
|
|
66
|
+
* Stream-parse a File into a DataFrame, with progress callback.
|
|
67
|
+
* Auto-detects XLSX/XLS and routes accordingly.
|
|
67
68
|
*/
|
|
68
69
|
async streamFile(file, options = {}) {
|
|
70
|
+
const ext = file.name.split('.').pop()?.toLowerCase();
|
|
71
|
+
if (ext === 'xlsx' || ext === 'xls') {
|
|
72
|
+
return this._parseXLSX(file, options);
|
|
73
|
+
}
|
|
69
74
|
const { delimiter = file.name.endsWith('.tsv') ? '\t' : ',', hasHeader = true, chunkSize = 64 * 1024, onProgress, maxRows, skipRows = 0, columns: selectCols } = options;
|
|
70
75
|
const totalSize = file.size;
|
|
71
76
|
let bytesRead = 0;
|
|
@@ -136,6 +141,89 @@ export class TabularDriver {
|
|
|
136
141
|
df = df.select(...selectCols);
|
|
137
142
|
return df;
|
|
138
143
|
}
|
|
144
|
+
/* ═══════════════════════════════════════════════════
|
|
145
|
+
* XLSX / XLS PARSING
|
|
146
|
+
* ═══════════════════════════════════════════════════ */
|
|
147
|
+
/**
|
|
148
|
+
* Parse an XLSX/XLS file into a DataFrame using SheetJS
|
|
149
|
+
*/
|
|
150
|
+
async _parseXLSX(file, options = {}) {
|
|
151
|
+
const { maxRows, skipRows = 0, columns: selectCols, sheet, onProgress, hasHeader = true } = options;
|
|
152
|
+
// Dynamic import — fails gracefully if xlsx not installed
|
|
153
|
+
let XLSX;
|
|
154
|
+
try {
|
|
155
|
+
XLSX = await import('xlsx');
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
throw new Error('XLSX support requires the "xlsx" package. Install it with: npm install xlsx');
|
|
159
|
+
}
|
|
160
|
+
if (onProgress)
|
|
161
|
+
onProgress(0, file.size);
|
|
162
|
+
const buffer = await file.arrayBuffer();
|
|
163
|
+
if (onProgress)
|
|
164
|
+
onProgress(file.size * 0.5, file.size);
|
|
165
|
+
const workbook = XLSX.read(buffer, { type: 'array' });
|
|
166
|
+
// Select sheet
|
|
167
|
+
let sheetName;
|
|
168
|
+
if (typeof sheet === 'number') {
|
|
169
|
+
sheetName = workbook.SheetNames[sheet] || workbook.SheetNames[0];
|
|
170
|
+
}
|
|
171
|
+
else if (typeof sheet === 'string') {
|
|
172
|
+
sheetName = sheet;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
sheetName = workbook.SheetNames[0];
|
|
176
|
+
}
|
|
177
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
178
|
+
if (!worksheet) {
|
|
179
|
+
throw new Error(`Sheet "${sheetName}" not found. Available: ${workbook.SheetNames.join(', ')}`);
|
|
180
|
+
}
|
|
181
|
+
// Convert to JSON rows
|
|
182
|
+
const jsonRows = XLSX.utils.sheet_to_json(worksheet, {
|
|
183
|
+
header: hasHeader ? undefined : 1,
|
|
184
|
+
defval: null,
|
|
185
|
+
raw: true
|
|
186
|
+
});
|
|
187
|
+
if (onProgress)
|
|
188
|
+
onProgress(file.size * 0.8, file.size);
|
|
189
|
+
// Apply skipRows and maxRows
|
|
190
|
+
let rows = jsonRows;
|
|
191
|
+
if (skipRows > 0) {
|
|
192
|
+
rows = rows.slice(skipRows);
|
|
193
|
+
}
|
|
194
|
+
if (maxRows !== undefined) {
|
|
195
|
+
rows = rows.slice(0, maxRows);
|
|
196
|
+
}
|
|
197
|
+
// Auto-type values
|
|
198
|
+
rows = rows.map(row => {
|
|
199
|
+
const typed = {};
|
|
200
|
+
for (const [key, value] of Object.entries(row)) {
|
|
201
|
+
typed[key] = this._autoType(value === null || value === undefined ? '' : String(value));
|
|
202
|
+
}
|
|
203
|
+
return typed;
|
|
204
|
+
});
|
|
205
|
+
if (onProgress)
|
|
206
|
+
onProgress(file.size, file.size);
|
|
207
|
+
let df = new DataFrame(rows);
|
|
208
|
+
if (selectCols)
|
|
209
|
+
df = df.select(...selectCols);
|
|
210
|
+
return df;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get sheet names from an XLSX file (useful for UI)
|
|
214
|
+
*/
|
|
215
|
+
async getSheetNames(file) {
|
|
216
|
+
let XLSX;
|
|
217
|
+
try {
|
|
218
|
+
XLSX = await import('xlsx');
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
throw new Error('XLSX support requires the "xlsx" package. Install it with: npm install xlsx');
|
|
222
|
+
}
|
|
223
|
+
const buffer = await file.arrayBuffer();
|
|
224
|
+
const workbook = XLSX.read(buffer, { type: 'array' });
|
|
225
|
+
return workbook.SheetNames;
|
|
226
|
+
}
|
|
139
227
|
/* ═══════════════════════════════════════════════════
|
|
140
228
|
* INDEXEDDB PERSISTENCE
|
|
141
229
|
* ═══════════════════════════════════════════════════ */
|
|
@@ -19,6 +19,7 @@ export interface ParseOptions {
|
|
|
19
19
|
maxRows?: number;
|
|
20
20
|
skipRows?: number;
|
|
21
21
|
columns?: string[];
|
|
22
|
+
sheet?: string | number; // ✅ For XLSX: sheet name or index
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export class TabularDriver {
|
|
@@ -108,9 +109,16 @@ export class TabularDriver {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
/**
|
|
111
|
-
* Stream-parse a File into a DataFrame, with progress callback
|
|
112
|
+
* Stream-parse a File into a DataFrame, with progress callback.
|
|
113
|
+
* Auto-detects XLSX/XLS and routes accordingly.
|
|
112
114
|
*/
|
|
113
115
|
async streamFile(file: File, options: ParseOptions = {}): Promise<DataFrame> {
|
|
116
|
+
const ext = file.name.split('.').pop()?.toLowerCase();
|
|
117
|
+
|
|
118
|
+
if (ext === 'xlsx' || ext === 'xls') {
|
|
119
|
+
return this._parseXLSX(file, options);
|
|
120
|
+
}
|
|
121
|
+
|
|
114
122
|
const {
|
|
115
123
|
delimiter = file.name.endsWith('.tsv') ? '\t' : ',',
|
|
116
124
|
hasHeader = true,
|
|
@@ -200,6 +208,100 @@ export class TabularDriver {
|
|
|
200
208
|
return df;
|
|
201
209
|
}
|
|
202
210
|
|
|
211
|
+
/* ═══════════════════════════════════════════════════
|
|
212
|
+
* XLSX / XLS PARSING
|
|
213
|
+
* ═══════════════════════════════════════════════════ */
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Parse an XLSX/XLS file into a DataFrame using SheetJS
|
|
217
|
+
*/
|
|
218
|
+
private async _parseXLSX(file: File, options: ParseOptions = {}): Promise<DataFrame> {
|
|
219
|
+
const { maxRows, skipRows = 0, columns: selectCols, sheet, onProgress, hasHeader = true } = options;
|
|
220
|
+
|
|
221
|
+
// Dynamic import — fails gracefully if xlsx not installed
|
|
222
|
+
let XLSX: any;
|
|
223
|
+
try {
|
|
224
|
+
XLSX = await import('xlsx');
|
|
225
|
+
} catch {
|
|
226
|
+
throw new Error(
|
|
227
|
+
'XLSX support requires the "xlsx" package. Install it with: npm install xlsx'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (onProgress) onProgress(0, file.size);
|
|
232
|
+
|
|
233
|
+
const buffer = await file.arrayBuffer();
|
|
234
|
+
|
|
235
|
+
if (onProgress) onProgress(file.size * 0.5, file.size);
|
|
236
|
+
|
|
237
|
+
const workbook = XLSX.read(buffer, { type: 'array' });
|
|
238
|
+
|
|
239
|
+
// Select sheet
|
|
240
|
+
let sheetName: string;
|
|
241
|
+
if (typeof sheet === 'number') {
|
|
242
|
+
sheetName = workbook.SheetNames[sheet] || workbook.SheetNames[0];
|
|
243
|
+
} else if (typeof sheet === 'string') {
|
|
244
|
+
sheetName = sheet;
|
|
245
|
+
} else {
|
|
246
|
+
sheetName = workbook.SheetNames[0];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
250
|
+
if (!worksheet) {
|
|
251
|
+
throw new Error(`Sheet "${sheetName}" not found. Available: ${workbook.SheetNames.join(', ')}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Convert to JSON rows
|
|
255
|
+
const jsonRows: Record<string, any>[] = XLSX.utils.sheet_to_json(worksheet, {
|
|
256
|
+
header: hasHeader ? undefined : 1,
|
|
257
|
+
defval: null,
|
|
258
|
+
raw: true
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
if (onProgress) onProgress(file.size * 0.8, file.size);
|
|
262
|
+
|
|
263
|
+
// Apply skipRows and maxRows
|
|
264
|
+
let rows = jsonRows;
|
|
265
|
+
if (skipRows > 0) {
|
|
266
|
+
rows = rows.slice(skipRows);
|
|
267
|
+
}
|
|
268
|
+
if (maxRows !== undefined) {
|
|
269
|
+
rows = rows.slice(0, maxRows);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Auto-type values
|
|
273
|
+
rows = rows.map(row => {
|
|
274
|
+
const typed: Record<string, any> = {};
|
|
275
|
+
for (const [key, value] of Object.entries(row)) {
|
|
276
|
+
typed[key] = this._autoType(value === null || value === undefined ? '' : String(value));
|
|
277
|
+
}
|
|
278
|
+
return typed;
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (onProgress) onProgress(file.size, file.size);
|
|
282
|
+
|
|
283
|
+
let df = new DataFrame(rows);
|
|
284
|
+
if (selectCols) df = df.select(...selectCols);
|
|
285
|
+
|
|
286
|
+
return df;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get sheet names from an XLSX file (useful for UI)
|
|
291
|
+
*/
|
|
292
|
+
async getSheetNames(file: File): Promise<string[]> {
|
|
293
|
+
let XLSX: any;
|
|
294
|
+
try {
|
|
295
|
+
XLSX = await import('xlsx');
|
|
296
|
+
} catch {
|
|
297
|
+
throw new Error('XLSX support requires the "xlsx" package. Install it with: npm install xlsx');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const buffer = await file.arrayBuffer();
|
|
301
|
+
const workbook = XLSX.read(buffer, { type: 'array' });
|
|
302
|
+
return workbook.SheetNames;
|
|
303
|
+
}
|
|
304
|
+
|
|
203
305
|
/* ═══════════════════════════════════════════════════
|
|
204
306
|
* INDEXEDDB PERSISTENCE
|
|
205
307
|
* ═══════════════════════════════════════════════════ */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juxscript",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.162",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A JavaScript UX authorship platform",
|
|
6
6
|
"main": "index.js",
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"chart.js": "^4.5.1",
|
|
60
60
|
"esbuild": "^0.19.0",
|
|
61
61
|
"express": "^4.18.2",
|
|
62
|
-
"ws": "^8.13.0"
|
|
62
|
+
"ws": "^8.13.0",
|
|
63
|
+
"xlsx": "^0.18.5"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/express": "^4.17.17",
|