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 +101 -73
- package/diffx-js.linux-x64-gnu.node +0 -0
- package/index.d.ts +0 -157
- package/package.json +48 -32
- package/examples.ts +0 -320
- package/test.js +0 -326
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# diffx-js
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
4
|
-
"description": "
|
|
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": "
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
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": ">=
|
|
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": "^
|
|
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
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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 };
|