diffx-js 0.5.21 → 0.6.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # diffx-js
2
2
 
3
- A Node.js wrapper for the `diffx` CLI tool.
3
+ Node.js bindings for [diffx](https://github.com/kako-jun/diffx) - semantic diff for structured data (JSON, YAML, TOML, XML, INI, CSV). Powered by Rust via napi-rs for blazing fast performance.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,98 +8,126 @@ A Node.js wrapper for the `diffx` CLI tool.
8
8
  npm install diffx-js
9
9
  ```
10
10
 
11
- This package includes pre-compiled `diffx` binaries for all supported platforms (Linux x64, macOS x64/ARM64, Windows x64), enabling **completely offline installation** with no external downloads required.
12
-
13
11
  ### Supported Platforms
14
12
 
15
- - **Linux x64** - Intel/AMD 64-bit
16
- - **macOS x64** - Intel-based Macs
17
- - **macOS ARM64** - Apple Silicon Macs (M1/M2/M3)
18
- - **Windows x64** - 64-bit Windows
19
-
20
- The appropriate binary is automatically selected at runtime based on your system.
21
-
22
- **Note:** Due to bundling all platform binaries, this package is larger (~20MB) than typical npm packages but provides complete offline functionality.
13
+ | Platform | Architecture |
14
+ |----------|--------------|
15
+ | Linux | x64 (glibc) |
16
+ | Linux | x64 (musl/Alpine) |
17
+ | Linux | ARM64 |
18
+ | macOS | x64 (Intel) |
19
+ | macOS | ARM64 (Apple Silicon) |
20
+ | Windows | x64 |
23
21
 
24
22
  ## Usage
25
23
 
24
+ ### Basic Diff
25
+
26
26
  ```javascript
27
27
  const { diff } = require('diffx-js');
28
28
 
29
- // Compare two JavaScript objects
30
- const old = { name: "Alice", age: 30, city: "Tokyo" };
31
- const newObj = { name: "Alice", age: 31, country: "Japan" };
32
-
33
- const result = diff(old, newObj);
34
-
35
- if (result.length === 0) {
36
- console.log("No differences found.");
37
- } else {
38
- console.log("Differences found:");
39
- for (const change of result) {
40
- console.log(`${change.diffType}: ${change.path}`);
41
- if (change.oldValue !== undefined) {
42
- console.log(` Old: ${change.oldValue}`);
43
- }
44
- if (change.newValue !== undefined) {
45
- console.log(` New: ${change.newValue}`);
46
- }
47
- }
29
+ const old = { name: "Alice", age: 30 };
30
+ const newObj = { name: "Alice", age: 31, city: "Tokyo" };
31
+
32
+ const results = diff(old, newObj);
33
+
34
+ for (const change of results) {
35
+ console.log(`${change.diffType}: ${change.path}`);
36
+ // Modified: age
37
+ // Added: city
48
38
  }
39
+ ```
40
+
41
+ ### With Options
49
42
 
50
- // Compare with options
51
- const data1 = {
52
- values: [1.0001, 2.0002, 3.0003],
53
- metadata: { timestamp: "2024-01-01" }
54
- };
55
- const data2 = {
56
- values: [1.0002, 2.0003, 3.0004],
57
- metadata: { timestamp: "2024-01-02" }
58
- };
59
-
60
- const preciseResult = diff(data1, data2, {
61
- epsilon: 0.001,
62
- ignoreKeysRegex: "timestamp"
43
+ ```javascript
44
+ const results = diff(data1, data2, {
45
+ epsilon: 0.001, // Tolerance for float comparison
46
+ arrayIdKey: 'id', // Match array elements by ID
47
+ ignoreKeysRegex: 'timestamp|updatedAt', // Ignore keys matching regex
48
+ pathFilter: 'user', // Only show diffs in paths containing "user"
49
+ ignoreCase: true, // Ignore case differences
50
+ ignoreWhitespace: true, // Ignore whitespace differences
63
51
  });
52
+ ```
53
+
54
+ ### Parsers
55
+
56
+ Parse various formats to JavaScript objects:
64
57
 
65
- console.log(`Found ${preciseResult.length} significant differences`);
58
+ ```javascript
59
+ const { parseJson, parseYaml, parseToml, parseCsv, parseIni, parseXml } = require('diffx-js');
60
+
61
+ const jsonObj = parseJson('{"name": "Alice"}');
62
+ const yamlObj = parseYaml('name: Alice\nage: 30');
63
+ const tomlObj = parseToml('name = "Alice"');
64
+ const csvArray = parseCsv('name,age\nAlice,30');
65
+ const iniObj = parseIni('[user]\nname = Alice');
66
+ const xmlObj = parseXml('<user><name>Alice</name></user>');
66
67
  ```
67
68
 
69
+ ### Format Output
68
70
 
69
- ### API Reference
70
-
71
- #### `diff(old, new, options?)`
72
- - **old**: The old JavaScript object, array, or primitive value
73
- - **new**: The new JavaScript object, array, or primitive value
74
- - **options**: Optional configuration object
75
- - `epsilon`: Tolerance for floating-point comparisons (default: 0.0)
76
- - `arrayIdKey`: Key to use for array element identification
77
- - `ignoreKeysRegex`: Regex pattern for keys to ignore
78
- - `pathFilter`: Only show differences in paths containing this string
79
- - `outputFormat`: Output format ("diffx", "json", "yaml")
80
- - `showUnchanged`: Show unchanged values as well
81
- - `showTypes`: Show type information in output
82
- - `ignoreWhitespace`: Ignore whitespace differences
83
- - `ignoreCase`: Ignore case differences
84
- - `briefMode`: Report only whether objects differ
85
- - `quietMode`: Suppress normal output; return only results
86
-
87
- #### Return Value
88
- Returns an array of `JsDiffResult` objects, each containing:
89
- - `diffType`: Type of difference ('Added', 'Removed', 'Modified', 'TypeChanged')
90
- - `path`: Path to the changed element
91
- - `oldValue`: Old value (for Modified/TypeChanged/Removed)
92
- - `newValue`: New value (for Modified/TypeChanged/Added)
93
- - `value`: Value (for Removed differences)
71
+ ```javascript
72
+ const { diff, formatOutput } = require('diffx-js');
94
73
 
95
- ## Development
74
+ const results = diff(old, newObj);
75
+ console.log(formatOutput(results, 'json')); // JSON format
76
+ console.log(formatOutput(results, 'yaml')); // YAML format
77
+ console.log(formatOutput(results, 'diffx')); // diffx format
78
+ ```
79
+
80
+ ## API Reference
81
+
82
+ ### `diff(old, new, options?)`
83
+
84
+ Compare two values and return differences.
85
+
86
+ **Options:**
87
+ | Option | Type | Description |
88
+ |--------|------|-------------|
89
+ | `epsilon` | number | Tolerance for floating-point comparisons |
90
+ | `arrayIdKey` | string | Key to identify array elements |
91
+ | `ignoreKeysRegex` | string | Regex pattern for keys to ignore |
92
+ | `pathFilter` | string | Only show diffs in matching paths |
93
+ | `outputFormat` | string | Output format ("diffx", "json", "yaml") |
94
+ | `ignoreWhitespace` | boolean | Ignore whitespace differences |
95
+ | `ignoreCase` | boolean | Ignore case differences |
96
+ | `briefMode` | boolean | Report only whether objects differ |
97
+ | `quietMode` | boolean | Suppress normal output |
98
+
99
+ **Returns:** Array of `JsDiffResult`:
100
+ ```typescript
101
+ interface JsDiffResult {
102
+ diffType: 'Added' | 'Removed' | 'Modified' | 'TypeChanged';
103
+ path: string;
104
+ oldValue?: any; // For Modified/TypeChanged
105
+ newValue?: any; // For Added/Modified/TypeChanged
106
+ value?: any; // For Removed
107
+ }
108
+ ```
109
+
110
+ ### Parsers
111
+
112
+ - `parseJson(content: string): any`
113
+ - `parseYaml(content: string): any`
114
+ - `parseToml(content: string): any`
115
+ - `parseCsv(content: string): any[]`
116
+ - `parseIni(content: string): any`
117
+ - `parseXml(content: string): any`
96
118
 
97
- To link for local development:
119
+ ### `formatOutput(results, format)`
120
+
121
+ Format diff results as string. Format: "json", "yaml", or "diffx".
122
+
123
+ ## Development
98
124
 
99
125
  ```bash
100
- npm link
126
+ npm install # Install dependencies
127
+ npm run build # Build native module
128
+ npm test # Run tests (51 tests)
101
129
  ```
102
130
 
103
131
  ## License
104
132
 
105
- This project is licensed under the MIT License.
133
+ MIT
Binary file
package/index.d.ts CHANGED
@@ -1,157 +0,0 @@
1
- /* tslint:disable */
2
- /* eslint-disable */
3
-
4
- /* auto-generated by NAPI-RS */
5
-
6
- export interface JsDiffOptions {
7
- /** Numerical comparison tolerance */
8
- epsilon?: number
9
- /** Key to use for array element identification */
10
- arrayIdKey?: string
11
- /** Regex pattern for keys to ignore */
12
- ignoreKeysRegex?: string
13
- /** Only show differences in paths containing this string */
14
- pathFilter?: string
15
- /** Output format */
16
- outputFormat?: string
17
- /** Show unchanged values as well */
18
- showUnchanged?: boolean
19
- /** Show type information in output */
20
- showTypes?: boolean
21
- /** Enable memory optimization for large files */
22
- useMemoryOptimization?: boolean
23
- /** Batch size for memory optimization */
24
- batchSize?: number
25
- /** Ignore whitespace differences */
26
- ignoreWhitespace?: boolean
27
- /** Ignore case differences */
28
- ignoreCase?: boolean
29
- /** Report only whether files differ */
30
- briefMode?: boolean
31
- /** Suppress normal output; return only exit status */
32
- quietMode?: boolean
33
- }
34
- export interface JsDiffResult {
35
- /** Type of difference ('Added', 'Removed', 'Modified', 'TypeChanged') */
36
- diffType: string
37
- /** Path to the changed element */
38
- path: string
39
- /** Old value (for Modified/TypeChanged) */
40
- oldValue?: any
41
- /** New value (for Modified/TypeChanged/Added) */
42
- newValue?: any
43
- /** Value (for Removed) */
44
- value?: any
45
- }
46
- /**
47
- * Unified diff function for JavaScript/Node.js
48
- *
49
- * Compare two JavaScript objects or values and return differences.
50
- *
51
- * # Arguments
52
- *
53
- * * `old` - The old value (JavaScript object, array, or primitive)
54
- * * `new` - The new value (JavaScript object, array, or primitive)
55
- * * `options` - Optional configuration object
56
- *
57
- * # Returns
58
- *
59
- * Array of difference objects
60
- *
61
- * # Example
62
- *
63
- * ```javascript
64
- * const { diff } = require('diffx-js');
65
- *
66
- * const old = { a: 1, b: 2 };
67
- * const new = { a: 1, b: 3 };
68
- * const result = diff(old, new);
69
- * console.log(result); // [{ type: 'Modified', path: 'b', oldValue: 2, newValue: 3 }]
70
- * ```
71
- */
72
- export declare function diff(old: any, new: any, options?: JsDiffOptions | undefined | null): Array<JsDiffResult>
73
- /**
74
- * Parse JSON string to JavaScript object
75
- *
76
- * # Arguments
77
- *
78
- * * `content` - JSON string to parse
79
- *
80
- * # Returns
81
- *
82
- * Parsed JavaScript object
83
- */
84
- export declare function parseJson(content: string): any
85
- /**
86
- * Parse CSV string to JavaScript array of objects
87
- *
88
- * # Arguments
89
- *
90
- * * `content` - CSV string to parse
91
- *
92
- * # Returns
93
- *
94
- * Array of JavaScript objects representing CSV rows
95
- */
96
- export declare function parseCsv(content: string): any
97
- /**
98
- * Parse YAML string to JavaScript object
99
- *
100
- * # Arguments
101
- *
102
- * * `content` - YAML string to parse
103
- *
104
- * # Returns
105
- *
106
- * Parsed JavaScript object
107
- */
108
- export declare function parseYaml(content: string): any
109
- /**
110
- * Parse TOML string to JavaScript object
111
- *
112
- * # Arguments
113
- *
114
- * * `content` - TOML string to parse
115
- *
116
- * # Returns
117
- *
118
- * Parsed JavaScript object
119
- */
120
- export declare function parseToml(content: string): any
121
- /**
122
- * Parse INI string to JavaScript object
123
- *
124
- * # Arguments
125
- *
126
- * * `content` - INI string to parse
127
- *
128
- * # Returns
129
- *
130
- * Parsed JavaScript object
131
- */
132
- export declare function parseIni(content: string): any
133
- /**
134
- * Parse XML string to JavaScript object
135
- *
136
- * # Arguments
137
- *
138
- * * `content` - XML string to parse
139
- *
140
- * # Returns
141
- *
142
- * Parsed JavaScript object
143
- */
144
- export declare function parseXml(content: string): any
145
- /**
146
- * Format diff results as string
147
- *
148
- * # Arguments
149
- *
150
- * * `results` - Array of diff results
151
- * * `format` - Output format ("diffx", "json", "yaml")
152
- *
153
- * # Returns
154
- *
155
- * Formatted string output
156
- */
157
- export declare function formatOutput(results: Array<JsDiffResult>, format: string): string
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "diffx-js",
3
- "version": "0.5.21",
4
- "description": "A Node.js wrapper for the diffx CLI tool - semantic diffing of JSON, YAML, TOML, XML, INI, and CSV files. Focuses on structural meaning rather than formatting.",
3
+ "version": "0.6.1",
4
+ "description": "Node.js bindings for diffx - semantic diffing of JSON, YAML, TOML, XML, INI, and CSV files. Powered by Rust for blazing fast performance.",
5
5
  "keywords": [
6
6
  "diff",
7
7
  "json",
@@ -10,7 +10,6 @@
10
10
  "xml",
11
11
  "ini",
12
12
  "csv",
13
- "cli",
14
13
  "structured",
15
14
  "configuration",
16
15
  "semantic",
@@ -18,29 +17,30 @@
18
17
  "devops",
19
18
  "ci-cd",
20
19
  "automation",
21
- "data-analysis"
20
+ "data-analysis",
21
+ "napi-rs",
22
+ "rust"
22
23
  ],
23
24
  "main": "index.js",
24
25
  "types": "index.d.ts",
25
26
  "scripts": {
26
27
  "build": "napi build --platform --release",
27
28
  "build:debug": "napi build --platform",
28
- "test": "npm run build && cd tests && npm test",
29
- "examples": "npm run build && npx tsx examples.ts",
30
- "verify": "npm run build && node -e \"console.log(require('./index.js'))\"",
31
- "prepublish": "npm run build",
32
- "artifacts": "napi artifacts"
29
+ "test": "jest",
30
+ "test:watch": "jest --watch",
31
+ "test:coverage": "jest --coverage",
32
+ "prepublishOnly": "napi prepublish -t npm",
33
+ "artifacts": "napi artifacts",
34
+ "version": "napi version",
35
+ "prepare": "husky"
33
36
  },
34
37
  "engines": {
35
- "node": ">=12.0.0"
38
+ "node": ">=16.0.0"
36
39
  },
37
40
  "files": [
38
41
  "index.js",
39
42
  "index.d.ts",
40
- "*.node",
41
- "README.md",
42
- "examples.ts",
43
- "test.js"
43
+ "*.node"
44
44
  ],
45
45
  "os": [
46
46
  "linux",
@@ -53,34 +53,50 @@
53
53
  ],
54
54
  "author": "kako-jun",
55
55
  "license": "MIT",
56
- "homepage": "https://github.com/kako-jun/diffx",
56
+ "homepage": "https://github.com/kako-jun/diffx-js",
57
57
  "repository": {
58
58
  "type": "git",
59
- "url": "git+https://github.com/kako-jun/diffx.git",
60
- "directory": "diffx-js"
59
+ "url": "git+https://github.com/kako-jun/diffx-js.git"
61
60
  },
62
61
  "bugs": {
63
- "url": "https://github.com/kako-jun/diffx/issues"
62
+ "url": "https://github.com/kako-jun/diffx-js/issues"
64
63
  },
65
64
  "funding": {
66
65
  "type": "github",
67
66
  "url": "https://github.com/sponsors/kako-jun"
68
67
  },
69
68
  "devDependencies": {
70
- "@napi-rs/cli": "^2.18.0"
69
+ "@napi-rs/cli": "^3.5.0",
70
+ "husky": "^9.1.7",
71
+ "jest": "^30.2.0"
72
+ },
73
+ "jest": {
74
+ "testEnvironment": "node",
75
+ "roots": [
76
+ "<rootDir>/tests"
77
+ ],
78
+ "testMatch": [
79
+ "**/*.test.js"
80
+ ],
81
+ "forceExit": true
71
82
  },
72
83
  "napi": {
73
- "name": "diffx-js",
74
- "triples": {
75
- "defaults": false,
76
- "additional": [
77
- "x86_64-pc-windows-msvc",
78
- "aarch64-pc-windows-msvc",
79
- "x86_64-apple-darwin",
80
- "aarch64-apple-darwin",
81
- "x86_64-unknown-linux-gnu",
82
- "aarch64-unknown-linux-gnu"
83
- ]
84
- }
84
+ "binaryName": "diffx-js",
85
+ "targets": [
86
+ "x86_64-unknown-linux-gnu",
87
+ "x86_64-unknown-linux-musl",
88
+ "aarch64-unknown-linux-gnu",
89
+ "x86_64-apple-darwin",
90
+ "aarch64-apple-darwin",
91
+ "x86_64-pc-windows-msvc"
92
+ ]
93
+ },
94
+ "optionalDependencies": {
95
+ "diffx-js-linux-x64-gnu": "0.6.1",
96
+ "diffx-js-linux-x64-musl": "0.6.1",
97
+ "diffx-js-linux-arm64-gnu": "0.6.1",
98
+ "diffx-js-darwin-x64": "0.6.1",
99
+ "diffx-js-darwin-arm64": "0.6.1",
100
+ "diffx-js-win32-x64-msvc": "0.6.1"
85
101
  }
86
- }
102
+ }
package/examples.ts DELETED
@@ -1,320 +0,0 @@
1
- #!/usr/bin/env tsx
2
-
3
- /**
4
- * diffx-js TypeScript Examples - UNIFIED API DESIGN
5
- *
6
- * Demonstrates native NAPI-RS API usage for semantic diffing
7
- * Users parse files themselves and call the unified diff() function
8
- */
9
-
10
- import { diff, DiffOptions, DiffResult } from './index';
11
- import * as fs from 'fs';
12
- import * as path from 'path';
13
- import * as os from 'os';
14
-
15
- // Colors for console output
16
- const colors = {
17
- green: '\x1b[32m',
18
- red: '\x1b[31m',
19
- yellow: '\x1b[33m',
20
- blue: '\x1b[34m',
21
- cyan: '\x1b[36m',
22
- magenta: '\x1b[35m',
23
- reset: '\x1b[0m'
24
- } as const;
25
-
26
- function log(message: string, color: keyof typeof colors = 'reset'): void {
27
- console.log(`${colors[color]}${message}${colors.reset}`);
28
- }
29
-
30
- function header(message: string): void {
31
- log(`\n${message}`, 'cyan');
32
- log('='.repeat(message.length), 'cyan');
33
- }
34
-
35
- function example(title: string, description: string): void {
36
- log(`\n${title}`, 'yellow');
37
- log(` ${description}`, 'blue');
38
- }
39
-
40
- async function runExamples(): Promise<void> {
41
- header('diffx-js Native API Examples');
42
-
43
- // Create temporary directory
44
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'diffx-examples-'));
45
- const oldCwd = process.cwd();
46
- process.chdir(tempDir);
47
-
48
- try {
49
- // Example 1: Basic JSON Configuration Comparison
50
- header('1. Basic JSON Configuration Comparison');
51
-
52
- const config1 = {
53
- app: {
54
- name: "my-app",
55
- version: "1.0.0",
56
- database: {
57
- host: "localhost",
58
- port: 5432,
59
- ssl: false
60
- }
61
- },
62
- features: ["auth", "logging"]
63
- };
64
-
65
- const config2 = {
66
- app: {
67
- name: "my-app",
68
- version: "1.1.0",
69
- database: {
70
- host: "prod-db.example.com",
71
- port: 5432,
72
- ssl: true
73
- }
74
- },
75
- features: ["auth", "logging", "metrics"]
76
- };
77
-
78
- example(
79
- 'Application Configuration Migration',
80
- 'Compare two versions of app configuration using native API'
81
- );
82
-
83
- const results1 = diff(config1, config2);
84
- log('API Results:', 'green');
85
- console.log(JSON.stringify(results1, null, 2));
86
-
87
- // Example 2: YAML Configuration with Options
88
- header('2. Advanced Options Usage');
89
-
90
- const oldYaml = `
91
- name: CI
92
- on:
93
- push:
94
- branches: [main]
95
- jobs:
96
- test:
97
- runs-on: ubuntu-latest
98
- steps:
99
- - uses: actions/checkout@v3
100
- - run: npm test
101
- `;
102
-
103
- const newYaml = `
104
- name: CI
105
- on:
106
- push:
107
- branches: [main, develop]
108
- jobs:
109
- test:
110
- runs-on: ubuntu-latest
111
- strategy:
112
- matrix:
113
- node-version: [16, 18, 20]
114
- steps:
115
- - uses: actions/checkout@v4
116
- - run: npm ci
117
- - run: npm test
118
- `;
119
-
120
- // Parse YAML using js-yaml (users would do this)
121
- const yaml = await import('js-yaml');
122
- const oldData = yaml.load(oldYaml) as any;
123
- const newData = yaml.load(newYaml) as any;
124
-
125
- const options: DiffOptions = {
126
- outputFormat: 'json',
127
- showTypes: true,
128
- ignoreKeysRegex: '^(timestamp|updated_at)',
129
- diffxOptions: {
130
- ignoreWhitespace: true,
131
- contextLines: 2
132
- }
133
- };
134
-
135
- example(
136
- 'YAML Comparison with Advanced Options',
137
- 'Parse YAML yourself and use diffx options for customized output'
138
- );
139
-
140
- const results2 = diff(oldData, newData, options);
141
- log('Filtered Results:', 'green');
142
- console.log(JSON.stringify(results2, null, 2));
143
-
144
- // Example 3: Array Comparison with ID Key
145
- header('3. Smart Array Comparison');
146
-
147
- const oldUsers = {
148
- users: [
149
- { id: 1, name: "Alice", role: "admin" },
150
- { id: 2, name: "Bob", role: "user" },
151
- { id: 3, name: "Charlie", role: "user" }
152
- ]
153
- };
154
-
155
- const newUsers = {
156
- users: [
157
- { id: 1, name: "Alice", role: "admin" },
158
- { id: 2, name: "Bob", role: "moderator" },
159
- { id: 4, name: "David", role: "user" }
160
- ]
161
- };
162
-
163
- const arrayOptions: DiffOptions = {
164
- arrayIdKey: 'id',
165
- showUnchanged: false
166
- };
167
-
168
- example(
169
- 'User Management Changes with Array ID Matching',
170
- 'Track user changes by ID rather than array position'
171
- );
172
-
173
- const results3 = diff(oldUsers, newUsers, arrayOptions);
174
- log('User Changes:', 'green');
175
- results3.forEach((result: DiffResult) => {
176
- console.log(`${result.type}: ${result.path}`);
177
- if (result.oldValue) console.log(` Old: ${JSON.stringify(result.oldValue)}`);
178
- if (result.newValue) console.log(` New: ${JSON.stringify(result.newValue)}`);
179
- });
180
-
181
- // Example 4: Error Handling
182
- header('4. Error Handling');
183
-
184
- example(
185
- 'Handling Invalid Data Gracefully',
186
- 'Demonstrate proper error handling for malformed data'
187
- );
188
-
189
- try {
190
- // Simulate circular reference (not serializable)
191
- const circularObj: any = { name: "test" };
192
- circularObj.self = circularObj;
193
-
194
- diff({ valid: "data" }, circularObj);
195
- } catch (error) {
196
- log(`Caught expected error: ${error}`, 'red');
197
- }
198
-
199
- // Example 5: Performance with Large Data
200
- header('5. Large Data Performance');
201
-
202
- const largeData1 = {
203
- items: Array.from({ length: 1000 }, (_, i) => ({
204
- id: i,
205
- value: Math.random(),
206
- category: `cat_${i % 10}`
207
- }))
208
- };
209
-
210
- const largeData2 = {
211
- items: Array.from({ length: 1000 }, (_, i) => ({
212
- id: i,
213
- value: Math.random(),
214
- category: `cat_${i % 10}`,
215
- newField: i % 100 === 0 ? "special" : undefined
216
- })).filter(item => item.newField !== undefined || Math.random() > 0.1)
217
- };
218
-
219
- const perfOptions: DiffOptions = {
220
- useMemoryOptimization: true,
221
- batchSize: 100,
222
- arrayIdKey: 'id'
223
- };
224
-
225
- example(
226
- 'Large Dataset Comparison with Memory Optimization',
227
- 'Handle large datasets efficiently with batching'
228
- );
229
-
230
- const startTime = Date.now();
231
- const results5 = diff(largeData1, largeData2, perfOptions);
232
- const endTime = Date.now();
233
-
234
- log(`Processed ${results5.length} differences in ${endTime - startTime}ms`, 'green');
235
-
236
- // Example 6: TypeScript Integration Patterns
237
- header('6. TypeScript Integration Patterns');
238
-
239
- interface ConfigSchema {
240
- database: {
241
- host: string;
242
- port: number;
243
- ssl: boolean;
244
- };
245
- features: string[];
246
- }
247
-
248
- const typedConfig1: ConfigSchema = {
249
- database: { host: "localhost", port: 5432, ssl: false },
250
- features: ["auth"]
251
- };
252
-
253
- const typedConfig2: ConfigSchema = {
254
- database: { host: "remote", port: 5433, ssl: true },
255
- features: ["auth", "logging"]
256
- };
257
-
258
- example(
259
- 'Type-Safe Configuration Comparison',
260
- 'Use TypeScript interfaces for better development experience'
261
- );
262
-
263
- const results6 = diff(typedConfig1, typedConfig2);
264
-
265
- // Type-safe result processing
266
- results6.forEach((result: DiffResult) => {
267
- switch (result.type) {
268
- case 'added':
269
- log(`➕ Added: ${result.path} = ${JSON.stringify(result.newValue)}`, 'green');
270
- break;
271
- case 'removed':
272
- log(`➖ Removed: ${result.path} = ${JSON.stringify(result.oldValue)}`, 'red');
273
- break;
274
- case 'modified':
275
- log(`🔄 Modified: ${result.path}`, 'yellow');
276
- log(` Old: ${JSON.stringify(result.oldValue)}`, 'red');
277
- log(` New: ${JSON.stringify(result.newValue)}`, 'green');
278
- break;
279
- case 'typeChanged':
280
- log(`🔀 Type Changed: ${result.path} (${result.oldType} → ${result.newType})`, 'magenta');
281
- break;
282
- }
283
- });
284
-
285
- // Summary
286
- header('Summary');
287
- log('✅ All examples completed successfully!', 'green');
288
- log('\nKey Benefits of Native API:', 'cyan');
289
- log(' • No external CLI dependency', 'blue');
290
- log(' • Better error handling', 'blue');
291
- log(' • Type safety with TypeScript', 'blue');
292
- log(' • Memory efficient for large data', 'blue');
293
- log(' • Customizable output formats', 'blue');
294
- log(' • Integration-friendly', 'blue');
295
-
296
- log('\nNext Steps:', 'cyan');
297
- log(' • See TypeScript definitions for full API', 'blue');
298
- log(' • Check documentation for advanced options', 'blue');
299
- log(' • Integrate into your CI/CD pipeline', 'blue');
300
-
301
- } catch (error) {
302
- log(`\nError running examples: ${error}`, 'red');
303
- console.error(error);
304
- } finally {
305
- // Cleanup
306
- process.chdir(oldCwd);
307
- try {
308
- fs.rmSync(tempDir, { recursive: true, force: true });
309
- } catch (cleanupErr) {
310
- log(`Cleanup warning: ${cleanupErr}`, 'yellow');
311
- }
312
- }
313
- }
314
-
315
- // Run examples if called directly
316
- if (require.main === module) {
317
- runExamples().catch(console.error);
318
- }
319
-
320
- export { runExamples };
package/test.js DELETED
@@ -1,326 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Test script for diffx-js npm package
5
- * Verifies basic functionality and integration
6
- */
7
-
8
- const { spawn } = require('child_process');
9
- const fs = require('fs');
10
- const path = require('path');
11
- const os = require('os');
12
-
13
- // Colors for output
14
- const colors = {
15
- green: '\x1b[32m',
16
- red: '\x1b[31m',
17
- yellow: '\x1b[33m',
18
- blue: '\x1b[34m',
19
- reset: '\x1b[0m'
20
- };
21
-
22
- function log(message, color = 'reset') {
23
- console.log(`${colors[color]}${message}${colors.reset}`);
24
- }
25
-
26
- function success(message) {
27
- log(`PASS: ${message}`, 'green');
28
- }
29
-
30
- function error(message) {
31
- log(`ERROR: ${message}`, 'red');
32
- }
33
-
34
- function info(message) {
35
- log(`INFO: ${message}`, 'blue');
36
- }
37
-
38
- // Test data
39
- const testData = {
40
- json1: '{"name": "test-app", "version": "1.0.0", "debug": true}',
41
- json2: '{"debug": false, "version": "1.1.0", "name": "test-app"}',
42
- yaml1: 'name: test-app\nversion: "1.0.0"\ndebug: true\n',
43
- yaml2: 'name: test-app\nversion: "1.1.0"\ndebug: false\n',
44
-
45
- // Test data for new options
46
- caseTest1: '{"status": "Active", "level": "Info"}',
47
- caseTest2: '{"status": "ACTIVE", "level": "INFO"}',
48
- whitespaceTest1: '{"text": "Hello World", "message": "Test\\tValue"}',
49
- whitespaceTest2: '{"text": "Hello World", "message": "Test Value"}',
50
- contextTest1: '{"host": "localhost", "port": 5432, "name": "myapp"}',
51
- contextTest2: '{"host": "localhost", "port": 5433, "name": "myapp"}'
52
- };
53
-
54
- // Create temporary test directory
55
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'diffx-test-'));
56
- process.chdir(tempDir);
57
-
58
- async function runCommand(command, args = [], options = {}) {
59
- return new Promise((resolve, reject) => {
60
- const child = spawn(command, args, {
61
- stdio: ['pipe', 'pipe', 'pipe'],
62
- ...options
63
- });
64
-
65
- let stdout = '';
66
- let stderr = '';
67
-
68
- child.stdout.on('data', (data) => {
69
- stdout += data.toString();
70
- });
71
-
72
- child.stderr.on('data', (data) => {
73
- stderr += data.toString();
74
- });
75
-
76
- child.on('close', (code) => {
77
- resolve({ code, stdout, stderr });
78
- });
79
-
80
- child.on('error', (err) => {
81
- reject(err);
82
- });
83
- });
84
- }
85
-
86
- async function runTests() {
87
- info('Starting diffx-js package tests...');
88
-
89
- try {
90
- // Test 1: Check if diffx command is available
91
- info('Test 1: Checking diffx command availability...');
92
- const versionResult = await runCommand('node', [path.join(__dirname, 'index.js'), '--version']);
93
- if (versionResult.code === 0) {
94
- success(`diffx command available: ${versionResult.stdout.trim()}`);
95
- } else {
96
- error('diffx command not available');
97
- throw new Error('Command not available');
98
- }
99
-
100
- // Test 2: Help command
101
- info('Test 2: Testing help command...');
102
- const helpResult = await runCommand('node', [path.join(__dirname, 'index.js'), '--help']);
103
- if (helpResult.code === 0 && helpResult.stdout.includes('diffx')) {
104
- success('Help command works correctly');
105
- } else {
106
- error('Help command failed');
107
- throw new Error('Help command failed');
108
- }
109
-
110
- // Test 3: Basic JSON diff
111
- info('Test 3: Testing basic JSON diff...');
112
- fs.writeFileSync('test1.json', testData.json1);
113
- fs.writeFileSync('test2.json', testData.json2);
114
-
115
- const diffResult = await runCommand('node', [
116
- path.join(__dirname, 'index.js'),
117
- 'test1.json',
118
- 'test2.json'
119
- ]);
120
-
121
- if (diffResult.code === 1 &&
122
- diffResult.stdout.includes('version') &&
123
- diffResult.stdout.includes('debug')) {
124
- success('Basic JSON diff works correctly');
125
- } else {
126
- error(`JSON diff failed. Code: ${diffResult.code}, Stdout: ${diffResult.stdout}, Stderr: ${diffResult.stderr}`);
127
- throw new Error('JSON diff failed');
128
- }
129
-
130
- // Test 4: JSON output format
131
- info('Test 4: Testing JSON output format...');
132
- const jsonOutputResult = await runCommand('node', [
133
- path.join(__dirname, 'index.js'),
134
- 'test1.json',
135
- 'test2.json',
136
- '--output',
137
- 'json'
138
- ]);
139
-
140
- if (jsonOutputResult.code === 1) {
141
- try {
142
- const output = JSON.parse(jsonOutputResult.stdout);
143
- if (Array.isArray(output) && output.length > 0) {
144
- success('JSON output format works correctly');
145
- } else {
146
- error('JSON output format invalid structure');
147
- throw new Error('Invalid JSON structure');
148
- }
149
- } catch (parseError) {
150
- error(`JSON output parsing failed: ${parseError.message}`);
151
- throw new Error('JSON parsing failed');
152
- }
153
- } else {
154
- error(`JSON output failed: ${jsonOutputResult.stderr}`);
155
- throw new Error('JSON output failed');
156
- }
157
-
158
- // Test 5: YAML files
159
- info('Test 5: Testing YAML file diff...');
160
- fs.writeFileSync('test1.yaml', testData.yaml1);
161
- fs.writeFileSync('test2.yaml', testData.yaml2);
162
-
163
- const yamlResult = await runCommand('node', [
164
- path.join(__dirname, 'index.js'),
165
- 'test1.yaml',
166
- 'test2.yaml'
167
- ]);
168
-
169
- if (yamlResult.code === 1 && yamlResult.stdout.includes('version')) {
170
- success('YAML diff works correctly');
171
- } else {
172
- error(`YAML diff failed: ${yamlResult.stderr}`);
173
- throw new Error('YAML diff failed');
174
- }
175
-
176
- // Test 6: Stdin processing
177
- info('Test 6: Testing stdin processing...');
178
-
179
- // Use spawn directly with proper stdin handling
180
- const stdinChild = spawn('node', [
181
- path.join(__dirname, 'index.js'),
182
- '-',
183
- path.join(__dirname, 'fixtures', 'test2.json')
184
- ], { stdio: ['pipe', 'pipe', 'pipe'] });
185
-
186
- stdinChild.stdin.write(testData.json1);
187
- stdinChild.stdin.end();
188
-
189
- let stdinOutput = '';
190
- stdinChild.stdout.on('data', (data) => {
191
- stdinOutput += data.toString();
192
- });
193
-
194
- const stdinExitCode = await new Promise((resolve) => {
195
- stdinChild.on('close', (code) => resolve(code));
196
- });
197
-
198
- if (stdinExitCode === 1 && stdinOutput.includes('debug')) {
199
- success('Stdin processing works correctly');
200
- } else {
201
- info(`Stdin test result: exit code ${stdinExitCode}, output length: ${stdinOutput.length}`);
202
- }
203
-
204
- // Test 7: Error handling
205
- info('Test 7: Testing error handling...');
206
- const errorResult = await runCommand('node', [
207
- path.join(__dirname, 'index.js'),
208
- 'nonexistent1.json',
209
- 'nonexistent2.json'
210
- ]);
211
-
212
- if (errorResult.code !== 0) {
213
- success('Error handling works correctly');
214
- } else {
215
- error('Error handling failed - should have failed with nonexistent files');
216
- throw new Error('Error handling failed');
217
- }
218
-
219
- // Test 8: Platform-specific binary verification
220
- info('Test 8: Testing platform-specific binary verification...');
221
-
222
- const platform = process.platform;
223
- const arch = process.arch;
224
- let expectedBinaryPath;
225
-
226
- if (platform === 'win32') {
227
- expectedBinaryPath = path.join(__dirname, 'bin', 'win32-x64', 'diffx.exe');
228
- } else if (platform === 'darwin') {
229
- if (arch === 'arm64') {
230
- expectedBinaryPath = path.join(__dirname, 'bin', 'darwin-arm64', 'diffx');
231
- } else {
232
- expectedBinaryPath = path.join(__dirname, 'bin', 'darwin-x64', 'diffx');
233
- }
234
- } else if (platform === 'linux') {
235
- expectedBinaryPath = path.join(__dirname, 'bin', 'linux-x64', 'diffx');
236
- }
237
-
238
- if (fs.existsSync(expectedBinaryPath)) {
239
- success(`Platform-specific binary found: ${expectedBinaryPath}`);
240
- } else {
241
- error(`Platform-specific binary not found: ${expectedBinaryPath}`);
242
- throw new Error('Platform binary missing');
243
- }
244
-
245
- // Test 9: API functionality with new options
246
- info('Test 9: Testing API functionality with new options...');
247
-
248
- // Test ignore case option
249
- try {
250
- const { diff, diffString } = require('./lib.js');
251
-
252
- // Test ignore case
253
- const caseResult = await diffString(testData.caseTest1, testData.caseTest2, 'json', {
254
- ignoreCase: true,
255
- output: 'json'
256
- });
257
-
258
- if (Array.isArray(caseResult) && caseResult.length === 0) {
259
- success('API ignore-case option works correctly');
260
- } else {
261
- info('API ignore-case test completed (may show differences)');
262
- }
263
-
264
- // Test ignore whitespace
265
- const whitespaceResult = await diffString(testData.whitespaceTest1, testData.whitespaceTest2, 'json', {
266
- ignoreWhitespace: true,
267
- output: 'json'
268
- });
269
-
270
- if (Array.isArray(whitespaceResult) && whitespaceResult.length === 0) {
271
- success('API ignore-whitespace option works correctly');
272
- } else {
273
- info('API ignore-whitespace test completed (may show differences)');
274
- }
275
-
276
- // Test quiet option
277
- const quietResult = await diffString(testData.json1, testData.json2, 'json', {
278
- quiet: true
279
- });
280
-
281
- if (quietResult === '') {
282
- success('API quiet option works correctly');
283
- } else {
284
- info('API quiet test completed');
285
- }
286
-
287
- // Test brief option
288
- const briefResult = await diffString(testData.json1, testData.json2, 'json', {
289
- brief: true
290
- });
291
-
292
- if (typeof briefResult === 'string') {
293
- success('API brief option works correctly');
294
- } else {
295
- info('API brief test completed');
296
- }
297
-
298
- success('API tests completed successfully');
299
-
300
- } catch (apiErr) {
301
- info(`API test completed with info: ${apiErr.message}`);
302
- }
303
-
304
- success('All tests passed!');
305
- info('diffx-js package is working correctly');
306
-
307
- } catch (err) {
308
- error(`Test failed: ${err.message}`);
309
- process.exit(1);
310
- } finally {
311
- // Cleanup
312
- process.chdir(__dirname);
313
- try {
314
- fs.rmSync(tempDir, { recursive: true, force: true });
315
- } catch (cleanupErr) {
316
- info(`Cleanup warning: ${cleanupErr.message}`);
317
- }
318
- }
319
- }
320
-
321
- // Run tests if called directly
322
- if (require.main === module) {
323
- runTests();
324
- }
325
-
326
- module.exports = { runTests };