@unrift/core 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/unrift.mjs +5 -0
- package/dist/cjs/index.cjs +31 -0
- package/dist/esm/cli.d.ts +3 -0
- package/dist/esm/cli.d.ts.map +1 -0
- package/dist/esm/cli.js +87 -0
- package/dist/esm/context.d.ts +15 -0
- package/dist/esm/context.d.ts.map +1 -0
- package/dist/esm/context.js +16 -0
- package/dist/esm/expect.d.ts +27 -0
- package/dist/esm/expect.d.ts.map +1 -0
- package/dist/esm/expect.js +43 -0
- package/dist/esm/hooks.d.ts +8 -0
- package/dist/esm/hooks.d.ts.map +1 -0
- package/dist/esm/hooks.js +18 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/injected/globals.d.ts +4 -0
- package/dist/esm/injected/globals.d.ts.map +1 -0
- package/dist/esm/injected/globals.js +6 -0
- package/dist/esm/interface.d.ts +18 -0
- package/dist/esm/interface.d.ts.map +1 -0
- package/dist/esm/interface.js +29 -0
- package/dist/esm/matchers.d.ts +2 -0
- package/dist/esm/matchers.d.ts.map +1 -0
- package/dist/esm/matchers.js +81 -0
- package/dist/esm/run.d.ts +21 -0
- package/dist/esm/run.d.ts.map +1 -0
- package/dist/esm/run.js +57 -0
- package/dist/esm/runner.d.ts +14 -0
- package/dist/esm/runner.d.ts.map +1 -0
- package/dist/esm/runner.js +207 -0
- package/dist/esm/suite.d.ts +58 -0
- package/dist/esm/suite.d.ts.map +1 -0
- package/dist/esm/suite.js +281 -0
- package/dist/esm/test.d.ts +18 -0
- package/dist/esm/test.d.ts.map +1 -0
- package/dist/esm/test.js +52 -0
- package/dist/esm/types.d.ts +24 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +16 -0
- package/dist/esm/utils/colors.d.ts +7 -0
- package/dist/esm/utils/colors.d.ts.map +1 -0
- package/dist/esm/utils/colors.js +12 -0
- package/dist/esm/utils/deepEqual.d.ts +9 -0
- package/dist/esm/utils/deepEqual.d.ts.map +1 -0
- package/dist/esm/utils/deepEqual.js +201 -0
- package/dist/esm/utils/defineConfig.d.ts +12 -0
- package/dist/esm/utils/defineConfig.d.ts.map +1 -0
- package/dist/esm/utils/defineConfig.js +3 -0
- package/dist/esm/utils/discoverTestFiles.d.ts +3 -0
- package/dist/esm/utils/discoverTestFiles.d.ts.map +1 -0
- package/dist/esm/utils/discoverTestFiles.js +22 -0
- package/dist/esm/utils/helpers.d.ts +13 -0
- package/dist/esm/utils/helpers.d.ts.map +1 -0
- package/dist/esm/utils/helpers.js +29 -0
- package/dist/esm/utils/loadConfig.d.ts +9 -0
- package/dist/esm/utils/loadConfig.d.ts.map +1 -0
- package/dist/esm/utils/loadConfig.js +89 -0
- package/dist/esm/utils/looseEqual.d.ts +2 -0
- package/dist/esm/utils/looseEqual.d.ts.map +1 -0
- package/dist/esm/utils/looseEqual.js +205 -0
- package/dist/esm/utils/toThrow.d.ts +11 -0
- package/dist/esm/utils/toThrow.d.ts.map +1 -0
- package/dist/esm/utils/toThrow.js +93 -0
- package/dist/esm/utils/transform.d.ts +10 -0
- package/dist/esm/utils/transform.d.ts.map +1 -0
- package/dist/esm/utils/transform.js +213 -0
- package/package.json +60 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const enabled = process.stdout.isTTY &&
|
|
2
|
+
process.env.NO_COLOR !== "1" &&
|
|
3
|
+
process.env.NO_COLOR !== "true";
|
|
4
|
+
function wrap(code) {
|
|
5
|
+
return (text) => (enabled ? `\x1b[${code}m${text}\x1b[0m` : text);
|
|
6
|
+
}
|
|
7
|
+
export const colors = {
|
|
8
|
+
green: wrap(32),
|
|
9
|
+
red: wrap(31),
|
|
10
|
+
yellow: wrap(33),
|
|
11
|
+
bold: wrap(1),
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep structural equality with:
|
|
3
|
+
* - Value semantics for primitives (+ NaN equal, +0/-0 equal)
|
|
4
|
+
* - Structural comparison for Arrays, Maps, Sets, TypedArrays, ArrayBuffer, DataView, Date, RegExp
|
|
5
|
+
* - Prototype-sensitive object comparison
|
|
6
|
+
* - Handles circular references
|
|
7
|
+
*/
|
|
8
|
+
export declare function deepEqual<T>(a: T, b: T): boolean;
|
|
9
|
+
//# sourceMappingURL=deepEqual.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
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
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Deep structural equality with:
|
|
187
|
+
* - Value semantics for primitives (+ NaN equal, +0/-0 equal)
|
|
188
|
+
* - Structural comparison for Arrays, Maps, Sets, TypedArrays, ArrayBuffer, DataView, Date, RegExp
|
|
189
|
+
* - Prototype-sensitive object comparison
|
|
190
|
+
* - Handles circular references
|
|
191
|
+
*/
|
|
192
|
+
export function deepEqual(a, b) {
|
|
193
|
+
if (sameValue(a, b))
|
|
194
|
+
return true;
|
|
195
|
+
// Fast-path for primitive inequality
|
|
196
|
+
if (isPrimitive(a) || isPrimitive(b))
|
|
197
|
+
return false;
|
|
198
|
+
if (!isObjectLike(a) || !isObjectLike(b))
|
|
199
|
+
return false;
|
|
200
|
+
return deepEqualInternal(a, b, new WeakMap());
|
|
201
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface UnriftConfigOptions {
|
|
2
|
+
testDir?: string;
|
|
3
|
+
rootDir?: string;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
bail?: boolean;
|
|
6
|
+
pattern?: string;
|
|
7
|
+
includes?: string[];
|
|
8
|
+
excludes?: string[];
|
|
9
|
+
matchers?: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function defineConfig(options: UnriftConfigOptions): UnriftConfigOptions;
|
|
12
|
+
//# sourceMappingURL=defineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../../src/utils/defineConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAErB"}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export function isTestFileName(name) {
|
|
4
|
+
return /\.(spec|test)\.(ts|js)$/.test(name);
|
|
5
|
+
}
|
|
6
|
+
export function discoverTestFiles(dir) {
|
|
7
|
+
if (!existsSync(dir))
|
|
8
|
+
return [];
|
|
9
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
10
|
+
const files = [];
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
const fullPath = join(dir, entry.name);
|
|
13
|
+
if (entry.isDirectory()) {
|
|
14
|
+
files.push(...discoverTestFiles(fullPath));
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (entry.isFile() && isTestFileName(entry.name)) {
|
|
18
|
+
files.push(fullPath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return files;
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
|
2
|
+
export type TypedArray = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
|
|
3
|
+
export declare function isPrimitive(value: unknown): value is Primitive;
|
|
4
|
+
export declare function isObjectLike(value: unknown): value is object;
|
|
5
|
+
export declare function isTypedArray(value: unknown): value is TypedArray;
|
|
6
|
+
/**
|
|
7
|
+
* SameValueZero-ish semantics:
|
|
8
|
+
* - NaN equals NaN
|
|
9
|
+
* - +0 and -0 are equal
|
|
10
|
+
*/
|
|
11
|
+
export declare function sameValue(a: unknown, b: unknown): boolean;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAY9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASzD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function isPrimitive(value) {
|
|
2
|
+
const t = typeof value;
|
|
3
|
+
return (value === null ||
|
|
4
|
+
t === "string" ||
|
|
5
|
+
t === "number" ||
|
|
6
|
+
t === "boolean" ||
|
|
7
|
+
t === "undefined" ||
|
|
8
|
+
t === "symbol" ||
|
|
9
|
+
t === "bigint");
|
|
10
|
+
}
|
|
11
|
+
export function isObjectLike(value) {
|
|
12
|
+
return typeof value === "object" && value !== null;
|
|
13
|
+
}
|
|
14
|
+
export function isTypedArray(value) {
|
|
15
|
+
return ArrayBuffer.isView(value) && !(value instanceof DataView);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* SameValueZero-ish semantics:
|
|
19
|
+
* - NaN equals NaN
|
|
20
|
+
* - +0 and -0 are equal
|
|
21
|
+
*/
|
|
22
|
+
export function sameValue(a, b) {
|
|
23
|
+
if (a === b)
|
|
24
|
+
return true;
|
|
25
|
+
return (typeof a === "number" &&
|
|
26
|
+
typeof b === "number" &&
|
|
27
|
+
Number.isNaN(a) &&
|
|
28
|
+
Number.isNaN(b));
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UnriftConfigOptions } from "./defineConfig";
|
|
2
|
+
export type LoadedConfig = {
|
|
3
|
+
config: UnriftConfigOptions;
|
|
4
|
+
configPath: string;
|
|
5
|
+
configDir: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function loadConfigFromPath(configPath: string): Promise<LoadedConfig>;
|
|
8
|
+
export declare function loadConfig(startDir: string): Promise<LoadedConfig | null>;
|
|
9
|
+
//# sourceMappingURL=loadConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadConfig.d.ts","sourceRoot":"","sources":["../../../src/utils/loadConfig.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAU1D,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,mBAAmB,CAAC;IAE5B,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAuCF,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CAevB;AAqCD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAc9B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { toImportUrl } from "./transform.js";
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Regex to match valid Unrift config file names.
|
|
6
|
+
* Matches:
|
|
7
|
+
* - unrift.config.ts/js/mjs/cjs/json
|
|
8
|
+
* - unrift.<anything>.config.ts/js/mjs/cjs/json (e.g. unrift.only.config.mjs)
|
|
9
|
+
*/
|
|
10
|
+
const CONFIG_RE = /^unrift(?:\.[^.]+)*\.config\.(ts|js|mjs|cjs|json)$/;
|
|
11
|
+
function isConfigFileName(name) {
|
|
12
|
+
return CONFIG_RE.test(name);
|
|
13
|
+
}
|
|
14
|
+
async function importConfigFile(configPath) {
|
|
15
|
+
if (configPath.endsWith(".json")) {
|
|
16
|
+
try {
|
|
17
|
+
const raw = readFileSync(configPath, "utf8");
|
|
18
|
+
return JSON.parse(raw);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
22
|
+
throw new Error(`Failed to parse JSON config at ${configPath}: ${msg}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const module = await import(toImportUrl(configPath, "bundle-config"));
|
|
26
|
+
return module.default ?? module.config;
|
|
27
|
+
}
|
|
28
|
+
function assertConfigObject(config, absolutePath) {
|
|
29
|
+
if (!config || typeof config !== "object") {
|
|
30
|
+
throw new Error(`Unrift config at ${absolutePath} must export an object (default export recommended).`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function toAbsolutePath(p) {
|
|
34
|
+
return isAbsolute(p) ? p : resolve(process.cwd(), p);
|
|
35
|
+
}
|
|
36
|
+
export async function loadConfigFromPath(configPath) {
|
|
37
|
+
const absolutePath = toAbsolutePath(configPath);
|
|
38
|
+
if (!existsSync(absolutePath)) {
|
|
39
|
+
throw new Error(`Config file not found: ${absolutePath}`);
|
|
40
|
+
}
|
|
41
|
+
const loaded = await importConfigFile(absolutePath);
|
|
42
|
+
assertConfigObject(loaded, absolutePath);
|
|
43
|
+
return {
|
|
44
|
+
config: loaded,
|
|
45
|
+
configPath: absolutePath,
|
|
46
|
+
configDir: dirname(absolutePath),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function findConfigPath(startDir) {
|
|
50
|
+
let dir = resolve(startDir);
|
|
51
|
+
while (true) {
|
|
52
|
+
let entries = [];
|
|
53
|
+
try {
|
|
54
|
+
entries = readdirSync(dir);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// ignore unreadable dirs
|
|
58
|
+
}
|
|
59
|
+
// Prefer the "default" config if multiple exist in same folder
|
|
60
|
+
const candidates = entries.filter(isConfigFileName).sort((a, b) => {
|
|
61
|
+
const aIsDefault = a.startsWith("unrift.config.");
|
|
62
|
+
const bIsDefault = b.startsWith("unrift.config.");
|
|
63
|
+
if (aIsDefault !== bIsDefault)
|
|
64
|
+
return aIsDefault ? -1 : 1;
|
|
65
|
+
return a.localeCompare(b);
|
|
66
|
+
});
|
|
67
|
+
if (candidates.length > 0) {
|
|
68
|
+
return join(dir, candidates[0]);
|
|
69
|
+
}
|
|
70
|
+
const parent = dirname(dir);
|
|
71
|
+
if (parent === dir)
|
|
72
|
+
break;
|
|
73
|
+
dir = parent;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
export async function loadConfig(startDir) {
|
|
78
|
+
const found = findConfigPath(startDir);
|
|
79
|
+
if (!found)
|
|
80
|
+
return null;
|
|
81
|
+
const absolutePath = toAbsolutePath(found);
|
|
82
|
+
const loaded = await importConfigFile(absolutePath);
|
|
83
|
+
assertConfigObject(loaded, absolutePath);
|
|
84
|
+
return {
|
|
85
|
+
config: loaded,
|
|
86
|
+
configPath: absolutePath,
|
|
87
|
+
configDir: dirname(absolutePath),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { isObjectLike, isPrimitive, isTypedArray, sameValue, } from "./helpers.js";
|
|
2
|
+
function looseEqualInternal(left, right, 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 / aliasing consistency (bijection-ish)
|
|
17
|
+
const mappedRight = leftToRightSeen.get(leftObj);
|
|
18
|
+
if (mappedRight !== undefined) {
|
|
19
|
+
if (mappedRight !== rightObj)
|
|
20
|
+
return false;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const mappedLeft = rightToLeftSeen.get(rightObj);
|
|
24
|
+
if (mappedLeft !== undefined) {
|
|
25
|
+
if (mappedLeft !== leftObj)
|
|
26
|
+
return false;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
leftToRightSeen.set(leftObj, rightObj);
|
|
30
|
+
rightToLeftSeen.set(rightObj, leftObj);
|
|
31
|
+
// Arrays: sparse holes treated as undefined
|
|
32
|
+
const leftIsArray = Array.isArray(currentLeft);
|
|
33
|
+
const rightIsArray = Array.isArray(currentRight);
|
|
34
|
+
if (leftIsArray || rightIsArray) {
|
|
35
|
+
if (!leftIsArray || !rightIsArray)
|
|
36
|
+
return false;
|
|
37
|
+
const leftArr = currentLeft;
|
|
38
|
+
const rightArr = currentRight;
|
|
39
|
+
if (leftArr.length !== rightArr.length)
|
|
40
|
+
return false;
|
|
41
|
+
for (let index = 0; index < leftArr.length; index++) {
|
|
42
|
+
const leftValue = Object.hasOwn(leftArr, index)
|
|
43
|
+
? leftArr[index]
|
|
44
|
+
: undefined;
|
|
45
|
+
const rightValue = Object.hasOwn(rightArr, index)
|
|
46
|
+
? rightArr[index]
|
|
47
|
+
: undefined;
|
|
48
|
+
worklist.push([leftValue, rightValue]);
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// Typed arrays
|
|
53
|
+
const leftIsTypedArray = isTypedArray(currentLeft);
|
|
54
|
+
const rightIsTypedArray = isTypedArray(currentRight);
|
|
55
|
+
if (leftIsTypedArray || rightIsTypedArray) {
|
|
56
|
+
if (!leftIsTypedArray || !rightIsTypedArray)
|
|
57
|
+
return false;
|
|
58
|
+
const leftTypedArray = currentLeft;
|
|
59
|
+
const rightTypedArray = currentRight;
|
|
60
|
+
if (leftTypedArray.constructor !== rightTypedArray.constructor)
|
|
61
|
+
return false;
|
|
62
|
+
if (leftTypedArray.length !== rightTypedArray.length)
|
|
63
|
+
return false;
|
|
64
|
+
for (let index = 0; index < leftTypedArray.length; index++) {
|
|
65
|
+
if (!sameValue(leftTypedArray[index], rightTypedArray[index]))
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// ArrayBuffer
|
|
71
|
+
const leftIsBuffer = currentLeft instanceof ArrayBuffer;
|
|
72
|
+
const rightIsBuffer = currentRight instanceof ArrayBuffer;
|
|
73
|
+
if (leftIsBuffer || rightIsBuffer) {
|
|
74
|
+
if (!leftIsBuffer || !rightIsBuffer)
|
|
75
|
+
return false;
|
|
76
|
+
const leftBuffer = currentLeft;
|
|
77
|
+
const rightBuffer = currentRight;
|
|
78
|
+
if (leftBuffer.byteLength !== rightBuffer.byteLength)
|
|
79
|
+
return false;
|
|
80
|
+
const leftBytes = new Uint8Array(leftBuffer);
|
|
81
|
+
const rightBytes = new Uint8Array(rightBuffer);
|
|
82
|
+
for (let index = 0; index < leftBytes.length; index++) {
|
|
83
|
+
if (leftBytes[index] !== rightBytes[index])
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// DataView
|
|
89
|
+
const leftIsDataView = currentLeft instanceof DataView;
|
|
90
|
+
const rightIsDataView = currentRight instanceof DataView;
|
|
91
|
+
if (leftIsDataView || rightIsDataView) {
|
|
92
|
+
if (!leftIsDataView || !rightIsDataView)
|
|
93
|
+
return false;
|
|
94
|
+
const leftView = currentLeft;
|
|
95
|
+
const rightView = currentRight;
|
|
96
|
+
if (leftView.byteLength !== rightView.byteLength)
|
|
97
|
+
return false;
|
|
98
|
+
for (let offset = 0; offset < leftView.byteLength; offset++) {
|
|
99
|
+
if (leftView.getUint8(offset) !== rightView.getUint8(offset))
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Date
|
|
105
|
+
const leftIsDate = currentLeft instanceof Date;
|
|
106
|
+
const rightIsDate = currentRight instanceof Date;
|
|
107
|
+
if (leftIsDate || rightIsDate) {
|
|
108
|
+
if (!leftIsDate || !rightIsDate)
|
|
109
|
+
return false;
|
|
110
|
+
if (currentLeft.getTime() !== currentRight.getTime()) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// RegExp
|
|
116
|
+
const leftIsRegExp = currentLeft instanceof RegExp;
|
|
117
|
+
const rightIsRegExp = currentRight instanceof RegExp;
|
|
118
|
+
if (leftIsRegExp || rightIsRegExp) {
|
|
119
|
+
if (!leftIsRegExp || !rightIsRegExp)
|
|
120
|
+
return false;
|
|
121
|
+
const leftRe = currentLeft;
|
|
122
|
+
const rightRe = currentRight;
|
|
123
|
+
if (leftRe.source !== rightRe.source)
|
|
124
|
+
return false;
|
|
125
|
+
if (leftRe.flags !== rightRe.flags)
|
|
126
|
+
return false;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// Set (order-insensitive)
|
|
130
|
+
const leftIsSet = currentLeft instanceof Set;
|
|
131
|
+
const rightIsSet = currentRight instanceof Set;
|
|
132
|
+
if (leftIsSet || rightIsSet) {
|
|
133
|
+
if (!leftIsSet || !rightIsSet)
|
|
134
|
+
return false;
|
|
135
|
+
const leftSet = currentLeft;
|
|
136
|
+
const rightSet = currentRight;
|
|
137
|
+
if (leftSet.size !== rightSet.size)
|
|
138
|
+
return false;
|
|
139
|
+
const remainingRight = new Set(rightSet);
|
|
140
|
+
outer: for (const leftValue of leftSet) {
|
|
141
|
+
for (const rightValue of remainingRight) {
|
|
142
|
+
if (looseEqualInternal(leftValue, rightValue, leftToRightSeen, rightToLeftSeen)) {
|
|
143
|
+
remainingRight.delete(rightValue);
|
|
144
|
+
continue outer;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Map (order-insensitive by entries; keys compared via looseEqual)
|
|
152
|
+
const leftIsMap = currentLeft instanceof Map;
|
|
153
|
+
const rightIsMap = currentRight instanceof Map;
|
|
154
|
+
if (leftIsMap || rightIsMap) {
|
|
155
|
+
if (!leftIsMap || !rightIsMap)
|
|
156
|
+
return false;
|
|
157
|
+
const leftMap = currentLeft;
|
|
158
|
+
const rightMap = currentRight;
|
|
159
|
+
if (leftMap.size !== rightMap.size)
|
|
160
|
+
return false;
|
|
161
|
+
const remainingRightEntries = new Set(rightMap.entries());
|
|
162
|
+
outer: for (const [leftKey, leftValue] of leftMap.entries()) {
|
|
163
|
+
for (const candidate of remainingRightEntries) {
|
|
164
|
+
const [rightKey, rightValue] = candidate;
|
|
165
|
+
if (looseEqualInternal(leftKey, rightKey, leftToRightSeen, rightToLeftSeen) &&
|
|
166
|
+
looseEqualInternal(leftValue, rightValue, leftToRightSeen, rightToLeftSeen)) {
|
|
167
|
+
remainingRightEntries.delete(candidate);
|
|
168
|
+
continue outer;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
// Fallback: compare by enumerable shape (prototype-insensitive).
|
|
176
|
+
// Missing ≈ undefined via union-of-keys comparison.
|
|
177
|
+
const leftKeys = Object.keys(currentLeft);
|
|
178
|
+
const rightKeys = Object.keys(currentRight);
|
|
179
|
+
const allKeys = new Set([...leftKeys, ...rightKeys]);
|
|
180
|
+
const leftRecord = currentLeft;
|
|
181
|
+
const rightRecord = currentRight;
|
|
182
|
+
for (const key of allKeys) {
|
|
183
|
+
const leftHasKey = Object.hasOwn(leftRecord, key);
|
|
184
|
+
const rightHasKey = Object.hasOwn(rightRecord, key);
|
|
185
|
+
const leftValue = leftHasKey ? leftRecord[key] : undefined;
|
|
186
|
+
const rightValue = rightHasKey ? rightRecord[key] : undefined;
|
|
187
|
+
// If one side is missing and the other side is present-but-not-undefined, fail.
|
|
188
|
+
if (leftHasKey !== rightHasKey) {
|
|
189
|
+
if (leftValue !== undefined || rightValue !== undefined)
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
worklist.push([leftValue, rightValue]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
export function looseEqual(left, right) {
|
|
198
|
+
if (sameValue(left, right))
|
|
199
|
+
return true;
|
|
200
|
+
if (isPrimitive(left) || isPrimitive(right))
|
|
201
|
+
return false;
|
|
202
|
+
if (!isObjectLike(left) || !isObjectLike(right))
|
|
203
|
+
return false;
|
|
204
|
+
return looseEqualInternal(left, right, new WeakMap(), new WeakMap());
|
|
205
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ToThrowExpected = undefined | string | RegExp | (new (...args: unknown[]) => Error) | {
|
|
2
|
+
message?: string | RegExp;
|
|
3
|
+
name?: string;
|
|
4
|
+
};
|
|
5
|
+
interface MatchResult {
|
|
6
|
+
pass: boolean;
|
|
7
|
+
message: () => string;
|
|
8
|
+
}
|
|
9
|
+
export declare function toThrow(received: unknown, expected?: ToThrowExpected, isNot?: boolean): MatchResult;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=toThrow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/toThrow.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,MAAM,GACN,MAAM,GACN,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,GACnC;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,UAAU,WAAW;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;AAgED,wBAAgB,OAAO,CACrB,QAAQ,EAAE,OAAO,EACjB,QAAQ,CAAC,EAAE,eAAe,EAC1B,KAAK,UAAQ,GACZ,WAAW,CAgDb"}
|