@yahoo/uds-create-config 5.55.0 → 5.55.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/entities/system/Component.js +21 -8
- package/dist/entities/system/component-module.js +9 -9
- package/dist/framework/Config.js +8 -1
- package/dist/framework/layer-styles.js +18 -1
- package/dist/framework/memo.d.ts +2 -2
- package/dist/framework/memo.js +7 -1
- package/dist/framework/prop-surface.d.ts +1 -0
- package/dist/framework/prop-surface.js +13 -0
- package/dist/framework/render-spec.d.ts +3 -16
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -755,6 +755,17 @@ function withNone(value, declaration) {
|
|
|
755
755
|
if (declaration?.required === true) return value;
|
|
756
756
|
return z.union([value, z.literal(false)]);
|
|
757
757
|
}
|
|
758
|
+
/** Optional values build their domain on first use, not while the bag enumerates its keys. */
|
|
759
|
+
function optionalBagValue(build) {
|
|
760
|
+
let schema;
|
|
761
|
+
return z.unknown().transform((input, ctx) => {
|
|
762
|
+
schema ??= build();
|
|
763
|
+
const result = schema.safeParse(input);
|
|
764
|
+
if (result.success) return result.data;
|
|
765
|
+
for (const issue of result.error.issues) ctx.addIssue({ ...issue });
|
|
766
|
+
return z.NEVER;
|
|
767
|
+
}).optional();
|
|
768
|
+
}
|
|
758
769
|
/** One element's bag, built. Reached only through the memo above. */
|
|
759
770
|
function buildBagFor(config, layerElement) {
|
|
760
771
|
const shape = { ...stylePropShape(config) };
|
|
@@ -762,13 +773,15 @@ function buildBagFor(config, layerElement) {
|
|
|
762
773
|
const glyphProps = component ? glyphPropsOf(config, component) : {};
|
|
763
774
|
for (const [name, decl] of Object.entries(component ? resolveComponentProps(config, component) : {})) {
|
|
764
775
|
const forwarded = decl?.type === "forward";
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
776
|
+
shape[name] = optionalBagValue(() => {
|
|
777
|
+
const value = styleBagValue({
|
|
778
|
+
config,
|
|
779
|
+
declaration: decl,
|
|
780
|
+
name,
|
|
781
|
+
glyphLibraries: forwarded ? glyphProps[name] : void 0
|
|
782
|
+
});
|
|
783
|
+
return forwarded ? withNone(value, decl) : value;
|
|
770
784
|
});
|
|
771
|
-
shape[name] = (forwarded ? withNone(value, decl) : value).optional();
|
|
772
785
|
}
|
|
773
786
|
const declared = component ? (config.resolve("component", component)?.toJSON())?.props ?? {} : {};
|
|
774
787
|
for (const [name, decl] of Object.entries(declared)) {
|
|
@@ -819,14 +832,14 @@ function stylePropShape(config) {
|
|
|
819
832
|
const cached = stylePropShapes.get(config);
|
|
820
833
|
if (cached) return cached;
|
|
821
834
|
const shape = {};
|
|
822
|
-
for (const prop of config.list("style-property")) shape[prop.path] = styleBagValue({
|
|
835
|
+
for (const prop of config.list("style-property")) shape[prop.path] = optionalBagValue(() => styleBagValue({
|
|
823
836
|
config,
|
|
824
837
|
declaration: {
|
|
825
838
|
type: "styleProperty",
|
|
826
839
|
value: { __ref: `style-property:${prop.path}` }
|
|
827
840
|
},
|
|
828
841
|
name: prop.path
|
|
829
|
-
})
|
|
842
|
+
}));
|
|
830
843
|
stylePropShapes.set(config, shape);
|
|
831
844
|
return shape;
|
|
832
845
|
}
|
|
@@ -55,7 +55,7 @@ function isCreatedComponent(config, path) {
|
|
|
55
55
|
if (isNativeConfig(config)) return false;
|
|
56
56
|
const component = Component.get(config, path);
|
|
57
57
|
if (!component || component.source !== void 0) return false;
|
|
58
|
-
const { file, export: exportName, anatomy } = component
|
|
58
|
+
const { file, export: exportName, anatomy } = component;
|
|
59
59
|
return !file && !exportName && Object.keys(anatomy ?? {}).length > 0;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
@@ -133,7 +133,7 @@ function componentsByFile(config) {
|
|
|
133
133
|
if (cached) return cached;
|
|
134
134
|
const byFile = /* @__PURE__ */ new Map();
|
|
135
135
|
for (const component of Component.list(config)) {
|
|
136
|
-
const { file, export: exportName } = component
|
|
136
|
+
const { file, export: exportName } = component;
|
|
137
137
|
if (!file || !exportName) continue;
|
|
138
138
|
const ref = splitRef(file.__ref);
|
|
139
139
|
if (ref.source) continue;
|
|
@@ -163,7 +163,7 @@ function componentRegistryImports(config, filePath) {
|
|
|
163
163
|
const byExport = /* @__PURE__ */ new Map();
|
|
164
164
|
const ambiguous = /* @__PURE__ */ new Set();
|
|
165
165
|
for (const component of byFile.get(target.path) ?? []) {
|
|
166
|
-
const { export: exportName } = component
|
|
166
|
+
const { export: exportName } = component;
|
|
167
167
|
if (!exportName) continue;
|
|
168
168
|
if (byExport.has(exportName)) ambiguous.add(exportName);
|
|
169
169
|
byExport.set(exportName, {
|
|
@@ -221,7 +221,8 @@ function componentModuleBuildPlan(config, filePath) {
|
|
|
221
221
|
const parsed = splitRef(target);
|
|
222
222
|
if (parsed.kind !== "component" || parsed.source) return false;
|
|
223
223
|
const component = Component.get(config, parsed.path);
|
|
224
|
-
const
|
|
224
|
+
const file = component?.file;
|
|
225
|
+
const exportName = component?.export;
|
|
225
226
|
if (!component || !file || !exportName) return false;
|
|
226
227
|
const owner = splitRef(file.__ref);
|
|
227
228
|
if (owner.kind !== "file" || owner.source) return false;
|
|
@@ -257,7 +258,7 @@ function componentModuleBuildPlan(config, filePath) {
|
|
|
257
258
|
const file = File.get(config, next);
|
|
258
259
|
if (!file?.hash) continue;
|
|
259
260
|
recordEntity(`file:${next}`);
|
|
260
|
-
const imports = file.
|
|
261
|
+
const imports = file.imports ?? {};
|
|
261
262
|
const registryImports = new Map(componentRegistryImports(config, next).map((entry) => [entry.specifier, entry]));
|
|
262
263
|
for (const [specifier, imported] of Object.entries(imports)) {
|
|
263
264
|
const registryImport = registryImports.get(specifier);
|
|
@@ -305,7 +306,7 @@ function componentModuleSource(config, componentPathOrRef) {
|
|
|
305
306
|
if (isNativeConfig(config)) return void 0;
|
|
306
307
|
const component = Component.get(config, componentPathOrRef);
|
|
307
308
|
if (!component) return void 0;
|
|
308
|
-
const { file, export: exportName } = component
|
|
309
|
+
const { file, export: exportName } = component;
|
|
309
310
|
if (!file || !exportName) {
|
|
310
311
|
if (!isCreatedComponent(config, component.path)) return void 0;
|
|
311
312
|
const moduleKey = createdModuleKey(config, component.path);
|
|
@@ -405,7 +406,7 @@ function cachedView(consumer, owner, slug, shadowed) {
|
|
|
405
406
|
function linkedComponentModule(config, componentPathOrRef) {
|
|
406
407
|
const component = Component.get(config, componentPathOrRef);
|
|
407
408
|
if (!component) return void 0;
|
|
408
|
-
const { file, export: exportName } = component
|
|
409
|
+
const { file, export: exportName } = component;
|
|
409
410
|
if (!file || !exportName) return void 0;
|
|
410
411
|
const asked = typeof componentPathOrRef === "string" ? componentPathOrRef : componentPathOrRef.__ref;
|
|
411
412
|
const parsed = asked.includes(":") ? splitRef(asked) : void 0;
|
|
@@ -422,8 +423,7 @@ function linkedComponentModule(config, componentPathOrRef) {
|
|
|
422
423
|
const moduleKey = componentModuleKey(view, filePath);
|
|
423
424
|
if (!moduleKey) return void 0;
|
|
424
425
|
const authored = Component.list(owner).find((candidate) => {
|
|
425
|
-
|
|
426
|
-
return fields.export === exportName && fields.file !== void 0 && splitRef(fields.file.__ref).path === filePath;
|
|
426
|
+
return candidate.export === exportName && candidate.file !== void 0 && splitRef(candidate.file.__ref).path === filePath;
|
|
427
427
|
});
|
|
428
428
|
return {
|
|
429
429
|
source: {
|
package/dist/framework/Config.js
CHANGED
|
@@ -280,6 +280,7 @@ function cachesFor(snapshot, sources) {
|
|
|
280
280
|
if (found) return found;
|
|
281
281
|
const bucket = {
|
|
282
282
|
sources: current,
|
|
283
|
+
entities: /* @__PURE__ */ new Map(),
|
|
283
284
|
extensions: /* @__PURE__ */ new Map(),
|
|
284
285
|
overlays: /* @__PURE__ */ new Map(),
|
|
285
286
|
lists: /* @__PURE__ */ new Map(),
|
|
@@ -2916,7 +2917,13 @@ var Config = class Config {
|
|
|
2916
2917
|
return new Entity(path, withComputed, [...entry.fieldKeys, ...Object.keys(computed)]);
|
|
2917
2918
|
}
|
|
2918
2919
|
resolve(kind, path) {
|
|
2919
|
-
|
|
2920
|
+
const cache = this.caches.entities;
|
|
2921
|
+
const key = `${kind}\u0000${path}`;
|
|
2922
|
+
const cached = cache.get(key);
|
|
2923
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
2924
|
+
const resolved = this.resolvedIn(kind, path)?.entity;
|
|
2925
|
+
cache.set(key, resolved ?? null);
|
|
2926
|
+
return resolved;
|
|
2920
2927
|
}
|
|
2921
2928
|
/**
|
|
2922
2929
|
* Whether this config holds `target`'s entity, at the path the source spells it, through `slug`.
|
|
@@ -45,6 +45,20 @@ function interactionHolds(state, key, value) {
|
|
|
45
45
|
if (on(state[key])) return true;
|
|
46
46
|
return on(state[`${key}@${value === true || value === "true" ? "root" : String(value)}`]);
|
|
47
47
|
}
|
|
48
|
+
const authoredBags = /* @__PURE__ */ new WeakMap();
|
|
49
|
+
/** Every cell reads the same authored rules under its own coordinate. */
|
|
50
|
+
function resolvedBag({ config, bag }) {
|
|
51
|
+
let bags = authoredBags.get(config);
|
|
52
|
+
if (!bags) {
|
|
53
|
+
bags = /* @__PURE__ */ new WeakMap();
|
|
54
|
+
authoredBags.set(config, bags);
|
|
55
|
+
}
|
|
56
|
+
const cached = bags.get(bag);
|
|
57
|
+
if (cached) return cached;
|
|
58
|
+
const resolved = authoredBag(config, resolveAppliedComposites(config, bag));
|
|
59
|
+
bags.set(bag, resolved);
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
48
62
|
/**
|
|
49
63
|
* A bag's values as declarations, flattening any forced modifier block one specificity step up.
|
|
50
64
|
*
|
|
@@ -99,7 +113,10 @@ function layerStyles(config, path, props = {}, options = {}) {
|
|
|
99
113
|
Object.values(styles).forEach((rule, index) => {
|
|
100
114
|
if (!ruleApplies(rule.when, state)) return;
|
|
101
115
|
for (const [layer, bag] of Object.entries(rule.layers ?? {})) collectBag({
|
|
102
|
-
bag:
|
|
116
|
+
bag: resolvedBag({
|
|
117
|
+
config,
|
|
118
|
+
bag: bag ?? {}
|
|
119
|
+
}),
|
|
103
120
|
forced,
|
|
104
121
|
specificity: ruleSpecificity(rule.when),
|
|
105
122
|
push: (key, value, specificity) => declarations.push({
|
package/dist/framework/memo.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Snapshot } from "./snapshot.js";
|
|
2
2
|
|
|
3
3
|
//#region src/framework/memo.d.ts
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
4
|
+
/** An immutable config value. A changed snapshot or source requires a new value.
|
|
5
|
+
* Structural to avoid importing `Config`, which memoizes through this module. */
|
|
6
6
|
interface HasSnapshot {
|
|
7
7
|
readonly snapshot: Snapshot;
|
|
8
8
|
/**
|
package/dist/framework/memo.js
CHANGED
|
@@ -63,7 +63,9 @@ function sameSliceKeys({ before, after }) {
|
|
|
63
63
|
function createSliceMemo({ kinds, compute }) {
|
|
64
64
|
if (kinds.length === 0) throw new Error("createSliceMemo needs at least one kind — a computation that reads nothing has nothing to key on");
|
|
65
65
|
const root = /* @__PURE__ */ new WeakMap();
|
|
66
|
+
const byConfig = /* @__PURE__ */ new WeakMap();
|
|
66
67
|
return (config) => {
|
|
68
|
+
if (byConfig.has(config)) return byConfig.get(config);
|
|
67
69
|
const keys = sliceKeys({
|
|
68
70
|
config,
|
|
69
71
|
kinds
|
|
@@ -78,9 +80,13 @@ function createSliceMemo({ kinds, compute }) {
|
|
|
78
80
|
level = next;
|
|
79
81
|
}
|
|
80
82
|
const cached = level.has(RESULT) ? level.get(RESULT) : MISS;
|
|
81
|
-
if (cached !== MISS)
|
|
83
|
+
if (cached !== MISS) {
|
|
84
|
+
byConfig.set(config, cached);
|
|
85
|
+
return cached;
|
|
86
|
+
}
|
|
82
87
|
const value = compute(config);
|
|
83
88
|
level.set(RESULT, value);
|
|
89
|
+
byConfig.set(config, value);
|
|
84
90
|
return value;
|
|
85
91
|
};
|
|
86
92
|
}
|
|
@@ -164,6 +164,7 @@ declare function routesContent(config: Config, layers: Readonly<Record<string, u
|
|
|
164
164
|
}): boolean;
|
|
165
165
|
/**
|
|
166
166
|
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
167
|
+
* Independent reads reuse the result for this immutable config.
|
|
167
168
|
*
|
|
168
169
|
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
169
170
|
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
@@ -277,13 +277,25 @@ function slotProp(config, componentPath, name, decl) {
|
|
|
277
277
|
...routedKind === "composite" ? { compositeName: refPath(routed?.value) } : {}
|
|
278
278
|
};
|
|
279
279
|
}
|
|
280
|
+
const surfaces = /* @__PURE__ */ new WeakMap();
|
|
280
281
|
/**
|
|
281
282
|
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
283
|
+
* Independent reads reuse the result for this immutable config.
|
|
282
284
|
*
|
|
283
285
|
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
284
286
|
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
285
287
|
*/
|
|
286
288
|
function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
289
|
+
let cache;
|
|
290
|
+
if (seen.size === 0) {
|
|
291
|
+
cache = surfaces.get(config);
|
|
292
|
+
if (!cache) {
|
|
293
|
+
cache = /* @__PURE__ */ new Map();
|
|
294
|
+
surfaces.set(config, cache);
|
|
295
|
+
}
|
|
296
|
+
const cached = cache.get(componentPath);
|
|
297
|
+
if (cached) return cached;
|
|
298
|
+
}
|
|
287
299
|
const declared = resolveComponentProps(config, componentPath);
|
|
288
300
|
const layers = (Component.get(config, componentPath)?.toJSON())?.layers;
|
|
289
301
|
const props = [];
|
|
@@ -346,6 +358,7 @@ function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
|
346
358
|
required
|
|
347
359
|
}, when));
|
|
348
360
|
}
|
|
361
|
+
cache?.set(componentPath, props);
|
|
349
362
|
return props;
|
|
350
363
|
}
|
|
351
364
|
/**
|
|
@@ -206,22 +206,9 @@ declare function componentSpec(config: Config, path: string): ComponentSpec;
|
|
|
206
206
|
*/
|
|
207
207
|
declare function previewSpec(config: Config, path: string): RenderSpec | undefined;
|
|
208
208
|
interface ExpandOptions {
|
|
209
|
-
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* A component in this set is LEFT NAMED, deliberately: its emitted module is the real thing, with
|
|
214
|
-
* whatever its render closes over (a hook, a context, an event handler) intact, and re-deriving it
|
|
215
|
-
* from data would be a worse copy of something that already exists. Expansion is for what the
|
|
216
|
-
* registry CAN'T name — which is exactly a component whose structure is data and whose module was
|
|
217
|
-
* never built.
|
|
218
|
-
*
|
|
219
|
-
* Omitted, everything the config describes expands, which is what a test wants and what a caller
|
|
220
|
-
* with no registry to consult gets.
|
|
221
|
-
*
|
|
222
|
-
* Only `has` is asked, so a caller can answer from its registry directly instead of copying every
|
|
223
|
-
* key into a `Set` first.
|
|
224
|
-
*/
|
|
209
|
+
/** Membership lookup for types the renderer can draw. A Set or a registry-backed `has` works.
|
|
210
|
+
* Recognized components keep their compiled modules, including hooks and handlers.
|
|
211
|
+
* Omitted, everything the config describes expands. */
|
|
225
212
|
readonly rendered?: Pick<ReadonlySet<string>, 'has'>;
|
|
226
213
|
/** The functions `$computed` values call. Absent, a computed value stays on the element for the
|
|
227
214
|
* renderer, and a node repeated over a computed list emits once. */
|