opshot 0.2.1 → 0.3.3
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/README.md +171 -78
- package/dist/index.d.ts +175 -46
- package/dist/index.js +2329 -119
- package/package.json +74 -74
- package/dist/react.d.ts +0 -11
- package/dist/react.js +0 -279
package/package.json
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
2
|
+
"name": "opshot",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "Plain-object state for React: mutate it directly, re-render only the components that read what changed, and track every change operation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"author": "Matt Cavender",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/visionsofparadise/opshot.git"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"check": "prettier --write . && eslint . --fix --cache && concurrently \"tsc --noEmit\" \"markdownlint-cli2 \\\"**/*.md\\\"\" \"textlint \\\"**/*.md\\\"\" \"knip --no-progress\" \"jscpd .\"",
|
|
27
|
+
"lint": "eslint . --fix --cache",
|
|
28
|
+
"lint:fix": "eslint . --fix",
|
|
29
|
+
"format": "prettier --write .",
|
|
30
|
+
"unit": "vitest run unit",
|
|
31
|
+
"integration": "vitest run integration",
|
|
32
|
+
"build": "tsup --config tsup.config.ts"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/compat": "^1.3.2",
|
|
39
|
+
"@eslint/js": "^9.39.5",
|
|
40
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
41
|
+
"@testing-library/react": "^16.3.2",
|
|
42
|
+
"@types/react": "^19.2.17",
|
|
43
|
+
"concurrently": "^10.0.3",
|
|
44
|
+
"eslint": "^9.39.5",
|
|
45
|
+
"eslint-config-prettier": "^10.1.8",
|
|
46
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
47
|
+
"eslint-plugin-barrel-files": "^3.0.1",
|
|
48
|
+
"eslint-plugin-check-file": "^3.3.1",
|
|
49
|
+
"eslint-plugin-comment-rules": "^0.1.5",
|
|
50
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
51
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
52
|
+
"eslint-plugin-react": "^7.37.5",
|
|
53
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
54
|
+
"globals": "^17.7.0",
|
|
55
|
+
"jscpd": "^5.0.12",
|
|
56
|
+
"jsdom": "^29.1.1",
|
|
57
|
+
"knip": "^6.29.0",
|
|
58
|
+
"markdownlint-cli2": "^0.23.1",
|
|
59
|
+
"prettier": "^3.6.2",
|
|
60
|
+
"proxy-compare": "^3.0.1",
|
|
61
|
+
"react": "^19.2.7",
|
|
62
|
+
"react-dom": "^19.2.7",
|
|
63
|
+
"textlint": "^15.2.2",
|
|
64
|
+
"textlint-filter-rule-comments": "^1.2.2",
|
|
65
|
+
"textlint-rule-no-dead-link": "^6.2.1",
|
|
66
|
+
"tsup": "^8.5.1",
|
|
67
|
+
"typescript": "^5.9.3",
|
|
68
|
+
"typescript-eslint": "^8.64.0",
|
|
69
|
+
"valtio": "2.3.2",
|
|
70
|
+
"vitest": "^4.1.10"
|
|
71
|
+
},
|
|
72
|
+
"allowScripts": {
|
|
73
|
+
"esbuild@0.27.7": true,
|
|
74
|
+
"unrs-resolver@1.12.2": true
|
|
75
|
+
}
|
|
76
76
|
}
|
package/dist/react.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
import { Group, Meta, Define, State } from './index.js';
|
|
3
|
-
import 'valtio/vanilla';
|
|
4
|
-
|
|
5
|
-
declare function retrack<P extends object>(component: FC<P>): FC<P>;
|
|
6
|
-
declare function useGroup(): Group;
|
|
7
|
-
declare function useGroup<In extends object, Out extends object>(meta: Meta<In, Out>): Group<In, Out>;
|
|
8
|
-
declare function useTrackedState<T extends object>(define: Define<T>): State<T>;
|
|
9
|
-
declare function useTrackedState<T extends object, In extends object, Out extends object>(define: Define<T, In, Out>, groupOrMeta: Group<In, Out> | Meta<In, Out>): State<T, In, Out>;
|
|
10
|
-
|
|
11
|
-
export { retrack, useGroup, useTrackedState };
|
package/dist/react.js
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { isChanged, createProxy } from 'proxy-compare';
|
|
2
|
-
import { memo, useState, useMemo, useRef, useCallback, useSyncExternalStore, useLayoutEffect } from 'react';
|
|
3
|
-
import { unstable_getInternalStates, ref, proxy, snapshot, subscribe } from 'valtio/vanilla';
|
|
4
|
-
|
|
5
|
-
// src/react.tsx
|
|
6
|
-
var { refSet } = unstable_getInternalStates();
|
|
7
|
-
var isPlainArray = (value) => Array.isArray(value) && !refSet.has(value);
|
|
8
|
-
var isPlainObject = (value) => {
|
|
9
|
-
if (typeof value !== "object" || value === null || Array.isArray(value) || refSet.has(value)) return false;
|
|
10
|
-
const prototype = Object.getPrototypeOf(value);
|
|
11
|
-
return prototype === Object.prototype || prototype === null;
|
|
12
|
-
};
|
|
13
|
-
var isCloneable = (value) => isPlainObject(value) || isPlainArray(value);
|
|
14
|
-
var cloneValue = (value) => {
|
|
15
|
-
if (isPlainArray(value)) return value.map(cloneValue);
|
|
16
|
-
if (isPlainObject(value)) {
|
|
17
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, cloneValue(child)]));
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
};
|
|
21
|
-
var toPointer = (path) => {
|
|
22
|
-
if (path.length === 0) return "";
|
|
23
|
-
return `/${path.map((segment) => String(segment).replaceAll("~", "~0").replaceAll("/", "~1")).join("/")}`;
|
|
24
|
-
};
|
|
25
|
-
var removing = (pointer) => ({ op: "remove", path: pointer });
|
|
26
|
-
var carrying = (op, pointer, value) => {
|
|
27
|
-
if (!isCloneable(value)) return { op, path: pointer, value };
|
|
28
|
-
return {
|
|
29
|
-
op,
|
|
30
|
-
path: pointer,
|
|
31
|
-
get value() {
|
|
32
|
-
return cloneValue(value);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
var addPair = (pointer, after) => ({ do: carrying("add", pointer, after), undo: removing(pointer) });
|
|
37
|
-
var removePair = (pointer, before) => ({ do: removing(pointer), undo: carrying("add", pointer, before) });
|
|
38
|
-
var replacePair = (pointer, before, after) => ({
|
|
39
|
-
do: carrying("replace", pointer, after),
|
|
40
|
-
undo: carrying("replace", pointer, before)
|
|
41
|
-
});
|
|
42
|
-
var diffValue = (before, after, path, ops) => {
|
|
43
|
-
if (Object.is(before, after)) return;
|
|
44
|
-
if (isPlainArray(before) && isPlainArray(after)) {
|
|
45
|
-
if (before.length !== after.length) {
|
|
46
|
-
ops.push(replacePair(toPointer(path), before, after));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
for (let index = 0; index < after.length; index++) diffValue(before[index], after[index], [...path, index], ops);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
53
|
-
for (const key of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) {
|
|
54
|
-
if (!Object.hasOwn(before, key)) ops.push(addPair(toPointer([...path, key]), after[key]));
|
|
55
|
-
else if (!Object.hasOwn(after, key)) ops.push(removePair(toPointer([...path, key]), before[key]));
|
|
56
|
-
else diffValue(before[key], after[key], [...path, key], ops);
|
|
57
|
-
}
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
ops.push(replacePair(toPointer(path), before, after));
|
|
61
|
-
};
|
|
62
|
-
function diffSnapshots(before, after) {
|
|
63
|
-
const ops = [];
|
|
64
|
-
diffValue(before, after, [], ops);
|
|
65
|
-
return ops;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/createState.ts
|
|
69
|
-
var stateBrand = /* @__PURE__ */ Symbol.for("opshot.state");
|
|
70
|
-
var metaBrand = /* @__PURE__ */ Symbol.for("opshot.meta");
|
|
71
|
-
var hasOwn = (value, key) => Object.hasOwn(value, key);
|
|
72
|
-
function isMeta(value) {
|
|
73
|
-
if (typeof value !== "object" || value === null || !hasOwn(value, metaBrand)) return false;
|
|
74
|
-
return value[metaBrand] === true;
|
|
75
|
-
}
|
|
76
|
-
function createGroupState(define, groupListeners, metaToken) {
|
|
77
|
-
const callback = typeof define === "function" ? define : () => define;
|
|
78
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
79
|
-
const created = {};
|
|
80
|
-
const requireProxy = () => {
|
|
81
|
-
const { proxied } = created;
|
|
82
|
-
if (!proxied) throw new Error("opshot: called during createState definition");
|
|
83
|
-
return proxied;
|
|
84
|
-
};
|
|
85
|
-
const get = () => snapshot(requireProxy());
|
|
86
|
-
const mutate = (callback2, ...metaArgs) => {
|
|
87
|
-
const [meta] = metaArgs;
|
|
88
|
-
const proxied = requireProxy();
|
|
89
|
-
if (handle.isMutating) throw new Error("opshot: nested mutate on the same state");
|
|
90
|
-
handle.isMutating = true;
|
|
91
|
-
const before = snapshot(proxied);
|
|
92
|
-
try {
|
|
93
|
-
callback2(proxied);
|
|
94
|
-
} finally {
|
|
95
|
-
handle.isMutating = false;
|
|
96
|
-
}
|
|
97
|
-
const after = snapshot(proxied);
|
|
98
|
-
if (before === after) return;
|
|
99
|
-
if (listeners.size === 0 && (groupListeners?.size ?? 0) === 0) return;
|
|
100
|
-
const ops = diffSnapshots(before, after);
|
|
101
|
-
if (ops.length === 0) return;
|
|
102
|
-
const emittedMeta = metaToken?.defaults !== void 0 ? { ...metaToken.defaults, ...meta } : meta ?? {};
|
|
103
|
-
for (const listener of [...groupListeners ?? []]) listener(after, ops, emittedMeta);
|
|
104
|
-
for (const listener of [...listeners]) listener(after, ops, emittedMeta);
|
|
105
|
-
};
|
|
106
|
-
const subscribe = (listener) => {
|
|
107
|
-
listeners.add(listener);
|
|
108
|
-
return () => {
|
|
109
|
-
listeners.delete(listener);
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
const isSameState = (other) => isState(other) && other.op === handle;
|
|
113
|
-
const unwrap = () => {
|
|
114
|
-
const { op, mutate: mutate2, ...rest } = get();
|
|
115
|
-
return rest;
|
|
116
|
-
};
|
|
117
|
-
const literal = callback(mutate, get);
|
|
118
|
-
for (const key of ["op", "mutate"]) {
|
|
119
|
-
if (Object.hasOwn(literal, key)) throw new Error(`opshot: "${key}" is a reserved key on a state`);
|
|
120
|
-
}
|
|
121
|
-
const base = Object.create(Reflect.getPrototypeOf(literal));
|
|
122
|
-
Object.defineProperties(base, Object.getOwnPropertyDescriptors(literal));
|
|
123
|
-
const handle = { unsafeMutable: base, isMutating: false, subscribe, isSameState, unwrap, [stateBrand]: true };
|
|
124
|
-
Object.defineProperty(base, "op", { value: ref(handle), enumerable: true, writable: false, configurable: false });
|
|
125
|
-
Object.defineProperty(base, "mutate", { value: mutate, enumerable: true, writable: false, configurable: false });
|
|
126
|
-
created.proxied = proxy(base);
|
|
127
|
-
handle.unsafeMutable = created.proxied;
|
|
128
|
-
return get();
|
|
129
|
-
}
|
|
130
|
-
function isState(value) {
|
|
131
|
-
if (typeof value !== "object" || value === null || !hasOwn(value, "op")) return false;
|
|
132
|
-
const handle = value.op;
|
|
133
|
-
if (typeof handle !== "object" || handle === null || !hasOwn(handle, stateBrand)) return false;
|
|
134
|
-
return handle[stateBrand] === true;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// src/createGroup.ts
|
|
138
|
-
function createGroup(meta) {
|
|
139
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
140
|
-
return {
|
|
141
|
-
createState(define) {
|
|
142
|
-
return createGroupState(define, listeners, meta);
|
|
143
|
-
},
|
|
144
|
-
subscribe(listener) {
|
|
145
|
-
listeners.add(listener);
|
|
146
|
-
return () => {
|
|
147
|
-
listeners.delete(listener);
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// src/react.tsx
|
|
154
|
-
function shouldTraverse(value) {
|
|
155
|
-
if (value === null || typeof value !== "object") return false;
|
|
156
|
-
if (Array.isArray(value)) return true;
|
|
157
|
-
const prototype = Object.getPrototypeOf(value);
|
|
158
|
-
return prototype === Object.prototype || prototype === null;
|
|
159
|
-
}
|
|
160
|
-
function findStatePaths(value, path = [], paths = []) {
|
|
161
|
-
if (isState(value)) {
|
|
162
|
-
paths.push(path);
|
|
163
|
-
return paths;
|
|
164
|
-
}
|
|
165
|
-
if (!shouldTraverse(value)) return paths;
|
|
166
|
-
if (Array.isArray(value)) {
|
|
167
|
-
value.forEach((item, index) => {
|
|
168
|
-
findStatePaths(item, [...path, index], paths);
|
|
169
|
-
});
|
|
170
|
-
} else {
|
|
171
|
-
for (const [key, propertyValue] of Object.entries(value)) {
|
|
172
|
-
if (key === "children") continue;
|
|
173
|
-
findStatePaths(propertyValue, [...path, key], paths);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return paths;
|
|
177
|
-
}
|
|
178
|
-
function getAtPath(object, path) {
|
|
179
|
-
let current = object;
|
|
180
|
-
for (const segment of path) {
|
|
181
|
-
if (current === null || current === void 0) return void 0;
|
|
182
|
-
current = current[segment];
|
|
183
|
-
}
|
|
184
|
-
return current;
|
|
185
|
-
}
|
|
186
|
-
function setAtPath(object, path, value) {
|
|
187
|
-
if (path.length === 0) return value;
|
|
188
|
-
const head = path[0];
|
|
189
|
-
if (head === void 0) throw new Error("setAtPath: non-empty path yielded no head segment");
|
|
190
|
-
const tail = path.slice(1);
|
|
191
|
-
const current = object[head];
|
|
192
|
-
const updated = setAtPath(current, tail, value);
|
|
193
|
-
if (Array.isArray(object)) {
|
|
194
|
-
const clone = [...object];
|
|
195
|
-
clone[head] = updated;
|
|
196
|
-
return clone;
|
|
197
|
-
}
|
|
198
|
-
return { ...object, [head]: updated };
|
|
199
|
-
}
|
|
200
|
-
var targetCache = /* @__PURE__ */ new WeakMap();
|
|
201
|
-
function useRetrackAll(states) {
|
|
202
|
-
const lastRendered = useRef([]);
|
|
203
|
-
const lastReturned = useRef([]);
|
|
204
|
-
const nextProxies = states.map((state) => state.op.unsafeMutable);
|
|
205
|
-
const [proxies, setProxies] = useState(nextProxies);
|
|
206
|
-
const isStale = proxies.length !== nextProxies.length || proxies.some((proxied, index) => proxied !== nextProxies[index]);
|
|
207
|
-
if (isStale) setProxies(nextProxies);
|
|
208
|
-
const trackings = useMemo(() => proxies.map(() => ({ affected: /* @__PURE__ */ new WeakMap(), proxyCache: /* @__PURE__ */ new WeakMap() })), [proxies]);
|
|
209
|
-
const getSnapshot = useCallback(() => {
|
|
210
|
-
const next = proxies.map((proxied) => snapshot(proxied));
|
|
211
|
-
const last = lastReturned.current;
|
|
212
|
-
if (last.length === next.length && last.every((snap, index) => snap === next[index])) return last;
|
|
213
|
-
lastReturned.current = next;
|
|
214
|
-
return next;
|
|
215
|
-
}, [proxies]);
|
|
216
|
-
const subscribe$1 = useCallback(
|
|
217
|
-
(callback) => {
|
|
218
|
-
const unsubscribes = proxies.map(
|
|
219
|
-
(proxied, index) => subscribe(proxied, () => {
|
|
220
|
-
const prev = lastRendered.current[index];
|
|
221
|
-
const tracking = trackings[index];
|
|
222
|
-
if (prev && tracking && prev !== snapshot(proxied)) {
|
|
223
|
-
if (!tracking.affected.has(prev)) return;
|
|
224
|
-
try {
|
|
225
|
-
if (!isChanged(prev, snapshot(proxied), tracking.affected, /* @__PURE__ */ new WeakMap())) return;
|
|
226
|
-
} catch {
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
callback();
|
|
230
|
-
})
|
|
231
|
-
);
|
|
232
|
-
return () => {
|
|
233
|
-
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
234
|
-
};
|
|
235
|
-
},
|
|
236
|
-
[proxies, trackings]
|
|
237
|
-
);
|
|
238
|
-
const freshStates = useSyncExternalStore(subscribe$1, getSnapshot);
|
|
239
|
-
useLayoutEffect(() => {
|
|
240
|
-
lastRendered.current = freshStates;
|
|
241
|
-
});
|
|
242
|
-
const trackedSnapshots = useMemo(
|
|
243
|
-
() => freshStates.map((snap, index) => {
|
|
244
|
-
const tracking = trackings[index];
|
|
245
|
-
if (!tracking) return snap;
|
|
246
|
-
return createProxy(snap, tracking.affected, tracking.proxyCache, targetCache);
|
|
247
|
-
}),
|
|
248
|
-
[freshStates, trackings]
|
|
249
|
-
);
|
|
250
|
-
return isStale ? states : trackedSnapshots;
|
|
251
|
-
}
|
|
252
|
-
function retrack(component) {
|
|
253
|
-
const componentName = component.displayName ?? component.name;
|
|
254
|
-
const Retracked = (props) => {
|
|
255
|
-
const snapshotPaths = useMemo(() => findStatePaths(props), [props]);
|
|
256
|
-
const staleStates = useMemo(() => snapshotPaths.map((path) => getAtPath(props, path)).filter(isState), [props, snapshotPaths]);
|
|
257
|
-
const freshStates = useRetrackAll(staleStates);
|
|
258
|
-
const freshProps = useMemo(() => {
|
|
259
|
-
if (freshStates === staleStates) return props;
|
|
260
|
-
return snapshotPaths.reduce((acc, path, index) => setAtPath(acc, path, freshStates[index]), props);
|
|
261
|
-
}, [props, snapshotPaths, staleStates, freshStates]);
|
|
262
|
-
return component(freshProps);
|
|
263
|
-
};
|
|
264
|
-
Retracked.displayName = `retrack(${componentName === "" ? "Anonymous" : componentName})`;
|
|
265
|
-
return memo(Retracked);
|
|
266
|
-
}
|
|
267
|
-
function useGroup(meta) {
|
|
268
|
-
return useState(() => meta === void 0 ? createGroup() : createGroup(meta))[0];
|
|
269
|
-
}
|
|
270
|
-
function useTrackedState(define, groupOrMeta) {
|
|
271
|
-
const created = useState(() => {
|
|
272
|
-
if (groupOrMeta !== void 0 && !isMeta(groupOrMeta)) return groupOrMeta.createState(define);
|
|
273
|
-
return createGroupState(define, void 0, groupOrMeta);
|
|
274
|
-
})[0];
|
|
275
|
-
const [fresh] = useRetrackAll([created]);
|
|
276
|
-
return fresh;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export { retrack, useGroup, useTrackedState };
|