@yahoo/uds-create-config 5.70.0 → 5.71.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/configs/system.js +2 -0
- package/dist/entities/system/Component.d.ts +10 -4
- package/dist/entities/system/Component.js +22 -12
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +1 -1
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/migrations/20261102193912_map_props_from.d.ts +12 -0
- package/dist/migrations/20261102193912_map_props_from.js +10 -0
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +2 -2
- package/dist/spec/prop-mapping.d.ts +34 -2
- package/dist/spec/prop-mapping.js +47 -10
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/configs/system.js
CHANGED
|
@@ -37,6 +37,7 @@ import { componentMapPropsMigration } from "../migrations/20261030134149_compone
|
|
|
37
37
|
import { layerPrefixMigration } from "../migrations/20261030163028_layer_prefix.js";
|
|
38
38
|
import { defaultColorsMigration } from "../migrations/20261102143821_default_colors.js";
|
|
39
39
|
import { linkReplaceMigration } from "../migrations/20261102185610_link_replace.js";
|
|
40
|
+
import { mapPropsFromMigration } from "../migrations/20261102193912_map_props_from.js";
|
|
40
41
|
import { CanvasRole } from "../entities/system/CanvasRole.js";
|
|
41
42
|
import { GlobalStyle } from "../entities/system/GlobalStyle.js";
|
|
42
43
|
import { Guidance } from "../entities/system/Guidance.js";
|
|
@@ -207,5 +208,6 @@ if (!registeredSchemaMigrations().has(20261030134149)) registerSchemaMigrations(
|
|
|
207
208
|
if (!registeredSchemaMigrations().has(20261030163028)) registerSchemaMigrations(layerPrefixMigration);
|
|
208
209
|
if (!registeredSchemaMigrations().has(20261102143821)) registerSchemaMigrations(defaultColorsMigration);
|
|
209
210
|
if (!registeredSchemaMigrations().has(20261102185610)) registerSchemaMigrations(linkReplaceMigration);
|
|
211
|
+
if (!registeredSchemaMigrations().has(20261102193912)) registerSchemaMigrations(mapPropsFromMigration);
|
|
210
212
|
//#endregion
|
|
211
213
|
export { System };
|
|
@@ -873,11 +873,16 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
873
873
|
readonly input: z.ZodObject<{
|
|
874
874
|
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
875
875
|
data: z.ZodObject<{
|
|
876
|
-
|
|
876
|
+
from: z.ZodOptional<z.ZodString>;
|
|
877
|
+
only: z.ZodOptional<z.ZodObject<{
|
|
878
|
+
canvas: z.ZodString;
|
|
879
|
+
nodes: z.ZodArray<z.ZodString>;
|
|
880
|
+
}, z.core.$strip>>;
|
|
881
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
877
882
|
when: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
878
883
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
879
884
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
880
|
-
}, z.core.$strip
|
|
885
|
+
}, z.core.$strip>>>;
|
|
881
886
|
}, z.core.$strip>;
|
|
882
887
|
}, z.core.$strip>;
|
|
883
888
|
};
|
|
@@ -885,11 +890,12 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
885
890
|
readonly input: z.ZodObject<{
|
|
886
891
|
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
887
892
|
data: z.ZodObject<{
|
|
888
|
-
|
|
893
|
+
from: z.ZodOptional<z.ZodString>;
|
|
894
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
889
895
|
when: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
890
896
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
891
897
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
892
|
-
}, z.core.$strip
|
|
898
|
+
}, z.core.$strip>>>;
|
|
893
899
|
instances: z.ZodDefault<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
894
900
|
}, z.core.$strip>;
|
|
895
901
|
}, z.core.$strip>;
|
|
@@ -24,7 +24,7 @@ import { slotAnatomyPropOf, slotTargetsOf, withoutTruthyTerm } from "../../frame
|
|
|
24
24
|
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
25
25
|
import { cellAt } from "../../spec/cell.js";
|
|
26
26
|
import { instanceAt } from "../../spec/instance.js";
|
|
27
|
-
import { mapComponentProps,
|
|
27
|
+
import { mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, propMappingErrors } from "../../spec/prop-mapping.js";
|
|
28
28
|
import { forwardOptions, forwardsWrite } from "./component-forwards.js";
|
|
29
29
|
import { assertComponentSourceInput } from "./component-source-fields.js";
|
|
30
30
|
import { checkStyleSet, styleSetEdits } from "./component-style-set.js";
|
|
@@ -2947,12 +2947,16 @@ element: refSchema })
|
|
|
2947
2947
|
"map-props": {
|
|
2948
2948
|
input: z.object({
|
|
2949
2949
|
path: pathInput("component"),
|
|
2950
|
-
data: z.object({
|
|
2950
|
+
data: z.object({
|
|
2951
|
+
from: mappingFromSchema.optional(),
|
|
2952
|
+
only: mappingScopeSchema.optional(),
|
|
2953
|
+
rules: mapPropsRulesSchema
|
|
2954
|
+
})
|
|
2951
2955
|
}),
|
|
2952
2956
|
readOnly: false,
|
|
2953
2957
|
approval: "reference-change",
|
|
2954
2958
|
label: "Map props",
|
|
2955
|
-
description: "Move a component's instances onto its props as they are now, after its API changed: `variant: 'primary'` becomes `color: 'brand', prominence: 'solid'`. It changes nothing in the config. Where it runs decides what it moves: in Create, the instances in the branch's design files; in a checkout (`uds config edit`, the local UDS MCP), the call sites in the project's source. Refuses a rule that writes a prop or value the component doesn't take. Run it with `plan: true` first: the plan says what it would move, and writes nothing.",
|
|
2959
|
+
description: "Move a component's instances onto its props as they are now, after its API changed: `variant: 'primary'` becomes `color: 'brand', prominence: 'solid'`. It changes nothing in the config. Where it runs decides what it moves: in Create, the instances in the branch's design files; in a checkout (`uds config edit`, the local UDS MCP), the call sites in the project's source. With `from`, it swaps the component too: instances of `from`, a component the system may no longer have, become this component's, and the rules move their props onto it (`when: {}` reaches every swapped instance). Refuses a rule that writes a prop or value the component doesn't take. Run it with `plan: true` first: the plan says what it would move, and writes nothing.",
|
|
2956
2960
|
scope: "item",
|
|
2957
2961
|
title: (entity) => `Map ${entity} props`,
|
|
2958
2962
|
example: ({ config, path }) => {
|
|
@@ -2963,10 +2967,7 @@ element: refSchema })
|
|
|
2963
2967
|
};
|
|
2964
2968
|
},
|
|
2965
2969
|
handler: (input, config) => {
|
|
2966
|
-
const errors = propMappingErrors(config,
|
|
2967
|
-
component: String(input.path),
|
|
2968
|
-
rules: input.data.rules
|
|
2969
|
-
});
|
|
2970
|
+
const errors = propMappingErrors(config, mappingOf(String(input.path), input.data));
|
|
2970
2971
|
if (errors.length > 0) rejectData(errors.join(" "));
|
|
2971
2972
|
return config;
|
|
2972
2973
|
}
|
|
@@ -2975,7 +2976,8 @@ element: refSchema })
|
|
|
2975
2976
|
input: z.object({
|
|
2976
2977
|
path: pathInput("component"),
|
|
2977
2978
|
data: z.object({
|
|
2978
|
-
|
|
2979
|
+
from: mappingFromSchema.optional(),
|
|
2980
|
+
rules: mapPropsRulesSchema,
|
|
2979
2981
|
instances: z.array(z.record(z.string(), z.unknown())).default([]).describe("Instances' props as they are stored or written: each comes back with the rules applied.")
|
|
2980
2982
|
})
|
|
2981
2983
|
}),
|
|
@@ -2987,10 +2989,7 @@ element: refSchema })
|
|
|
2987
2989
|
example: ({ config, path }) => exampleMapping(config, path),
|
|
2988
2990
|
handler: (input, config) => {
|
|
2989
2991
|
const data = input.data;
|
|
2990
|
-
return mapComponentProps(config,
|
|
2991
|
-
component: String(input.path),
|
|
2992
|
-
rules: data.rules
|
|
2993
|
-
}, data.instances ?? []);
|
|
2992
|
+
return mapComponentProps(config, mappingOf(String(input.path), input.data), data.instances ?? []);
|
|
2994
2993
|
}
|
|
2995
2994
|
}
|
|
2996
2995
|
},
|
|
@@ -3140,6 +3139,17 @@ function exampleProps(config, componentPath) {
|
|
|
3140
3139
|
}
|
|
3141
3140
|
return {};
|
|
3142
3141
|
}
|
|
3142
|
+
/** The mapping a `map-props` op's input names, refused when a mapping without `from` has no rule. */
|
|
3143
|
+
function mappingOf(component, data) {
|
|
3144
|
+
const { from, only, rules = [] } = data ?? {};
|
|
3145
|
+
if (from === void 0 && rules.length === 0) rejectData("Name at least one rule in `rules`, or `from` to swap another component's instances onto this one.");
|
|
3146
|
+
return {
|
|
3147
|
+
component,
|
|
3148
|
+
...from === void 0 ? {} : { from: from.replace(/^component:/, "") },
|
|
3149
|
+
...only === void 0 ? {} : { only },
|
|
3150
|
+
rules
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3143
3153
|
/** A runnable `map-props-plan` example: an instance holding the first variant prop's first value, and
|
|
3144
3154
|
* a rule moving it onto the prop's second value (or the same one, for a prop with a single value).
|
|
3145
3155
|
* A component with no variant gets the other common case, dropping a prop it no longer has.
|
|
@@ -74,7 +74,7 @@ interface RecordedSource {
|
|
|
74
74
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
75
75
|
* that replaced it (see `detectedWireVersion`).
|
|
76
76
|
*/
|
|
77
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
77
|
+
declare const SERIALIZED_CONFIG_VERSION = 20261102193912;
|
|
78
78
|
interface SerializedConfig {
|
|
79
79
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
80
80
|
readonly version: number;
|
package/dist/framework/Config.js
CHANGED
|
@@ -6391,7 +6391,7 @@ var Config = class Config {
|
|
|
6391
6391
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
6392
6392
|
hydrateFrom(stored, options) {
|
|
6393
6393
|
const claimed = schemaVersionOf(stored);
|
|
6394
|
-
if (claimed >
|
|
6394
|
+
if (claimed > 20261102193912) throw new SchemaVersionTooNew(claimed);
|
|
6395
6395
|
const wire = upgradeSerializedConfig(stored);
|
|
6396
6396
|
if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating.`);
|
|
6397
6397
|
const leftover = wire.options;
|
|
@@ -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 = 20261102193912;
|
|
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 = 20261102193912;
|
|
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 > 20261102193912) 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 ?? 20261102193912;
|
|
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 ?? 20261102193912;
|
|
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 ?? 20261102193912;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `component/map-props` op takes `from` and `only`. `from` names a component the system no
|
|
3
|
+
* longer has (a rename or removal its design files didn't follow): the mapping moves that
|
|
4
|
+
* component's instances onto the op's own component, then maps their props, and with `from` the
|
|
5
|
+
* rules may be empty. `only` limits it to some nodes of one design file.
|
|
6
|
+
*
|
|
7
|
+
* Only the op's input moved. A mapping writes nothing to the config, so no stored config or draft
|
|
8
|
+
* patch holds one, and `up` is identity with no `upPatch`.
|
|
9
|
+
*/
|
|
10
|
+
import type { SchemaMigration } from '../framework/schema-version';
|
|
11
|
+
export declare const MAP_PROPS_FROM_VERSION = 20261102193912;
|
|
12
|
+
export declare const mapPropsFromMigration: SchemaMigration;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/migrations/20261102193912_map_props_from.ts
|
|
2
|
+
const MAP_PROPS_FROM_VERSION = 20261102193912;
|
|
3
|
+
const mapPropsFromMigration = {
|
|
4
|
+
version: MAP_PROPS_FROM_VERSION,
|
|
5
|
+
up(json) {
|
|
6
|
+
return json;
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { MAP_PROPS_FROM_VERSION, mapPropsFromMigration };
|
package/dist/spec/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { AcceptsChildNodes, ChildNodesClassification, ClassifyChildNodes, buildA
|
|
|
7
7
|
import { CollapseTextLabelsResult, CollapsedTextLabel, collapseWrappedTextLabels } from "./collapse-text-labels.js";
|
|
8
8
|
import { GlyphJsxForm, GlyphNodeResolver, glyphJsxForm, glyphMemberOf, jsxIdentifier, parseGlyphType } from "./glyph-jsx.js";
|
|
9
9
|
import { JsxToSpecOptions, UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps } from "./jsxToSpec.js";
|
|
10
|
-
import { MappedInstance, MappedProps, MatchedValue, PropMapping, PropMappingConflict, PropMappingResult, PropMappingRule, applyPropMapping, mapComponentProps, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn } from "./prop-mapping.js";
|
|
10
|
+
import { MappedInstance, MappedProps, MappingScope, MatchedValue, PropMapping, PropMappingConflict, PropMappingResult, PropMappingRule, applyPropMapping, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, swapMappingRulesSchema } from "./prop-mapping.js";
|
|
11
11
|
import { SpecToJsxOptions, SpecToJsxResult, specToJsx } from "./specToJsx.js";
|
|
12
12
|
|
|
13
13
|
//#region src/spec/index.d.ts
|
|
@@ -29,4 +29,4 @@ import { SpecToJsxOptions, SpecToJsxResult, specToJsx } from "./specToJsx.js";
|
|
|
29
29
|
* element, without changing the rendered layer hierarchy. */
|
|
30
30
|
declare const SYNTHETIC_TEXT_SLOT_PROP = "data-uds-synthetic-text-slot";
|
|
31
31
|
//#endregion
|
|
32
|
-
export { type AcceptsChildNodes, type Cell, type CellSlot, type ChildNodesClassification, type ClassifyChildNodes, type CollapseTextLabelsResult, type CollapsedTextLabel, type DocumentRename, type GlyphJsxForm, type GlyphNodeResolver, type GraftableElement, type GraftableSpec, type JsxToSpecOptions, type MappedInstance, type MappedProps, type MatchedValue, type PreviewElement, type PreviewRef, type PreviewSpecNode, type PreviewValue, type PropMapping, type PropMappingConflict, type PropMappingResult, type PropMappingRule, type RewritableElement, type RewritableSpec, SYNTHETIC_TEXT_SLOT_PROP, type Slot, type SlotCell, type SpecRewrite, type SpecToJsxOptions, type SpecToJsxResult, UNRESOLVED, applyForcedModifiers, applyPropMapping, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, componentPathAfter, composeRenames, documentRenamesFromPatches, documentRenamesFromSource, glyphJsxForm, glyphMemberOf, graftPreviewElements, graftSlotContent, hasPreviewElementDeep, hasUnresolvedProps, isComponentRef, isPreviewElement, isPreviewRef, jsxIdentifier, jsxToSpec, mapComponentProps, onlyMapsProps, parseGlyphType, previewElementNodes, previewElementType, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, styleNumberReadingRenames, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
32
|
+
export { type AcceptsChildNodes, type Cell, type CellSlot, type ChildNodesClassification, type ClassifyChildNodes, type CollapseTextLabelsResult, type CollapsedTextLabel, type DocumentRename, type GlyphJsxForm, type GlyphNodeResolver, type GraftableElement, type GraftableSpec, type JsxToSpecOptions, type MappedInstance, type MappedProps, type MappingScope, type MatchedValue, type PreviewElement, type PreviewRef, type PreviewSpecNode, type PreviewValue, type PropMapping, type PropMappingConflict, type PropMappingResult, type PropMappingRule, type RewritableElement, type RewritableSpec, SYNTHETIC_TEXT_SLOT_PROP, type Slot, type SlotCell, type SpecRewrite, type SpecToJsxOptions, type SpecToJsxResult, UNRESOLVED, applyForcedModifiers, applyPropMapping, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, componentPathAfter, composeRenames, documentRenamesFromPatches, documentRenamesFromSource, glyphJsxForm, glyphMemberOf, graftPreviewElements, graftSlotContent, hasPreviewElementDeep, hasUnresolvedProps, isComponentRef, isPreviewElement, isPreviewRef, jsxIdentifier, jsxToSpec, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, parseGlyphType, previewElementNodes, previewElementType, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, styleNumberReadingRenames, swapMappingRulesSchema, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
package/dist/spec/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { graftPreviewElements, graftSlotContent, hasPreviewElementDeep, isComponentRef, isPreviewElement, isPreviewRef, previewElementNodes, previewElementType } from "./preview-elements.js";
|
|
2
2
|
import { componentPathAfter, composeRenames, documentRenamesFromPatches, documentRenamesFromSource, rewriteSpecRefs, styleNumberReadingRenames } from "./rewrite-refs.js";
|
|
3
|
-
import { applyPropMapping, mapComponentProps, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn } from "./prop-mapping.js";
|
|
3
|
+
import { applyPropMapping, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, swapMappingRulesSchema } from "./prop-mapping.js";
|
|
4
4
|
import { glyphJsxForm, glyphMemberOf, jsxIdentifier, parseGlyphType } from "./glyph-jsx.js";
|
|
5
5
|
import { applyForcedModifiers, collectForcedModifierProps } from "./apply-forced-modifiers.js";
|
|
6
6
|
import { collapseWrappedTextLabels } from "./collapse-text-labels.js";
|
|
@@ -26,4 +26,4 @@ import { specToJsx } from "./specToJsx.js";
|
|
|
26
26
|
* element, without changing the rendered layer hierarchy. */
|
|
27
27
|
const SYNTHETIC_TEXT_SLOT_PROP = "data-uds-synthetic-text-slot";
|
|
28
28
|
//#endregion
|
|
29
|
-
export { SYNTHETIC_TEXT_SLOT_PROP, UNRESOLVED, applyForcedModifiers, applyPropMapping, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, componentPathAfter, composeRenames, documentRenamesFromPatches, documentRenamesFromSource, glyphJsxForm, glyphMemberOf, graftPreviewElements, graftSlotContent, hasPreviewElementDeep, hasUnresolvedProps, isComponentRef, isPreviewElement, isPreviewRef, jsxIdentifier, jsxToSpec, mapComponentProps, onlyMapsProps, parseGlyphType, previewElementNodes, previewElementType, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, styleNumberReadingRenames, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
29
|
+
export { SYNTHETIC_TEXT_SLOT_PROP, UNRESOLVED, applyForcedModifiers, applyPropMapping, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, componentPathAfter, composeRenames, documentRenamesFromPatches, documentRenamesFromSource, glyphJsxForm, glyphMemberOf, graftPreviewElements, graftSlotContent, hasPreviewElementDeep, hasUnresolvedProps, isComponentRef, isPreviewElement, isPreviewRef, jsxIdentifier, jsxToSpec, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, parseGlyphType, previewElementNodes, previewElementType, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, styleNumberReadingRenames, swapMappingRulesSchema, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
@@ -15,10 +15,19 @@ interface PropMappingRule {
|
|
|
15
15
|
readonly unset?: readonly string[];
|
|
16
16
|
}
|
|
17
17
|
interface PropMapping {
|
|
18
|
-
/** The component whose instances it rewrites, as a path. */
|
|
18
|
+
/** The component whose instances it rewrites, as a path. With `from`, the one they become. */
|
|
19
19
|
readonly component: string;
|
|
20
|
+
/** The component whose instances become `component`'s, as a path; it needn't exist anymore. */
|
|
21
|
+
readonly from?: string;
|
|
22
|
+
/** Limits it to some nodes of one design file, by its canvas id and their ids: Create's alone. */
|
|
23
|
+
readonly only?: MappingScope;
|
|
20
24
|
readonly rules: readonly PropMappingRule[];
|
|
21
25
|
}
|
|
26
|
+
/** Some nodes of one design file. */
|
|
27
|
+
interface MappingScope {
|
|
28
|
+
readonly canvas: string;
|
|
29
|
+
readonly nodes: readonly string[];
|
|
30
|
+
}
|
|
22
31
|
/** A rule as a tool takes it: the shape every surface that applies a mapping parses its input with. */
|
|
23
32
|
declare const propMappingRuleSchema: z.ZodObject<{
|
|
24
33
|
when: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -31,6 +40,29 @@ declare const propMappingRulesSchema: z.ZodArray<z.ZodObject<{
|
|
|
31
40
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
32
41
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
33
42
|
}, z.core.$strip>>;
|
|
43
|
+
/** A swap's rules: none is a swap that keeps every prop, and `when: {}` reaches every swapped instance. */
|
|
44
|
+
declare const swapMappingRulesSchema: z.ZodArray<z.ZodObject<{
|
|
45
|
+
when: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
46
|
+
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
47
|
+
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
/**
|
|
50
|
+
* A mapping's rules as `map-props` takes them: at least one for a mapping, any number for a swap
|
|
51
|
+
* (`from`), where none keeps the swapped instances' props and `when: {}` reaches every one of them.
|
|
52
|
+
* Required by the op's own check rather than the schema, so one shape serves both.
|
|
53
|
+
*/
|
|
54
|
+
declare const mapPropsRulesSchema: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
55
|
+
when: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
56
|
+
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
57
|
+
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
58
|
+
}, z.core.$strip>>>;
|
|
59
|
+
/** `only` as a tool takes it. */
|
|
60
|
+
declare const mappingScopeSchema: z.ZodObject<{
|
|
61
|
+
canvas: z.ZodString;
|
|
62
|
+
nodes: z.ZodArray<z.ZodString>;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
/** `from` as a tool takes it. */
|
|
65
|
+
declare const mappingFromSchema: z.ZodString;
|
|
34
66
|
/**
|
|
35
67
|
* The mappings a batch of edits carries, in order: each `component/map-props` op as the mapping it
|
|
36
68
|
* applies. The op changes nothing in the config, so the host that ran the batch applies these to the
|
|
@@ -94,4 +126,4 @@ type MappedProps = {
|
|
|
94
126
|
*/
|
|
95
127
|
declare function mapComponentProps(config: Config, mapping: PropMapping, instances: readonly Record<string, unknown>[]): MappedProps;
|
|
96
128
|
//#endregion
|
|
97
|
-
export { MappedInstance, MappedProps, MatchedValue, PropMapping, PropMappingConflict, PropMappingResult, PropMappingRule, applyPropMapping, mapComponentProps, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn };
|
|
129
|
+
export { MappedInstance, MappedProps, MappingScope, MatchedValue, PropMapping, PropMappingConflict, PropMappingResult, PropMappingRule, applyPropMapping, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, swapMappingRulesSchema };
|
|
@@ -22,6 +22,11 @@ import { z } from "zod";
|
|
|
22
22
|
* Positions follow the rename rewriter's: an element's own props, every modifier block nested in
|
|
23
23
|
* them (`_hover: { variant: … }` is the same element's props under a condition), and each
|
|
24
24
|
* `layerProps` bag whose layer renders the component.
|
|
25
|
+
*
|
|
26
|
+
* A mapping with `from` also swaps the component: instances of `from`, a component the system
|
|
27
|
+
* may no longer have (the Bridge's `SelectContent`, after a take made in code replaced it), become
|
|
28
|
+
* instances of `component`, and the rules move their props onto it. Which component replaces which
|
|
29
|
+
* is as much a decision as a prop's new spelling, so it comes from the person too.
|
|
25
30
|
*/
|
|
26
31
|
/** A rule as a tool takes it: the shape every surface that applies a mapping parses its input with. */
|
|
27
32
|
const propMappingRuleSchema = z.object({
|
|
@@ -35,6 +40,21 @@ const propMappingRuleSchema = z.object({
|
|
|
35
40
|
});
|
|
36
41
|
/** The rules of a mapping, as a tool takes them. */
|
|
37
42
|
const propMappingRulesSchema = z.array(propMappingRuleSchema).min(1).describe("Every rule whose `when` matches an instance as stored applies to it, so separate props are mapped by separate rules, and a combination by one rule naming both.");
|
|
43
|
+
/** A swap's rules: none is a swap that keeps every prop, and `when: {}` reaches every swapped instance. */
|
|
44
|
+
const swapMappingRulesSchema = z.array(propMappingRuleSchema).describe("The rules for the swapped instances, as a mapping has them. `when: {}` applies to every one of them (to `unset` a prop the new component lacks), and none keeps their props as they are.");
|
|
45
|
+
/**
|
|
46
|
+
* A mapping's rules as `map-props` takes them: at least one for a mapping, any number for a swap
|
|
47
|
+
* (`from`), where none keeps the swapped instances' props and `when: {}` reaches every one of them.
|
|
48
|
+
* Required by the op's own check rather than the schema, so one shape serves both.
|
|
49
|
+
*/
|
|
50
|
+
const mapPropsRulesSchema = z.array(propMappingRuleSchema).default([]).describe("Every rule whose `when` matches an instance as stored applies to it, so separate props are mapped by separate rules, and a combination by one rule naming both. A mapping needs at least one. With `from`, none keeps the swapped instances' props, and `when: {}` reaches every swapped instance.");
|
|
51
|
+
/** `only` as a tool takes it. */
|
|
52
|
+
const mappingScopeSchema = z.object({
|
|
53
|
+
canvas: z.string().min(1).describe("The design file's canvas id."),
|
|
54
|
+
nodes: z.array(z.string().min(1)).min(1).describe("The ids of the nodes it reaches, in that design file.")
|
|
55
|
+
}).describe("Create only: limits the mapping to these nodes of one design file, for fixing one instance before asking about the rest. A checkout's call sites aren't nodes, so there it isn't taken.");
|
|
56
|
+
/** `from` as a tool takes it. */
|
|
57
|
+
const mappingFromSchema = z.string().min(1).describe("The component whose instances become this one's, as a path: the one a design file still names after the system lost it (`SelectContent`, replaced by `SelectMenu`). It needn't exist. Which component replaces which is the user's call: propose it, and apply it only once they confirm.");
|
|
38
58
|
/**
|
|
39
59
|
* The mappings a batch of edits carries, in order: each `component/map-props` op as the mapping it
|
|
40
60
|
* applies. The op changes nothing in the config, so the host that ran the batch applies these to the
|
|
@@ -45,10 +65,15 @@ function propMappingsIn(edits) {
|
|
|
45
65
|
return edits.flatMap((edit) => {
|
|
46
66
|
const { op } = editOp(edit);
|
|
47
67
|
if (op.kind !== "component" || op.operation !== "map-props") return [];
|
|
48
|
-
const
|
|
68
|
+
const data = op.data;
|
|
69
|
+
const from = typeof data?.from === "string" ? data.from : void 0;
|
|
70
|
+
const only = mappingScopeSchema.safeParse(data?.only);
|
|
71
|
+
const rules = (from ? swapMappingRulesSchema : propMappingRulesSchema).safeParse(data?.rules ?? (from ? [] : void 0));
|
|
49
72
|
if (!rules.success || typeof op.path !== "string") return [];
|
|
50
73
|
return [{
|
|
51
74
|
component: op.path.replace(/^component:/, ""),
|
|
75
|
+
...from ? { from: from.replace(/^component:/, "") } : {},
|
|
76
|
+
...only.success ? { only: only.data } : {},
|
|
52
77
|
rules: rules.data
|
|
53
78
|
}];
|
|
54
79
|
});
|
|
@@ -81,9 +106,10 @@ function valueRefusal(config, component, prop, value) {
|
|
|
81
106
|
*/
|
|
82
107
|
function propMappingErrors(config, mapping) {
|
|
83
108
|
if (!config.resolve("component", mapping.component)) return [`No component "${mapping.component}"`];
|
|
109
|
+
if (mapping.from === mapping.component) return [`"${mapping.component}" can't replace itself: \`from\` names the component its instances are now`];
|
|
84
110
|
const errors = [];
|
|
85
111
|
mapping.rules.forEach((rule, i) => {
|
|
86
|
-
if (Object.keys(rule.when).length === 0) errors.push(`Rule ${i + 1} matches every instance: name what it matches in \`when\``);
|
|
112
|
+
if (Object.keys(rule.when).length === 0 && mapping.from === void 0) errors.push(`Rule ${i + 1} matches every instance: name what it matches in \`when\``);
|
|
87
113
|
for (const [name, value] of Object.entries(rule.set ?? {})) {
|
|
88
114
|
const prop = surfaceProp(config, mapping.component, name);
|
|
89
115
|
if (!prop) {
|
|
@@ -125,6 +151,11 @@ function mapBag(bag, rules) {
|
|
|
125
151
|
bag: next
|
|
126
152
|
};
|
|
127
153
|
}
|
|
154
|
+
/** A stored type naming `to` in place of what it names, keeping the source it was placed through. */
|
|
155
|
+
function retyped(type, to) {
|
|
156
|
+
const at = type.lastIndexOf("@");
|
|
157
|
+
return `component:${to}${type.includes(":") && at > 0 ? type.slice(at) : ""}`;
|
|
158
|
+
}
|
|
128
159
|
/**
|
|
129
160
|
* A props bag on `component`, with the mapping applied to it when it's the mapped component's, and
|
|
130
161
|
* to the modifier blocks and layer overrides inside it either way. `undefined` when nothing moved.
|
|
@@ -192,8 +223,10 @@ function applyPropMapping(config, spec, mapping) {
|
|
|
192
223
|
let elements;
|
|
193
224
|
let changed = 0;
|
|
194
225
|
const conflicts = [];
|
|
226
|
+
const reached = mapping.only ? new Set(mapping.only.nodes) : void 0;
|
|
195
227
|
for (const [key, element] of Object.entries(spec.elements ?? {})) {
|
|
196
|
-
if (!element
|
|
228
|
+
if (!element) continue;
|
|
229
|
+
if (reached && !reached.has(key)) continue;
|
|
197
230
|
const walk = {
|
|
198
231
|
config,
|
|
199
232
|
mapping,
|
|
@@ -201,14 +234,18 @@ function applyPropMapping(config, spec, mapping) {
|
|
|
201
234
|
conflicts,
|
|
202
235
|
changed: 0
|
|
203
236
|
};
|
|
204
|
-
const
|
|
205
|
-
|
|
237
|
+
const component = componentOf(element.type);
|
|
238
|
+
const swapped = mapping.from !== void 0 && component === mapping.from && typeof element.type === "string";
|
|
239
|
+
if (!swapped && !element.props) continue;
|
|
240
|
+
const props = mapProps(walk, swapped ? mapping.component : component, element.props ?? {}, "props");
|
|
241
|
+
if (!props && !swapped) continue;
|
|
206
242
|
elements ??= { ...spec.elements };
|
|
207
243
|
elements[key] = {
|
|
208
244
|
...element,
|
|
209
|
-
|
|
245
|
+
...swapped ? { type: retyped(element.type, mapping.component) } : {},
|
|
246
|
+
...props ? { props } : {}
|
|
210
247
|
};
|
|
211
|
-
changed += walk.changed;
|
|
248
|
+
changed += walk.changed + (swapped && walk.changed === 0 ? 1 : 0);
|
|
212
249
|
}
|
|
213
250
|
return elements ? {
|
|
214
251
|
spec: {
|
|
@@ -236,7 +273,7 @@ function mapComponentProps(config, mapping, instances) {
|
|
|
236
273
|
errors
|
|
237
274
|
};
|
|
238
275
|
const { spec, conflicts } = applyPropMapping(config, { elements: Object.fromEntries(instances.map((props, i) => [String(i), {
|
|
239
|
-
type: `component:${mapping.component}`,
|
|
276
|
+
type: `component:${mapping.from ?? mapping.component}`,
|
|
240
277
|
props
|
|
241
278
|
}])) }, mapping);
|
|
242
279
|
return {
|
|
@@ -245,11 +282,11 @@ function mapComponentProps(config, mapping, instances) {
|
|
|
245
282
|
const after = spec.elements?.[String(i)]?.props ?? props;
|
|
246
283
|
return {
|
|
247
284
|
props: after,
|
|
248
|
-
changed: after !== props,
|
|
285
|
+
changed: after !== props || mapping.from !== void 0,
|
|
249
286
|
conflicts: conflicts.filter((conflict) => conflict.element === String(i)).flatMap((conflict) => conflict.props)
|
|
250
287
|
};
|
|
251
288
|
})
|
|
252
289
|
};
|
|
253
290
|
}
|
|
254
291
|
//#endregion
|
|
255
|
-
export { applyPropMapping, mapComponentProps, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn };
|
|
292
|
+
export { applyPropMapping, mapComponentProps, mapPropsRulesSchema, mappingFromSchema, mappingScopeSchema, onlyMapsProps, propMappingErrors, propMappingRuleSchema, propMappingRulesSchema, propMappingsIn, swapMappingRulesSchema };
|