@glubean/sdk 0.1.0

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/dist/data.js ADDED
@@ -0,0 +1,543 @@
1
+ /**
2
+ * Data loading utilities for test.each data-driven tests.
3
+ *
4
+ * These helpers load test data from various file formats and directories,
5
+ * returning plain arrays suitable for `test.each()`.
6
+ *
7
+ * All paths are **relative to the project root** (the directory containing
8
+ * `package.json`). The runner guarantees that `process.cwd()` points to the
9
+ * project root at execution time.
10
+ *
11
+ * @module data
12
+ *
13
+ * @example Load JSON (use native import instead)
14
+ * ```ts
15
+ * import cases from "./data/cases.json" with { type: "json" };
16
+ * export const tests = test.each(cases)("case-$id", fn);
17
+ * ```
18
+ *
19
+ * @example Load CSV
20
+ * ```ts
21
+ * import { test, fromCsv } from "@glubean/sdk";
22
+ * export const tests = test.each(await fromCsv("./data/cases.csv"))
23
+ * ("case-$id", async (ctx, row) => { ... });
24
+ * ```
25
+ *
26
+ * @example Load YAML
27
+ * ```ts
28
+ * import { test, fromYaml } from "@glubean/sdk";
29
+ * export const tests = test.each(await fromYaml("./data/cases.yaml"))
30
+ * ("case-$id", async (ctx, row) => { ... });
31
+ * ```
32
+ *
33
+ * @example Load JSONL
34
+ * ```ts
35
+ * import { test, fromJsonl } from "@glubean/sdk";
36
+ * export const tests = test.each(await fromJsonl("./data/requests.jsonl"))
37
+ * ("req-$index", async (ctx, row) => { ... });
38
+ * ```
39
+ *
40
+ * @example Load directory of files
41
+ * ```ts
42
+ * import { test, fromDir } from "@glubean/sdk";
43
+ * export const tests = test.each(await fromDir("./cases/"))
44
+ * ("case-$_name", async (ctx, row) => { ... });
45
+ * ```
46
+ */
47
+ import { readFile, readdir } from "node:fs/promises";
48
+ import { resolve } from "node:path";
49
+ import { parse as parseYaml } from "yaml";
50
+ // =============================================================================
51
+ // Shared utilities
52
+ // =============================================================================
53
+ function safeCwd() {
54
+ try {
55
+ return process.cwd();
56
+ }
57
+ catch {
58
+ return "(unavailable)";
59
+ }
60
+ }
61
+ function formatPathErrorContext(path, action, error) {
62
+ const cwd = safeCwd();
63
+ const resolvedPath = cwd === "(unavailable)" ? path : resolve(cwd, path);
64
+ const cause = error instanceof Error ? error : undefined;
65
+ const reason = error instanceof Error ? error.message : String(error);
66
+ return new Error(`Failed to ${action}: "${path}".\n` +
67
+ `Current working directory: ${cwd}\n` +
68
+ `Resolved path: ${resolvedPath}\n` +
69
+ 'Hint: data loader paths are resolved from project root (where "package.json" is).\n' +
70
+ 'Hint: if your file is in the standard data folder, use a path like "./data/cases.csv".\n' +
71
+ `Cause: ${reason}`, cause ? { cause } : undefined);
72
+ }
73
+ async function readTextFileWithContext(path) {
74
+ try {
75
+ return await readFile(path, "utf-8");
76
+ }
77
+ catch (error) {
78
+ throw formatPathErrorContext(path, "read file", error);
79
+ }
80
+ }
81
+ function parseJsonWithContext(path, content) {
82
+ try {
83
+ return JSON.parse(content);
84
+ }
85
+ catch (error) {
86
+ throw formatPathErrorContext(path, "parse JSON file", error);
87
+ }
88
+ }
89
+ /**
90
+ * Normalize `string | string[]` to `string[]`.
91
+ * @internal
92
+ */
93
+ export function toArray(value) {
94
+ if (!value)
95
+ return [];
96
+ return Array.isArray(value) ? value : [value];
97
+ }
98
+ /**
99
+ * Resolve a dot-separated path into a nested object.
100
+ * Returns `undefined` if any segment is missing.
101
+ *
102
+ * @internal
103
+ * @example
104
+ * pickByPath({ a: { b: [1, 2] } }, "a.b") // → [1, 2]
105
+ */
106
+ function pickByPath(obj, path) {
107
+ let current = obj;
108
+ for (const segment of path.split(".")) {
109
+ if (current == null || typeof current !== "object")
110
+ return undefined;
111
+ current = current[segment];
112
+ }
113
+ return current;
114
+ }
115
+ /**
116
+ * Extract an array from parsed data using an optional `pick` path.
117
+ * If no pick is provided, the data must be a top-level array.
118
+ * Provides helpful error messages when the data shape is unexpected.
119
+ *
120
+ * @internal
121
+ */
122
+ function extractArray(data, pick, sourcePath) {
123
+ if (pick) {
124
+ const picked = pickByPath(data, pick);
125
+ if (!Array.isArray(picked)) {
126
+ throw new Error(`${sourcePath}: pick path "${pick}" did not resolve to an array. ` +
127
+ `Got: ${picked === undefined ? "undefined" : typeof picked}`);
128
+ }
129
+ return picked;
130
+ }
131
+ if (Array.isArray(data)) {
132
+ return data;
133
+ }
134
+ // Data is an object — provide helpful error with discovered array fields
135
+ if (data && typeof data === "object" && !Array.isArray(data)) {
136
+ const arrayFields = [];
137
+ for (const [key, value] of Object.entries(data)) {
138
+ if (Array.isArray(value)) {
139
+ arrayFields.push(`"${key}" (${value.length} items)`);
140
+ }
141
+ }
142
+ const hint = arrayFields.length > 0
143
+ ? `\nFound these array fields: ${arrayFields.join(", ")}` +
144
+ `\nHint: use { pick: "${arrayFields[0]?.match(/"([^"]+)"/)?.[1] ?? ""}" } to select one.`
145
+ : "\nNo array fields found at the top level.";
146
+ throw new Error(`${sourcePath}: root is an object, not an array.${hint}`);
147
+ }
148
+ throw new Error(`${sourcePath}: expected an array, got ${typeof data}`);
149
+ }
150
+ /**
151
+ * Load test data from a CSV file.
152
+ *
153
+ * Returns an array of records. All values are strings (CSV has no type info).
154
+ * Use the returned data with `test.each()` for data-driven tests.
155
+ *
156
+ * @param path Path to the CSV file, relative to project root
157
+ * @param options CSV parsing options
158
+ * @returns Array of row objects
159
+ *
160
+ * @example Basic usage
161
+ * ```ts
162
+ * import { test, fromCsv } from "@glubean/sdk";
163
+ *
164
+ * export const tests = test.each(await fromCsv("./data/cases.csv"))
165
+ * ("case-$index-$country", async (ctx, row) => {
166
+ * const res = await ctx.http.get(`${ctx.vars.require("BASE_URL")}/users/${row.id}`);
167
+ * ctx.assert(res.status === row.expected, "status check");
168
+ * });
169
+ * ```
170
+ *
171
+ * @example Custom separator
172
+ * ```ts
173
+ * const data = await fromCsv("./data/cases.tsv", { separator: "\t" });
174
+ * ```
175
+ */
176
+ export async function fromCsv(path, options) {
177
+ const content = await readTextFileWithContext(path);
178
+ const separator = options?.separator ?? ",";
179
+ const hasHeaders = options?.headers !== false;
180
+ const lines = content.split("\n").filter((line) => line.trim() !== "");
181
+ if (lines.length === 0)
182
+ return [];
183
+ const parseLine = (line) => {
184
+ const fields = [];
185
+ let current = "";
186
+ let inQuotes = false;
187
+ for (let i = 0; i < line.length; i++) {
188
+ const char = line[i];
189
+ if (inQuotes) {
190
+ if (char === '"') {
191
+ if (i + 1 < line.length && line[i + 1] === '"') {
192
+ current += '"';
193
+ i++; // Skip escaped quote
194
+ }
195
+ else {
196
+ inQuotes = false;
197
+ }
198
+ }
199
+ else {
200
+ current += char;
201
+ }
202
+ }
203
+ else {
204
+ if (char === '"') {
205
+ inQuotes = true;
206
+ }
207
+ else if (char === separator) {
208
+ fields.push(current.trim());
209
+ current = "";
210
+ }
211
+ else {
212
+ current += char;
213
+ }
214
+ }
215
+ }
216
+ fields.push(current.trim());
217
+ return fields;
218
+ };
219
+ if (hasHeaders) {
220
+ const headers = parseLine(lines[0]);
221
+ return lines.slice(1).map((line) => {
222
+ const values = parseLine(line);
223
+ const record = {};
224
+ for (let i = 0; i < headers.length; i++) {
225
+ record[headers[i]] = values[i] ?? "";
226
+ }
227
+ return record;
228
+ });
229
+ }
230
+ else {
231
+ return lines.map((line) => {
232
+ const values = parseLine(line);
233
+ const record = {};
234
+ for (let i = 0; i < values.length; i++) {
235
+ record[String(i)] = values[i];
236
+ }
237
+ return record;
238
+ });
239
+ }
240
+ }
241
+ /**
242
+ * Load test data from a YAML file.
243
+ *
244
+ * The file must contain a top-level array, or use the `pick` option
245
+ * to specify the dot-path to an array within the document.
246
+ *
247
+ * @param path Path to the YAML file, relative to project root
248
+ * @param options YAML loading options
249
+ * @returns Array of row objects
250
+ *
251
+ * @example Top-level array
252
+ * ```ts
253
+ * // cases.yaml:
254
+ * // - id: 1
255
+ * // expected: 200
256
+ * // - id: 999
257
+ * // expected: 404
258
+ *
259
+ * import { test, fromYaml } from "@glubean/sdk";
260
+ * export const tests = test.each(await fromYaml("./data/cases.yaml"))
261
+ * ("case-$id", async (ctx, row) => { ... });
262
+ * ```
263
+ *
264
+ * @example Nested array with pick
265
+ * ```ts
266
+ * // collection.yaml:
267
+ * // info:
268
+ * // name: API Tests
269
+ * // testCases:
270
+ * // - id: 1
271
+ * // expected: 200
272
+ *
273
+ * const data = await fromYaml("./data/collection.yaml", { pick: "testCases" });
274
+ * ```
275
+ */
276
+ export async function fromYaml(path, options) {
277
+ const content = await readTextFileWithContext(path);
278
+ const data = parseYaml(content);
279
+ return extractArray(data, options?.pick, path);
280
+ }
281
+ // =============================================================================
282
+ // JSONL loader
283
+ // =============================================================================
284
+ /**
285
+ * Load test data from a JSONL (JSON Lines) file.
286
+ *
287
+ * Each line must be a valid JSON object. Empty lines are skipped.
288
+ *
289
+ * @param path Path to the JSONL file, relative to project root
290
+ * @returns Array of row objects
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * // requests.jsonl:
295
+ * // {"method":"GET","url":"/users/1","expected":200}
296
+ * // {"method":"GET","url":"/users/999","expected":404}
297
+ *
298
+ * import { test, fromJsonl } from "@glubean/sdk";
299
+ * export const tests = test.each(await fromJsonl("./data/requests.jsonl"))
300
+ * ("req-$index", async (ctx, row) => { ... });
301
+ * ```
302
+ */
303
+ export async function fromJsonl(path) {
304
+ const content = await readTextFileWithContext(path);
305
+ const lines = content.split("\n").filter((line) => line.trim() !== "");
306
+ return lines.map((line, index) => {
307
+ try {
308
+ return JSON.parse(line);
309
+ }
310
+ catch {
311
+ throw new Error(`${path}: invalid JSON at line ${index + 1}: ${line.substring(0, 80)}`);
312
+ }
313
+ });
314
+ }
315
+ /**
316
+ * Load test data from a directory of files.
317
+ *
318
+ * Each file becomes one row in the data table. The file contents are spread
319
+ * into the row, plus `_name` (filename without extension) and `_path`
320
+ * (relative path) are auto-injected.
321
+ *
322
+ * For other modes, use `fromDir.concat()` or `fromDir.merge()`.
323
+ *
324
+ * Supported file types: `.json`, `.yaml`, `.yml`, `.jsonl`, `.csv`.
325
+ *
326
+ * @param path Path to the directory, relative to project root
327
+ * @param options Directory loading options
328
+ * @returns Array of row objects (one per file)
329
+ *
330
+ * @example One file = one test
331
+ * ```ts
332
+ * // cases/
333
+ * // user-1.json → { "id": 1, "expected": 200 }
334
+ * // user-999.json → { "id": 999, "expected": 404 }
335
+ *
336
+ * import { test, fromDir } from "@glubean/sdk";
337
+ * export const tests = test.each(await fromDir("./cases/"))
338
+ * ("case-$_name", async (ctx, row) => {
339
+ * const res = await ctx.http.get(`${ctx.vars.require("BASE_URL")}/users/${row.id}`);
340
+ * ctx.assert(res.status === row.expected, "status check");
341
+ * });
342
+ * ```
343
+ */
344
+ export async function fromDir(path, options) {
345
+ const files = await _collectAndSort(path, options);
346
+ if (files.length === 0) {
347
+ return [];
348
+ }
349
+ const result = [];
350
+ for (const filePath of files) {
351
+ const content = await loadSingleFileAsObject(filePath);
352
+ const name = fileNameWithoutExt(filePath);
353
+ const relativePath = filePath.startsWith(path) ? filePath.slice(path.length).replace(/^\//, "") : filePath;
354
+ result.push({
355
+ _name: name,
356
+ _path: relativePath,
357
+ ...content,
358
+ });
359
+ }
360
+ return result;
361
+ }
362
+ /**
363
+ * Concatenate arrays from all files in a directory into one flat table.
364
+ *
365
+ * Each file should contain an array. All arrays are concatenated.
366
+ * Use `pick` to extract a nested array from each file.
367
+ *
368
+ * @param path Path to the directory, relative to project root
369
+ * @param options Directory loading options (supports `pick` for nested arrays)
370
+ * @returns One flat array with rows from all files
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * // batches/
375
+ * // batch-001.json → [{ id: 1, ... }, { id: 2, ... }]
376
+ * // batch-002.json → [{ id: 3, ... }, { id: 4, ... }]
377
+ *
378
+ * export const tests = test.each(await fromDir.concat("./batches/"))
379
+ * ("case-$id", async (ctx, row) => { ... });
380
+ * ```
381
+ *
382
+ * @example YAML with pick
383
+ * ```ts
384
+ * const data = await fromDir.concat("./specs/", {
385
+ * ext: ".yaml",
386
+ * pick: "cases",
387
+ * });
388
+ * ```
389
+ */
390
+ fromDir.concat = async function fromDirConcat(path, options) {
391
+ const files = await _collectAndSort(path, options);
392
+ if (files.length === 0) {
393
+ return [];
394
+ }
395
+ const result = [];
396
+ for (const filePath of files) {
397
+ const fileData = await loadFileAuto(filePath, options?.pick);
398
+ result.push(...fileData);
399
+ }
400
+ return result;
401
+ };
402
+ /**
403
+ * Merge objects from all files in a directory into one combined map.
404
+ *
405
+ * Each file should contain a JSON/YAML object with named keys.
406
+ * All keys are shallow-merged; later files override earlier ones
407
+ * (files are sorted alphabetically).
408
+ *
409
+ * Designed for `test.pick` where named examples are split across files
410
+ * (e.g. by region, environment, or tenant).
411
+ *
412
+ * @param path Path to the directory, relative to project root
413
+ * @param options Directory loading options
414
+ * @returns A single merged object containing all keys from all files
415
+ *
416
+ * @example
417
+ * ```ts
418
+ * // data/regions/
419
+ * // us-east.json → { "us-east-1": {...}, "us-east-2": {...} }
420
+ * // eu-west.json → { "eu-west-1": {...} }
421
+ *
422
+ * const allRegions = await fromDir.merge("./data/regions/");
423
+ * // → { "us-east-1": {...}, "us-east-2": {...}, "eu-west-1": {...} }
424
+ *
425
+ * export const regionTest = test.pick(allRegions)
426
+ * ("region-$_pick", async (ctx, data) => { ... });
427
+ * ```
428
+ */
429
+ fromDir.merge = async function fromDirMerge(path, options) {
430
+ const files = await _collectAndSort(path, options);
431
+ const result = {};
432
+ for (const filePath of files) {
433
+ const content = await loadSingleFileAsObject(filePath);
434
+ Object.assign(result, content);
435
+ }
436
+ return result;
437
+ };
438
+ /**
439
+ * Collect and sort files from a directory.
440
+ * Shared by all fromDir modes.
441
+ * @internal
442
+ */
443
+ async function _collectAndSort(path, options) {
444
+ const extensions = toArray(options?.ext || ".json");
445
+ const recursive = options?.recursive ?? false;
446
+ const files = [];
447
+ await collectFiles(path, extensions, recursive, files);
448
+ files.sort();
449
+ return files;
450
+ }
451
+ // =============================================================================
452
+ // Internal helpers for fromDir
453
+ // =============================================================================
454
+ /**
455
+ * Recursively collect files matching the given extensions.
456
+ * @internal
457
+ */
458
+ async function collectFiles(dir, extensions, recursive, result) {
459
+ try {
460
+ const entries = await readdir(dir, { withFileTypes: true });
461
+ for (const entry of entries) {
462
+ const fullPath = dir.endsWith("/") ? `${dir}${entry.name}` : `${dir}/${entry.name}`;
463
+ if (entry.isFile()) {
464
+ const matchesExt = extensions.some((ext) => entry.name.toLowerCase().endsWith(ext.toLowerCase()));
465
+ if (matchesExt) {
466
+ result.push(fullPath);
467
+ }
468
+ }
469
+ else if (entry.isDirectory() && recursive) {
470
+ await collectFiles(fullPath, extensions, recursive, result);
471
+ }
472
+ }
473
+ }
474
+ catch (error) {
475
+ throw formatPathErrorContext(dir, "read directory", error);
476
+ }
477
+ }
478
+ /**
479
+ * Load a single file as an array of rows, auto-detecting format.
480
+ * Used in concat mode.
481
+ * @internal
482
+ */
483
+ async function loadFileAuto(filePath, pick) {
484
+ const lower = filePath.toLowerCase();
485
+ if (lower.endsWith(".csv")) {
486
+ return (await fromCsv(filePath));
487
+ }
488
+ if (lower.endsWith(".jsonl")) {
489
+ return await fromJsonl(filePath);
490
+ }
491
+ if (lower.endsWith(".yaml") || lower.endsWith(".yml")) {
492
+ return await fromYaml(filePath, { pick });
493
+ }
494
+ // Default: JSON
495
+ const content = await readTextFileWithContext(filePath);
496
+ const data = parseJsonWithContext(filePath, content);
497
+ return extractArray(data, pick, filePath);
498
+ }
499
+ /**
500
+ * Load a single file as one object (for default fromDir mode).
501
+ * @internal
502
+ */
503
+ async function loadSingleFileAsObject(filePath) {
504
+ const lower = filePath.toLowerCase();
505
+ const content = await readTextFileWithContext(filePath);
506
+ if (lower.endsWith(".yaml") || lower.endsWith(".yml")) {
507
+ const data = parseYaml(content);
508
+ if (data && typeof data === "object" && !Array.isArray(data)) {
509
+ return data;
510
+ }
511
+ return { data };
512
+ }
513
+ if (lower.endsWith(".jsonl")) {
514
+ // JSONL in single-file mode: return first line as the object
515
+ const firstLine = content.split("\n").find((l) => l.trim() !== "");
516
+ if (firstLine) {
517
+ return JSON.parse(firstLine);
518
+ }
519
+ return {};
520
+ }
521
+ if (lower.endsWith(".csv")) {
522
+ // CSV in single-file mode: return first row as the object
523
+ const rows = await fromCsv(filePath);
524
+ return rows[0] ?? {};
525
+ }
526
+ // Default: JSON
527
+ const data = JSON.parse(content);
528
+ if (data && typeof data === "object" && !Array.isArray(data)) {
529
+ return data;
530
+ }
531
+ return { data };
532
+ }
533
+ /**
534
+ * Extract filename without extension.
535
+ * @internal
536
+ */
537
+ function fileNameWithoutExt(filePath) {
538
+ const parts = filePath.split("/");
539
+ const filename = parts[parts.length - 1];
540
+ const lastDot = filename.lastIndexOf(".");
541
+ return lastDot === -1 ? filename : filename.substring(0, lastDot);
542
+ }
543
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}