rowpipe 1.0.0 → 1.2.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/README.md +327 -41
- package/dist/cli/commands/diff.d.ts +30 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +143 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/files.d.ts +35 -0
- package/dist/cli/commands/files.d.ts.map +1 -0
- package/dist/cli/commands/files.js +93 -0
- package/dist/cli/commands/files.js.map +1 -0
- package/dist/cli/index.js +89 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/core/errors.d.ts +23 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +38 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/diff/comparator.d.ts +17 -0
- package/dist/diff/comparator.d.ts.map +1 -0
- package/dist/diff/comparator.js +158 -0
- package/dist/diff/comparator.js.map +1 -0
- package/dist/diff/engine.d.ts +10 -0
- package/dist/diff/engine.d.ts.map +1 -0
- package/dist/diff/engine.js +333 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/diff/hash.d.ts +6 -0
- package/dist/diff/hash.d.ts.map +1 -0
- package/dist/diff/hash.js +50 -0
- package/dist/diff/hash.js.map +1 -0
- package/dist/diff/key.d.ts +21 -0
- package/dist/diff/key.d.ts.map +1 -0
- package/dist/diff/key.js +107 -0
- package/dist/diff/key.js.map +1 -0
- package/dist/diff/reporter.d.ts +18 -0
- package/dist/diff/reporter.d.ts.map +1 -0
- package/dist/diff/reporter.js +133 -0
- package/dist/diff/reporter.js.map +1 -0
- package/dist/diff/schema.d.ts +7 -0
- package/dist/diff/schema.d.ts.map +1 -0
- package/dist/diff/schema.js +65 -0
- package/dist/diff/schema.js.map +1 -0
- package/dist/diff/storage/disk-index.d.ts +28 -0
- package/dist/diff/storage/disk-index.d.ts.map +1 -0
- package/dist/diff/storage/disk-index.js +105 -0
- package/dist/diff/storage/disk-index.js.map +1 -0
- package/dist/diff/storage/memory-index.d.ts +23 -0
- package/dist/diff/storage/memory-index.d.ts.map +1 -0
- package/dist/diff/storage/memory-index.js +69 -0
- package/dist/diff/storage/memory-index.js.map +1 -0
- package/dist/diff/storage/spillable-index.d.ts +30 -0
- package/dist/diff/storage/spillable-index.d.ts.map +1 -0
- package/dist/diff/storage/spillable-index.js +108 -0
- package/dist/diff/storage/spillable-index.js.map +1 -0
- package/dist/diff/types.d.ts +127 -0
- package/dist/diff/types.d.ts.map +1 -0
- package/dist/diff/types.js +2 -0
- package/dist/diff/types.js.map +1 -0
- package/dist/files/glob.d.ts +21 -0
- package/dist/files/glob.d.ts.map +1 -0
- package/dist/files/glob.js +132 -0
- package/dist/files/glob.js.map +1 -0
- package/dist/files/hash.d.ts +10 -0
- package/dist/files/hash.d.ts.map +1 -0
- package/dist/files/hash.js +67 -0
- package/dist/files/hash.js.map +1 -0
- package/dist/files/index.d.ts +6 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +6 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/mime.d.ts +9 -0
- package/dist/files/mime.d.ts.map +1 -0
- package/dist/files/mime.js +128 -0
- package/dist/files/mime.js.map +1 -0
- package/dist/files/reader.d.ts +19 -0
- package/dist/files/reader.d.ts.map +1 -0
- package/dist/files/reader.js +344 -0
- package/dist/files/reader.js.map +1 -0
- package/dist/files/types.d.ts +47 -0
- package/dist/files/types.d.ts.map +1 -0
- package/dist/files/types.js +2 -0
- package/dist/files/types.js.map +1 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/readers/csv.d.ts.map +1 -1
- package/dist/readers/csv.js +59 -27
- package/dist/readers/csv.js.map +1 -1
- package/dist/readers/index.d.ts +2 -0
- package/dist/readers/index.d.ts.map +1 -1
- package/dist/readers/index.js +57 -3
- package/dist/readers/index.js.map +1 -1
- package/dist/readers/json.d.ts.map +1 -1
- package/dist/readers/json.js +6 -8
- package/dist/readers/json.js.map +1 -1
- package/dist/readers/jsonl.d.ts.map +1 -1
- package/dist/readers/jsonl.js +5 -7
- package/dist/readers/jsonl.js.map +1 -1
- package/dist/readers/parquet.d.ts +17 -0
- package/dist/readers/parquet.d.ts.map +1 -0
- package/dist/readers/parquet.js +146 -0
- package/dist/readers/parquet.js.map +1 -0
- package/dist/transforms/expression.d.ts.map +1 -1
- package/dist/transforms/expression.js +73 -7
- package/dist/transforms/expression.js.map +1 -1
- package/dist/utils/compression.d.ts +30 -6
- package/dist/utils/compression.d.ts.map +1 -1
- package/dist/utils/compression.js +95 -18
- package/dist/utils/compression.js.map +1 -1
- package/dist/writers/csv.d.ts.map +1 -1
- package/dist/writers/csv.js +29 -17
- package/dist/writers/csv.js.map +1 -1
- package/dist/writers/index.d.ts +2 -0
- package/dist/writers/index.d.ts.map +1 -1
- package/dist/writers/index.js +49 -4
- package/dist/writers/index.js.map +1 -1
- package/dist/writers/json.d.ts +1 -1
- package/dist/writers/json.d.ts.map +1 -1
- package/dist/writers/json.js +9 -11
- package/dist/writers/json.js.map +1 -1
- package/dist/writers/jsonl.d.ts +1 -1
- package/dist/writers/jsonl.d.ts.map +1 -1
- package/dist/writers/jsonl.js +9 -11
- package/dist/writers/jsonl.js.map +1 -1
- package/dist/writers/markdown.d.ts +21 -0
- package/dist/writers/markdown.d.ts.map +1 -0
- package/dist/writers/markdown.js +82 -0
- package/dist/writers/markdown.js.map +1 -0
- package/dist/writers/parquet.d.ts +19 -0
- package/dist/writers/parquet.d.ts.map +1 -0
- package/dist/writers/parquet.js +129 -0
- package/dist/writers/parquet.js.map +1 -0
- package/package.json +16 -3
- package/skills/rowpipe/SKILL.md +263 -0
- package/benchmarks/memory-bench.ts +0 -109
- package/src/analytics/reduce.ts +0 -388
- package/src/analytics/schema-inference.ts +0 -217
- package/src/analytics/semantic-types.ts +0 -36
- package/src/analytics/stats.ts +0 -383
- package/src/analytics/validator.ts +0 -134
- package/src/cli/commands/cast.ts +0 -60
- package/src/cli/commands/convert.ts +0 -128
- package/src/cli/commands/filter.ts +0 -58
- package/src/cli/commands/inspect.ts +0 -193
- package/src/cli/commands/map.ts +0 -66
- package/src/cli/commands/reduce.ts +0 -74
- package/src/cli/commands/rename.ts +0 -59
- package/src/cli/commands/sample.ts +0 -61
- package/src/cli/commands/schema.ts +0 -86
- package/src/cli/commands/select.ts +0 -59
- package/src/cli/commands/stats.ts +0 -100
- package/src/cli/commands/validate.ts +0 -123
- package/src/cli/index.ts +0 -285
- package/src/core/batch.ts +0 -81
- package/src/core/errors.ts +0 -81
- package/src/core/pipeline.ts +0 -150
- package/src/core/types.ts +0 -110
- package/src/index.ts +0 -52
- package/src/readers/csv.ts +0 -302
- package/src/readers/index.ts +0 -88
- package/src/readers/json.ts +0 -256
- package/src/readers/jsonl.ts +0 -126
- package/src/readers/xlsx.ts +0 -182
- package/src/transforms/cast.ts +0 -212
- package/src/transforms/expression.ts +0 -1114
- package/src/transforms/filter.ts +0 -38
- package/src/transforms/map.ts +0 -99
- package/src/transforms/rename.ts +0 -47
- package/src/transforms/sample.ts +0 -57
- package/src/transforms/select.ts +0 -64
- package/src/utils/compression.ts +0 -43
- package/src/utils/formatting.ts +0 -75
- package/src/utils/progress.ts +0 -37
- package/src/writers/csv.ts +0 -106
- package/src/writers/index.ts +0 -87
- package/src/writers/json.ts +0 -52
- package/src/writers/jsonl.ts +0 -49
- package/src/writers/xlsx.ts +0 -87
- package/tests/analytics.test.ts +0 -119
- package/tests/cli-integration.test.ts +0 -187
- package/tests/map-reduce.test.ts +0 -223
- package/tests/readers-writers.test.ts +0 -189
- package/tests/transforms.test.ts +0 -199
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -9
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Rowpipe
|
|
2
2
|
|
|
3
|
-
> **A stream-first tabular data toolkit for CSV, JSON, JSONL, and
|
|
3
|
+
> **A stream-first tabular data toolkit for CSV, TSV, JSON, JSONL, XLSX, Apache Parquet, and Markdown.**
|
|
4
4
|
>
|
|
5
5
|
> *Don't load the dataset. Stream through it.*
|
|
6
6
|
|
|
7
|
-
Rowpipe is a high-performance, bounded-memory command-line toolkit and Node.js library for reading, inspecting, analyzing, transforming, validating, and converting tabular datasets across CSV, JSON, JSONL, and
|
|
7
|
+
Rowpipe is a high-performance, bounded-memory command-line toolkit and Node.js library for reading, inspecting, analyzing, transforming, validating, and converting tabular datasets across CSV, TSV, PSV, JSON, JSONL, XLSX, Apache Parquet (`.parquet`), Markdown tables (`.md`), and transparent Gzip (`.gz`) streams.
|
|
8
8
|
|
|
9
9
|
Designed around stream backpressure and batch processing, Rowpipe processes multi-gigabyte and multi-million-row datasets with constant $O(1)$ memory usage.
|
|
10
10
|
|
|
@@ -13,8 +13,14 @@ Designed around stream backpressure and batch processing, Rowpipe processes mult
|
|
|
13
13
|
## Highlights
|
|
14
14
|
|
|
15
15
|
- **Stream-First Architecture**: Datasets are never buffered entirely in memory; rows flow in configurable batches through async generator pipelines.
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
16
|
+
- **Rich Format Ecosystem**: Native streaming support for **CSV, TSV / PSV, JSON, JSONL, XLSX, Apache Parquet (`.parquet`), Markdown tables (`.md`), and Gzip (`.gz`)**.
|
|
17
|
+
- **Apache Parquet Support**: High-performance columnar binary format reader (Snappy, Zstd, Gzip decompression via pure JS) and streaming writer.
|
|
18
|
+
- **Cross-Format Conversion & Multi-Sheet Export**: Convert seamlessly across all formats. Export individual Excel sheets or bulk export all worksheets with `--all-sheets`.
|
|
19
|
+
- **Filesystem as Data (`rowpipe files`)**: First-class streaming filesystem source adapter. Directories and files become streams of tabular records (`path`, `size`, `type`, `extension`, `modified_at`, streaming `hash`, `mime`) composable with `filter`, `select`, `stats`, `convert`, and `diff`.
|
|
20
|
+
- **Cross-Format Dataset Diffing (`rowpipe diff`)**: High-performance, stream-first comparison across CSV, JSONL, XLSX, and Parquet with bounded memory and automatic spill-to-disk. Supports composite keys, duplicate policies, value tolerance, column filtering, schema diffing, JSONL patch generation, and CI `--fail-on-diff` mode.
|
|
21
|
+
|
|
22
|
+
- **Zero-`eval` Safe Expression Engine**: Ultra-fast JIT closure-compiled evaluators supporting arithmetic (`revenue - cost`), string/date pipe functions (`email | lower | trim`), and direct JSON dot-notation (`payload.user.city`).
|
|
23
|
+
- **Map & Reduce Streaming Engine**: Compute row derivations (`rowpipe map`) and global or group-by aggregations (`rowpipe reduce --by country`) in a single pass.
|
|
18
24
|
- **Numerically Stable Streaming Stats**: Online Welford statistics (mean, variance, stddev, min, max, sum) and $O(1)$ HyperLogLog distinct cardinality estimation.
|
|
19
25
|
- **Incremental Schema Inference & Semantic Types**: Detects data types with confidence scoring and semantic patterns (`email`, `url`, `uuid`, `ipv4`, `country-code`, `currency`, `phone`).
|
|
20
26
|
- **Streaming Schema Validation**: Validates stream against JSON schemas with detailed violation reporting.
|
|
@@ -45,14 +51,19 @@ npm install rowpipe
|
|
|
45
51
|
|
|
46
52
|
## CLI Usage & Examples
|
|
47
53
|
|
|
48
|
-
### 1. Inspect Dataset & Multi-Sheet Excel Analysis
|
|
54
|
+
### 1. Inspect Dataset & Multi-Sheet Excel / Parquet Analysis
|
|
49
55
|
Inspect format, row count, column list, data types, null percentage, and approximate distinct counts:
|
|
50
56
|
|
|
51
57
|
```bash
|
|
58
|
+
# CSV / TSV / JSONL
|
|
52
59
|
rowpipe inspect users.csv
|
|
60
|
+
rowpipe inspect data.tsv
|
|
61
|
+
|
|
62
|
+
# Apache Parquet dataset
|
|
63
|
+
rowpipe inspect dataset.parquet
|
|
53
64
|
|
|
54
65
|
# Machine-readable JSON output
|
|
55
|
-
rowpipe inspect
|
|
66
|
+
rowpipe inspect dataset.parquet --json
|
|
56
67
|
|
|
57
68
|
# Analyze all sheets in an Excel workbook
|
|
58
69
|
rowpipe inspect workbook.xlsx
|
|
@@ -61,39 +72,24 @@ rowpipe inspect workbook.xlsx
|
|
|
61
72
|
rowpipe inspect workbook.xlsx --sheet Users
|
|
62
73
|
```
|
|
63
74
|
|
|
64
|
-
|
|
65
|
-
```text
|
|
66
|
-
File: workbook.xlsx
|
|
67
|
-
Format: XLSX
|
|
68
|
-
Size: 1.25 MB
|
|
69
|
-
Sheets: 3
|
|
70
|
-
|
|
71
|
-
SHEET ROWS COLUMNS PREVIEW COLUMNS
|
|
72
|
-
Users 1,200 5 id, name, email, age, created_at
|
|
73
|
-
Orders 8,400 4 order_id, user_id, total, status
|
|
74
|
-
Products 300 3 sku, title, price
|
|
75
|
-
|
|
76
|
-
Tip: Run with --sheet <name> to inspect a specific sheet in full detail.
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 2. Sheet-Based Export & Format Conversion
|
|
75
|
+
### 2. Format Conversion & Export
|
|
80
76
|
Convert across formats without intermediate buffering:
|
|
81
77
|
|
|
82
78
|
```bash
|
|
83
|
-
#
|
|
84
|
-
rowpipe convert
|
|
79
|
+
# CSV / TSV to Apache Parquet
|
|
80
|
+
rowpipe convert sales.csv sales.parquet
|
|
85
81
|
|
|
86
|
-
#
|
|
87
|
-
rowpipe convert
|
|
82
|
+
# Parquet to Gzipped JSONL
|
|
83
|
+
rowpipe convert sales.parquet sales.jsonl.gz
|
|
88
84
|
|
|
89
|
-
#
|
|
90
|
-
rowpipe
|
|
85
|
+
# Filter and output directly as a GitHub Markdown Table
|
|
86
|
+
rowpipe filter dataset.parquet "status == 'ACTIVE' && score >= 90" --to markdown
|
|
91
87
|
|
|
92
|
-
#
|
|
93
|
-
rowpipe convert
|
|
88
|
+
# Export specific Excel worksheet to CSV / TSV
|
|
89
|
+
rowpipe convert workbook.xlsx users.tsv --sheet Users
|
|
94
90
|
|
|
95
|
-
#
|
|
96
|
-
rowpipe convert
|
|
91
|
+
# Bulk export ALL worksheets to individual files in a directory
|
|
92
|
+
rowpipe convert workbook.xlsx --all-sheets --out-dir ./exported/ --to csv
|
|
97
93
|
|
|
98
94
|
# Streaming through gzip
|
|
99
95
|
rowpipe convert data.csv.gz data.jsonl.gz
|
|
@@ -312,6 +308,253 @@ cat transactions.csv |
|
|
|
312
308
|
|
|
313
309
|
---
|
|
314
310
|
|
|
311
|
+
## Compare Datasets (`rowpipe diff`)
|
|
312
|
+
|
|
313
|
+
`rowpipe diff` is a production-grade, stream-first comparison engine that compares two tabular datasets by primary or composite key and reports:
|
|
314
|
+
|
|
315
|
+
- **Added rows** (present in right dataset, absent in left)
|
|
316
|
+
- **Removed rows** (present in left dataset, absent in right)
|
|
317
|
+
- **Changed rows** (matching key, different values)
|
|
318
|
+
- **Unchanged rows** (matching key, identical values)
|
|
319
|
+
- **Changed columns breakdown** (ranked by frequency of changes)
|
|
320
|
+
- **Schema differences** (added/removed columns and type changes)
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
rowpipe diff yesterday.csv today.csv --key id
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Example Summary Output:
|
|
327
|
+
|
|
328
|
+
```text
|
|
329
|
+
Comparing:
|
|
330
|
+
yesterday.csv
|
|
331
|
+
today.csv
|
|
332
|
+
|
|
333
|
+
Key: id
|
|
334
|
+
|
|
335
|
+
Rows
|
|
336
|
+
added 1,283
|
|
337
|
+
removed 412
|
|
338
|
+
changed 8,921
|
|
339
|
+
unchanged 91,204
|
|
340
|
+
|
|
341
|
+
Changed columns
|
|
342
|
+
price 5,821
|
|
343
|
+
status 2,101
|
|
344
|
+
email 999
|
|
345
|
+
|
|
346
|
+
Schema
|
|
347
|
+
+ loyalty_level: string
|
|
348
|
+
~ price: integer -> number
|
|
349
|
+
- legacy_code: string
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Key Capabilities & Examples
|
|
353
|
+
|
|
354
|
+
#### 1. Composite Keys
|
|
355
|
+
Use comma-separated column names for multi-column composite keys with collision-proof typed encoding:
|
|
356
|
+
```bash
|
|
357
|
+
rowpipe diff old.csv new.csv --key country,user_id
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
#### 2. Cross-Format Comparison
|
|
361
|
+
Compare datasets seamlessly across any combination of supported formats (CSV, TSV, JSONL, XLSX, Apache Parquet):
|
|
362
|
+
```bash
|
|
363
|
+
# Compare CSV with Parquet
|
|
364
|
+
rowpipe diff old.csv new.parquet --key id
|
|
365
|
+
|
|
366
|
+
# Compare JSONL with Excel
|
|
367
|
+
rowpipe diff old.jsonl new.xlsx --key user_id --sheet Users
|
|
368
|
+
|
|
369
|
+
# Compare specific sheets between two Excel workbooks
|
|
370
|
+
rowpipe diff old.xlsx new.xlsx --left-sheet Nov --right-sheet Dec --key sku
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### 3. Ignore or Select Specific Columns
|
|
374
|
+
```bash
|
|
375
|
+
# Ignore volatile timestamp or audit columns
|
|
376
|
+
rowpipe diff old.csv new.csv --key id --ignore updated_at,last_seen
|
|
377
|
+
|
|
378
|
+
# Compare only specific columns for changes
|
|
379
|
+
rowpipe diff old.csv new.csv --key id --columns price,status
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### 4. Value Equality, Tolerance & Coercion
|
|
383
|
+
- **Strict by default**: `null != ""` and `0 != "0"`.
|
|
384
|
+
- **`--coerce`**: Coerces types (e.g. `"42" == 42`, `"true" == true`) across formats.
|
|
385
|
+
- **`--epsilon <val>`**: Floating point comparison tolerance (`abs(a - b) <= epsilon`).
|
|
386
|
+
- **`--trim` & `--ignore-case`**: String normalization options.
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
rowpipe diff old.csv new.csv --key id --epsilon 0.001 --trim --ignore-case
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### 5. Duplicate Key Policies
|
|
393
|
+
Duplicate keys in either dataset are never silently ignored:
|
|
394
|
+
- `--duplicate-key error` *(default)*: Exits immediately with row context.
|
|
395
|
+
- `--duplicate-key first`: Keeps the first occurrence.
|
|
396
|
+
- `--duplicate-key last`: Keeps the latest occurrence.
|
|
397
|
+
|
|
398
|
+
#### 6. Detailed Row & JSONL Patch Output Modes
|
|
399
|
+
```bash
|
|
400
|
+
# Detailed row change output with limit
|
|
401
|
+
rowpipe diff old.csv new.csv --key id --format rows --only changed --limit 50
|
|
402
|
+
|
|
403
|
+
# Stream JSONL patches (suitable for ETL change feeds or audit logs)
|
|
404
|
+
rowpipe diff old.csv new.csv --key id --format patch > changes.jsonl
|
|
405
|
+
|
|
406
|
+
# Machine-readable JSON summary metadata
|
|
407
|
+
rowpipe diff old.csv new.csv --key id --json
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Example JSONL patch output:
|
|
411
|
+
```json
|
|
412
|
+
{"op":"update","key":{"id":24},"changes":{"price":{"old":120,"new":125}}}
|
|
413
|
+
{"op":"insert","key":{"id":31},"row":{"id":31,"name":"Alice"}}
|
|
414
|
+
{"op":"delete","key":{"id":51},"row":{"id":51,"name":"Bob"}}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### 7. CI/CD Validation (`--fail-on-diff`)
|
|
418
|
+
Exit with non-zero code (`1`) when differences exist, or `0` when datasets are equivalent:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
rowpipe diff expected.csv actual.csv \
|
|
422
|
+
--key id \
|
|
423
|
+
--fail-on-diff
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
This makes Rowpipe ideal for automated verification of:
|
|
427
|
+
- **Database migrations**
|
|
428
|
+
- **ETL jobs & data pipelines**
|
|
429
|
+
- **API export validation**
|
|
430
|
+
- **Regression test fixtures**
|
|
431
|
+
- **Scheduled report auditing**
|
|
432
|
+
|
|
433
|
+
#### 8. Bounded Memory Architecture & Automatic Spill-to-Disk
|
|
434
|
+
Keyed diffing is classified as **Global State / Spillable**. Rowpipe buffers indexed keys in memory and automatically spills to disk using an append-only temp file index when `--memory-limit` is reached (default: 256MB).
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
# Handle multi-million-row diffs with bounded RAM
|
|
438
|
+
rowpipe diff huge-old.csv huge-new.csv \
|
|
439
|
+
--key id \
|
|
440
|
+
--memory-limit 128mb
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Filesystem as Data (`rowpipe files`)
|
|
446
|
+
|
|
447
|
+
> **Everything becomes a stream of records.**
|
|
448
|
+
|
|
449
|
+
Rowpipe treats files and directories as another first-class streaming record source. A directory tree becomes a stream of metadata records that can be filtered, selected, mapped, reduced, converted, and diffed using the exact same stream pipeline used for CSV, JSONL, XLSX, and Parquet.
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
rowpipe files ./uploads
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Example Output (as Table / CSV / JSONL):
|
|
456
|
+
|
|
457
|
+
```text
|
|
458
|
+
path name ext size modified_at
|
|
459
|
+
uploads/avatar.png avatar.png png 182312 2026-09-16T08:13:11.923Z
|
|
460
|
+
uploads/users.csv users.csv csv 8123102 2026-09-15T19:42:01.114Z
|
|
461
|
+
uploads/archive/data.zip data.zip zip 12931231 2026-09-12T11:05:30.852Z
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Standard Record Fields
|
|
465
|
+
Each file record contains rich, standardized metadata:
|
|
466
|
+
- `path`: Full normalized path
|
|
467
|
+
- `relative_path`: Normalized path relative to root directory (uses `/` across all operating systems)
|
|
468
|
+
- `name`: File name with extension (e.g. `logo.png`)
|
|
469
|
+
- `basename`: File name without extension (e.g. `logo`)
|
|
470
|
+
- `extension`: Lowercase extension without dot (e.g. `png`)
|
|
471
|
+
- `directory`: Parent directory path
|
|
472
|
+
- `type`: Record type (`"file"`, `"directory"`, `"symlink"`)
|
|
473
|
+
- `size`: Numeric size in bytes (`0` for directories)
|
|
474
|
+
- `created_at`, `modified_at`, `accessed_at`: ISO 8601 timestamp strings
|
|
475
|
+
- `mode`: File permission mode
|
|
476
|
+
- `is_file`, `is_directory`, `is_symlink`: Boolean flags
|
|
477
|
+
- `hash` *(optional)*: Streaming content hash (`sha256`, `sha1`, `md5`, `fast`)
|
|
478
|
+
- `mime` & `category` *(optional)*: Inferred MIME type (`image/png`, `text/csv`) and category (`image`, `data`, `code`, `archive`, `document`, `video`, `audio`)
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
### Filesystem CLI Workflows & Examples
|
|
483
|
+
|
|
484
|
+
#### 1. Recursive Traversal & Glob Filtering
|
|
485
|
+
```bash
|
|
486
|
+
# Scan directory recursively (default)
|
|
487
|
+
rowpipe files ./src
|
|
488
|
+
|
|
489
|
+
# Limit traversal depth
|
|
490
|
+
rowpipe files . --max-depth 2
|
|
491
|
+
|
|
492
|
+
# Include specific globs
|
|
493
|
+
rowpipe files ./src --include "**/*.ts"
|
|
494
|
+
|
|
495
|
+
# Exclude patterns (e.g. node_modules, build artifacts)
|
|
496
|
+
rowpipe files . --exclude "dist/**" --exclude "*.tmp"
|
|
497
|
+
|
|
498
|
+
# Include hidden files & dot directories
|
|
499
|
+
rowpipe files . --hidden
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
#### 2. Streaming Hashes & MIME Type Detection
|
|
503
|
+
```bash
|
|
504
|
+
# Compute streaming SHA-256 hashes (never loads full file into memory)
|
|
505
|
+
rowpipe files ./assets --hash sha256
|
|
506
|
+
|
|
507
|
+
# Fast non-cryptographic fingerprinting (size + mtime + content sampling)
|
|
508
|
+
rowpipe files ./dataset --hash fast
|
|
509
|
+
|
|
510
|
+
# Infer MIME types and high-level categories
|
|
511
|
+
rowpipe files ./uploads --mime
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### 3. Unix Pipeline Composition
|
|
515
|
+
Compose filesystem metadata directly into Rowpipe streams:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
# Filter large files (> 1MB)
|
|
519
|
+
rowpipe files ./uploads | rowpipe filter - 'size > 1000000'
|
|
520
|
+
|
|
521
|
+
# Project specific columns
|
|
522
|
+
rowpipe files ./src | rowpipe select - path,size,extension
|
|
523
|
+
|
|
524
|
+
# Calculate disk usage stats across file types
|
|
525
|
+
rowpipe files ./src --to jsonl | \
|
|
526
|
+
rowpipe reduce - "total_size=sum(size)" "file_count=count()" --by extension
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
#### 4. Deterministic Snapshots & Build Verification
|
|
530
|
+
Create stable, reproducible file inventory snapshots for build artifacts, deployments, or backups:
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
# Generate deterministic snapshot
|
|
534
|
+
rowpipe files snapshot ./dist \
|
|
535
|
+
--hash sha256 \
|
|
536
|
+
--to jsonl > dist.snapshot.v1.jsonl
|
|
537
|
+
|
|
538
|
+
# Generate snapshot of next build
|
|
539
|
+
rowpipe files snapshot ./dist \
|
|
540
|
+
--hash sha256 \
|
|
541
|
+
--to jsonl > dist.snapshot.v2.jsonl
|
|
542
|
+
|
|
543
|
+
# Compare snapshots using Rowpipe's diff engine
|
|
544
|
+
rowpipe diff dist.snapshot.v1.jsonl dist.snapshot.v2.jsonl \
|
|
545
|
+
--key relative_path \
|
|
546
|
+
--ignore modified_at,accessed_at
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
#### 5. Native Directory Diffing (`rowpipe files diff`)
|
|
550
|
+
Compare two directory trees directly:
|
|
551
|
+
|
|
552
|
+
```bash
|
|
553
|
+
rowpipe files diff ./dist-v1 ./dist-v2 --hash sha256
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
315
558
|
## Node.js Library API
|
|
316
559
|
|
|
317
560
|
Rowpipe can be imported directly in your Node.js projects:
|
|
@@ -322,12 +565,15 @@ import {
|
|
|
322
565
|
CSVReader,
|
|
323
566
|
JSONLWriter,
|
|
324
567
|
XLSXReader,
|
|
568
|
+
ParquetReader,
|
|
569
|
+
FileSystemReader,
|
|
325
570
|
filterRows,
|
|
326
571
|
selectColumns,
|
|
327
572
|
castColumns,
|
|
328
573
|
mapRows,
|
|
329
574
|
reduceRows,
|
|
330
|
-
|
|
575
|
+
diffRows,
|
|
576
|
+
computeDiff,
|
|
331
577
|
} from "rowpipe";
|
|
332
578
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
333
579
|
|
|
@@ -351,10 +597,31 @@ await createPipeline(reader)
|
|
|
351
597
|
}))
|
|
352
598
|
.to(writer);
|
|
353
599
|
|
|
354
|
-
// 2.
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
600
|
+
// 2. Stream Filesystem Directory as Tabular Rows
|
|
601
|
+
const fsReader = new FileSystemReader({
|
|
602
|
+
root: "./src",
|
|
603
|
+
include: ["**/*.ts"],
|
|
604
|
+
hash: "sha256",
|
|
605
|
+
mime: true,
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
for await (const batch of fsReader.read()) {
|
|
609
|
+
for (const file of batch.rows) {
|
|
610
|
+
console.log(`${file.relative_path} (${file.size} bytes) - Hash: ${file.hash}`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// 3. Streaming Dataset Diffing (Async Iterable Events)
|
|
615
|
+
for await (const event of diffRows({
|
|
616
|
+
leftPath: "old.csv",
|
|
617
|
+
rightPath: "new.parquet",
|
|
618
|
+
keys: ["id"],
|
|
619
|
+
ignore: ["updated_at"],
|
|
620
|
+
})) {
|
|
621
|
+
if (event.type === "changed") {
|
|
622
|
+
console.log(`Key ${JSON.stringify(event.key)} changed:`, event.changes);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
358
625
|
```
|
|
359
626
|
|
|
360
627
|
---
|
|
@@ -366,32 +633,49 @@ Rowpipe uses standardized POSIX exit codes:
|
|
|
366
633
|
| Code | Meaning | Description |
|
|
367
634
|
|------|---------|-------------|
|
|
368
635
|
| `0` | Success | Command executed successfully |
|
|
369
|
-
| `1` | Generic
|
|
636
|
+
| `1` | Generic / Diff Mismatch | Runtime error or diff mismatch when `--fail-on-diff` is specified |
|
|
370
637
|
| `2` | Invalid Arguments | Missing or invalid CLI flags or arguments |
|
|
371
638
|
| `3` | Parse Error | Corrupted or malformed CSV/JSON/XLSX input with row/column context |
|
|
372
639
|
| `4` | Validation Failure | Schema validation violations detected |
|
|
640
|
+
| `5` | Duplicate Key Error | Duplicate key encountered during keyed diff under `--duplicate-key error` |
|
|
373
641
|
|
|
374
642
|
---
|
|
375
643
|
|
|
376
644
|
## Memory & Performance Benchmarks
|
|
377
645
|
|
|
378
|
-
|
|
646
|
+
### 1. Pipeline Benchmark (`Filter` -> `Select` -> `Cast` -> `Online Stats`):
|
|
379
647
|
|
|
380
648
|
| Dataset Size | Throughput | Execution Time | Peak RSS Memory | Memory Scaling |
|
|
381
649
|
|--------------|------------|----------------|-----------------|----------------|
|
|
382
650
|
| **100,000 rows** | **~318,000 rows/s** | 0.31s | ~106 MB | $O(1)$ Bounded |
|
|
383
651
|
| **1,000,000 rows** | **~500,000 rows/s** | 2.00s | ~153 MB | $O(1)$ Bounded |
|
|
384
652
|
|
|
385
|
-
|
|
653
|
+
### 2. Diff Engine Benchmark (`rowpipe diff`):
|
|
654
|
+
|
|
655
|
+
| Comparison Size | Memory Limit | Throughput | Peak RSS Memory | Disk Spilled | Result |
|
|
656
|
+
|-----------------|--------------|------------|-----------------|--------------|--------|
|
|
657
|
+
| **2,000,000 rows** (1M vs 1M) | 64 MB | **~73,000 rows/s** | ~145 MB | Active | 100% Exact Match |
|
|
658
|
+
|
|
659
|
+
### 3. Filesystem Streaming Benchmark (`rowpipe files`):
|
|
660
|
+
|
|
661
|
+
| File Count | Operation | Throughput | Peak RSS Memory | Memory Scaling |
|
|
662
|
+
|------------|-----------|------------|-----------------|----------------|
|
|
663
|
+
| **50,000 files** | Stream Traversal + Metadata | **~24,100 files/s** | ~147 MB | $O(1)$ Bounded |
|
|
664
|
+
| **50,000 files** | Filter + Select Pipeline | **~13,800 files/s** | ~147 MB | $O(1)$ Bounded |
|
|
665
|
+
| **50,000 files** | Fast Fingerprint Hashing | **~3,470 files/s** | ~148 MB | $O(1)$ Bounded |
|
|
666
|
+
|
|
667
|
+
To run the benchmarks locally:
|
|
386
668
|
|
|
387
669
|
```bash
|
|
388
670
|
npm run bench
|
|
671
|
+
npm run benchmark:diff
|
|
672
|
+
npm run benchmark:files
|
|
389
673
|
```
|
|
390
674
|
|
|
391
675
|
To enable real-time memory debugging on any command:
|
|
392
676
|
|
|
393
677
|
```bash
|
|
394
|
-
ROWPIPE_DEBUG_MEMORY=1 rowpipe
|
|
678
|
+
ROWPIPE_DEBUG_MEMORY=1 rowpipe files ./huge-directory --hash fast
|
|
395
679
|
```
|
|
396
680
|
|
|
397
681
|
---
|
|
@@ -399,3 +683,5 @@ ROWPIPE_DEBUG_MEMORY=1 rowpipe stats huge.csv
|
|
|
399
683
|
## License
|
|
400
684
|
|
|
401
685
|
MIT
|
|
686
|
+
|
|
687
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DiffOnlyFilter, DiffOutputFormat, DuplicateKeyPolicy } from "../../diff/types.js";
|
|
2
|
+
export interface DiffCommandOptions {
|
|
3
|
+
key?: string;
|
|
4
|
+
format?: DiffOutputFormat;
|
|
5
|
+
only?: DiffOnlyFilter;
|
|
6
|
+
columns?: string;
|
|
7
|
+
ignore?: string;
|
|
8
|
+
limit?: string | number;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
output?: string;
|
|
11
|
+
failOnDiff?: boolean;
|
|
12
|
+
duplicateKey?: DuplicateKeyPolicy;
|
|
13
|
+
coerce?: boolean;
|
|
14
|
+
epsilon?: string | number;
|
|
15
|
+
ignoreCase?: boolean;
|
|
16
|
+
trim?: boolean;
|
|
17
|
+
memoryLimit?: string;
|
|
18
|
+
sheet?: string;
|
|
19
|
+
leftSheet?: string;
|
|
20
|
+
rightSheet?: string;
|
|
21
|
+
from?: string;
|
|
22
|
+
fromLeft?: string;
|
|
23
|
+
fromRight?: string;
|
|
24
|
+
schema?: boolean;
|
|
25
|
+
quiet?: boolean;
|
|
26
|
+
noProgress?: boolean;
|
|
27
|
+
batchSize?: string | number;
|
|
28
|
+
}
|
|
29
|
+
export declare function diffCommand(leftPath: string, rightPath: string, options?: DiffCommandOptions): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA+Jf"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { DiffMismatchError, InvalidArgumentError } from "../../core/errors.js";
|
|
3
|
+
import { computeDiff, diffRows } from "../../diff/engine.js";
|
|
4
|
+
import { formatJson, formatPatchEvent, formatRowEvent, formatSummary, } from "../../diff/reporter.js";
|
|
5
|
+
import { formatNumber } from "../../utils/formatting.js";
|
|
6
|
+
import { parseMemoryLimit } from "../../diff/storage/spillable-index.js";
|
|
7
|
+
export async function diffCommand(leftPath, rightPath, options = {}) {
|
|
8
|
+
if (leftPath === "-" && rightPath === "-") {
|
|
9
|
+
throw new InvalidArgumentError("Cannot diff stdin against stdin ('- -'). One side must be a file or named source.");
|
|
10
|
+
}
|
|
11
|
+
if (!options.key) {
|
|
12
|
+
throw new InvalidArgumentError("Missing required option: --key <column1,column2,...>");
|
|
13
|
+
}
|
|
14
|
+
const keys = options.key.split(",").map((k) => k.trim()).filter(Boolean);
|
|
15
|
+
const compareColumns = options.columns
|
|
16
|
+
? options.columns.split(",").map((c) => c.trim()).filter(Boolean)
|
|
17
|
+
: undefined;
|
|
18
|
+
const ignoreColumns = options.ignore
|
|
19
|
+
? options.ignore.split(",").map((c) => c.trim()).filter(Boolean)
|
|
20
|
+
: undefined;
|
|
21
|
+
const leftSheet = options.leftSheet || options.sheet;
|
|
22
|
+
const rightSheet = options.rightSheet || options.sheet;
|
|
23
|
+
const leftFormat = options.fromLeft || options.from;
|
|
24
|
+
const rightFormat = options.fromRight || options.from;
|
|
25
|
+
const batchSize = Number(options.batchSize) || 1000;
|
|
26
|
+
const leftOptions = {
|
|
27
|
+
sheet: leftSheet,
|
|
28
|
+
format: leftFormat,
|
|
29
|
+
batchSize,
|
|
30
|
+
filePath: leftPath,
|
|
31
|
+
};
|
|
32
|
+
const rightOptions = {
|
|
33
|
+
sheet: rightSheet,
|
|
34
|
+
format: rightFormat,
|
|
35
|
+
batchSize,
|
|
36
|
+
filePath: rightPath,
|
|
37
|
+
};
|
|
38
|
+
const isTty = process.stderr.isTTY && !options.quiet && options.noProgress !== true;
|
|
39
|
+
const onProgress = (info) => {
|
|
40
|
+
if (!isTty)
|
|
41
|
+
return;
|
|
42
|
+
const isSpilledText = info.isSpilled ? " (disk spilled)" : "";
|
|
43
|
+
if (info.phase === "indexing_left") {
|
|
44
|
+
process.stderr.write(`\r\x1b[2K Indexing left: ${formatNumber(info.leftRowsProcessed)} rows${isSpilledText}...`);
|
|
45
|
+
}
|
|
46
|
+
else if (info.phase === "comparing_right") {
|
|
47
|
+
process.stderr.write(`\r\x1b[2K Comparing right: ${formatNumber(info.rightRowsProcessed)} rows [added: ${formatNumber(info.addedCount)}, changed: ${formatNumber(info.changedCount)}, unchanged: ${formatNumber(info.unchangedCount)}]${isSpilledText}...`);
|
|
48
|
+
}
|
|
49
|
+
else if (info.phase === "finishing") {
|
|
50
|
+
process.stderr.write(`\r\x1b[2K Done comparing.\n`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const engineOptions = {
|
|
54
|
+
left: leftPath,
|
|
55
|
+
right: rightPath,
|
|
56
|
+
keys,
|
|
57
|
+
columns: compareColumns,
|
|
58
|
+
ignore: ignoreColumns,
|
|
59
|
+
duplicateKey: options.duplicateKey || "error",
|
|
60
|
+
coerce: options.coerce,
|
|
61
|
+
epsilon: options.epsilon !== undefined ? Number(options.epsilon) : undefined,
|
|
62
|
+
ignoreCase: options.ignoreCase,
|
|
63
|
+
trim: options.trim,
|
|
64
|
+
memoryLimitBytes: parseMemoryLimit(options.memoryLimit),
|
|
65
|
+
includeSchema: options.schema !== false,
|
|
66
|
+
leftOptions,
|
|
67
|
+
rightOptions,
|
|
68
|
+
onProgress,
|
|
69
|
+
};
|
|
70
|
+
const formatMode = options.format || "summary";
|
|
71
|
+
const limit = options.limit !== undefined ? Number(options.limit) : undefined;
|
|
72
|
+
const onlyFilter = options.only;
|
|
73
|
+
let outStream = process.stdout;
|
|
74
|
+
let fileStream = null;
|
|
75
|
+
if (options.output) {
|
|
76
|
+
fileStream = createWriteStream(options.output, "utf-8");
|
|
77
|
+
outStream = fileStream;
|
|
78
|
+
}
|
|
79
|
+
const writeOut = async (chunk) => {
|
|
80
|
+
if (!outStream.write(chunk)) {
|
|
81
|
+
await new Promise((resolve) => outStream.once("drain", resolve));
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
if (options.json || formatMode === "summary") {
|
|
86
|
+
const summary = await computeDiff(engineOptions);
|
|
87
|
+
if (isTty) {
|
|
88
|
+
process.stderr.write("\r\x1b[2K");
|
|
89
|
+
}
|
|
90
|
+
if (options.json) {
|
|
91
|
+
await writeOut(formatJson(summary));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await writeOut(formatSummary(summary));
|
|
95
|
+
}
|
|
96
|
+
const totalDiffs = summary.rows.added + summary.rows.removed + summary.rows.changed;
|
|
97
|
+
if (options.failOnDiff && totalDiffs > 0) {
|
|
98
|
+
throw new DiffMismatchError(totalDiffs);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// -----------------------------------------------------------
|
|
103
|
+
// Streaming row-level output (rows or patch)
|
|
104
|
+
// -----------------------------------------------------------
|
|
105
|
+
let emittedCount = 0;
|
|
106
|
+
let totalDiffCount = 0;
|
|
107
|
+
for await (const event of diffRows(engineOptions)) {
|
|
108
|
+
if (event.type === "added" || event.type === "removed" || event.type === "changed") {
|
|
109
|
+
totalDiffCount++;
|
|
110
|
+
}
|
|
111
|
+
// Filter by --only
|
|
112
|
+
if (onlyFilter && event.type !== onlyFilter) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (limit !== undefined && emittedCount >= limit) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
let formattedText = null;
|
|
119
|
+
if (formatMode === "rows") {
|
|
120
|
+
formattedText = formatRowEvent(event);
|
|
121
|
+
}
|
|
122
|
+
else if (formatMode === "patch") {
|
|
123
|
+
formattedText = formatPatchEvent(event);
|
|
124
|
+
}
|
|
125
|
+
if (formattedText) {
|
|
126
|
+
await writeOut(formattedText);
|
|
127
|
+
emittedCount++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (isTty) {
|
|
131
|
+
process.stderr.write("\r\x1b[2K");
|
|
132
|
+
}
|
|
133
|
+
if (options.failOnDiff && totalDiffCount > 0) {
|
|
134
|
+
throw new DiffMismatchError(totalDiffCount);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
if (fileStream) {
|
|
139
|
+
await new Promise((resolve) => fileStream.end(() => resolve()));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"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"}
|