@vorplex/core 0.0.11 → 0.0.20
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.
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type Result<TValue, TFailure extends {
|
|
2
|
+
reason: string;
|
|
3
|
+
}> = [null, TValue] | [TFailure, TValue];
|
|
4
|
+
export declare function ok<T>(value: T): Result<T, null>;
|
|
5
|
+
export declare function fail<TReason extends string, T extends {
|
|
6
|
+
reason: TReason;
|
|
7
|
+
}>(error: T): Result<null, T>;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './consts/mime-type.const';
|
|
|
2
2
|
export * from './consts/unit.const';
|
|
3
3
|
export * from './functions/debounce.function';
|
|
4
4
|
export * from './functions/is-node-environment.function';
|
|
5
|
+
export * from './functions/ok.function';
|
|
5
6
|
export * from './functions/parse-path-selector.function';
|
|
6
7
|
export * from './functions/parse-url.function';
|
|
7
8
|
export * from './interfaces/group.interface';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from './consts/mime-type.const';
|
|
|
3
3
|
export * from './consts/unit.const';
|
|
4
4
|
export * from './functions/debounce.function';
|
|
5
5
|
export * from './functions/is-node-environment.function';
|
|
6
|
+
export * from './functions/ok.function';
|
|
6
7
|
export * from './functions/parse-path-selector.function';
|
|
7
8
|
export * from './functions/parse-url.function';
|
|
8
9
|
export * from './interfaces/group.interface';
|
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
export type ArrayChange = Record<`$${number}` | `$${number}+`, any | typeof $Changes.deleted>;
|
|
2
|
-
export interface
|
|
2
|
+
export interface ChangeCompareResult {
|
|
3
|
+
similarities: any;
|
|
3
4
|
conflicts: any;
|
|
4
5
|
differences: any;
|
|
5
6
|
}
|
|
6
7
|
export interface ChangeRebase<T = any> {
|
|
8
|
+
/**
|
|
9
|
+
* The remote with local changes
|
|
10
|
+
*/
|
|
7
11
|
result: T;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
remote:
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Only defined when the rebase contains conflicts.
|
|
14
|
+
* Contains rebase conflicts and merge
|
|
15
|
+
*/
|
|
16
|
+
conflict?: {
|
|
17
|
+
local: ChangeCompareResult;
|
|
18
|
+
remote: ChangeCompareResult;
|
|
19
|
+
merge?: {
|
|
20
|
+
/**
|
|
21
|
+
* The source with remote and local none conflicting changes
|
|
22
|
+
*/
|
|
23
|
+
source: T;
|
|
24
|
+
/**
|
|
25
|
+
* The `.source` with remote conflict changes
|
|
26
|
+
*/
|
|
27
|
+
remote: T;
|
|
28
|
+
/**
|
|
29
|
+
* The `.source` with local conflict changes
|
|
30
|
+
*/
|
|
31
|
+
local: T;
|
|
32
|
+
/**
|
|
33
|
+
* The remote with local none conflicting changes
|
|
34
|
+
*/
|
|
35
|
+
result: T;
|
|
36
|
+
};
|
|
17
37
|
};
|
|
18
38
|
}
|
|
19
39
|
export declare class $Changes {
|
|
@@ -22,15 +42,11 @@ export declare class $Changes {
|
|
|
22
42
|
static getArrayChanges(a: any[], b: any[]): ArrayChange | undefined;
|
|
23
43
|
static getObjectChanges(a: Record<string, any>, b: Record<string, any>): Record<string, any | typeof $Changes.deleted>;
|
|
24
44
|
static get(a: any, b: any): undefined | any | Record<string, any | typeof $Changes.deleted> | ArrayChange;
|
|
25
|
-
static
|
|
26
|
-
conflicts: string[];
|
|
27
|
-
differences: string[];
|
|
28
|
-
};
|
|
29
|
-
static resolveConflicts(changesA: any, changesB: any): ChangeConflicts;
|
|
45
|
+
static compareChanges(changesA: any, changesB: any): ChangeCompareResult;
|
|
30
46
|
private static pathsOverlap;
|
|
31
47
|
static hasConflict(changesA: any, changesB: any): boolean;
|
|
32
48
|
static asValue(changes: any): any;
|
|
33
|
-
static apply(value: any, changes: any): any;
|
|
49
|
+
static apply(value: any, ...changes: any[]): any;
|
|
34
50
|
static rebase(source: any, local: any, remote: any): ChangeRebase;
|
|
35
51
|
/**
|
|
36
52
|
* Excludes specific paths from a changes object and cleans up empty containers.
|
|
@@ -107,33 +107,31 @@ export class $Changes {
|
|
|
107
107
|
return $Changes.getArrayChanges(a, b);
|
|
108
108
|
return $Changes.getObjectChanges(a, b);
|
|
109
109
|
}
|
|
110
|
-
static
|
|
110
|
+
static compareChanges(changesA, changesB) {
|
|
111
111
|
const aPaths = $Object.getPaths(changesA);
|
|
112
112
|
const bPaths = $Object.getPaths(changesB);
|
|
113
|
+
const similarities = new Set();
|
|
113
114
|
const conflicts = new Set();
|
|
114
115
|
const differences = new Set();
|
|
115
|
-
for (const aPath of aPaths) {
|
|
116
|
-
if (bPaths.some(bPath => this.pathsOverlap(aPath, bPath)))
|
|
117
|
-
conflicts.add(aPath);
|
|
118
|
-
else
|
|
119
|
-
differences.add(aPath);
|
|
120
|
-
}
|
|
121
116
|
for (const bPath of bPaths) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
let overlapped;
|
|
118
|
+
for (const aPath of aPaths) {
|
|
119
|
+
if (this.pathsOverlap(aPath, bPath)) {
|
|
120
|
+
overlapped = true;
|
|
121
|
+
const longestPath = aPath.length > bPath.length ? aPath : bPath;
|
|
122
|
+
if ($Value.equals($Value.get(changesA, longestPath), $Value.get(changesB, longestPath)))
|
|
123
|
+
similarities.add(bPath);
|
|
124
|
+
else
|
|
125
|
+
conflicts.add(bPath);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!overlapped)
|
|
125
129
|
differences.add(bPath);
|
|
126
130
|
}
|
|
127
131
|
return {
|
|
128
|
-
|
|
129
|
-
differences:
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
static resolveConflicts(changesA, changesB) {
|
|
133
|
-
const { conflicts, differences } = this.classifyPathsByOverlap(changesA, changesB);
|
|
134
|
-
return {
|
|
135
|
-
differences: $Changes.excludeChanges(changesB, conflicts),
|
|
136
|
-
conflicts: $Changes.excludeChanges(changesB, differences)
|
|
132
|
+
similarities: $Changes.excludeChanges(changesB, [...conflicts, ...differences]),
|
|
133
|
+
differences: $Changes.excludeChanges(changesB, [...similarities, ...conflicts]),
|
|
134
|
+
conflicts: $Changes.excludeChanges(changesB, [...similarities, ...differences])
|
|
137
135
|
};
|
|
138
136
|
}
|
|
139
137
|
static pathsOverlap(a, b) {
|
|
@@ -151,8 +149,11 @@ export class $Changes {
|
|
|
151
149
|
const bPaths = $Object.getPaths(changesB);
|
|
152
150
|
for (const bPath of bPaths) {
|
|
153
151
|
for (const aPath of aPaths) {
|
|
154
|
-
if (this.pathsOverlap(aPath, bPath))
|
|
155
|
-
|
|
152
|
+
if (this.pathsOverlap(aPath, bPath)) {
|
|
153
|
+
const longestPath = aPath.length > bPath.length ? aPath : bPath;
|
|
154
|
+
if (!$Value.equals($Value.get(changesA, longestPath), $Value.get(changesB, longestPath)))
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
return false;
|
|
@@ -164,7 +165,6 @@ export class $Changes {
|
|
|
164
165
|
return changes.map(item => $Changes.asValue(item));
|
|
165
166
|
}
|
|
166
167
|
if (typeof changes === 'object' && changes !== null) {
|
|
167
|
-
// cannot materialize array index changes without a base; strip them
|
|
168
168
|
if ($Changes.isArrayIndexChange(changes))
|
|
169
169
|
return undefined;
|
|
170
170
|
const result = {};
|
|
@@ -177,80 +177,86 @@ export class $Changes {
|
|
|
177
177
|
}
|
|
178
178
|
return changes;
|
|
179
179
|
}
|
|
180
|
-
static apply(value, changes) {
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
180
|
+
static apply(value, ...changes) {
|
|
181
|
+
function apply(value, changes) {
|
|
182
|
+
function applyArrayChange(originalArray, change) {
|
|
183
|
+
if (!$Changes.isArrayIndexChange(change))
|
|
184
|
+
return $Value.clone(change);
|
|
185
|
+
const result = $Value.clone(originalArray);
|
|
186
|
+
const entries = Object.entries(change)
|
|
187
|
+
.map(([k, v]) => {
|
|
188
|
+
const isInsert = k.endsWith('+');
|
|
189
|
+
const nStr = isInsert ? k.slice(1, -1) : k.slice(1);
|
|
190
|
+
return [Number.parseInt(nStr, 10), isInsert, v];
|
|
191
|
+
})
|
|
192
|
+
.filter(([i]) => !Number.isNaN(i))
|
|
193
|
+
.sort(([iA, insA, vA], [iB, insB, vB]) => {
|
|
194
|
+
const aDel = vA === $Changes.deleted;
|
|
195
|
+
const bDel = vB === $Changes.deleted;
|
|
196
|
+
// deletes first, highest -> lowest
|
|
197
|
+
if (aDel !== bDel)
|
|
198
|
+
return aDel ? -1 : 1;
|
|
199
|
+
if (aDel && bDel)
|
|
200
|
+
return iB - iA;
|
|
201
|
+
// inserts next, lowest -> highest
|
|
202
|
+
if (insA !== insB)
|
|
203
|
+
return insA ? -1 : 1;
|
|
204
|
+
if (insA && insB)
|
|
205
|
+
return iA - iB;
|
|
206
|
+
// sets last, lowest -> highest
|
|
204
207
|
return iA - iB;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
result[index] = $Changes.apply(result[index], op);
|
|
208
|
+
});
|
|
209
|
+
for (const [index, isInsert, op] of entries) {
|
|
210
|
+
if (op === $Changes.deleted) {
|
|
211
|
+
if (index >= 0 && index < result.length)
|
|
212
|
+
result.splice(index, 1);
|
|
213
|
+
}
|
|
214
|
+
else if (isInsert) {
|
|
215
|
+
const v = $Value.clone(op);
|
|
216
|
+
const idx = Math.min(Math.max(index, 0), result.length);
|
|
217
|
+
result.splice(idx, 0, v);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
if (index >= result.length)
|
|
221
|
+
result.length = index + 1;
|
|
222
|
+
result[index] = $Changes.apply(result[index], op);
|
|
223
|
+
}
|
|
222
224
|
}
|
|
225
|
+
return result;
|
|
223
226
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return value;
|
|
228
|
-
if (value == null || typeof changes !== 'object')
|
|
229
|
-
return $Changes.asValue(changes);
|
|
230
|
-
if (Array.isArray(value)) {
|
|
231
|
-
return applyArrayChange(value, changes);
|
|
232
|
-
}
|
|
233
|
-
else if (typeof value === 'object') {
|
|
234
|
-
if (Array.isArray(changes))
|
|
227
|
+
if (changes === undefined)
|
|
228
|
+
return value;
|
|
229
|
+
if (value == null || typeof changes !== 'object')
|
|
235
230
|
return $Changes.asValue(changes);
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
231
|
+
if (Array.isArray(value)) {
|
|
232
|
+
return applyArrayChange(value, changes);
|
|
233
|
+
}
|
|
234
|
+
else if (typeof value === 'object') {
|
|
235
|
+
if (Array.isArray(changes))
|
|
236
|
+
return $Changes.asValue(changes);
|
|
237
|
+
const result = { ...value };
|
|
238
|
+
for (const [key, change] of Object.entries(changes)) {
|
|
239
|
+
if (change === $Changes.deleted) {
|
|
240
|
+
delete result[key];
|
|
241
|
+
}
|
|
242
|
+
else if (Array.isArray(result[key])) {
|
|
243
|
+
result[key] = applyArrayChange(result[key] || [], change);
|
|
244
|
+
}
|
|
245
|
+
else if (typeof change === 'object' && change !== null) {
|
|
246
|
+
result[key] = $Changes.apply(result[key], change);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
result[key] = change;
|
|
250
|
+
}
|
|
249
251
|
}
|
|
252
|
+
return result;
|
|
250
253
|
}
|
|
251
|
-
return
|
|
254
|
+
return $Changes.asValue(changes);
|
|
255
|
+
}
|
|
256
|
+
for (const change of changes) {
|
|
257
|
+
value = apply(value, change);
|
|
252
258
|
}
|
|
253
|
-
return
|
|
259
|
+
return value;
|
|
254
260
|
}
|
|
255
261
|
static rebase(source, local, remote) {
|
|
256
262
|
const localChanges = $Changes.get(source, local);
|
|
@@ -267,20 +273,20 @@ export class $Changes {
|
|
|
267
273
|
return { result };
|
|
268
274
|
}
|
|
269
275
|
else {
|
|
270
|
-
const localConflict = $Changes.
|
|
271
|
-
const remoteConflict = $Changes.
|
|
272
|
-
const sourceWithDifferences = $Changes.apply(
|
|
276
|
+
const localConflict = $Changes.compareChanges(remoteChanges, localChanges);
|
|
277
|
+
const remoteConflict = $Changes.compareChanges(localChanges, remoteChanges);
|
|
278
|
+
const sourceWithDifferences = $Changes.apply(source, remoteConflict.differences, localConflict.differences, remoteConflict.similarities, localConflict.similarities);
|
|
273
279
|
const mergedWithLocalDifferences = $Changes.apply(remote, localConflict.differences);
|
|
274
280
|
return {
|
|
275
|
-
|
|
281
|
+
conflict: {
|
|
276
282
|
local: localConflict,
|
|
277
283
|
remote: remoteConflict,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
+
merge: {
|
|
285
|
+
source: sourceWithDifferences,
|
|
286
|
+
remote: $Changes.apply(sourceWithDifferences, remoteConflict.conflicts),
|
|
287
|
+
local: $Changes.apply(sourceWithDifferences, localConflict.conflicts),
|
|
288
|
+
result: mergedWithLocalDifferences
|
|
289
|
+
},
|
|
284
290
|
},
|
|
285
291
|
result: $Changes.apply(mergedWithLocalDifferences, localConflict.conflicts)
|
|
286
292
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vorplex/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -15,16 +15,14 @@
|
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"main": "./dist/index.js",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"tslib": "
|
|
18
|
+
"tslib": "2.8.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"
|
|
22
|
-
"jest": "^29.5.0",
|
|
23
|
-
"ts-jest": "^29.1.0"
|
|
21
|
+
"vitest": "3.2.4"
|
|
24
22
|
},
|
|
25
23
|
"scripts": {
|
|
26
24
|
"build": "tsc -b --force tsconfig.build.json",
|
|
27
|
-
"test": "
|
|
25
|
+
"test": "vitest run",
|
|
28
26
|
"npm:publish": "pnpm publish --registry=https://registry.npmjs.org/"
|
|
29
27
|
}
|
|
30
28
|
}
|