@unrift/core 0.0.0 → 0.2.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.
Files changed (54) hide show
  1. package/dist/esm/cli.js +75 -5
  2. package/dist/esm/expect.d.ts +8 -0
  3. package/dist/esm/expect.d.ts.map +1 -1
  4. package/dist/esm/expect.js +54 -4
  5. package/dist/esm/index.d.ts +3 -2
  6. package/dist/esm/index.d.ts.map +1 -1
  7. package/dist/esm/index.js +1 -1
  8. package/dist/esm/interface.d.ts +4 -1
  9. package/dist/esm/interface.d.ts.map +1 -1
  10. package/dist/esm/interface.js +4 -1
  11. package/dist/esm/matchers.d.ts +1 -0
  12. package/dist/esm/matchers.d.ts.map +1 -1
  13. package/dist/esm/matchers.js +61 -0
  14. package/dist/esm/run.d.ts +1 -1
  15. package/dist/esm/run.d.ts.map +1 -1
  16. package/dist/esm/run.js +3 -4
  17. package/dist/esm/runner.d.ts.map +1 -1
  18. package/dist/esm/runner.js +201 -33
  19. package/dist/esm/suite.d.ts +2 -10
  20. package/dist/esm/suite.d.ts.map +1 -1
  21. package/dist/esm/suite.js +29 -10
  22. package/dist/esm/test.d.ts +1 -7
  23. package/dist/esm/test.d.ts.map +1 -1
  24. package/dist/esm/test.js +11 -2
  25. package/dist/esm/types.d.ts +3 -3
  26. package/dist/esm/types.d.ts.map +1 -1
  27. package/dist/esm/types.js +1 -0
  28. package/dist/esm/utils/colors.d.ts +21 -0
  29. package/dist/esm/utils/colors.d.ts.map +1 -1
  30. package/dist/esm/utils/colors.js +34 -4
  31. package/dist/esm/utils/compareEngine.d.ts +10 -0
  32. package/dist/esm/utils/compareEngine.d.ts.map +1 -0
  33. package/dist/esm/utils/compareEngine.js +222 -0
  34. package/dist/esm/utils/deepEqual.d.ts.map +1 -1
  35. package/dist/esm/utils/deepEqual.js +7 -185
  36. package/dist/esm/utils/diff.d.ts +2 -0
  37. package/dist/esm/utils/diff.d.ts.map +1 -0
  38. package/dist/esm/utils/diff.js +84 -0
  39. package/dist/esm/utils/discoverTestFiles.d.ts.map +1 -1
  40. package/dist/esm/utils/discoverTestFiles.js +17 -2
  41. package/dist/esm/utils/looseEqual.d.ts +9 -0
  42. package/dist/esm/utils/looseEqual.d.ts.map +1 -1
  43. package/dist/esm/utils/looseEqual.js +16 -197
  44. package/dist/esm/utils/normalizePath.d.ts +2 -0
  45. package/dist/esm/utils/normalizePath.d.ts.map +1 -0
  46. package/dist/esm/utils/normalizePath.js +4 -0
  47. package/dist/esm/utils/toError.d.ts +2 -0
  48. package/dist/esm/utils/toError.d.ts.map +1 -0
  49. package/dist/esm/utils/toError.js +3 -0
  50. package/dist/esm/utils/toThrow.d.ts.map +1 -1
  51. package/dist/esm/utils/toThrow.js +12 -1
  52. package/dist/esm/utils/transform.d.ts.map +1 -1
  53. package/dist/esm/utils/transform.js +31 -21
  54. package/package.json +21 -3
@@ -0,0 +1,222 @@
1
+ import { isObjectLike, isPrimitive, isTypedArray, sameValue, } from "./helpers.js";
2
+ export function compareInternal(left, right, options, leftToRightSeen, rightToLeftSeen) {
3
+ const worklist = [[left, right]];
4
+ while (worklist.length) {
5
+ const [currentLeft, currentRight] = worklist.pop();
6
+ if (sameValue(currentLeft, currentRight))
7
+ continue;
8
+ if (typeof currentLeft !== typeof currentRight)
9
+ return false;
10
+ if (isPrimitive(currentLeft) || isPrimitive(currentRight))
11
+ return false;
12
+ if (!isObjectLike(currentLeft) || !isObjectLike(currentRight))
13
+ return false;
14
+ const leftObj = currentLeft;
15
+ const rightObj = currentRight;
16
+ // Cycle detection
17
+ const mappedRight = leftToRightSeen.get(leftObj);
18
+ if (mappedRight !== undefined) {
19
+ if (mappedRight !== rightObj)
20
+ return false;
21
+ continue;
22
+ }
23
+ if (options.bijectiveCycleCheck && rightToLeftSeen) {
24
+ const mappedLeft = rightToLeftSeen.get(rightObj);
25
+ if (mappedLeft !== undefined) {
26
+ if (mappedLeft !== leftObj)
27
+ return false;
28
+ continue;
29
+ }
30
+ rightToLeftSeen.set(rightObj, leftObj);
31
+ }
32
+ leftToRightSeen.set(leftObj, rightObj);
33
+ // Arrays
34
+ const leftIsArray = Array.isArray(currentLeft);
35
+ const rightIsArray = Array.isArray(currentRight);
36
+ if (leftIsArray || rightIsArray) {
37
+ if (!leftIsArray || !rightIsArray)
38
+ return false;
39
+ const leftArr = currentLeft;
40
+ const rightArr = currentRight;
41
+ if (leftArr.length !== rightArr.length)
42
+ return false;
43
+ for (let index = 0; index < leftArr.length; index++) {
44
+ if (options.treatSparseAsUndefined) {
45
+ const leftValue = Object.hasOwn(leftArr, index)
46
+ ? leftArr[index]
47
+ : undefined;
48
+ const rightValue = Object.hasOwn(rightArr, index)
49
+ ? rightArr[index]
50
+ : undefined;
51
+ worklist.push([leftValue, rightValue]);
52
+ }
53
+ else {
54
+ worklist.push([leftArr[index], rightArr[index]]);
55
+ }
56
+ }
57
+ continue;
58
+ }
59
+ // Typed arrays
60
+ const leftIsTyped = isTypedArray(currentLeft);
61
+ const rightIsTyped = isTypedArray(currentRight);
62
+ if (leftIsTyped || rightIsTyped) {
63
+ if (!leftIsTyped || !rightIsTyped)
64
+ return false;
65
+ const leftTA = currentLeft;
66
+ const rightTA = currentRight;
67
+ if (leftTA.constructor !== rightTA.constructor)
68
+ return false;
69
+ if (leftTA.length !== rightTA.length)
70
+ return false;
71
+ for (let index = 0; index < leftTA.length; index++) {
72
+ if (!sameValue(leftTA[index], rightTA[index]))
73
+ return false;
74
+ }
75
+ continue;
76
+ }
77
+ // ArrayBuffer
78
+ const leftIsBuffer = currentLeft instanceof ArrayBuffer;
79
+ const rightIsBuffer = currentRight instanceof ArrayBuffer;
80
+ if (leftIsBuffer || rightIsBuffer) {
81
+ if (!leftIsBuffer || !rightIsBuffer)
82
+ return false;
83
+ const leftBuf = currentLeft;
84
+ const rightBuf = currentRight;
85
+ if (leftBuf.byteLength !== rightBuf.byteLength)
86
+ return false;
87
+ const leftBytes = new Uint8Array(leftBuf);
88
+ const rightBytes = new Uint8Array(rightBuf);
89
+ for (let index = 0; index < leftBytes.length; index++) {
90
+ if (leftBytes[index] !== rightBytes[index])
91
+ return false;
92
+ }
93
+ continue;
94
+ }
95
+ // DataView
96
+ const leftIsView = currentLeft instanceof DataView;
97
+ const rightIsView = currentRight instanceof DataView;
98
+ if (leftIsView || rightIsView) {
99
+ if (!leftIsView || !rightIsView)
100
+ return false;
101
+ const leftView = currentLeft;
102
+ const rightView = currentRight;
103
+ if (leftView.byteLength !== rightView.byteLength)
104
+ return false;
105
+ for (let offset = 0; offset < leftView.byteLength; offset++) {
106
+ if (leftView.getUint8(offset) !== rightView.getUint8(offset))
107
+ return false;
108
+ }
109
+ continue;
110
+ }
111
+ // Date
112
+ const leftIsDate = currentLeft instanceof Date;
113
+ const rightIsDate = currentRight instanceof Date;
114
+ if (leftIsDate || rightIsDate) {
115
+ if (!leftIsDate || !rightIsDate)
116
+ return false;
117
+ if (currentLeft.getTime() !== currentRight.getTime())
118
+ return false;
119
+ continue;
120
+ }
121
+ // RegExp
122
+ const leftIsRegExp = currentLeft instanceof RegExp;
123
+ const rightIsRegExp = currentRight instanceof RegExp;
124
+ if (leftIsRegExp || rightIsRegExp) {
125
+ if (!leftIsRegExp || !rightIsRegExp)
126
+ return false;
127
+ const leftRe = currentLeft;
128
+ const rightRe = currentRight;
129
+ if (leftRe.source !== rightRe.source)
130
+ return false;
131
+ if (leftRe.flags !== rightRe.flags)
132
+ return false;
133
+ continue;
134
+ }
135
+ // Set (order-insensitive)
136
+ const leftIsSet = currentLeft instanceof Set;
137
+ const rightIsSet = currentRight instanceof Set;
138
+ if (leftIsSet || rightIsSet) {
139
+ if (!leftIsSet || !rightIsSet)
140
+ return false;
141
+ const leftSet = currentLeft;
142
+ const rightSet = currentRight;
143
+ if (leftSet.size !== rightSet.size)
144
+ return false;
145
+ const remaining = new Set(rightSet);
146
+ outer: for (const leftValue of leftSet) {
147
+ for (const rightValue of remaining) {
148
+ if (compareInternal(leftValue, rightValue, options, leftToRightSeen, rightToLeftSeen)) {
149
+ remaining.delete(rightValue);
150
+ continue outer;
151
+ }
152
+ }
153
+ return false;
154
+ }
155
+ continue;
156
+ }
157
+ // Map (order-insensitive)
158
+ const leftIsMap = currentLeft instanceof Map;
159
+ const rightIsMap = currentRight instanceof Map;
160
+ if (leftIsMap || rightIsMap) {
161
+ if (!leftIsMap || !rightIsMap)
162
+ return false;
163
+ const leftMap = currentLeft;
164
+ const rightMap = currentRight;
165
+ if (leftMap.size !== rightMap.size)
166
+ return false;
167
+ const remainingEntries = new Set(rightMap.entries());
168
+ outer: for (const [leftKey, leftValue] of leftMap.entries()) {
169
+ for (const candidate of remainingEntries) {
170
+ const [rightKey, rightValue] = candidate;
171
+ if (compareInternal(leftKey, rightKey, options, leftToRightSeen, rightToLeftSeen) &&
172
+ compareInternal(leftValue, rightValue, options, leftToRightSeen, rightToLeftSeen)) {
173
+ remainingEntries.delete(candidate);
174
+ continue outer;
175
+ }
176
+ }
177
+ return false;
178
+ }
179
+ continue;
180
+ }
181
+ // Fallback: plain objects / custom class instances
182
+ if (options.checkPrototype) {
183
+ // Prototype-sensitive (deepEqual)
184
+ const leftProto = Object.getPrototypeOf(currentLeft);
185
+ const rightProto = Object.getPrototypeOf(currentRight);
186
+ if (leftProto !== rightProto)
187
+ return false;
188
+ const leftKeys = Object.keys(currentLeft);
189
+ const rightKeys = Object.keys(currentRight);
190
+ if (leftKeys.length !== rightKeys.length)
191
+ return false;
192
+ const leftRecord = currentLeft;
193
+ const rightRecord = currentRight;
194
+ for (let i = 0; i < leftKeys.length; i++) {
195
+ const key = leftKeys[i];
196
+ if (!Object.hasOwn(rightRecord, key))
197
+ return false;
198
+ worklist.push([leftRecord[key], rightRecord[key]]);
199
+ }
200
+ }
201
+ else {
202
+ // Prototype-insensitive (looseEqual) — union-of-keys, missing ≈ undefined
203
+ const leftKeys = Object.keys(currentLeft);
204
+ const rightKeys = Object.keys(currentRight);
205
+ const allKeys = new Set([...leftKeys, ...rightKeys]);
206
+ const leftRecord = currentLeft;
207
+ const rightRecord = currentRight;
208
+ for (const key of allKeys) {
209
+ const leftHasKey = Object.hasOwn(leftRecord, key);
210
+ const rightHasKey = Object.hasOwn(rightRecord, key);
211
+ const leftValue = leftHasKey ? leftRecord[key] : undefined;
212
+ const rightValue = rightHasKey ? rightRecord[key] : undefined;
213
+ if (leftHasKey !== rightHasKey) {
214
+ if (leftValue !== undefined || rightValue !== undefined)
215
+ return false;
216
+ }
217
+ worklist.push([leftValue, rightValue]);
218
+ }
219
+ }
220
+ }
221
+ return true;
222
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"deepEqual.d.ts","sourceRoot":"","sources":["../../../src/utils/deepEqual.ts"],"names":[],"mappings":"AA+OA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAShD"}
1
+ {"version":3,"file":"deepEqual.d.ts","sourceRoot":"","sources":["../../../src/utils/deepEqual.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAkBhD"}
@@ -1,187 +1,5 @@
1
- import { isObjectLike, isPrimitive, isTypedArray, sameValue, } from "./helpers.js";
2
- function deepEqualInternal(left, right, leftToRightSeen) {
3
- const worklist = [[left, right]];
4
- while (worklist.length) {
5
- const [currentLeft, currentRight] = worklist.pop();
6
- if (sameValue(currentLeft, currentRight))
7
- continue;
8
- // Types must match at this point
9
- if (typeof currentLeft !== typeof currentRight)
10
- return false;
11
- // Primitive mismatch - we already handled equality above
12
- if (isPrimitive(currentLeft) || isPrimitive(currentRight))
13
- return false;
14
- // Functions, etc. – only ever equal by reference, which we've already checked
15
- if (!isObjectLike(currentLeft) || !isObjectLike(currentRight))
16
- return false;
17
- const leftObj = currentLeft;
18
- const rightObj = currentRight;
19
- // Cycle detection: require consistent mapping for left-side objects
20
- const previouslyMappedRight = leftToRightSeen.get(leftObj);
21
- if (previouslyMappedRight !== undefined) {
22
- if (previouslyMappedRight !== rightObj)
23
- return false;
24
- continue;
25
- }
26
- leftToRightSeen.set(leftObj, rightObj);
27
- // Arrays - prototype-sensitive handled by prototype check later
28
- const leftIsArray = Array.isArray(currentLeft);
29
- const rightIsArray = Array.isArray(currentRight);
30
- if (leftIsArray || rightIsArray) {
31
- if (!leftIsArray || !rightIsArray)
32
- return false;
33
- const leftArr = currentLeft;
34
- const rightArr = currentRight;
35
- if (leftArr.length !== rightArr.length)
36
- return false;
37
- // Preserve sparseness by reading indexed values directly.
38
- for (let index = 0; index < leftArr.length; index++) {
39
- worklist.push([leftArr[index], rightArr[index]]);
40
- }
41
- continue;
42
- }
43
- // Typed arrays
44
- const leftIsTyped = isTypedArray(currentLeft);
45
- const rightIsTyped = isTypedArray(currentRight);
46
- if (leftIsTyped || rightIsTyped) {
47
- if (!leftIsTyped || !rightIsTyped)
48
- return false;
49
- const leftTA = currentLeft;
50
- const rightTA = currentRight;
51
- if (leftTA.constructor !== rightTA.constructor)
52
- return false;
53
- if (leftTA.length !== rightTA.length)
54
- return false;
55
- for (let index = 0; index < leftTA.length; index++) {
56
- if (!sameValue(leftTA[index], rightTA[index]))
57
- return false;
58
- }
59
- continue;
60
- }
61
- // ArrayBuffer
62
- const leftIsBuffer = currentLeft instanceof ArrayBuffer;
63
- const rightIsBuffer = currentRight instanceof ArrayBuffer;
64
- if (leftIsBuffer || rightIsBuffer) {
65
- if (!leftIsBuffer || !rightIsBuffer)
66
- return false;
67
- const leftBuf = currentLeft;
68
- const rightBuf = currentRight;
69
- if (leftBuf.byteLength !== rightBuf.byteLength)
70
- return false;
71
- const leftBytes = new Uint8Array(leftBuf);
72
- const rightBytes = new Uint8Array(rightBuf);
73
- for (let index = 0; index < leftBytes.length; index++) {
74
- if (leftBytes[index] !== rightBytes[index])
75
- return false;
76
- }
77
- continue;
78
- }
79
- // DataView
80
- const leftIsView = currentLeft instanceof DataView;
81
- const rightIsView = currentRight instanceof DataView;
82
- if (leftIsView || rightIsView) {
83
- if (!leftIsView || !rightIsView)
84
- return false;
85
- const leftView = currentLeft;
86
- const rightView = currentRight;
87
- if (leftView.byteLength !== rightView.byteLength)
88
- return false;
89
- for (let offset = 0; offset < leftView.byteLength; offset++) {
90
- if (leftView.getUint8(offset) !== rightView.getUint8(offset))
91
- return false;
92
- }
93
- continue;
94
- }
95
- // Date
96
- const leftIsDate = currentLeft instanceof Date;
97
- const rightIsDate = currentRight instanceof Date;
98
- if (leftIsDate || rightIsDate) {
99
- if (!leftIsDate || !rightIsDate)
100
- return false;
101
- if (currentLeft.getTime() !== currentRight.getTime())
102
- return false;
103
- continue;
104
- }
105
- // RegExp
106
- const leftIsRegExp = currentLeft instanceof RegExp;
107
- const rightIsRegExp = currentRight instanceof RegExp;
108
- if (leftIsRegExp || rightIsRegExp) {
109
- if (!leftIsRegExp || !rightIsRegExp)
110
- return false;
111
- const leftRe = currentLeft;
112
- const rightRe = currentRight;
113
- if (leftRe.source !== rightRe.source)
114
- return false;
115
- if (leftRe.flags !== rightRe.flags)
116
- return false;
117
- continue;
118
- }
119
- // Set
120
- const leftIsSet = currentLeft instanceof Set;
121
- const rightIsSet = currentRight instanceof Set;
122
- if (leftIsSet || rightIsSet) {
123
- if (!leftIsSet || !rightIsSet)
124
- return false;
125
- const leftSet = currentLeft;
126
- const rightSet = currentRight;
127
- if (leftSet.size !== rightSet.size)
128
- return false;
129
- const unmatchedRightValues = new Set(rightSet);
130
- outer: for (const leftValue of leftSet) {
131
- for (const rightValue of unmatchedRightValues) {
132
- if (deepEqualInternal(leftValue, rightValue, leftToRightSeen)) {
133
- unmatchedRightValues.delete(rightValue);
134
- continue outer;
135
- }
136
- }
137
- return false;
138
- }
139
- continue;
140
- }
141
- // Map
142
- const leftIsMap = currentLeft instanceof Map;
143
- const rightIsMap = currentRight instanceof Map;
144
- if (leftIsMap || rightIsMap) {
145
- if (!leftIsMap || !rightIsMap)
146
- return false;
147
- const leftMap = currentLeft;
148
- const rightMap = currentRight;
149
- if (leftMap.size !== rightMap.size)
150
- return false;
151
- const unmatchedRightEntries = new Set(rightMap.entries());
152
- outer: for (const [leftKey, leftValue] of leftMap.entries()) {
153
- for (const candidate of unmatchedRightEntries) {
154
- const [rightKey, rightValue] = candidate;
155
- if (deepEqualInternal(leftKey, rightKey, leftToRightSeen) &&
156
- deepEqualInternal(leftValue, rightValue, leftToRightSeen)) {
157
- unmatchedRightEntries.delete(candidate);
158
- continue outer;
159
- }
160
- }
161
- return false;
162
- }
163
- continue;
164
- }
165
- // Fallback: plain objects / custom class instances (prototype-sensitive)
166
- const leftProto = Object.getPrototypeOf(currentLeft);
167
- const rightProto = Object.getPrototypeOf(currentRight);
168
- if (leftProto !== rightProto)
169
- return false;
170
- const leftKeys = Object.keys(currentLeft);
171
- const rightKeys = Object.keys(currentRight);
172
- if (leftKeys.length !== rightKeys.length)
173
- return false;
174
- const leftRecord = currentLeft;
175
- const rightRecord = currentRight;
176
- for (let i = 0; i < leftKeys.length; i++) {
177
- const key = leftKeys[i];
178
- if (!Object.hasOwn(rightRecord, key))
179
- return false;
180
- worklist.push([leftRecord[key], rightRecord[key]]);
181
- }
182
- }
183
- return true;
184
- }
1
+ import { isObjectLike, isPrimitive, sameValue } from "./helpers.js";
2
+ import { compareInternal } from "./compareEngine.js";
185
3
  /**
186
4
  * Deep structural equality with:
187
5
  * - Value semantics for primitives (+ NaN equal, +0/-0 equal)
@@ -197,5 +15,9 @@ export function deepEqual(a, b) {
197
15
  return false;
198
16
  if (!isObjectLike(a) || !isObjectLike(b))
199
17
  return false;
200
- return deepEqualInternal(a, b, new WeakMap());
18
+ return compareInternal(a, b, {
19
+ checkPrototype: true,
20
+ treatSparseAsUndefined: false,
21
+ bijectiveCycleCheck: false,
22
+ }, new WeakMap());
201
23
  }
@@ -0,0 +1,2 @@
1
+ export declare function formatDiff(received: unknown, expected: unknown): string;
2
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/utils/diff.ts"],"names":[],"mappings":"AA2EA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CA6BvE"}
@@ -0,0 +1,84 @@
1
+ import { colors } from "./colors.js";
2
+ function formatValue(value, indent = 2) {
3
+ if (value === undefined)
4
+ return "undefined";
5
+ if (value === null)
6
+ return "null";
7
+ if (typeof value === "string")
8
+ return JSON.stringify(value);
9
+ if (typeof value === "number" || typeof value === "boolean")
10
+ return String(value);
11
+ if (typeof value === "bigint")
12
+ return `${value}n`;
13
+ if (typeof value === "symbol")
14
+ return value.toString();
15
+ if (typeof value === "function")
16
+ return `[Function: ${value.name || "anonymous"}]`;
17
+ if (value instanceof Date)
18
+ return `Date(${value.toISOString()})`;
19
+ if (value instanceof RegExp)
20
+ return String(value);
21
+ if (value instanceof Error)
22
+ return `${value.name}: ${value.message}`;
23
+ if (Array.isArray(value)) {
24
+ if (value.length === 0)
25
+ return "[]";
26
+ const padding = " ".repeat(indent);
27
+ const items = value.map((v) => `${padding}${formatValue(v, indent + 2)}`);
28
+ return `[\n${items.join(",\n")}\n${" ".repeat(indent - 2)}]`;
29
+ }
30
+ if (typeof value === "object") {
31
+ const keys = Object.keys(value);
32
+ if (keys.length === 0)
33
+ return "{}";
34
+ const padding = " ".repeat(indent);
35
+ const entries = keys.map((k) => `${padding}${k}: ${formatValue(value[k], indent + 2)}`);
36
+ return `{\n${entries.join(",\n")}\n${" ".repeat(indent - 2)}}`;
37
+ }
38
+ return String(value);
39
+ }
40
+ function diffObjects(received, expected) {
41
+ const allKeys = new Set([...Object.keys(received), ...Object.keys(expected)]);
42
+ const lines = [];
43
+ for (const key of allKeys) {
44
+ const inReceived = Object.hasOwn(received, key);
45
+ const inExpected = Object.hasOwn(expected, key);
46
+ if (inReceived && inExpected) {
47
+ const rv = formatValue(received[key]);
48
+ const ev = formatValue(expected[key]);
49
+ if (rv !== ev) {
50
+ lines.push(colors.red(` - ${key}: ${rv}`));
51
+ lines.push(colors.green(` + ${key}: ${ev}`));
52
+ }
53
+ else {
54
+ lines.push(` ${key}: ${rv}`);
55
+ }
56
+ }
57
+ else if (inReceived) {
58
+ lines.push(colors.red(` - ${key}: ${formatValue(received[key])}`));
59
+ }
60
+ else {
61
+ lines.push(colors.green(` + ${key}: ${formatValue(expected[key])}`));
62
+ }
63
+ }
64
+ return lines.join("\n");
65
+ }
66
+ export function formatDiff(received, expected) {
67
+ // For objects, provide a structural diff
68
+ if (received !== null &&
69
+ expected !== null &&
70
+ typeof received === "object" &&
71
+ typeof expected === "object" &&
72
+ !Array.isArray(received) &&
73
+ !Array.isArray(expected) &&
74
+ !(received instanceof Date) &&
75
+ !(expected instanceof Date) &&
76
+ !(received instanceof RegExp) &&
77
+ !(expected instanceof RegExp)) {
78
+ const diff = diffObjects(received, expected);
79
+ return (`\n${colors.red("- Received")} / ${colors.green("+ Expected")}\n\n` + diff);
80
+ }
81
+ // Default: simple received/expected display
82
+ return (`\n ${colors.red("Received:")} ${formatValue(received)}` +
83
+ `\n ${colors.green("Expected:")} ${formatValue(expected)}`);
84
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"discoverTestFiles.d.ts","sourceRoot":"","sources":["../../../src/utils/discoverTestFiles.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBvD"}
1
+ {"version":3,"file":"discoverTestFiles.d.ts","sourceRoot":"","sources":["../../../src/utils/discoverTestFiles.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAqCvD"}
@@ -1,7 +1,7 @@
1
- import { existsSync, readdirSync } from "node:fs";
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  export function isTestFileName(name) {
4
- return /\.(spec|test)\.(ts|js)$/.test(name);
4
+ return /\.(spec|test)\.(ts|js|mts|cts|tsx|jsx|mjs|cjs)$/.test(name);
5
5
  }
6
6
  export function discoverTestFiles(dir) {
7
7
  if (!existsSync(dir))
@@ -10,6 +10,21 @@ export function discoverTestFiles(dir) {
10
10
  const files = [];
11
11
  for (const entry of entries) {
12
12
  const fullPath = join(dir, entry.name);
13
+ if (entry.isSymbolicLink()) {
14
+ try {
15
+ const stat = statSync(fullPath);
16
+ if (stat.isDirectory()) {
17
+ files.push(...discoverTestFiles(fullPath));
18
+ }
19
+ else if (stat.isFile() && isTestFileName(entry.name)) {
20
+ files.push(fullPath);
21
+ }
22
+ }
23
+ catch {
24
+ // Broken symlink — skip silently
25
+ }
26
+ continue;
27
+ }
13
28
  if (entry.isDirectory()) {
14
29
  files.push(...discoverTestFiles(fullPath));
15
30
  continue;
@@ -1,2 +1,11 @@
1
+ /**
2
+ * Loose structural equality with:
3
+ * - Value semantics for primitives (+ NaN equal, +0/-0 equal)
4
+ * - Prototype-insensitive object comparison
5
+ * - Sparse array holes treated as undefined
6
+ * - Missing keys ≈ undefined (union-of-keys approach)
7
+ * - Bidirectional cycle tracking
8
+ * - Order-insensitive Set/Map comparison
9
+ */
1
10
  export declare function looseEqual<T>(left: T, right: T): boolean;
2
11
  //# sourceMappingURL=looseEqual.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"looseEqual.d.ts","sourceRoot":"","sources":["../../../src/utils/looseEqual.ts"],"names":[],"mappings":"AAuRA,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAWxD"}
1
+ {"version":3,"file":"looseEqual.d.ts","sourceRoot":"","sources":["../../../src/utils/looseEqual.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAgBxD"}