@fumari/stf 0.0.3 → 1.0.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.
- package/dist/index.d.ts +40 -19
- package/dist/index.js +105 -51
- package/dist/lib/utils.d.ts +6 -5
- package/dist/lib/utils.js +17 -13
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ declare function useStf(options: {
|
|
|
19
19
|
*/
|
|
20
20
|
defaultValues?: DefaultValue<Record<string, unknown>>;
|
|
21
21
|
}): Stf;
|
|
22
|
-
declare function useDataEngine(
|
|
22
|
+
declare function useDataEngine(instance?: Stf | DataEngine): DataEngine;
|
|
23
23
|
interface ArrayItemInfo {
|
|
24
24
|
field: FieldKey;
|
|
25
25
|
index: number;
|
|
@@ -62,27 +62,43 @@ interface DataEngineListener {
|
|
|
62
62
|
*/
|
|
63
63
|
field?: FieldKey;
|
|
64
64
|
/**
|
|
65
|
-
* when field value is changed
|
|
65
|
+
* when field value is changed.
|
|
66
66
|
*/
|
|
67
67
|
onUpdate?: (key: FieldKey, ctx: OnUpdateContext) => void;
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* fired on `init(field)`.
|
|
70
70
|
*/
|
|
71
|
-
onInit?: (key: FieldKey) => void;
|
|
71
|
+
onInit?: (key: FieldKey, ctx: OnInitContext) => void;
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* fired on `delete(field)`.
|
|
74
|
+
*
|
|
75
|
+
* when `field` is specified, this is also fired when parent is deleted.
|
|
76
|
+
*/
|
|
77
|
+
onDelete?: (key: FieldKey, ctx: OnDeleteContext) => void;
|
|
78
|
+
/**
|
|
79
|
+
* For listener attached to a namespace's engine, this is fired when the namespace is removed.
|
|
74
80
|
*/
|
|
75
|
-
|
|
81
|
+
onUnmount?: () => void;
|
|
76
82
|
}
|
|
77
83
|
interface OnUpdateContext {
|
|
78
84
|
/**
|
|
79
85
|
* An update is swallow if the change doesn't affect the values of children fields.
|
|
80
86
|
*/
|
|
81
87
|
swallow: boolean;
|
|
88
|
+
/** custom data */
|
|
89
|
+
custom?: Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
interface OnDeleteContext {
|
|
92
|
+
/** custom data */
|
|
93
|
+
custom?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
interface OnInitContext {
|
|
96
|
+
/** custom data */
|
|
97
|
+
custom?: Record<string, unknown>;
|
|
82
98
|
}
|
|
83
99
|
declare class DataEngine {
|
|
84
100
|
private data;
|
|
85
|
-
private
|
|
101
|
+
private readonly namespaces;
|
|
86
102
|
private readonly listeners;
|
|
87
103
|
constructor(defaultValues?: DefaultValue<NonNullable<object>>);
|
|
88
104
|
listen(listener: DataEngineListener): void;
|
|
@@ -94,23 +110,23 @@ declare class DataEngine {
|
|
|
94
110
|
* @param defaultValue the initial value, the field is also created for `undefined`
|
|
95
111
|
* @returns the value of initialized field, or the current value of field if already initialized
|
|
96
112
|
*/
|
|
97
|
-
init(key: FieldKey, defaultValue?: DefaultValue): unknown;
|
|
98
|
-
delete(key: FieldKey): unknown | undefined;
|
|
113
|
+
init(key: FieldKey, defaultValue?: DefaultValue, ctx?: OnInitContext): unknown;
|
|
114
|
+
delete(key: FieldKey, ctx?: OnDeleteContext): unknown | undefined;
|
|
99
115
|
get(key: FieldKey): unknown;
|
|
100
116
|
/**
|
|
101
117
|
* update the value of field if it exists
|
|
102
118
|
* @returns if the field is updated
|
|
103
119
|
*/
|
|
104
|
-
update(key: FieldKey, value: unknown): boolean;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
120
|
+
update(key: FieldKey, value: unknown, ctx?: Partial<OnUpdateContext>): boolean;
|
|
121
|
+
/**
|
|
122
|
+
* create an isolated data engine
|
|
123
|
+
*/
|
|
124
|
+
namespace(namespace: string, initialValue?: DefaultValue<NonNullable<object>>): DataEngine;
|
|
125
|
+
reset(data: NonNullable<object>): void;
|
|
126
|
+
clearNamespaces(): void;
|
|
111
127
|
}
|
|
112
128
|
declare function useFieldValue<V = unknown>(key: FieldKey, options?: {
|
|
113
|
-
stf?: Stf;
|
|
129
|
+
stf?: Stf | DataEngine;
|
|
114
130
|
defaultValue?: DefaultValue;
|
|
115
131
|
/**
|
|
116
132
|
* compute value from the actual field value.
|
|
@@ -121,7 +137,12 @@ declare function useFieldValue<V = unknown>(key: FieldKey, options?: {
|
|
|
121
137
|
isChanged?: (prev: V, next: V) => boolean;
|
|
122
138
|
}): readonly [V, (newValue: unknown) => boolean];
|
|
123
139
|
declare function useListener(listener: DataEngineListener & {
|
|
124
|
-
stf?: Stf;
|
|
140
|
+
stf?: Stf | DataEngine;
|
|
125
141
|
}): void;
|
|
142
|
+
declare function useNamespace(options: {
|
|
143
|
+
namespace: string;
|
|
144
|
+
initial?: DefaultValue<NonNullable<object>>;
|
|
145
|
+
stf?: Stf | DataEngine;
|
|
146
|
+
}): DataEngine;
|
|
126
147
|
//#endregion
|
|
127
|
-
export { ArrayItemInfo, DataEngine, DataEngineListener, DefaultValue, FieldKey, PropertyItemInfo, Stf, StfProvider, useArray, useDataEngine, useFieldValue, useListener, useObject, useStf };
|
|
148
|
+
export { ArrayItemInfo, DataEngine, DataEngineListener, DefaultValue, FieldKey, OnDeleteContext, OnInitContext, OnUpdateContext, PropertyItemInfo, Stf, StfProvider, useArray, useDataEngine, useFieldValue, useListener, useNamespace, useObject, useStf };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { deepEqual, objectGet, objectSet, stringifyFieldKey } from "./lib/utils.js";
|
|
3
|
+
import { deepEqual, fieldKeyStartsWith, isPlainObject, objectGet, objectSet, stringifyFieldKey } from "./lib/utils.js";
|
|
4
4
|
import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
|
|
@@ -17,8 +17,9 @@ function useStf(options) {
|
|
|
17
17
|
const dataEngine = useMemo(() => new DataEngine(defaultValues), []);
|
|
18
18
|
return useMemo(() => ({ dataEngine }), [dataEngine]);
|
|
19
19
|
}
|
|
20
|
-
function useDataEngine(
|
|
21
|
-
if (
|
|
20
|
+
function useDataEngine(instance) {
|
|
21
|
+
if (instance instanceof DataEngine) return instance;
|
|
22
|
+
if (instance) return instance.dataEngine;
|
|
22
23
|
return use(Context).dataEngine;
|
|
23
24
|
}
|
|
24
25
|
function useArray(field, options = {}) {
|
|
@@ -142,24 +143,31 @@ var ListenerManager = class {
|
|
|
142
143
|
const set = this.indexed.get(updatedKey);
|
|
143
144
|
if (set) for (const v of set) v.onUpdate?.(field, ctx);
|
|
144
145
|
} else for (const [k, listeners] of this.indexed.entries()) {
|
|
145
|
-
if (
|
|
146
|
+
if (!fieldKeyStartsWith(k, updatedKey)) continue;
|
|
146
147
|
for (const v of listeners) v.onUpdate?.(field, ctx);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
|
-
onInit(field) {
|
|
150
|
-
for (const v of this.unindexed) v.onInit?.(field);
|
|
150
|
+
onInit(field, ctx) {
|
|
151
|
+
for (const v of this.unindexed) v.onInit?.(field, ctx);
|
|
151
152
|
const set = this.indexed.get(stringifyFieldKey(field));
|
|
152
|
-
if (set) for (const v of set) v.onInit?.(field);
|
|
153
|
+
if (set) for (const v of set) v.onInit?.(field, ctx);
|
|
153
154
|
}
|
|
154
|
-
onDelete(field) {
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
155
|
+
onDelete(field, ctx) {
|
|
156
|
+
const fieldKey = stringifyFieldKey(field);
|
|
157
|
+
for (const v of this.unindexed) v.onDelete?.(field, ctx);
|
|
158
|
+
for (const [k, listeners] of this.indexed.entries()) {
|
|
159
|
+
if (!fieldKeyStartsWith(k, fieldKey)) continue;
|
|
160
|
+
for (const v of listeners) v.onDelete?.(field, ctx);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
onUnmount() {
|
|
164
|
+
for (const v of this.unindexed) v.onUnmount?.();
|
|
165
|
+
for (const listeners of this.indexed.values()) for (const v of listeners) v.onUnmount?.();
|
|
158
166
|
}
|
|
159
167
|
};
|
|
160
|
-
var DataEngine = class {
|
|
168
|
+
var DataEngine = class DataEngine {
|
|
161
169
|
constructor(defaultValues = {}) {
|
|
162
|
-
this.
|
|
170
|
+
this.namespaces = /* @__PURE__ */ new Map();
|
|
163
171
|
this.listeners = new ListenerManager();
|
|
164
172
|
this.data = getDefaultValue(defaultValues);
|
|
165
173
|
}
|
|
@@ -178,43 +186,59 @@ var DataEngine = class {
|
|
|
178
186
|
* @param defaultValue the initial value, the field is also created for `undefined`
|
|
179
187
|
* @returns the value of initialized field, or the current value of field if already initialized
|
|
180
188
|
*/
|
|
181
|
-
init(key, defaultValue) {
|
|
189
|
+
init(key, defaultValue, ctx = {}) {
|
|
182
190
|
if (key.length === 0) return this.data;
|
|
191
|
+
const parentKey = [];
|
|
192
|
+
const parentUpdateCtx = {
|
|
193
|
+
swallow: true,
|
|
194
|
+
...ctx
|
|
195
|
+
};
|
|
183
196
|
let cur = this.data;
|
|
184
|
-
const currentKey = [];
|
|
185
197
|
for (let i = 0; i < key.length; i++) {
|
|
186
198
|
const propKey = key[i];
|
|
187
199
|
const propValue = cur[propKey];
|
|
188
200
|
if (i === key.length - 1) {
|
|
189
201
|
if (propValue !== void 0) return propValue;
|
|
190
202
|
cur[propKey] = getDefaultValue(defaultValue);
|
|
191
|
-
this.listeners.onUpdate(
|
|
192
|
-
this.listeners.onInit(key);
|
|
203
|
+
this.listeners.onUpdate(parentKey, parentUpdateCtx);
|
|
204
|
+
this.listeners.onInit(key, ctx);
|
|
193
205
|
return cur[propKey];
|
|
194
|
-
} else if (
|
|
195
|
-
|
|
196
|
-
|
|
206
|
+
} else if (isPlainObject(propValue)) {
|
|
207
|
+
cur = propValue;
|
|
208
|
+
parentKey.push(propKey);
|
|
209
|
+
} else {
|
|
197
210
|
cur = cur[propKey] = {};
|
|
198
|
-
this.listeners.onUpdate(
|
|
211
|
+
this.listeners.onUpdate(parentKey, parentUpdateCtx);
|
|
212
|
+
parentKey.push(propKey);
|
|
213
|
+
if (propValue !== void 0) {
|
|
214
|
+
console.warn(`the original value of field ${parentKey.join(".")} is overidden, this might be unexpected.`);
|
|
215
|
+
this.listeners.onUpdate(parentKey, parentUpdateCtx);
|
|
216
|
+
}
|
|
199
217
|
}
|
|
200
|
-
currentKey.push(propKey);
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
|
-
delete(key) {
|
|
220
|
+
delete(key, ctx = {}) {
|
|
204
221
|
if (key.length === 0) return;
|
|
205
222
|
const parentKey = key.slice(0, -1);
|
|
206
223
|
const prop = key[key.length - 1];
|
|
207
224
|
const parent = this.get(parentKey);
|
|
208
225
|
if (Array.isArray(parent) && typeof prop === "number") {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
this.listeners.onDelete(key);
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
const deleted = parent.splice(prop, 1);
|
|
227
|
+
if (deleted.length === 0) return;
|
|
228
|
+
this.listeners.onDelete(key, ctx);
|
|
229
|
+
this.listeners.onUpdate(parentKey, {
|
|
230
|
+
swallow: false,
|
|
231
|
+
...ctx
|
|
232
|
+
});
|
|
233
|
+
return deleted[0];
|
|
234
|
+
} else if (isPlainObject(parent)) {
|
|
214
235
|
const temp = parent[prop];
|
|
215
236
|
delete parent[prop];
|
|
216
|
-
this.listeners.
|
|
217
|
-
this.listeners.
|
|
237
|
+
this.listeners.onDelete(key, ctx);
|
|
238
|
+
this.listeners.onUpdate(parentKey, {
|
|
239
|
+
swallow: true,
|
|
240
|
+
...ctx
|
|
241
|
+
});
|
|
218
242
|
return temp;
|
|
219
243
|
}
|
|
220
244
|
}
|
|
@@ -225,47 +249,62 @@ var DataEngine = class {
|
|
|
225
249
|
* update the value of field if it exists
|
|
226
250
|
* @returns if the field is updated
|
|
227
251
|
*/
|
|
228
|
-
update(key, value) {
|
|
252
|
+
update(key, value, ctx) {
|
|
229
253
|
try {
|
|
230
254
|
this.data = objectSet(this.data, key, value);
|
|
231
|
-
this.listeners.onUpdate(key, {
|
|
255
|
+
this.listeners.onUpdate(key, {
|
|
256
|
+
swallow: false,
|
|
257
|
+
...ctx
|
|
258
|
+
});
|
|
232
259
|
return true;
|
|
233
260
|
} catch {
|
|
234
261
|
return false;
|
|
235
262
|
}
|
|
236
263
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
else for (const key of this.attachedDataMap.keys()) if (key.startsWith(`${namespace}:`)) this.attachedDataMap.delete(key);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
264
|
+
/**
|
|
265
|
+
* create an isolated data engine
|
|
266
|
+
*/
|
|
267
|
+
namespace(namespace, initialValue) {
|
|
268
|
+
let child = this.namespaces.get(namespace);
|
|
269
|
+
if (!child) {
|
|
270
|
+
child = new DataEngine(initialValue);
|
|
271
|
+
this.namespaces.set(namespace, child);
|
|
272
|
+
}
|
|
273
|
+
return child;
|
|
250
274
|
}
|
|
251
275
|
reset(data) {
|
|
252
|
-
this.attachedDataMap.clear();
|
|
253
276
|
this.update([], data);
|
|
254
277
|
}
|
|
278
|
+
clearNamespaces() {
|
|
279
|
+
for (const [name, engine] of this.namespaces) {
|
|
280
|
+
this.namespaces.delete(name);
|
|
281
|
+
engine.listeners.onUnmount();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
255
284
|
};
|
|
256
285
|
function useFieldValue(key, options = {}) {
|
|
257
|
-
const
|
|
258
|
-
const
|
|
286
|
+
const { stf, compute = (v) => v, defaultValue, isChanged = (a, b) => a !== b } = options;
|
|
287
|
+
const engine = useDataEngine(stf);
|
|
259
288
|
const [value, setValue] = useState(() => compute(engine.init(key, defaultValue)));
|
|
289
|
+
const prevEngineRef = useRef(engine);
|
|
290
|
+
if (prevEngineRef.current !== engine) {
|
|
291
|
+
setValue(compute(engine.init(key, defaultValue)));
|
|
292
|
+
prevEngineRef.current = engine;
|
|
293
|
+
}
|
|
260
294
|
useListener({
|
|
261
295
|
field: key,
|
|
296
|
+
stf,
|
|
297
|
+
onInit() {
|
|
298
|
+
const computed = compute(engine.get(key));
|
|
299
|
+
setValue((prev) => isChanged(prev, computed) ? computed : prev);
|
|
300
|
+
},
|
|
262
301
|
onUpdate() {
|
|
263
302
|
const computed = compute(engine.get(key));
|
|
264
|
-
|
|
303
|
+
setValue((prev) => isChanged(prev, computed) ? computed : prev);
|
|
265
304
|
},
|
|
266
305
|
onDelete() {
|
|
267
306
|
const computed = compute(void 0);
|
|
268
|
-
|
|
307
|
+
setValue((prev) => isChanged(prev, computed) ? computed : prev);
|
|
269
308
|
}
|
|
270
309
|
});
|
|
271
310
|
return [value, (newValue) => engine.update(key, newValue)];
|
|
@@ -277,6 +316,9 @@ function useListener(listener) {
|
|
|
277
316
|
useEffect(() => {
|
|
278
317
|
const internal = {
|
|
279
318
|
field: listener.field,
|
|
319
|
+
onUnmount(...args) {
|
|
320
|
+
return listenerRef.current.onUnmount?.(...args);
|
|
321
|
+
},
|
|
280
322
|
onDelete(...args) {
|
|
281
323
|
return listenerRef.current.onDelete?.(...args);
|
|
282
324
|
},
|
|
@@ -293,6 +335,18 @@ function useListener(listener) {
|
|
|
293
335
|
};
|
|
294
336
|
}, [engine, listener.field]);
|
|
295
337
|
}
|
|
338
|
+
function useNamespace(options) {
|
|
339
|
+
const { namespace, stf, initial } = options;
|
|
340
|
+
const engine = useDataEngine(stf);
|
|
341
|
+
const [value, setValue] = useState(() => engine.namespace(namespace, initial));
|
|
342
|
+
useListener({
|
|
343
|
+
stf: value,
|
|
344
|
+
onUnmount() {
|
|
345
|
+
setValue(engine.namespace(namespace, initial));
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
return value;
|
|
349
|
+
}
|
|
296
350
|
|
|
297
351
|
//#endregion
|
|
298
|
-
export { DataEngine, StfProvider, useArray, useDataEngine, useFieldValue, useListener, useObject, useStf };
|
|
352
|
+
export { DataEngine, StfProvider, useArray, useDataEngine, useFieldValue, useListener, useNamespace, useObject, useStf };
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { t as FieldKey } from "../types-Do_aTV5I.js";
|
|
2
2
|
|
|
3
3
|
//#region src/lib/utils.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* test if array a starts with array b, only compare values via `===`.
|
|
6
|
-
*/
|
|
7
|
-
declare function arrayStartsWith(a: unknown[], b: unknown[]): boolean;
|
|
8
4
|
declare function objectGet(obj: unknown, key: (string | number)[]): unknown | undefined;
|
|
9
5
|
/**
|
|
10
6
|
* set the value of field if it exists (in place)
|
|
@@ -17,5 +13,10 @@ declare function objectSet(obj: unknown, key: FieldKey, value: unknown): unknown
|
|
|
17
13
|
*/
|
|
18
14
|
declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
19
15
|
declare function stringifyFieldKey(fieldKey: FieldKey): string;
|
|
16
|
+
/**
|
|
17
|
+
* @returns if `a` starts with `b`.
|
|
18
|
+
*/
|
|
19
|
+
declare function fieldKeyStartsWith(a: string, b: string): boolean;
|
|
20
|
+
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
20
21
|
//#endregion
|
|
21
|
-
export {
|
|
22
|
+
export { deepEqual, fieldKeyStartsWith, isPlainObject, objectGet, objectSet, stringifyFieldKey };
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
//#region src/lib/utils.ts
|
|
2
|
-
/**
|
|
3
|
-
* test if array a starts with array b, only compare values via `===`.
|
|
4
|
-
*/
|
|
5
|
-
function arrayStartsWith(a, b) {
|
|
6
|
-
if (b.length > a.length) return false;
|
|
7
|
-
for (let i = 0; i < b.length; i++) if (a[i] !== b[i]) return false;
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
2
|
function objectGet(obj, key) {
|
|
11
3
|
let cur = obj;
|
|
12
4
|
for (const prop of key) {
|
|
13
|
-
if (
|
|
5
|
+
if (!isPlainObject(cur) || !(prop in cur)) return;
|
|
14
6
|
cur = cur[prop];
|
|
15
7
|
}
|
|
16
8
|
return cur;
|
|
@@ -23,7 +15,7 @@ function objectGet(obj, key) {
|
|
|
23
15
|
function objectSet(obj, key, value) {
|
|
24
16
|
if (key.length === 0) return value;
|
|
25
17
|
const parent = objectGet(obj, key.slice(0, -1));
|
|
26
|
-
if (
|
|
18
|
+
if (!isPlainObject(parent)) throw new Error("missing parent object");
|
|
27
19
|
parent[key[key.length - 1]] = value;
|
|
28
20
|
return obj;
|
|
29
21
|
}
|
|
@@ -39,14 +31,26 @@ function deepEqual(a, b) {
|
|
|
39
31
|
return a.every((item, index) => deepEqual(item, b[index]));
|
|
40
32
|
}
|
|
41
33
|
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
34
|
+
if (!isPlainObject(a) || !isPlainObject(b)) return false;
|
|
42
35
|
const keysA = Object.keys(a);
|
|
43
36
|
const keysB = Object.keys(b);
|
|
44
37
|
if (keysA.length !== keysB.length) return false;
|
|
45
|
-
return keysA.every((key) =>
|
|
38
|
+
return keysA.every((key) => key in b && deepEqual(a[key], b[key]));
|
|
46
39
|
}
|
|
47
40
|
function stringifyFieldKey(fieldKey) {
|
|
48
|
-
return fieldKey.map((v) =>
|
|
41
|
+
return fieldKey.map((v) => typeof v === "string" ? `_${v}` : `n${v}`).join(".");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @returns if `a` starts with `b`.
|
|
45
|
+
*/
|
|
46
|
+
function fieldKeyStartsWith(a, b) {
|
|
47
|
+
return b.length === 0 || a === b || a.startsWith(b + ".");
|
|
48
|
+
}
|
|
49
|
+
function isPlainObject(value) {
|
|
50
|
+
if (typeof value !== "object" || value === null) return false;
|
|
51
|
+
const prototype = Object.getPrototypeOf(value);
|
|
52
|
+
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
//#endregion
|
|
52
|
-
export {
|
|
56
|
+
export { deepEqual, fieldKeyStartsWith, isPlainObject, objectGet, objectSet, stringifyFieldKey };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fumari/stf",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Schema to Form.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@types/node": "25.2.
|
|
23
|
-
"@types/react": "^19.2.
|
|
22
|
+
"@types/node": "25.2.3",
|
|
23
|
+
"@types/react": "^19.2.14",
|
|
24
24
|
"tsdown": "^0.20.3",
|
|
25
25
|
"eslint-config-custom": "0.0.0",
|
|
26
26
|
"tsconfig": "0.0.0"
|