@poveste/shared 0.15.0 → 0.16.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/dist/state.d.ts +27 -0
- package/dist/state.js +44 -2
- package/package.json +8 -6
package/dist/state.d.ts
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
export declare function clone(data: any): any;
|
|
2
2
|
export declare function omit(data: any, keys: string[]): Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* Whether Vue has marked this value raw, and the walkers must stop here.
|
|
5
|
+
*
|
|
6
|
+
* Read as a property rather than through Vue's `isReactive`, because this
|
|
7
|
+
* package does not depend on Vue — and because the flag is what has to be
|
|
8
|
+
* asked anyway: `markRaw` defines `__v_skip` **non-enumerable**, so it crosses
|
|
9
|
+
* neither `structuredClone` nor JSON, and by the time a value has been through
|
|
10
|
+
* the sandbox bridge the mark is gone (#957).
|
|
11
|
+
*
|
|
12
|
+
* A marked value looks plain to every predicate here: a component's exposed
|
|
13
|
+
* object and `markRaw({ … })` both have `Object.prototype` and own enumerable
|
|
14
|
+
* keys, so without this the compare and the copy descend into whatever is
|
|
15
|
+
* behind them.
|
|
16
|
+
*
|
|
17
|
+
* The read is guarded because state is user data and may be a proxy with a
|
|
18
|
+
* throwing trap; an unanswerable value is treated as unmarked, which is the
|
|
19
|
+
* behaviour this had before.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isMarkedRaw(value: any): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Exported because `poveste-app`'s walker has to draw the same line. The two
|
|
24
|
+
* disagreeing about what a non-plain value is was #977: the walker flattened a
|
|
25
|
+
* `Date` to `{}` before `isEquivalent` ever saw it, so the defence below —
|
|
26
|
+
* written for exactly that case — was handed two empty plain objects and
|
|
27
|
+
* reported them equivalent.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isPlainObject(value: any): boolean;
|
|
3
30
|
/**
|
|
4
31
|
* Structural comparison, deliberately narrow: it recurses into plain objects and
|
|
5
32
|
* arrays and compares everything else by `Object.is`.
|
package/dist/state.js
CHANGED
|
@@ -24,7 +24,43 @@ export function omit(data, keys) {
|
|
|
24
24
|
}
|
|
25
25
|
return copy;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Whether Vue has marked this value raw, and the walkers must stop here.
|
|
29
|
+
*
|
|
30
|
+
* Read as a property rather than through Vue's `isReactive`, because this
|
|
31
|
+
* package does not depend on Vue — and because the flag is what has to be
|
|
32
|
+
* asked anyway: `markRaw` defines `__v_skip` **non-enumerable**, so it crosses
|
|
33
|
+
* neither `structuredClone` nor JSON, and by the time a value has been through
|
|
34
|
+
* the sandbox bridge the mark is gone (#957).
|
|
35
|
+
*
|
|
36
|
+
* A marked value looks plain to every predicate here: a component's exposed
|
|
37
|
+
* object and `markRaw({ … })` both have `Object.prototype` and own enumerable
|
|
38
|
+
* keys, so without this the compare and the copy descend into whatever is
|
|
39
|
+
* behind them.
|
|
40
|
+
*
|
|
41
|
+
* The read is guarded because state is user data and may be a proxy with a
|
|
42
|
+
* throwing trap; an unanswerable value is treated as unmarked, which is the
|
|
43
|
+
* behaviour this had before.
|
|
44
|
+
*/
|
|
45
|
+
export function isMarkedRaw(value) {
|
|
46
|
+
if (value === null || typeof value !== 'object') {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return value.__v_skip === true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Exported because `poveste-app`'s walker has to draw the same line. The two
|
|
58
|
+
* disagreeing about what a non-plain value is was #977: the walker flattened a
|
|
59
|
+
* `Date` to `{}` before `isEquivalent` ever saw it, so the defence below —
|
|
60
|
+
* written for exactly that case — was handed two empty plain objects and
|
|
61
|
+
* reported them equivalent.
|
|
62
|
+
*/
|
|
63
|
+
export function isPlainObject(value) {
|
|
28
64
|
if (value === null || typeof value !== 'object') {
|
|
29
65
|
return false;
|
|
30
66
|
}
|
|
@@ -49,6 +85,12 @@ export function isEquivalent(a, b, seen) {
|
|
|
49
85
|
if (Object.is(a, b)) {
|
|
50
86
|
return true;
|
|
51
87
|
}
|
|
88
|
+
// Same reason as the prototype test below, reached differently: a marked
|
|
89
|
+
// value is one Vue itself refuses to look inside, and two distinct ones are
|
|
90
|
+
// not the same value whatever their keys say.
|
|
91
|
+
if (isMarkedRaw(a) || isMarkedRaw(b)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
52
94
|
const bothArrays = Array.isArray(a) && Array.isArray(b);
|
|
53
95
|
if (!bothArrays && !(isPlainObject(a) && isPlainObject(b))) {
|
|
54
96
|
return false;
|
|
@@ -236,7 +278,7 @@ export function diffState(baseline, next) {
|
|
|
236
278
|
* `Object.is`, so a reference is the identity the comparison is about.
|
|
237
279
|
*/
|
|
238
280
|
function copyState(value, seen = new WeakMap()) {
|
|
239
|
-
if (!Array.isArray(value) && !isPlainObject(value)) {
|
|
281
|
+
if (isMarkedRaw(value) || (!Array.isArray(value) && !isPlainObject(value))) {
|
|
240
282
|
return value;
|
|
241
283
|
}
|
|
242
284
|
if (seen.has(value)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poveste/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.0",
|
|
5
5
|
"description": "Shared utilities for Poveste",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan",
|
|
@@ -33,24 +33,26 @@
|
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": "
|
|
36
|
+
"node": ">=22.22.2"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"vite": "^8.0.0"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@poveste/vendors": "^0.
|
|
42
|
+
"@poveste/vendors": "^0.16.0",
|
|
43
43
|
"@types/fs-extra": "^11.0.4",
|
|
44
44
|
"chokidar": "^5.0.0",
|
|
45
45
|
"markdown-it": "^15.0.2",
|
|
46
46
|
"pathe": "^2.0.3",
|
|
47
47
|
"picocolors": "^1.1.1",
|
|
48
|
-
"unhead": "^3.1
|
|
48
|
+
"unhead": "^3.4.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
+
"@types/node": "^26.6.3",
|
|
51
52
|
"typescript": "6.0.3",
|
|
52
|
-
"vite": "^8.
|
|
53
|
-
"vitest": "^5.0.
|
|
53
|
+
"vite": "^8.3.1",
|
|
54
|
+
"vitest": "^5.0.2",
|
|
55
|
+
"vue-router": "^5.3.1"
|
|
54
56
|
},
|
|
55
57
|
"scripts": {
|
|
56
58
|
"build": "rimraf dist && tsc",
|