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;CACtB;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;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IA8F5E;;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"}
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.161",
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",