@yahoo/uds-create-config 4.10.2 → 4.10.4
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/configs/CanvasConfig.d.ts +165 -77
- package/dist/configs/documentation.d.ts +1 -1
- package/dist/configs/react-native-system.d.ts +111 -52
- package/dist/configs/system.d.ts +121 -87
- package/dist/configs/system.js +4 -0
- package/dist/entities/documentation/Documentation.d.ts +1 -1
- package/dist/entities/native/NativeModifier.d.ts +1 -1
- package/dist/entities/native/NativeSettings.d.ts +1 -1
- package/dist/entities/native/NativeStyleProperty.d.ts +2 -2
- package/dist/entities/native/NativeToken.d.ts +4 -3
- package/dist/entities/system/CanvasRole.d.ts +1 -1
- package/dist/entities/system/Component.d.ts +23 -13
- package/dist/entities/system/Component.js +41 -15
- package/dist/entities/system/Composite.d.ts +1 -1
- package/dist/entities/system/Device.d.ts +1 -1
- package/dist/entities/system/File.d.ts +2 -2
- package/dist/entities/system/Font.d.ts +1 -1
- package/dist/entities/system/GlobalStyle.d.ts +1 -1
- package/dist/entities/system/Guidance.d.ts +1 -1
- package/dist/entities/system/GuidanceStyle.d.ts +1 -1
- package/dist/entities/system/Icon.d.ts +63 -11
- package/dist/entities/system/Icon.js +70 -14
- package/dist/entities/system/LinkedSystem.d.ts +1 -1
- package/dist/entities/system/Modifier.d.ts +2 -2
- package/dist/entities/system/Motion.d.ts +1 -1
- package/dist/entities/system/Package.d.ts +1 -1
- package/dist/entities/system/Settings.d.ts +1 -1
- package/dist/entities/system/StyleProperty.d.ts +12 -19
- package/dist/entities/system/StyleProperty.js +7 -10
- package/dist/entities/system/Token.d.ts +4 -3
- package/dist/entities/system/defineComponent.d.ts +21 -6
- package/dist/entities/system/defineComponent.js +7 -12
- package/dist/entities/system/glyph-identity.d.ts +7 -0
- package/dist/entities/system/glyph-identity.js +153 -0
- package/dist/entities/system/icon-domain-invariants.d.ts +11 -0
- package/dist/entities/system/icon-domain-invariants.js +178 -0
- package/dist/entities/system/icon-library.d.ts +93 -34
- package/dist/entities/system/icon-library.js +218 -50
- package/dist/entities/system/icon-metadata.d.ts +10 -4
- package/dist/entities/system/icon-metadata.js +45 -5
- package/dist/entities/system/runtime-modules.js +5 -5
- package/dist/entities/system/style-bag.js +14 -2
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +34 -5
- package/dist/framework/defineConfig.d.ts +6 -3
- package/dist/framework/defineEntity.d.ts +54 -15
- package/dist/framework/defineEntity.js +56 -2
- package/dist/framework/projections.d.ts +40 -2
- package/dist/framework/projections.js +99 -5
- package/dist/framework/prop-surface.d.ts +6 -5
- package/dist/framework/prop-surface.js +12 -14
- package/dist/framework/registry.d.ts +17 -1
- package/dist/framework/registry.js +2 -1
- package/dist/framework/render-spec.d.ts +6 -5
- package/dist/framework/render-spec.js +16 -11
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/signature.js +5 -1
- package/dist/framework/utils/group.d.ts +15 -1
- package/dist/framework/utils/ref-grammar.d.ts +35 -0
- package/dist/framework/utils/ref-grammar.js +76 -0
- package/dist/framework/utils/refs.d.ts +13 -45
- package/dist/framework/utils/refs.js +31 -94
- package/dist/framework/value-domain.js +53 -8
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/migrations/2.0.0/v1-artifact.d.ts +62 -45
- package/dist/migrations/2.0.0/v1-artifact.js +5 -7
- package/dist/migrations/20260921044042_icon_library_without_component.d.ts +19 -0
- package/dist/migrations/20260921044042_icon_library_without_component.js +86 -0
- package/dist/migrations/20260922013625_icon_libraries.d.ts +18 -0
- package/dist/migrations/20260922013625_icon_libraries.js +8 -0
- package/dist/renderer/UdsRenderer.d.ts +8 -1
- package/dist/renderer/UdsRenderer.js +7 -3
- package/dist/renderer/glyphEntries.d.ts +32 -0
- package/dist/renderer/glyphEntries.js +48 -0
- package/dist/renderer/glyphRenderable.d.ts +10 -0
- package/dist/renderer/glyphRenderable.js +40 -0
- package/dist/renderer/icon-library.d.ts +18 -11
- package/dist/renderer/index.d.ts +4 -2
- package/dist/renderer/index.js +4 -2
- package/dist/renderer/resolveGlyph.d.ts +47 -0
- package/dist/renderer/resolveGlyph.js +78 -0
- package/dist/renderer/wrapRegistry.d.ts +13 -4
- package/dist/renderer/wrapRegistry.js +7 -5
- package/dist/renderer/wrappers/component-refs.js +6 -2
- package/dist/renderer/wrappers/glyph-props.d.ts +15 -0
- package/dist/renderer/wrappers/glyph-props.js +65 -0
- package/dist/spec/glyph-jsx.d.ts +41 -0
- package/dist/spec/{asset-jsx.js → glyph-jsx.js} +7 -25
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +2 -2
- package/dist/spec/jsxToSpec.d.ts +10 -4
- package/dist/spec/jsxToSpec.js +21 -4
- package/dist/spec/specToJsx.d.ts +20 -9
- package/dist/spec/specToJsx.js +77 -16
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/renderer/assetEntries.d.ts +0 -37
- package/dist/renderer/assetEntries.js +0 -38
- package/dist/renderer/assetRenderable.d.ts +0 -25
- package/dist/renderer/assetRenderable.js +0 -19
- package/dist/spec/asset-jsx.d.ts +0 -61
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf, refLeaf } from "./utils/refs.js";
|
|
2
2
|
import { forwardsOf, rootLayerOf } from "../entities/system/element.js";
|
|
3
|
-
import { propValueDomain, resolveComponentProps } from "./projections.js";
|
|
3
|
+
import { propValueDomain, refListOf, resolveComponentProps } from "./projections.js";
|
|
4
4
|
import { Component } from "../entities/system/Component.js";
|
|
5
5
|
//#region src/framework/prop-surface.ts
|
|
6
6
|
/**
|
|
@@ -56,18 +56,16 @@ function acceptsRefs(accepts) {
|
|
|
56
56
|
return (Array.isArray(accepts) ? accepts : [accepts]).filter(isRef).map((ref) => ref.__ref);
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* The icon
|
|
60
|
-
*
|
|
61
|
-
* its `#field` marker and is not a library: its leaves are the
|
|
62
|
-
* own field values, which a plain list control serves fine. A ref
|
|
63
|
-
* (`icon:phosphor/StarIcon`) is a single-leaf domain, not a library
|
|
59
|
+
* The icon libraries a variant's value domain delegates to, when the domain is
|
|
60
|
+
* a group itself (`icon:phosphor` — one leaf per glyph) or a list of groups. A
|
|
61
|
+
* facet ref keeps its `#field` marker and is not a library: its leaves are the
|
|
62
|
+
* group node's own field values, which a plain list control serves fine. A ref
|
|
63
|
+
* at one item (`icon:phosphor/StarIcon`) is a single-leaf domain, not a library
|
|
64
|
+
* either. `undefined` when no element of the domain is a library.
|
|
64
65
|
*/
|
|
65
|
-
function
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const path = pathOf(value);
|
|
69
|
-
if (config.resolve("icon", path)) return void 0;
|
|
70
|
-
return path;
|
|
66
|
+
function variantIconLibraries(config, value) {
|
|
67
|
+
const libraries = (refListOf(value) ?? (isRef(value) ? [value.__ref] : [])).filter((target) => kindOf(target) === "icon" && memberOf(target) === void 0 && !config.resolve("icon", pathOf(target)));
|
|
68
|
+
return libraries.length > 0 ? libraries.map(pathOf) : void 0;
|
|
71
69
|
}
|
|
72
70
|
/**
|
|
73
71
|
* The prop a slot routes INTO, resolved through the layer it targets: the layer's element is a
|
|
@@ -205,13 +203,13 @@ function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
|
205
203
|
continue;
|
|
206
204
|
}
|
|
207
205
|
if (decl.type === "variant") {
|
|
208
|
-
const
|
|
206
|
+
const iconLibraries = variantIconLibraries(config, decl.value);
|
|
209
207
|
props.push(conditioned({
|
|
210
208
|
name,
|
|
211
209
|
kind: "variant",
|
|
212
210
|
required,
|
|
213
211
|
values: propValueDomain(config, decl)?.leaves ?? [],
|
|
214
|
-
...
|
|
212
|
+
...iconLibraries !== void 0 ? { iconLibraries } : {}
|
|
215
213
|
}, when));
|
|
216
214
|
continue;
|
|
217
215
|
}
|
|
@@ -41,6 +41,12 @@ type Linkable = boolean | ((args: {
|
|
|
41
41
|
readonly config: Config;
|
|
42
42
|
readonly source: Config;
|
|
43
43
|
}) => boolean);
|
|
44
|
+
/** See {@link EntityKind.authoredValue}. */
|
|
45
|
+
type AuthoredValueForm = (ctx: {
|
|
46
|
+
readonly config: Config; /** The ref the domain names: an item, a group, or a facet of this kind. */
|
|
47
|
+
readonly target: string; /** The leaves the target offers, which is what the form has to answer with. */
|
|
48
|
+
readonly leaves: readonly string[];
|
|
49
|
+
}) => z.ZodTypeAny | undefined;
|
|
44
50
|
interface EntityKind {
|
|
45
51
|
readonly name: string;
|
|
46
52
|
/** The entity class's name (`style-property` → `StyleProperty`) — what a consumer writes to reach
|
|
@@ -259,6 +265,16 @@ interface EntityKind {
|
|
|
259
265
|
* leaf, since neither can hold a slash.
|
|
260
266
|
*/
|
|
261
267
|
readonly uniqueLeaves?: boolean;
|
|
268
|
+
/**
|
|
269
|
+
* An extra authored form for a value whose domain is this kind, beside the leaf and the ref every
|
|
270
|
+
* domain takes. Asked when a ref domain's schema is built, with the target the domain names and the
|
|
271
|
+
* leaves it offers; the schema answers the leaf the value stands for, and the domain binds that
|
|
272
|
+
* leaf the way it binds a written one. `undefined` adds no form.
|
|
273
|
+
*
|
|
274
|
+
* Declared by the kind rather than tested for by name: the value-domain rule knows "a kind may
|
|
275
|
+
* take its values in another spelling" as a property, never which kind or which spelling.
|
|
276
|
+
*/
|
|
277
|
+
readonly authoredValue?: AuthoredValueForm;
|
|
262
278
|
/**
|
|
263
279
|
* Rules that hold across the kind's items and groups together, which no single item's schema can
|
|
264
280
|
* see — a typed group nested under another typed group. Returns the violations as sentences; a
|
|
@@ -298,4 +314,4 @@ interface EntityKind {
|
|
|
298
314
|
* kind def a `Config` holds (`config.entityOf(kind)`); `undefined` → no ops. */
|
|
299
315
|
declare function opsForKind(entry: EntityKind | undefined, config?: Config): DerivedOp[];
|
|
300
316
|
//#endregion
|
|
301
|
-
export { ComputedFields, ComputedInput, EntityKind, Linkable, opsForKind };
|
|
317
|
+
export { AuthoredValueForm, ComputedFields, ComputedInput, EntityKind, Linkable, opsForKind };
|
|
@@ -32,7 +32,7 @@ function titleCase(kind) {
|
|
|
32
32
|
/** Derive a kind's immutable metadata from its field schemas — the value a `defineEntity`/
|
|
33
33
|
* `defineDerivedEntity` attaches to its class and a `Config.register` stores in `#entities`. */
|
|
34
34
|
function buildKind(spec) {
|
|
35
|
-
const { name, fields, groupFields, subEntities = {}, computed, label, labelPlural, schemas: userSchemas, derived, sourceIdentity, sourceOrigin, authoredRefs, linkable, localGroupFields, emergentGroups, singleton = false, bareMember, sourceResolution, bulkAdopts, bulkOverlay, bulkDirectives, bulkOverlayWrite, nameEdges, rewriteName, styleBags, uniqueLeaves, invariants } = spec;
|
|
35
|
+
const { name, fields, groupFields, subEntities = {}, computed, label, labelPlural, schemas: userSchemas, derived, sourceIdentity, sourceOrigin, authoredRefs, linkable, localGroupFields, emergentGroups, singleton = false, bareMember, sourceResolution, bulkAdopts, bulkOverlay, bulkDirectives, bulkOverlayWrite, nameEdges, rewriteName, styleBags, uniqueLeaves, authoredValue, invariants } = spec;
|
|
36
36
|
const allComputed = {
|
|
37
37
|
sources: ({ member, config }) => sourceSlugs(member, config),
|
|
38
38
|
borrowedFrom: ({ config, path }) => config.borrowedFrom(name, path),
|
|
@@ -77,6 +77,7 @@ function buildKind(spec) {
|
|
|
77
77
|
rewriteName,
|
|
78
78
|
styleBags,
|
|
79
79
|
...uniqueLeaves ? { uniqueLeaves } : {},
|
|
80
|
+
...authoredValue ? { authoredValue } : {},
|
|
80
81
|
...invariants ? { invariants } : {}
|
|
81
82
|
};
|
|
82
83
|
}
|
|
@@ -314,7 +314,7 @@ declare function withoutTruthyTerm({
|
|
|
314
314
|
prop: string;
|
|
315
315
|
}): unknown;
|
|
316
316
|
/**
|
|
317
|
-
* The type a
|
|
317
|
+
* The type a bound element resolves to, given the value its prop was handed.
|
|
318
318
|
*
|
|
319
319
|
* This is the one thing json-render has no vocabulary for — `UIElement.type` is a plain string — so
|
|
320
320
|
* a stored spec can't hold it and `deriveSpec` declines. An expansion is a different position: the
|
|
@@ -323,10 +323,11 @@ declare function withoutTruthyTerm({
|
|
|
323
323
|
* rather than 51 conditioned siblings copying a library's index into every component that draws a
|
|
324
324
|
* glyph.
|
|
325
325
|
*
|
|
326
|
-
* Two ways the domain is known, in order: the prop
|
|
327
|
-
* which is the shape that keeps 1,530 names in one
|
|
328
|
-
* member is found by asking which group declares
|
|
329
|
-
* from v1 spells an icon prop as an enumeration, and
|
|
326
|
+
* Two ways the domain is known, in order: the prop delegates it (`value` is a ref to the library, or
|
|
327
|
+
* a list of refs for a host drawing from several, which is the shape that keeps 1,530 names in one
|
|
328
|
+
* place), or the prop enumerates its values and the member is found by asking which group declares
|
|
329
|
+
* it. The second exists because a config migrated from v1 spells an icon prop as an enumeration, and
|
|
330
|
+
* a glyph is no less resolvable for it.
|
|
330
331
|
*/
|
|
331
332
|
declare function boundElementType(config: Config, componentPath: string, prop: string, value: unknown): string | undefined;
|
|
332
333
|
/** Where one slot prop's content lands. */
|
|
@@ -2,7 +2,7 @@ import { isRef, kindOf, memberOf, pathOf, ref, splitRef } from "./utils/refs.js"
|
|
|
2
2
|
import { renderedElement } from "../entities/system/element.js";
|
|
3
3
|
import { createSliceMemo } from "./memo.js";
|
|
4
4
|
import { unconditionalPreviewProps } from "./preview-store.js";
|
|
5
|
-
import { authoredBag, authoredValue, declaredPropDefaults, memberFromLeaf, resolveComponentProps, stylePropertyPathFor } from "./projections.js";
|
|
5
|
+
import { authoredBag, authoredValue, declaredPropDefaults, memberFromLeaf, refListOf, resolveComponentProps, stylePropertyPathFor } from "./projections.js";
|
|
6
6
|
import { forwardedLayers, intoName, routesContent } from "./prop-surface.js";
|
|
7
7
|
import { graftPreviewElements } from "../spec/preview-elements.js";
|
|
8
8
|
import { componentLayerClass, componentPropClasses, componentRuleClasses, layerRoutedProps, splitStyleProps, styleRuleMotionClasses } from "./class-names.js";
|
|
@@ -720,7 +720,7 @@ function spentBy({ condition, prop }) {
|
|
|
720
720
|
return test.$state.replace(/^\//, "") === prop && test.not !== true && (operatorOf(test) === void 0 || operatorOf(test) === "eq" && test.eq === true);
|
|
721
721
|
}
|
|
722
722
|
/**
|
|
723
|
-
* The type a
|
|
723
|
+
* The type a bound element resolves to, given the value its prop was handed.
|
|
724
724
|
*
|
|
725
725
|
* This is the one thing json-render has no vocabulary for — `UIElement.type` is a plain string — so
|
|
726
726
|
* a stored spec can't hold it and `deriveSpec` declines. An expansion is a different position: the
|
|
@@ -729,20 +729,25 @@ function spentBy({ condition, prop }) {
|
|
|
729
729
|
* rather than 51 conditioned siblings copying a library's index into every component that draws a
|
|
730
730
|
* glyph.
|
|
731
731
|
*
|
|
732
|
-
* Two ways the domain is known, in order: the prop
|
|
733
|
-
* which is the shape that keeps 1,530 names in one
|
|
734
|
-
* member is found by asking which group declares
|
|
735
|
-
* from v1 spells an icon prop as an enumeration, and
|
|
732
|
+
* Two ways the domain is known, in order: the prop delegates it (`value` is a ref to the library, or
|
|
733
|
+
* a list of refs for a host drawing from several, which is the shape that keeps 1,530 names in one
|
|
734
|
+
* place), or the prop enumerates its values and the member is found by asking which group declares
|
|
735
|
+
* it. The second exists because a config migrated from v1 spells an icon prop as an enumeration, and
|
|
736
|
+
* a glyph is no less resolvable for it.
|
|
736
737
|
*/
|
|
737
738
|
function boundElementType(config, componentPath, prop, value) {
|
|
738
739
|
if (typeof value !== "string" || !value) return void 0;
|
|
739
740
|
if (value.includes("/")) return void 0;
|
|
740
741
|
const decl = resolveComponentProps(config, componentPath)[prop];
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
742
|
+
const single = refOf(decl?.value);
|
|
743
|
+
const targets = refListOf(decl?.value) ?? (single ? [single] : []);
|
|
744
|
+
if (targets.length > 0) {
|
|
745
|
+
for (const target of targets) {
|
|
746
|
+
if (memberOf(target) !== void 0) continue;
|
|
747
|
+
const member = memberFromLeaf(config, target, value);
|
|
748
|
+
if (member) return `${kindOf(target)}:${member}`;
|
|
749
|
+
}
|
|
750
|
+
return;
|
|
746
751
|
}
|
|
747
752
|
const matches = config.list("icon").filter((member) => (member.path.split("/").pop() ?? "") === value);
|
|
748
753
|
return matches.length === 1 ? `icon:${matches[0]?.path}` : void 0;
|
|
@@ -15,7 +15,7 @@ import { Patch, SerializedConfig } from "./Config.js";
|
|
|
15
15
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
16
16
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
17
17
|
*/
|
|
18
|
-
declare const CURRENT_SCHEMA_VERSION =
|
|
18
|
+
declare const CURRENT_SCHEMA_VERSION = 20260922013625;
|
|
19
19
|
/** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
|
|
20
20
|
* and a raw old-shape record both flow in without casts. */
|
|
21
21
|
interface VersionStamped {
|
|
@@ -13,7 +13,7 @@ import { ConfigFormatError } from "./rejection.js";
|
|
|
13
13
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
14
14
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
15
15
|
*/
|
|
16
|
-
const CURRENT_SCHEMA_VERSION =
|
|
16
|
+
const CURRENT_SCHEMA_VERSION = 20260922013625;
|
|
17
17
|
/** The mint that moved `options` into the `settings` kind — restated here, rather than imported
|
|
18
18
|
* from the migration that owns it, because that migration imports this module. */
|
|
19
19
|
const SETTINGS_AS_KIND_VERSION = 20260908171448;
|
|
@@ -45,7 +45,7 @@ function registerSchemaMigrations(...migrations) {
|
|
|
45
45
|
for (const migration of migrations) {
|
|
46
46
|
if (migration.version !== 1 && !isMintTimestamp(migration.version)) throw new Error(`Schema migration version ${migration.version} is not a mint timestamp — mint one with \`date +%Y%m%d%H%M%S\`, like a supabase migration.`);
|
|
47
47
|
if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
|
|
48
|
-
if (migration.version >
|
|
48
|
+
if (migration.version > 20260922013625) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
|
|
49
49
|
REGISTERED.set(migration.version, migration);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -102,7 +102,7 @@ function pendingFor(version, target, options) {
|
|
|
102
102
|
* Already-current input passes through untouched — same reference, so hot paths pay nothing.
|
|
103
103
|
*/
|
|
104
104
|
function upgradeSerializedConfig(json, options) {
|
|
105
|
-
const target = options?.target ??
|
|
105
|
+
const target = options?.target ?? 20260922013625;
|
|
106
106
|
const version = detectedWireVersion(json);
|
|
107
107
|
if (version > target) throw new SchemaVersionTooNew(version, target);
|
|
108
108
|
const raw = json;
|
|
@@ -160,7 +160,7 @@ function upgradedSources(json, options) {
|
|
|
160
160
|
* meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
|
|
161
161
|
*/
|
|
162
162
|
function upgradePatch(patch, writtenAt, options) {
|
|
163
|
-
const target = options?.target ??
|
|
163
|
+
const target = options?.target ?? 20260922013625;
|
|
164
164
|
if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
|
|
165
165
|
let current = patch;
|
|
166
166
|
for (const migration of pendingFor(writtenAt, target, options)) {
|
|
@@ -179,7 +179,7 @@ function upgradePatch(patch, writtenAt, options) {
|
|
|
179
179
|
* stamp would cause.
|
|
180
180
|
*/
|
|
181
181
|
function upgradeDraftEntries(draft, options) {
|
|
182
|
-
const target = options?.target ??
|
|
182
|
+
const target = options?.target ?? 20260922013625;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -9,6 +9,10 @@ import { z } from "zod";
|
|
|
9
9
|
* `address` describe away. Two levels is enough to show a kind's fields and the shape of each field's
|
|
10
10
|
* members; a token's color operation is recursive and would otherwise unfold without end.
|
|
11
11
|
*/
|
|
12
|
+
/** A schema no value satisfies — `{ not: {} }`. */
|
|
13
|
+
function isNever(node) {
|
|
14
|
+
return node.not !== void 0 && typeof node.not === "object" && Object.keys(node.not).length === 0 && Object.keys(node).length === 1;
|
|
15
|
+
}
|
|
12
16
|
const DEFAULT_DEPTH = 2;
|
|
13
17
|
const DEFAULT_ENUM_LIMIT = 8;
|
|
14
18
|
function isNode(value) {
|
|
@@ -39,7 +43,7 @@ function renderSignature(schema, options = {}) {
|
|
|
39
43
|
return shown.join(" | ");
|
|
40
44
|
}
|
|
41
45
|
const variants = node.anyOf ?? node.oneOf;
|
|
42
|
-
if (variants) return unique(variants.map((member) => render(member, remaining))).join(" | ");
|
|
46
|
+
if (variants) return unique(variants.filter((member) => !isNever(member)).map((member) => render(member, remaining))).join(" | ");
|
|
43
47
|
if (node.allOf) return unique(node.allOf.map((member) => render(member, remaining))).join(" & ");
|
|
44
48
|
if (Array.isArray(node.type)) return unique(node.type.map((type) => render({
|
|
45
49
|
...node,
|
|
@@ -31,7 +31,21 @@ type GroupBody<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<G>
|
|
|
31
31
|
readonly items?: Readonly<Record<string, AuthoredEntry<F, G>>>;
|
|
32
32
|
readonly [GROUP]?: true;
|
|
33
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* A registration-time input: a key of an authored group body that the kind's `group()` hands to this
|
|
36
|
+
* handler, with the rest of the body, and then strips. It is never stored, never part of the group
|
|
37
|
+
* schema, and never seen by a hydrated config. What the handler does with it is the kind's business.
|
|
38
|
+
*/
|
|
39
|
+
type GroupInputHandler<I> = (args: {
|
|
40
|
+
readonly input: I; /** The body without its inputs: the members under `items` and the group's own fields. */
|
|
41
|
+
readonly body: Readonly<Record<string, unknown>>;
|
|
42
|
+
}) => void;
|
|
43
|
+
/** A kind's registration-time inputs, keyed by the body key each one consumes. `never` is the
|
|
44
|
+
* parameter position's bottom, so a handler declaring any input type fits. */
|
|
45
|
+
type GroupInputs = Readonly<Record<string, GroupInputHandler<never>>>;
|
|
46
|
+
/** The input keys a kind's `group()` takes, typed off each handler's declared input. */
|
|
47
|
+
type GroupInputValues<GI extends GroupInputs> = { readonly [K in keyof GI]?: GI[K] extends GroupInputHandler<infer I> ? I : never };
|
|
34
48
|
declare function brandGroup<F extends FieldsSchema, G extends FieldsSchema>(meta: GroupBody<F, G>): GroupBody<F, G>;
|
|
35
49
|
declare function isGroupBody(value: unknown): boolean;
|
|
36
50
|
//#endregion
|
|
37
|
-
export { AuthoredEntry, GROUP, GroupBody, brandGroup, isGroupBody };
|
|
51
|
+
export { AuthoredEntry, GROUP, GroupBody, GroupInputValues, GroupInputs, brandGroup, isGroupBody };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/framework/utils/ref-grammar.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The ref grammar — `kind:path[@source][#member]` — and its one reader, with nothing else imported.
|
|
4
|
+
* A renderer bundle reads a stored ref through this module without carrying the schema half of
|
|
5
|
+
* `refs.ts`; everything there re-exports from here.
|
|
6
|
+
*/
|
|
7
|
+
interface Ref {
|
|
8
|
+
readonly __ref: string;
|
|
9
|
+
}
|
|
10
|
+
/** A ref's parts. */
|
|
11
|
+
interface RefParts {
|
|
12
|
+
readonly kind: string;
|
|
13
|
+
readonly source: string | undefined;
|
|
14
|
+
/** without the source — `pathOf`'s answer. */
|
|
15
|
+
readonly path: string;
|
|
16
|
+
/** with the source, when there is one — the form an authored value and an emitted union spell,
|
|
17
|
+
* because a string in value position has nowhere to put a second argument. */
|
|
18
|
+
readonly qualifiedPath: string;
|
|
19
|
+
readonly member: string | undefined;
|
|
20
|
+
/** whether a `kind:` marker was present — without one, `kind` and `path` are both the whole
|
|
21
|
+
* string, and each caller reads the one it means. */
|
|
22
|
+
readonly marked: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* `kind:path[@source][#member]`, split — the one place a ref is read. This is the ref spelling of the
|
|
26
|
+
* address grammar written down whole in `framework/config-op.ts`.
|
|
27
|
+
*
|
|
28
|
+
* Every accessor below goes through this, and so does anything outside this file that needs a part of
|
|
29
|
+
* a ref. Code that slices at `indexOf(':')` or tests `startsWith('token:')` has its own copy of the
|
|
30
|
+
* grammar, which means the grammar cannot move without hunting for the copies — and a copy that is
|
|
31
|
+
* subtly wrong (a prefix test that a sourced ref fails) is silent.
|
|
32
|
+
*/
|
|
33
|
+
declare function splitRef(target: string | Ref): RefParts;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Ref, splitRef };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** The `@source` suffix for a ref, or `''` when it's local. */
|
|
2
|
+
const qualifier = (source) => source === void 0 ? "" : `@${source}`;
|
|
3
|
+
/**
|
|
4
|
+
* Splits a qualified path into what it names and where from.
|
|
5
|
+
*
|
|
6
|
+
* A path can OPEN with `@`: a package's path is an npm specifier, and `package:@ariakit/react` is
|
|
7
|
+
* scoped. So the source is the last `@`, and never a leading one — a scope opens a path, it doesn't
|
|
8
|
+
* qualify it. `package:@ariakit/react@yahoo-os` is that package, as their system has it.
|
|
9
|
+
*
|
|
10
|
+
* Total for every path {@link isEntityPath} admits, which is what makes "the last `@`" a rule rather
|
|
11
|
+
* than a heuristic: with at most a leading `@` in the path, any later one is the marker.
|
|
12
|
+
*/
|
|
13
|
+
function splitSource(qualified) {
|
|
14
|
+
const at = qualified.lastIndexOf("@");
|
|
15
|
+
if (at <= 0) return [qualified, void 0];
|
|
16
|
+
return [qualified.slice(0, at), qualified.slice(at + 1)];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `kind:path[@source][#member]`, split — the one place a ref is read. This is the ref spelling of the
|
|
20
|
+
* address grammar written down whole in `framework/config-op.ts`.
|
|
21
|
+
*
|
|
22
|
+
* Every accessor below goes through this, and so does anything outside this file that needs a part of
|
|
23
|
+
* a ref. Code that slices at `indexOf(':')` or tests `startsWith('token:')` has its own copy of the
|
|
24
|
+
* grammar, which means the grammar cannot move without hunting for the copies — and a copy that is
|
|
25
|
+
* subtly wrong (a prefix test that a sourced ref fails) is silent.
|
|
26
|
+
*/
|
|
27
|
+
function splitRef(target) {
|
|
28
|
+
const raw = isRef(target) ? target.__ref : target;
|
|
29
|
+
const hash = raw.indexOf("#");
|
|
30
|
+
const entity = hash === -1 ? raw : raw.slice(0, hash);
|
|
31
|
+
const member = hash === -1 ? void 0 : raw.slice(hash + 1);
|
|
32
|
+
const colon = entity.indexOf(":");
|
|
33
|
+
const kind = colon === -1 ? entity : entity.slice(0, colon);
|
|
34
|
+
const qualifiedPath = colon === -1 ? entity : entity.slice(colon + 1);
|
|
35
|
+
const [path, source] = splitSource(qualifiedPath);
|
|
36
|
+
return {
|
|
37
|
+
kind,
|
|
38
|
+
source,
|
|
39
|
+
path,
|
|
40
|
+
qualifiedPath,
|
|
41
|
+
member,
|
|
42
|
+
marked: colon !== -1
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** The member half (`props/gap`), or `undefined` for a plain entity ref. Takes the ref itself or its
|
|
46
|
+
* string form, like {@link pathOf} / {@link kindOf} / {@link sourceOf}. */
|
|
47
|
+
function memberOf(target) {
|
|
48
|
+
const raw = isRef(target) ? target.__ref : target;
|
|
49
|
+
const at = raw.indexOf("#");
|
|
50
|
+
return at === -1 ? void 0 : raw.slice(at + 1);
|
|
51
|
+
}
|
|
52
|
+
/** The path of the entity a ref points at — kind, source and any member stripped, so a member ref
|
|
53
|
+
* resolves to the item that contains it (`component:buttons/Primary#props/gap` → `buttons/Primary`)
|
|
54
|
+
* and a linked ref yields the path as its source spells it (`token:color/brand@yahoo-os` →
|
|
55
|
+
* `color/brand`). Takes the ref itself or its string form, so a caller holding a ref field never
|
|
56
|
+
* spells `__ref`. */
|
|
57
|
+
function pathOf(target) {
|
|
58
|
+
return splitRef(target).path;
|
|
59
|
+
}
|
|
60
|
+
/** The source half — the link slug a ref points through, or `undefined` when it points at something
|
|
61
|
+
* in this config. This is the one question that distinguishes a linked entity from a local one, and
|
|
62
|
+
* it replaces reading a per-entity provenance marker. */
|
|
63
|
+
function sourceOf(target) {
|
|
64
|
+
return splitRef(target).source;
|
|
65
|
+
}
|
|
66
|
+
/** The kind a ref points at (`component:buttons/Primary#props/gap` → `component`) — the twin of
|
|
67
|
+
* {@link pathOf}, so a consumer holding a `kind:path` string (a `dependentsOf` result) never splits
|
|
68
|
+
* it by hand. Takes the ref itself or its string form. */
|
|
69
|
+
function kindOf(target) {
|
|
70
|
+
return splitRef(target).kind;
|
|
71
|
+
}
|
|
72
|
+
function isRef(value) {
|
|
73
|
+
return typeof value === "object" && value !== null && "__ref" in value;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { isRef, kindOf, memberOf, pathOf, qualifier, sourceOf, splitRef };
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
import { Ref as Ref$1, splitRef as splitRef$1 } from "./ref-grammar.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
|
|
3
4
|
//#region src/framework/utils/refs.d.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
type Ref = Ref$1;
|
|
6
|
+
/** `kind:path[@source][#member]`, split — the one reader of the ref grammar. */
|
|
7
|
+
declare function splitRef(target: string | Ref): ReturnType<typeof splitRef$1>;
|
|
8
|
+
declare function isRef(value: unknown): value is Ref;
|
|
9
|
+
/** The kind a ref points at (`component:buttons/Primary#props/gap` → `component`). */
|
|
10
|
+
declare function kindOf(target: string | Ref): string;
|
|
11
|
+
/** The path of the entity a ref points at — kind, source and any member stripped. */
|
|
12
|
+
declare function pathOf(target: string | Ref): string;
|
|
13
|
+
/** The source half — the link slug a ref points through, or `undefined` for a local one. */
|
|
14
|
+
declare function sourceOf(target: string | Ref): string | undefined;
|
|
15
|
+
/** The member half (`props/gap`), or `undefined` for a plain entity ref. */
|
|
16
|
+
declare function memberOf(target: string | Ref): string | undefined;
|
|
7
17
|
/** A ref as the authoring API returns it. The method is non-enumerable, so an ordinary ref remains
|
|
8
18
|
* exactly `{ __ref }` in JSON and anywhere that walks its data. Calling it produces the explicit
|
|
9
19
|
* wire value below: a base ref plus the sparse fields this config owns.
|
|
@@ -43,30 +53,6 @@ interface ExtendedRef<Delta extends Record<string, unknown> = Record<string, unk
|
|
|
43
53
|
declare function isEntityPath(path: string): boolean;
|
|
44
54
|
/** What a refused path should say, in one place, so a create, a rename and a register word it alike. */
|
|
45
55
|
declare const ENTITY_PATH_MESSAGE = "An entity path may not contain \"@\" except as a leading npm scope \u2014 \"@\" marks the source a ref is drawn from, so a path carrying one cannot be told apart from a borrowed address.";
|
|
46
|
-
/** A ref's parts. */
|
|
47
|
-
interface RefParts {
|
|
48
|
-
readonly kind: string;
|
|
49
|
-
readonly source: string | undefined;
|
|
50
|
-
/** without the source — `pathOf`'s answer. */
|
|
51
|
-
readonly path: string;
|
|
52
|
-
/** with the source, when there is one — the form an authored value and an emitted union spell,
|
|
53
|
-
* because a string in value position has nowhere to put a second argument. */
|
|
54
|
-
readonly qualifiedPath: string;
|
|
55
|
-
readonly member: string | undefined;
|
|
56
|
-
/** whether a `kind:` marker was present — without one, `kind` and `path` are both the whole
|
|
57
|
-
* string, and each caller reads the one it means. */
|
|
58
|
-
readonly marked: boolean;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* `kind:path[@source][#member]`, split — the one place a ref is read. This is the ref spelling of the
|
|
62
|
-
* address grammar written down whole in `framework/config-op.ts`.
|
|
63
|
-
*
|
|
64
|
-
* Every accessor below goes through this, and so does anything outside this file that needs a part of
|
|
65
|
-
* a ref. Code that slices at `indexOf(':')` or tests `startsWith('token:')` has its own copy of the
|
|
66
|
-
* grammar, which means the grammar cannot move without hunting for the copies — and a copy that is
|
|
67
|
-
* subtly wrong (a prefix test that a sourced ref fails) is silent.
|
|
68
|
-
*/
|
|
69
|
-
declare function splitRef(target: string | Ref): RefParts;
|
|
70
56
|
/**
|
|
71
57
|
* A reference to another entity: `ref('token', 'color/brand')`. Resolution is prefix-or-leaf against
|
|
72
58
|
* the flat store.
|
|
@@ -84,23 +70,6 @@ declare function memberRef(kind: string, path: string, sub: string, member: stri
|
|
|
84
70
|
/** The entity half of any ref — a plain entity ref is itself. This is the form the dependency
|
|
85
71
|
* graph and kind-narrowing speak, so a member ref participates in both unchanged. */
|
|
86
72
|
declare function entityRefOf(target: string): string;
|
|
87
|
-
/** The member half (`props/gap`), or `undefined` for a plain entity ref. Takes the ref itself or its
|
|
88
|
-
* string form, like {@link pathOf} / {@link kindOf} / {@link sourceOf}. */
|
|
89
|
-
declare function memberOf(target: string | Ref): string | undefined;
|
|
90
|
-
/** The path of the entity a ref points at — kind, source and any member stripped, so a member ref
|
|
91
|
-
* resolves to the item that contains it (`component:buttons/Primary#props/gap` → `buttons/Primary`)
|
|
92
|
-
* and a linked ref yields the path as its source spells it (`token:color/brand@yahoo-os` →
|
|
93
|
-
* `color/brand`). Takes the ref itself or its string form, so a caller holding a ref field never
|
|
94
|
-
* spells `__ref`. */
|
|
95
|
-
declare function pathOf(target: string | Ref): string;
|
|
96
|
-
/** The source half — the link slug a ref points through, or `undefined` when it points at something
|
|
97
|
-
* in this config. This is the one question that distinguishes a linked entity from a local one, and
|
|
98
|
-
* it replaces reading a per-entity provenance marker. */
|
|
99
|
-
declare function sourceOf(target: string | Ref): string | undefined;
|
|
100
|
-
/** The kind a ref points at (`component:buttons/Primary#props/gap` → `component`) — the twin of
|
|
101
|
-
* {@link pathOf}, so a consumer holding a `kind:path` string (a `dependentsOf` result) never splits
|
|
102
|
-
* it by hand. Takes the ref itself or its string form. */
|
|
103
|
-
declare function kindOf(target: string | Ref): string;
|
|
104
73
|
/** The zod schema of a ref value — used via {@link orRef} so a field never spells the
|
|
105
74
|
* `{ __ref }` shape by hand. `.meta({ ref: true })` marks it as a ref for any consumer (JSON
|
|
106
75
|
* Schema, an authoring UI) — this generic form carries no target kind (use an entity as the field
|
|
@@ -112,7 +81,6 @@ declare const refSchema: z.ZodObject<{
|
|
|
112
81
|
declare function orRef<T extends z.ZodTypeAny>(schema: T): z.ZodUnion<readonly [T, z.ZodObject<{
|
|
113
82
|
__ref: z.ZodString;
|
|
114
83
|
}, z.core.$strip>]>;
|
|
115
|
-
declare function isRef(value: unknown): value is Ref;
|
|
116
84
|
/** Whether a ref is the stored result of `.extend(delta)`. Kept separate from {@link isRef}: every
|
|
117
85
|
* existing ref consumer should continue to see the base pointer, while Config is the place that
|
|
118
86
|
* gives the sibling delta its merge semantics. */
|