@yahoo/uds-create-config 5.75.0 → 5.77.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.
@@ -1,19 +1,59 @@
1
1
  import { isRef, pathOf } from "../framework/utils/refs.js";
2
2
  import { className, renderStyleValue, resolveComponentProps, resolveTokenValue, stylePropEntries } from "../framework/projections.js";
3
3
  import { intoName, routesContent, routesIntoText } from "../framework/prop-surface.js";
4
- import { componentLayerClass, componentRuleClasses, stylePropClasses } from "../framework/class-names.js";
4
+ import { arbitraryClassName, componentLayerClass, componentRuleClasses, stylePropClasses } from "../framework/class-names.js";
5
5
  //#region src/capture/class-grammar.ts
6
6
  const VIEWPORT_UNIT = /\d(vh|vw|dvh|dvw|svh|svw|lvh|lvw|vmin|vmax)\b/;
7
7
  /** `0px` → `0`, collapsed spaces, lowercase keywords; what two spellings of one value share. */
8
+ /** CSS properties whose value is a colour. */
9
+ const COLOR_PROPERTY = /(^|-)(color|fill|stroke)$|^background$/;
10
+ /** Whether an off-scale value is a colour (`#f00`, `rgb(…)`, a named colour), not a length or a number. */
11
+ function isColorValue(value) {
12
+ const v = value.trim().toLowerCase();
13
+ if (/^(#|rgba?\(|hsla?\(|oklch\(|oklab\(|lab\(|lch\(|color\(|color-mix\()/.test(v)) return true;
14
+ if (/^(color|colour):/.test(v)) return true;
15
+ if (/^[-\d.]/.test(v) || /^(calc|min|max|clamp|var)\(/.test(v)) return false;
16
+ return /^[a-z]+$/.test(v) && v !== "auto" && v !== "none";
17
+ }
8
18
  function normalizeCssValue(value) {
9
19
  return value.trim().replace(/\s+/g, " ").replace(/(^|[\s,(])0(?:px|rem|em|%)(?=$|[\s,)])/g, "$10").toLowerCase();
10
20
  }
11
21
  function classGrammar(config) {
12
22
  const styleProps = /* @__PURE__ */ new Map();
13
- for (const entity of config.list("style-property")) for (const [leaf, cls] of stylePropClasses(config, entity.path)) if (!styleProps.has(cls)) styleProps.set(cls, {
14
- path: entity.path,
15
- leaf
16
- });
23
+ const arbitraryStems = /* @__PURE__ */ new Map();
24
+ for (const entity of config.list("style-property")) {
25
+ for (const [leaf, cls] of stylePropClasses(config, entity.path)) if (!styleProps.has(cls)) styleProps.set(cls, {
26
+ path: entity.path,
27
+ leaf
28
+ });
29
+ if (entity.toJSON().arbitrary) {
30
+ const stem = arbitraryClassName({
31
+ config,
32
+ path: entity.path,
33
+ value: "[x]"
34
+ }).slice(0, -3);
35
+ arbitraryStems.set(stem, [...arbitraryStems.get(stem) ?? [], entity.path]);
36
+ }
37
+ }
38
+ const arbitraryMatch = (cls) => {
39
+ const open = cls.indexOf("[");
40
+ if (open <= 0) return void 0;
41
+ const close = cls.indexOf("]", open);
42
+ if (close === -1) return void 0;
43
+ const rest = cls.slice(close + 1);
44
+ if (rest !== "" && !/^\/(?:\[[^\]]+\]|[\w.-]+)$/.test(rest)) return void 0;
45
+ const paths = arbitraryStems.get(cls.slice(0, open)) ?? [];
46
+ const inner = cls.slice(open + 1, close);
47
+ if (!inner || paths.length === 0) return void 0;
48
+ return {
49
+ path: paths.length === 1 ? paths[0] : paths.find((each) => writesColor(each) === isColorValue(inner)) ?? paths[0],
50
+ leaf: `[${inner}]`
51
+ };
52
+ };
53
+ function writesColor(path) {
54
+ const { properties = [] } = config.resolve("style-property", path)?.toJSON() ?? {};
55
+ return properties.some((property) => COLOR_PROPERTY.test(property));
56
+ }
17
57
  const composites = config.list("composite").map((entity) => ({
18
58
  path: entity.path,
19
59
  cls: className(config, "composite", entity.path)
@@ -126,7 +166,7 @@ function classGrammar(config) {
126
166
  };
127
167
  };
128
168
  return {
129
- styleProp: (cls) => styleProps.get(cls),
169
+ styleProp: (cls) => styleProps.get(cls) ?? arbitraryMatch(cls),
130
170
  stylePropsFor: (cssProperty) => byCss.get(cssProperty.toLowerCase()) ?? [],
131
171
  viewportLeaf(path, leaf) {
132
172
  return (valuesOf(path).get(leaf) ?? []).some((v) => VIEWPORT_UNIT.test(v));
@@ -129,6 +129,16 @@ const buildFields = z.strictObject({
129
129
  title: "React version",
130
130
  description: `The React major the app this repo builds for runs. \`18\` wraps each emitted web component in \`forwardRef\`, so a call site's \`ref\` reaches its element. Unset, \`${BUILD_DEFAULTS.react}\`.`,
131
131
  default: BUILD_DEFAULTS.react
132
+ }).optional(),
133
+ /**
134
+ * Whether the component modules `uds build` writes carry the component data attributes:
135
+ * `data-uds-component`, `data-uds-layer` and `data-uds-slot`, which Create's tools read to map an
136
+ * app's rendered markup back to its components. Unset, off; `uds build --debug` turns it on for
137
+ * one build.
138
+ */
139
+ debug: z.boolean().meta({
140
+ title: "Debug",
141
+ description: "Have `uds build` write the component data attributes (`data-uds-component`, `data-uds-layer`, `data-uds-slot`) on the elements components render. Create's tools read them to map the app's rendered markup back to its components, such as the canvas capture rebuilding a page as components. Unset, off; `uds build --debug` turns it on for one build."
132
142
  }).optional()
133
143
  }, { error: (issue) => issue.code === "unrecognized_keys" && issue.keys.includes("include") ? "`settings.build.include` was removed: every source file under `inputDir` now ships by default. Delete it, and list any file to keep out in `settings.build.exclude`." : void 0 });
134
144
  //#endregion
@@ -42,6 +42,7 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
42
42
  outputAlias: _$zod.ZodOptional<_$zod.ZodString>;
43
43
  linkedDir: _$zod.ZodOptional<_$zod.ZodString>;
44
44
  react: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodLiteral<18>, _$zod.ZodLiteral<19>]>>;
45
+ debug: _$zod.ZodOptional<_$zod.ZodBoolean>;
45
46
  }, _$zod_v4_core0.$strict>>;
46
47
  css: _$zod.ZodOptional<_$zod.ZodObject<{
47
48
  prefix: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
@@ -39,6 +39,7 @@ import { defaultColorsMigration } from "../migrations/20261102143821_default_col
39
39
  import { linkReplaceMigration } from "../migrations/20261102185610_link_replace.js";
40
40
  import { mapPropsFromMigration } from "../migrations/20261102193912_map_props_from.js";
41
41
  import { sourcesAuthoringMigration } from "../migrations/20261103115059_sources_authoring.js";
42
+ import { buildDebugMigration } from "../migrations/20261104151013_build_debug.js";
42
43
  import { CanvasRole } from "../entities/system/CanvasRole.js";
43
44
  import { GlobalStyle } from "../entities/system/GlobalStyle.js";
44
45
  import { Guidance } from "../entities/system/Guidance.js";
@@ -214,5 +215,6 @@ if (!registeredSchemaMigrations().has(20261102143821)) registerSchemaMigrations(
214
215
  if (!registeredSchemaMigrations().has(20261102185610)) registerSchemaMigrations(linkReplaceMigration);
215
216
  if (!registeredSchemaMigrations().has(20261102193912)) registerSchemaMigrations(mapPropsFromMigration);
216
217
  if (!registeredSchemaMigrations().has(20261103115059)) registerSchemaMigrations(sourcesAuthoringMigration);
218
+ if (!registeredSchemaMigrations().has(20261104151013)) registerSchemaMigrations(buildDebugMigration);
217
219
  //#endregion
218
220
  export { System };
@@ -31,6 +31,7 @@ declare const NativeSettings: EntityClass<z.ZodObject<Omit<{
31
31
  outputAlias: z.ZodOptional<z.ZodString>;
32
32
  linkedDir: z.ZodOptional<z.ZodString>;
33
33
  react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
34
+ debug: z.ZodOptional<z.ZodBoolean>;
34
35
  }, z.core.$strict>>;
35
36
  css: z.ZodOptional<z.ZodObject<{
36
37
  prefix: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -2183,7 +2183,7 @@ const ComponentEntity = defineEntity({
2183
2183
  input: z.object({ path: pathInput("component") }),
2184
2184
  readOnly: false,
2185
2185
  label: "Create blank",
2186
- description: "Create an empty component at a new qualified `path`, to design on the canvas first: one `div` root layer and the node that renders it, with no props, no variants, no slot, no styles and no preview content. This is exactly what Studio's \"+\" creates. Takes only `path`. Use it for \"a new component\", \"a blank component\" or \"start a component from nothing\"; `create` is for a component whose body is already known.",
2186
+ description: "Create an empty component at a new qualified `path`, to design on the canvas first: one `div` root layer and the node that renders it, with no props, no variants, no slot, no styles and no preview content. This is exactly what Create's \"+\" creates. Takes only `path`. Use it for \"a new component\", \"a blank component\" or \"start a component from nothing\"; `create` is for a component whose body is already known.",
2187
2187
  scope: "item",
2188
2188
  creates: true,
2189
2189
  title: (entity) => `Create blank ${entity}`,
@@ -2202,7 +2202,7 @@ const ComponentEntity = defineEntity({
2202
2202
  example: ({ config }) => forwardsCreateExample(config)
2203
2203
  },
2204
2204
  "sub-upsert/forwards": { description: `Set what one layer forwards, added when absent and replaced whole when present. ${FORWARDS_DESCRIPTION}` },
2205
- "sub-update/forwards": { description: `Replace what one layer forwards: the member is \`'*'\` or a list, so \`data\` is the whole new value. ${FORWARDS_DESCRIPTION}` },
2205
+ "sub-update/forwards": { description: `Replace what one layer forwards: the member is a list of prop names, so \`data\` is the whole new list. ${FORWARDS_DESCRIPTION}` },
2206
2206
  /**
2207
2207
  * Add an element to a composition — a layer and the node that targets it, together.
2208
2208
  *
@@ -2500,7 +2500,7 @@ count: z.number().int().min(1).max(50).optional() }).prefault({})
2500
2500
  }),
2501
2501
  readOnly: false,
2502
2502
  label: "Forward layer props",
2503
- description: "Expose a layer's props at the component's top level (\"forward everything from the root but icon\", \"also forward width\"): `props` is `\"*\"` for every prop the layer's element takes, or a list added to what the layer forwards now, or that replaces it with `replace`; `except` leaves props out of either. A prop the element lacks, one the component declares itself, and one a sibling layer already forwards are refused. Read `component/get` for what a layer forwards now.",
2503
+ description: "Expose a layer's props at the component's top level (\"also forward width\", \"forward onClick from the root\"): `props` is a list of prop names, added to what the layer forwards now, or replacing it with `replace`. A prop the element lacks, one the component declares itself, and one a sibling layer already forwards are refused. Read `component/get` for what a layer forwards now.",
2504
2504
  scope: "item",
2505
2505
  title: (entity) => `Forward ${entity} layer props`,
2506
2506
  handler: (input, config) => {
@@ -24,6 +24,7 @@ declare const BuildSectionDefinition: SubEntityClass<z.ZodObject<{
24
24
  outputAlias: z.ZodOptional<z.ZodString>;
25
25
  linkedDir: z.ZodOptional<z.ZodString>;
26
26
  react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
27
+ debug: z.ZodOptional<z.ZodBoolean>;
27
28
  }, z.core.$strict>>;
28
29
  interface BuildSectionClass extends Named<typeof BuildSectionDefinition> {}
29
30
  declare const BuildSection: BuildSectionClass;
@@ -194,6 +195,7 @@ declare const SettingsDefinition: EntityClass<z.ZodObject<{
194
195
  outputAlias: z.ZodOptional<z.ZodString>;
195
196
  linkedDir: z.ZodOptional<z.ZodString>;
196
197
  react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
198
+ debug: z.ZodOptional<z.ZodBoolean>;
197
199
  }, z.core.$strict>>;
198
200
  css: z.ZodOptional<z.ZodObject<{
199
201
  prefix: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -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 = 20261103115059;
77
+ declare const SERIALIZED_CONFIG_VERSION = 20261104151013;
78
78
  interface SerializedConfig {
79
79
  /** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
80
80
  readonly version: number;
@@ -6406,7 +6406,7 @@ var Config = class Config {
6406
6406
  * links from the provided sources. A declared `linkedKind` with no provided source throws. */
6407
6407
  hydrateFrom(stored, options) {
6408
6408
  const claimed = schemaVersionOf(stored);
6409
- if (claimed > 20261103115059) throw new SchemaVersionTooNew(claimed);
6409
+ if (claimed > 20261104151013) throw new SchemaVersionTooNew(claimed);
6410
6410
  const wire = upgradeSerializedConfig(stored);
6411
6411
  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.`);
6412
6412
  const leftover = wire.options;
@@ -14,7 +14,7 @@ import { z } from "zod";
14
14
  * non-serializable projection (a zod schema, a function). Each fn declares its own provenance.
15
15
  *
16
16
  * A derived kind self-derives on registration, sourcing from the config it's registered into;
17
- * `Config.register` routes it by whether the KIND is derived. See `docs/config-v2.md`.
17
+ * `Config.register` routes it by whether the kind is derived.
18
18
  */
19
19
  /** What `extend` accepts. Checked at runtime because `extend` is shadowed: an unrecognized key is a
20
20
  * typo, or a zod raw shape reaching this method expecting zod's `extend`. Either should say so
@@ -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 = 20261103115059;
18
+ declare const CURRENT_SCHEMA_VERSION = 20261104151013;
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 = 20261103115059;
16
+ const CURRENT_SCHEMA_VERSION = 20261104151013;
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 > 20261103115059) 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.`);
48
+ if (migration.version > 20261104151013) 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 ?? 20261103115059;
105
+ const target = options?.target ?? 20261104151013;
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 ?? 20261103115059;
163
+ const target = options?.target ?? 20261104151013;
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 ?? 20261103115059;
182
+ const target = options?.target ?? 20261104151013;
183
183
  const entries = [];
184
184
  const held = [];
185
185
  const retired = [];
package/dist/index.js CHANGED
@@ -66,11 +66,11 @@ import { styleSetEdits } from "./entities/system/component-style-set.js";
66
66
  import { convertLinkedTokenValue, prepareLinkedTokenBody } from "./entities/system/linked-token-values.js";
67
67
  import { Token, defineOverride, overrideCondition, overrideKey, overrideKeyModifiers, overrideModifiers } from "./entities/system/Token.js";
68
68
  import { Component, SLOT_CODE_FORMS, blankComponentBody, canonicalWhen, forwardedNames, layerRef, ownValues, ownsItsValues, valueRef } from "./entities/system/Component.js";
69
+ import { Icon, iconVariantAs } from "./entities/system/Icon.js";
70
+ import { glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, iconToolLibraries, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries } from "./entities/system/icon-library.js";
69
71
  import { CapturedNode, capturedFromDom, elementFromCaptured } from "./capture/captured-tree.js";
70
72
  import { classGrammar } from "./capture/class-grammar.js";
71
73
  import { specFromCapture } from "./capture/capture-to-spec.js";
72
- import { Icon, iconVariantAs } from "./entities/system/Icon.js";
73
- import { glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, iconToolLibraries, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries } from "./entities/system/icon-library.js";
74
74
  import { glyphSourcesOf, iconResolver, nameIconsInTree } from "./capture/icon-resolver.js";
75
75
  import { PLACED_NODE_KEY, specToNodePatches } from "./entities/canvas/node-patches.js";
76
76
  import { Device } from "./entities/system/Device.js";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Additions only, so the envelope passes through as it is:
3
+ *
4
+ * - A system's `settings.build` may name `debug`: whether the component modules `uds build` writes
5
+ * carry the component data attributes.
6
+ */
7
+ import type { SchemaMigration } from '../framework/schema-version';
8
+ export declare const BUILD_DEBUG_VERSION = 20261104151013;
9
+ export declare const buildDebugMigration: SchemaMigration;
@@ -0,0 +1,10 @@
1
+ //#region src/migrations/20261104151013_build_debug.ts
2
+ const BUILD_DEBUG_VERSION = 20261104151013;
3
+ const buildDebugMigration = {
4
+ version: BUILD_DEBUG_VERSION,
5
+ up(json) {
6
+ return json;
7
+ }
8
+ };
9
+ //#endregion
10
+ export { BUILD_DEBUG_VERSION, buildDebugMigration };