@usefragments/core 1.10.2 → 2.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/dist/{chunk-MZ4SW3TP.js → chunk-3IOWHECM.js} +8 -1
- package/dist/{chunk-MZ4SW3TP.js.map → chunk-3IOWHECM.js.map} +1 -1
- package/dist/chunk-7ULGH74M.js +66 -0
- package/dist/chunk-7ULGH74M.js.map +1 -0
- package/dist/{chunk-XN3LSDPY.js → chunk-BMPYIUZE.js} +612 -344
- package/dist/chunk-BMPYIUZE.js.map +1 -0
- package/dist/{chunk-YF65VYRY.js → chunk-ML5S6QNU.js} +191 -169
- package/dist/chunk-ML5S6QNU.js.map +1 -0
- package/dist/{chunk-3LLRNCPX.js → chunk-MZ2FS7U4.js} +1 -1
- package/dist/chunk-MZ2FS7U4.js.map +1 -0
- package/dist/chunk-PWIJMOI4.js +202 -0
- package/dist/chunk-PWIJMOI4.js.map +1 -0
- package/dist/chunk-RYFULE43.js +578 -0
- package/dist/chunk-RYFULE43.js.map +1 -0
- package/dist/codes/index.d.ts +2 -2
- package/dist/codes/index.js +3 -2
- package/dist/compiled-types/index.d.ts +327 -2
- package/dist/compiled-types/index.js +1 -1
- package/dist/generate/index.d.ts +3 -2
- package/dist/{governance-CLk_wkP9.d.ts → governance-hOPXGbbs.d.ts} +474 -515
- package/dist/governance-telemetry.d.ts +6 -0
- package/dist/governance-telemetry.js +1 -1
- package/dist/{index-_sxhUNqx.d.ts → index-C8bcXVav.d.ts} +448 -448
- package/dist/index.d.ts +3280 -1305
- package/dist/index.js +2414 -350
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +228 -0
- package/dist/manifest.js +24 -0
- package/dist/manifest.js.map +1 -0
- package/dist/preview/index.js +45 -1
- package/dist/preview/index.js.map +1 -1
- package/dist/preview-runtime.d.ts +1 -2
- package/dist/preview-runtime.js +150 -14
- package/dist/preview-runtime.js.map +1 -1
- package/dist/react-types.d.ts +1 -2
- package/dist/registry.d.ts +1412 -203
- package/dist/registry.js +30 -3
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +3 -2
- package/dist/storyAdapter.d.ts +1 -2
- package/dist/storyAdapter.js +11 -49
- package/dist/storyAdapter.js.map +1 -1
- package/dist/test-utils.d.ts +3 -2
- package/dist/topology/index.d.ts +1 -1
- package/dist/topology/index.js +1 -1
- package/package.json +8 -2
- package/src/__tests__/contract-parser.test.ts +318 -277
- package/src/__tests__/preview-runtime-hook.test.tsx +315 -0
- package/src/__tests__/preview-runtime.test.tsx +30 -8
- package/src/__tests__/schema.test.ts +191 -14
- package/src/analysis-plan/analysis-plan-v1.test.ts +320 -0
- package/src/analysis-plan/coverage.ts +181 -0
- package/src/analysis-plan/digest.ts +141 -0
- package/src/analysis-plan/index.ts +34 -0
- package/src/analysis-plan/types.ts +207 -0
- package/src/approved-contract-tokens.test.ts +39 -0
- package/src/approved-contract-tokens.ts +18 -0
- package/src/codes/__tests__/codes.test.ts +13 -0
- package/src/codes/codes.ts +40 -0
- package/src/compiled-types/index.ts +640 -39
- package/src/compiled-types/parse.test.ts +145 -4
- package/src/component-contract.ts +95 -53
- package/src/composition.ts +7 -13
- package/src/constants.ts +3 -6
- package/src/contract/hash.test.ts +20 -0
- package/src/contract/hash.ts +66 -9
- package/src/contract/index.ts +24 -1
- package/src/contract/manifest.test.ts +94 -0
- package/src/contract/manifest.ts +68 -0
- package/src/contract/preimage.test.ts +219 -1
- package/src/contract/preimage.ts +326 -6
- package/src/contract/stamp.test.ts +3 -0
- package/src/contract/stamp.ts +1 -1
- package/src/contract-parser.ts +54 -30
- package/src/defineFragment.test.ts +476 -91
- package/src/defineFragment.ts +204 -114
- package/src/domain-ids.test.ts +35 -0
- package/src/domain-ids.ts +61 -0
- package/src/evaluation/evaluate.test.ts +522 -0
- package/src/evaluation/evaluate.ts +690 -0
- package/src/evaluation/evaluation-v2-receipt-v1.test.ts +772 -0
- package/src/evaluation/index.ts +58 -0
- package/src/evaluation/receipt.ts +753 -0
- package/src/evaluation/types.ts +406 -0
- package/src/facts/builders.ts +2 -0
- package/src/facts/compile.ts +29 -6
- package/src/facts/fact-index.ts +13 -3
- package/src/facts/fact-integrity-v1.test.ts +172 -0
- package/src/facts/facts.test.ts +15 -0
- package/src/facts/ids.ts +46 -3
- package/src/facts/index.ts +14 -1
- package/src/facts/integrity.ts +134 -0
- package/src/facts/types.ts +36 -0
- package/src/governance-integrity.test.ts +1 -0
- package/src/governance-integrity.ts +5 -3
- package/src/governance-telemetry.ts +8 -0
- package/src/governance.ts +70 -8
- package/src/index.ts +230 -37
- package/src/preview/validation.test.ts +62 -0
- package/src/preview/validation.ts +48 -2
- package/src/preview-runtime.tsx +227 -20
- package/src/registry-install-plan.ts +200 -109
- package/src/registry-shards.test.ts +263 -0
- package/src/registry.ts +237 -0
- package/src/repository-binding.test.ts +50 -0
- package/src/repository-binding.ts +96 -0
- package/src/rules/families.test.ts +36 -0
- package/src/rules/finding.ts +7 -2
- package/src/rules/index.ts +17 -1
- package/src/rules/rule-config.test.ts +66 -0
- package/src/rules/rule-config.ts +73 -0
- package/src/rules/rules.test.ts +26 -0
- package/src/rules/tokens-css-vars-must-be-defined.test.ts +51 -2
- package/src/rules/tokens-css-vars-must-be-defined.ts +34 -1
- package/src/schema.ts +293 -113
- package/src/schemas/index.ts +1 -1
- package/src/storyAdapter.test.ts +68 -12
- package/src/storyAdapter.ts +44 -75
- package/src/topology/resolve-area.ts +1 -1
- package/src/types.ts +258 -40
- package/dist/chunk-3LLRNCPX.js.map +0 -1
- package/dist/chunk-RANPUC6C.js +0 -72
- package/dist/chunk-RANPUC6C.js.map +0 -1
- package/dist/chunk-XN3LSDPY.js.map +0 -1
- package/dist/chunk-YF65VYRY.js.map +0 -1
- package/src/fragment-types.ts +0 -214
- package/src/react-create-element.test.ts +0 -22
- package/src/react-create-element.ts +0 -12
- package/src/storyFilters.test.ts +0 -350
- package/src/storyFilters.ts +0 -253
package/src/preview-runtime.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState, type ReactNode } from "react";
|
|
1
|
+
import { useEffect, useRef, useState, type ReactNode } from "react";
|
|
2
2
|
import type { VariantLoader, VariantRenderOptions } from "./types.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -29,17 +29,208 @@ const EMPTY_STATE: PreviewRuntimeState = {
|
|
|
29
29
|
loadedData: undefined,
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
const LOADING_STATE: PreviewRuntimeState = {
|
|
33
|
+
content: null,
|
|
34
|
+
isLoading: true,
|
|
35
|
+
error: null,
|
|
36
|
+
loadedData: undefined,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const LOADED_DATA_COMPARISON_MAX_DEPTH = 32;
|
|
40
|
+
const LOADED_DATA_COMPARISON_MAX_OBJECTS = 1_000;
|
|
41
|
+
const LOADED_DATA_COMPARISON_MAX_PROPERTIES = 4_000;
|
|
42
|
+
|
|
43
|
+
const LOADED_DATA_COMPARISON_ERROR = new Error(
|
|
44
|
+
"Preview loadedData could not be compared safely. Pass a stable object reference, or use " +
|
|
45
|
+
`JSON-like data within ${LOADED_DATA_COMPARISON_MAX_DEPTH} levels, ` +
|
|
46
|
+
`${LOADED_DATA_COMPARISON_MAX_OBJECTS} objects, and ` +
|
|
47
|
+
`${LOADED_DATA_COMPARISON_MAX_PROPERTIES} property inspections.`
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const LOADED_DATA_COMPARISON_ERROR_STATE: PreviewRuntimeState = {
|
|
51
|
+
content: null,
|
|
52
|
+
isLoading: false,
|
|
53
|
+
error: LOADED_DATA_COMPARISON_ERROR,
|
|
54
|
+
loadedData: undefined,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
interface PreviewRuntimeResolution {
|
|
58
|
+
variant: PreviewVariantLike | null;
|
|
59
|
+
loadedData?: Record<string, unknown>;
|
|
60
|
+
state: PreviewRuntimeState;
|
|
61
|
+
}
|
|
62
|
+
|
|
32
63
|
function toError(error: unknown): Error {
|
|
33
64
|
return error instanceof Error ? error : new Error(String(error));
|
|
34
65
|
}
|
|
35
66
|
|
|
67
|
+
type LoadedDataComparison = "equal" | "different" | "indeterminate";
|
|
68
|
+
const NO_PENDING_LOADED_DATA = Symbol("no-pending-loaded-data");
|
|
69
|
+
|
|
70
|
+
interface LoadedDataComparisonContext {
|
|
71
|
+
comparedObjects: number;
|
|
72
|
+
inspectedProperties: number;
|
|
73
|
+
leftToRight: WeakMap<object, object>;
|
|
74
|
+
rightToLeft: WeakMap<object, object>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isPlainRecord(value: object): value is Record<string, unknown> {
|
|
78
|
+
const prototype = Object.getPrototypeOf(value);
|
|
79
|
+
return prototype === Object.prototype || prototype === null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function compareLoadedDataProperties(
|
|
83
|
+
left: object,
|
|
84
|
+
right: object,
|
|
85
|
+
depth: number,
|
|
86
|
+
context: LoadedDataComparisonContext
|
|
87
|
+
): LoadedDataComparison {
|
|
88
|
+
let leftPropertyCount = 0;
|
|
89
|
+
for (const key in left) {
|
|
90
|
+
if (context.inspectedProperties >= LOADED_DATA_COMPARISON_MAX_PROPERTIES) {
|
|
91
|
+
return "indeterminate";
|
|
92
|
+
}
|
|
93
|
+
context.inspectedProperties += 1;
|
|
94
|
+
|
|
95
|
+
if (!Object.prototype.hasOwnProperty.call(left, key)) continue;
|
|
96
|
+
leftPropertyCount += 1;
|
|
97
|
+
if (!Object.prototype.hasOwnProperty.call(right, key)) return "different";
|
|
98
|
+
|
|
99
|
+
const leftDescriptor = Object.getOwnPropertyDescriptor(left, key);
|
|
100
|
+
const rightDescriptor = Object.getOwnPropertyDescriptor(right, key);
|
|
101
|
+
if (
|
|
102
|
+
!leftDescriptor ||
|
|
103
|
+
!rightDescriptor ||
|
|
104
|
+
!("value" in leftDescriptor) ||
|
|
105
|
+
!("value" in rightDescriptor)
|
|
106
|
+
) {
|
|
107
|
+
return "indeterminate";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const comparison = compareLoadedDataValue(
|
|
111
|
+
leftDescriptor.value,
|
|
112
|
+
rightDescriptor.value,
|
|
113
|
+
depth + 1,
|
|
114
|
+
context
|
|
115
|
+
);
|
|
116
|
+
if (comparison !== "equal") return comparison;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let rightPropertyCount = 0;
|
|
120
|
+
for (const key in right) {
|
|
121
|
+
if (context.inspectedProperties >= LOADED_DATA_COMPARISON_MAX_PROPERTIES) {
|
|
122
|
+
return "indeterminate";
|
|
123
|
+
}
|
|
124
|
+
context.inspectedProperties += 1;
|
|
125
|
+
if (Object.prototype.hasOwnProperty.call(right, key)) rightPropertyCount += 1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return leftPropertyCount === rightPropertyCount ? "equal" : "different";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function compareLoadedDataValue(
|
|
132
|
+
left: unknown,
|
|
133
|
+
right: unknown,
|
|
134
|
+
depth: number,
|
|
135
|
+
context: LoadedDataComparisonContext
|
|
136
|
+
): LoadedDataComparison {
|
|
137
|
+
if (Object.is(left, right)) return "equal";
|
|
138
|
+
|
|
139
|
+
const leftType = typeof left;
|
|
140
|
+
const rightType = typeof right;
|
|
141
|
+
if (leftType !== rightType || left === null || right === null) return "different";
|
|
142
|
+
if (leftType === "function" || leftType === "symbol") return "indeterminate";
|
|
143
|
+
if (leftType !== "object") return "different";
|
|
144
|
+
|
|
145
|
+
const leftObject = left as object;
|
|
146
|
+
const rightObject = right as object;
|
|
147
|
+
const pairedRight = context.leftToRight.get(leftObject);
|
|
148
|
+
const pairedLeft = context.rightToLeft.get(rightObject);
|
|
149
|
+
if (pairedRight || pairedLeft) {
|
|
150
|
+
return pairedRight === rightObject && pairedLeft === leftObject ? "equal" : "different";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (depth >= LOADED_DATA_COMPARISON_MAX_DEPTH) return "indeterminate";
|
|
154
|
+
if (context.comparedObjects >= LOADED_DATA_COMPARISON_MAX_OBJECTS) {
|
|
155
|
+
return "indeterminate";
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const leftIsArray = Array.isArray(leftObject);
|
|
159
|
+
const rightIsArray = Array.isArray(rightObject);
|
|
160
|
+
if (leftIsArray !== rightIsArray) return "different";
|
|
161
|
+
if (leftIsArray && (leftObject as unknown[]).length !== (rightObject as unknown[]).length) {
|
|
162
|
+
return "different";
|
|
163
|
+
}
|
|
164
|
+
if (!leftIsArray) {
|
|
165
|
+
const leftIsPlainRecord = isPlainRecord(leftObject);
|
|
166
|
+
const rightIsPlainRecord = isPlainRecord(rightObject);
|
|
167
|
+
if (leftIsPlainRecord !== rightIsPlainRecord) return "different";
|
|
168
|
+
if (!leftIsPlainRecord) return "indeterminate";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
context.comparedObjects += 1;
|
|
172
|
+
context.leftToRight.set(leftObject, rightObject);
|
|
173
|
+
context.rightToLeft.set(rightObject, leftObject);
|
|
174
|
+
|
|
175
|
+
return compareLoadedDataProperties(leftObject, rightObject, depth, context);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function compareLoadedData(
|
|
179
|
+
left: Record<string, unknown> | undefined,
|
|
180
|
+
right: Record<string, unknown> | undefined
|
|
181
|
+
): LoadedDataComparison {
|
|
182
|
+
try {
|
|
183
|
+
return compareLoadedDataValue(left, right, 0, {
|
|
184
|
+
comparedObjects: 0,
|
|
185
|
+
inspectedProperties: 0,
|
|
186
|
+
leftToRight: new WeakMap(),
|
|
187
|
+
rightToLeft: new WeakMap(),
|
|
188
|
+
});
|
|
189
|
+
} catch {
|
|
190
|
+
// Host data must not make render fail when an accessor or proxy cannot be inspected safely.
|
|
191
|
+
return "indeterminate";
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface StableLoadedDataResult {
|
|
196
|
+
loadedData: Record<string, unknown> | undefined;
|
|
197
|
+
comparisonError: Error | null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function useStableLoadedData(
|
|
201
|
+
loadedData: Record<string, unknown> | undefined
|
|
202
|
+
): StableLoadedDataResult {
|
|
203
|
+
const stableLoadedData = useRef(loadedData);
|
|
204
|
+
const pendingLoadedData = useRef<
|
|
205
|
+
Record<string, unknown> | undefined | typeof NO_PENDING_LOADED_DATA
|
|
206
|
+
>(NO_PENDING_LOADED_DATA);
|
|
207
|
+
const comparison = compareLoadedData(stableLoadedData.current, loadedData);
|
|
208
|
+
|
|
209
|
+
if (comparison === "equal") {
|
|
210
|
+
pendingLoadedData.current = NO_PENDING_LOADED_DATA;
|
|
211
|
+
return { loadedData: stableLoadedData.current, comparisonError: null };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (comparison === "different" || pendingLoadedData.current === loadedData) {
|
|
215
|
+
stableLoadedData.current = loadedData;
|
|
216
|
+
pendingLoadedData.current = NO_PENDING_LOADED_DATA;
|
|
217
|
+
return { loadedData, comparisonError: null };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
pendingLoadedData.current = loadedData;
|
|
221
|
+
return {
|
|
222
|
+
loadedData: stableLoadedData.current,
|
|
223
|
+
comparisonError: LOADED_DATA_COMPARISON_ERROR,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
36
227
|
/**
|
|
37
228
|
* Execute all variant loaders and merge their payloads.
|
|
38
229
|
* `loadedData` is applied last so host-level overrides win.
|
|
39
230
|
*/
|
|
40
231
|
export async function executeVariantLoaders(
|
|
41
232
|
loaders: VariantLoader[] | undefined,
|
|
42
|
-
loadedData?: Record<string, unknown
|
|
233
|
+
loadedData?: Record<string, unknown>
|
|
43
234
|
): Promise<Record<string, unknown> | undefined> {
|
|
44
235
|
const hasLoaders = !!loaders && loaders.length > 0;
|
|
45
236
|
if (!hasLoaders) {
|
|
@@ -49,7 +240,7 @@ export async function executeVariantLoaders(
|
|
|
49
240
|
const results = await Promise.all(loaders.map((loader) => loader()));
|
|
50
241
|
const mergedFromLoaders = results.reduce<Record<string, unknown>>(
|
|
51
242
|
(acc, result) => ({ ...acc, ...result }),
|
|
52
|
-
{}
|
|
243
|
+
{}
|
|
53
244
|
);
|
|
54
245
|
|
|
55
246
|
return loadedData ? { ...mergedFromLoaders, ...loadedData } : mergedFromLoaders;
|
|
@@ -60,7 +251,7 @@ export async function executeVariantLoaders(
|
|
|
60
251
|
* This is useful for testing and for hook/component orchestration.
|
|
61
252
|
*/
|
|
62
253
|
export async function resolvePreviewRuntimeState(
|
|
63
|
-
options: PreviewRuntimeOptions
|
|
254
|
+
options: PreviewRuntimeOptions
|
|
64
255
|
): Promise<PreviewRuntimeState> {
|
|
65
256
|
const { variant, loadedData } = options;
|
|
66
257
|
if (!variant) {
|
|
@@ -89,42 +280,58 @@ export async function resolvePreviewRuntimeState(
|
|
|
89
280
|
/**
|
|
90
281
|
* Hook for rendering a preview variant with loader support.
|
|
91
282
|
*/
|
|
92
|
-
export function usePreviewVariantRuntime(
|
|
93
|
-
options
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
283
|
+
export function usePreviewVariantRuntime(options: PreviewRuntimeOptions): PreviewRuntimeState {
|
|
284
|
+
const { variant } = options;
|
|
285
|
+
const { loadedData, comparisonError } = useStableLoadedData(options.loadedData);
|
|
286
|
+
const [resolution, setResolution] = useState<PreviewRuntimeResolution>({
|
|
287
|
+
variant: null,
|
|
288
|
+
loadedData: undefined,
|
|
289
|
+
state: EMPTY_STATE,
|
|
290
|
+
});
|
|
97
291
|
|
|
98
292
|
useEffect(() => {
|
|
99
293
|
let cancelled = false;
|
|
100
294
|
|
|
101
295
|
if (!variant) {
|
|
102
|
-
|
|
296
|
+
setResolution({ variant: null, loadedData, state: EMPTY_STATE });
|
|
103
297
|
return () => {
|
|
104
298
|
cancelled = true;
|
|
105
299
|
};
|
|
106
300
|
}
|
|
107
301
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
302
|
+
if (comparisonError) {
|
|
303
|
+
setResolution({ variant, loadedData, state: LOADED_DATA_COMPARISON_ERROR_STATE });
|
|
304
|
+
return () => {
|
|
305
|
+
cancelled = true;
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
setResolution({ variant, loadedData, state: LOADING_STATE });
|
|
115
310
|
|
|
116
311
|
resolvePreviewRuntimeState({ variant, loadedData }).then((nextState) => {
|
|
117
312
|
if (!cancelled) {
|
|
118
|
-
|
|
313
|
+
setResolution({ variant, loadedData, state: nextState });
|
|
119
314
|
}
|
|
120
315
|
});
|
|
121
316
|
|
|
122
317
|
return () => {
|
|
123
318
|
cancelled = true;
|
|
124
319
|
};
|
|
125
|
-
}, [variant, loadedData]);
|
|
320
|
+
}, [variant, loadedData, comparisonError]);
|
|
321
|
+
|
|
322
|
+
if (!variant) {
|
|
323
|
+
return EMPTY_STATE;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (comparisonError) {
|
|
327
|
+
return LOADED_DATA_COMPARISON_ERROR_STATE;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (resolution.variant !== variant || resolution.loadedData !== loadedData) {
|
|
331
|
+
return LOADING_STATE;
|
|
332
|
+
}
|
|
126
333
|
|
|
127
|
-
return state;
|
|
334
|
+
return resolution.state;
|
|
128
335
|
}
|
|
129
336
|
|
|
130
337
|
interface PreviewVariantRuntimeProps extends PreviewRuntimeOptions {
|