@yahoo/uds-create-config 4.36.0 → 4.37.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/CanvasConfig.d.ts +68 -5167
- package/dist/configs/CanvasConfig.js +0 -76
- package/dist/configs/documentation.d.ts +11 -251
- package/dist/configs/documentation.js +0 -1
- package/dist/configs/react-native-system.d.ts +39 -4239
- package/dist/configs/react-native-system.js +0 -11
- package/dist/configs/system.d.ts +44 -4209
- package/dist/configs/system.js +2 -9
- package/dist/entities/documentation/Documentation.d.ts +5 -18
- package/dist/entities/documentation/Documentation.js +0 -1
- package/dist/entities/native/NativeModifier.d.ts +6 -3
- package/dist/entities/native/NativeSettings.d.ts +6 -3
- package/dist/entities/native/NativeSettings.js +0 -1
- package/dist/entities/native/NativeStyleProperty.d.ts +1 -20
- package/dist/entities/native/NativeToken.d.ts +2 -6
- package/dist/entities/system/CanvasRole.d.ts +6 -7
- package/dist/entities/system/Component.d.ts +86 -1588
- package/dist/entities/system/Component.js +0 -9
- package/dist/entities/system/Composite.d.ts +8 -6
- package/dist/entities/system/Composite.js +0 -1
- package/dist/entities/system/Device.d.ts +6 -3
- package/dist/entities/system/Device.js +0 -6
- package/dist/entities/system/File.d.ts +43 -8
- package/dist/entities/system/File.js +0 -51
- package/dist/entities/system/Font.d.ts +10 -11
- package/dist/entities/system/Font.js +0 -21
- package/dist/entities/system/GlobalStyle.d.ts +6 -3
- package/dist/entities/system/Guidance.d.ts +6 -3
- package/dist/entities/system/GuidanceStyle.d.ts +6 -3
- package/dist/entities/system/Icon.d.ts +8 -8
- package/dist/entities/system/Icon.js +0 -16
- package/dist/entities/system/LinkedSystem.d.ts +13 -155
- package/dist/entities/system/LinkedSystem.js +22 -12
- package/dist/entities/system/Modifier.d.ts +8 -8
- package/dist/entities/system/Motion.d.ts +6 -3
- package/dist/entities/system/Operation.d.ts +5 -2
- package/dist/entities/system/Package.d.ts +24 -4
- package/dist/entities/system/Package.js +0 -46
- package/dist/entities/system/Settings.d.ts +18 -7
- package/dist/entities/system/Settings.js +0 -6
- package/dist/entities/system/StyleProperty.d.ts +14 -27
- package/dist/entities/system/StyleProperty.js +0 -6
- package/dist/entities/system/Token.d.ts +12 -9
- package/dist/entities/system/Tool.d.ts +7 -90
- package/dist/entities/system/composed-values.d.ts +1 -1
- package/dist/entities/system/copy-plan.d.ts +2 -2
- package/dist/entities/system/copy-plan.js +32 -10
- package/dist/entities/system/defineComponent.d.ts +1 -1
- package/dist/entities/system/icon-metadata.d.ts +2 -6
- package/dist/entities/system/link-plan.d.ts +26 -5
- package/dist/entities/system/link-plan.js +71 -15
- package/dist/entities/system/style-bag.d.ts +27 -1
- package/dist/entities/system/style-bag.js +0 -10
- package/dist/framework/Config.d.ts +19 -3
- package/dist/framework/Config.js +71 -16
- package/dist/framework/class-names.js +1 -0
- package/dist/framework/defineConfig.d.ts +2 -2
- package/dist/framework/defineEntity.d.ts +27 -7
- package/dist/framework/named.d.ts +9 -0
- package/dist/framework/plan.d.ts +3 -0
- package/dist/framework/plan.js +4 -1
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/utils/group.d.ts +15 -5
- package/dist/index.d.ts +47 -46
- package/dist/migrations/2.0.0/v1-artifact.d.ts +38 -2109
- package/dist/migrations/20260928180801_link_on_linked.d.ts +10 -0
- package/dist/migrations/20260928180801_link_on_linked.js +8 -0
- package/dist/renderer/wrappers/html-aliases.js +1 -0
- package/dist/spec/cell.d.ts +1 -1
- package/dist/spec/preview-content.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { SubEntityClass } from "../../framework/defineSubEntity.js";
|
|
2
|
+
import { RegisteredModifiers, RegisteredStyleProps } from "../../framework/registered.js";
|
|
3
|
+
import { Named } from "../../framework/named.js";
|
|
1
4
|
import { ComposedValue } from "./composed-values.js";
|
|
2
5
|
import { z } from "zod";
|
|
3
6
|
|
|
@@ -16,5 +19,28 @@ type StyleValue = string | number | boolean | {
|
|
|
16
19
|
} | ComposedValue | {
|
|
17
20
|
readonly [key: string]: StyleValue;
|
|
18
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* A style bag as a keyed COLLECTION — style-prop key → {@link styleValue}, with each key a member
|
|
24
|
+
* in its own right.
|
|
25
|
+
*
|
|
26
|
+
* Being a sub-entity is what makes a per-declaration edit addressable: setting `boxShadow` names
|
|
27
|
+
* `boxShadow`, rather than being an update of the whole bag that first has to read the current one
|
|
28
|
+
* to avoid erasing its siblings. It also gives the bag a rename that keeps a key's position, which
|
|
29
|
+
* matters because key order is declaration order in the emitted rule — for a shorthand/longhand
|
|
30
|
+
* pair, moving one changes what gets painted.
|
|
31
|
+
*/
|
|
32
|
+
declare const StyleDefinition: SubEntityClass<z.ZodType<StyleValue, unknown, z.core.$ZodTypeInternals<StyleValue, unknown>>>;
|
|
33
|
+
interface StyleClass extends Named<typeof StyleDefinition> {}
|
|
34
|
+
/** The style props the system registers, each taking any value a bag stores. */
|
|
35
|
+
type RegisteredStyleBag = { [K in keyof RegisteredStyleProps]?: StyleValue };
|
|
36
|
+
/**
|
|
37
|
+
* A bag as a config file writes one when nothing but style props and modifiers may key it: the style
|
|
38
|
+
* props the system registers, and a `_modifier` block of the same. Open until the build has filled
|
|
39
|
+
* `RegisteredStyleProps`, since before that no key can be told from a style prop.
|
|
40
|
+
*/
|
|
41
|
+
type AuthoredStyleBag = [keyof RegisteredStyleProps] extends [never] ? Record<string, StyleValue> : RegisteredStyleBag & { [M in keyof RegisteredModifiers]?: RegisteredStyleBag };
|
|
42
|
+
/** {@link Style} as a field whose authored input is an {@link AuthoredStyleBag}. The stored value is
|
|
43
|
+
* unchanged. */
|
|
44
|
+
type AuthoredStyleField = z.ZodType<z.output<StyleClass>, AuthoredStyleBag>;
|
|
19
45
|
//#endregion
|
|
20
|
-
export { StyleValue };
|
|
46
|
+
export { AuthoredStyleBag, AuthoredStyleField, RegisteredStyleBag, StyleClass, StyleValue };
|
|
@@ -32,16 +32,6 @@ const anatomyPropValue = z.lazy(() => z.union([
|
|
|
32
32
|
])),
|
|
33
33
|
z.record(z.string(), anatomyPropValue)
|
|
34
34
|
]));
|
|
35
|
-
/**
|
|
36
|
-
* A style bag as a keyed COLLECTION — style-prop key → {@link styleValue}, with each key a member
|
|
37
|
-
* in its own right.
|
|
38
|
-
*
|
|
39
|
-
* Being a sub-entity is what makes a per-declaration edit addressable: setting `boxShadow` names
|
|
40
|
-
* `boxShadow`, rather than being an update of the whole bag that first has to read the current one
|
|
41
|
-
* to avoid erasing its siblings. It also gives the bag a rename that keeps a key's position, which
|
|
42
|
-
* matters because key order is declaration order in the emitted rule — for a shorthand/longhand
|
|
43
|
-
* pair, moving one changes what gets painted.
|
|
44
|
-
*/
|
|
45
35
|
const Style = defineSubEntity({
|
|
46
36
|
name: "style",
|
|
47
37
|
label: "Style",
|
|
@@ -72,7 +72,7 @@ interface RecordedSource {
|
|
|
72
72
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
73
73
|
* that replaced it (see `detectedWireVersion`).
|
|
74
74
|
*/
|
|
75
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
75
|
+
declare const SERIALIZED_CONFIG_VERSION = 20260928180801;
|
|
76
76
|
interface SerializedConfig {
|
|
77
77
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
78
78
|
readonly version: number;
|
|
@@ -2056,9 +2056,12 @@ declare class Config {
|
|
|
2056
2056
|
*/
|
|
2057
2057
|
private computeSourceClosure;
|
|
2058
2058
|
/**
|
|
2059
|
-
* A refusal for a
|
|
2060
|
-
*
|
|
2059
|
+
* A refusal for a patch whose derive pass would retire a minted row that something authored here
|
|
2060
|
+
* still points at. A minted row has no body of its own, so once it goes the referrer dangles;
|
|
2061
2061
|
* copying what is used, or breaking the link with `keep`, is how the value stays.
|
|
2062
|
+
*
|
|
2063
|
+
* `action` names what is refused, after "Cannot": a pin patch removes the link, and any other patch
|
|
2064
|
+
* that reaches derivation — a deleted extension whose source reached the row — says what it did.
|
|
2062
2065
|
*/
|
|
2063
2066
|
private assertDerivedDropsUnreferenced;
|
|
2064
2067
|
/**
|
|
@@ -2089,6 +2092,8 @@ declare class Config {
|
|
|
2089
2092
|
* system's namespace, which this config has no `@slug` for and no claim on.
|
|
2090
2093
|
*/
|
|
2091
2094
|
withDerivedRows(): this;
|
|
2095
|
+
/** {@link withDerivedRows} for a derivation already in hand. */
|
|
2096
|
+
private withRowsOf;
|
|
2092
2097
|
/**
|
|
2093
2098
|
* The rows an edit changes, derived inside that edit's own apply.
|
|
2094
2099
|
*
|
|
@@ -2411,6 +2416,17 @@ declare class Config {
|
|
|
2411
2416
|
/** Every `kind:path` whose definition references the given entity — the reverse
|
|
2412
2417
|
* dependency graph, harvested generically from refs in each item's data. */
|
|
2413
2418
|
dependentsOf(kind: string, path: string, opts?: TraverseOptions): string[];
|
|
2419
|
+
/**
|
|
2420
|
+
* The dependents of `kind:path` that use it only through a source: rows here that point whole at a
|
|
2421
|
+
* source entity which, in that source, points at `kind:path`. A rename's cascade can't rewrite
|
|
2422
|
+
* them, since the body that names the path is the source's.
|
|
2423
|
+
*
|
|
2424
|
+
* A pointer row's body lives in its source, so the index here holds only the pointer. Each source's
|
|
2425
|
+
* own index answers what its bodies name, and a source's bare ref means the path here, so each
|
|
2426
|
+
* referrer there comes back as the rows here pointing at it: the row the link minted, or an
|
|
2427
|
+
* extension of it. A source's pins are its own, so a pin here has none of these.
|
|
2428
|
+
*/
|
|
2429
|
+
sourceDependentsOf(kind: string, path: string, opts?: TraverseOptions): string[];
|
|
2414
2430
|
/** The inverse: what `kind:path` needs in order to resolve. `{ transitive: true }` returns the
|
|
2415
2431
|
* whole closure — what a sealed/exported copy would have to carry along with it. */
|
|
2416
2432
|
dependenciesOf(kind: string, path: string, opts?: TraverseOptions): string[];
|
package/dist/framework/Config.js
CHANGED
|
@@ -564,6 +564,15 @@ function rekeyAt(node, path, from, to) {
|
|
|
564
564
|
};
|
|
565
565
|
}
|
|
566
566
|
/** Whether `ref` names a row or folder the build minted, at the item or group the snapshot holds. */
|
|
567
|
+
/** What a refused edit of several patches is called. */
|
|
568
|
+
const EDIT_ACTION = "make this edit";
|
|
569
|
+
/** What an edit does, for a refusal that begins "Cannot": `delete component:Mine` for one patch. */
|
|
570
|
+
function actionOf(patches) {
|
|
571
|
+
const list = Array.isArray(patches) ? patches : [patches];
|
|
572
|
+
const [only] = list;
|
|
573
|
+
if (list.length !== 1 || !only || !("path" in only)) return EDIT_ACTION;
|
|
574
|
+
return `${only.operation} ${only.kind}:${only.path}`;
|
|
575
|
+
}
|
|
567
576
|
function isMintedAt(snapshot, ref) {
|
|
568
577
|
const kind = kindOf(ref);
|
|
569
578
|
const path = pathOf(ref);
|
|
@@ -1218,7 +1227,7 @@ var Config = class Config {
|
|
|
1218
1227
|
deferred.reached = true;
|
|
1219
1228
|
return applied;
|
|
1220
1229
|
}
|
|
1221
|
-
return applied.derivedForEdit();
|
|
1230
|
+
return applied.derivedForEdit(actionOf(patch));
|
|
1222
1231
|
}
|
|
1223
1232
|
/**
|
|
1224
1233
|
* `run` with each kind's invariants judged once, on the config it returns, rather than after every
|
|
@@ -1245,7 +1254,8 @@ var Config = class Config {
|
|
|
1245
1254
|
deferred.open = false;
|
|
1246
1255
|
const settled = result.derive({ deferredInvariants: void 0 });
|
|
1247
1256
|
settled.assertInvariantsOf(settled.state.snapshot, deferred.kinds);
|
|
1248
|
-
|
|
1257
|
+
if (!deferred.reached) return settled;
|
|
1258
|
+
return settled.derivedForEdit(EDIT_ACTION);
|
|
1249
1259
|
} catch {
|
|
1250
1260
|
deferred.open = false;
|
|
1251
1261
|
return run(this);
|
|
@@ -1319,11 +1329,12 @@ var Config = class Config {
|
|
|
1319
1329
|
};
|
|
1320
1330
|
const landed = settled();
|
|
1321
1331
|
const edits = patches.filter((patch) => !this.entityOf(patch.kind)?.sourceIdentity);
|
|
1322
|
-
|
|
1332
|
+
if (!(edits.length > 0 && this.reachesDerivation({
|
|
1323
1333
|
patches: edits,
|
|
1324
1334
|
before: this.state.snapshot,
|
|
1325
1335
|
after: landed.state.snapshot
|
|
1326
|
-
})
|
|
1336
|
+
}))) return landed;
|
|
1337
|
+
return landed.derivedForEdit(actionOf(edits));
|
|
1327
1338
|
}
|
|
1328
1339
|
const land = (checked) => {
|
|
1329
1340
|
let config = checked ? this : this.derive({ snapshot: this.state.snapshot.drafting() });
|
|
@@ -1340,11 +1351,12 @@ var Config = class Config {
|
|
|
1340
1351
|
}
|
|
1341
1352
|
};
|
|
1342
1353
|
const config = settle().derive({ pending: [...this.state.pending, ...patches.map(stampOf)] });
|
|
1343
|
-
|
|
1354
|
+
if (!this.reachesDerivation({
|
|
1344
1355
|
patches,
|
|
1345
1356
|
before: this.state.snapshot,
|
|
1346
1357
|
after: config.state.snapshot
|
|
1347
|
-
})
|
|
1358
|
+
})) return config;
|
|
1359
|
+
return config.derivedForEdit(actionOf(patches));
|
|
1348
1360
|
}
|
|
1349
1361
|
/**
|
|
1350
1362
|
* Whether patches on kinds that name no source can change the rows a derive mints between `before`
|
|
@@ -3932,20 +3944,23 @@ var Config = class Config {
|
|
|
3932
3944
|
return [...reached].sort();
|
|
3933
3945
|
}
|
|
3934
3946
|
/**
|
|
3935
|
-
* A refusal for a
|
|
3936
|
-
*
|
|
3947
|
+
* A refusal for a patch whose derive pass would retire a minted row that something authored here
|
|
3948
|
+
* still points at. A minted row has no body of its own, so once it goes the referrer dangles;
|
|
3937
3949
|
* copying what is used, or breaking the link with `keep`, is how the value stays.
|
|
3950
|
+
*
|
|
3951
|
+
* `action` names what is refused, after "Cannot": a pin patch removes the link, and any other patch
|
|
3952
|
+
* that reaches derivation — a deleted extension whose source reached the row — says what it did.
|
|
3938
3953
|
*/
|
|
3939
|
-
assertDerivedDropsUnreferenced() {
|
|
3954
|
+
assertDerivedDropsUnreferenced({ action = "remove the link", derivation = this.rowDerivation() } = {}) {
|
|
3940
3955
|
const { snapshot } = this.state;
|
|
3941
3956
|
const stranded = [];
|
|
3942
|
-
for (const change of
|
|
3957
|
+
for (const change of derivation.changes) {
|
|
3943
3958
|
if (change.value !== void 0) continue;
|
|
3944
3959
|
const referrers = this.referrersOf(snapshot, change.kind, change.path).filter((referrer) => !isMintedAt(snapshot, referrer));
|
|
3945
3960
|
if (referrers.length > 0) stranded.push(`${change.kind}:${change.path} (used by ${referrers.join(", ")})`);
|
|
3946
3961
|
}
|
|
3947
3962
|
if (stranded.length === 0) return;
|
|
3948
|
-
reject("REFERRERS_BLOCK", `Cannot
|
|
3963
|
+
reject("REFERRERS_BLOCK", `Cannot ${action} — it would take away ${stranded.join("; ")}. Copy what is used first (\`linked-system/copy\`), or break the link keeping its values (\`linked-system/break\` with \`keep: true\`).`);
|
|
3949
3964
|
}
|
|
3950
3965
|
/**
|
|
3951
3966
|
* This config with a row for every entity it inherits — the build's output. A pin patch runs this
|
|
@@ -3976,7 +3991,11 @@ var Config = class Config {
|
|
|
3976
3991
|
*/
|
|
3977
3992
|
withDerivedRows() {
|
|
3978
3993
|
if (derivedInEdit.has(this)) return this;
|
|
3979
|
-
|
|
3994
|
+
return this.withRowsOf(this.rowDerivation());
|
|
3995
|
+
}
|
|
3996
|
+
/** {@link withDerivedRows} for a derivation already in hand. */
|
|
3997
|
+
withRowsOf(derived) {
|
|
3998
|
+
const moved = derived.changes.filter((change) => !this.holdsDerivedRow(change));
|
|
3980
3999
|
if (moved.length === 0) return this;
|
|
3981
4000
|
return this.derive({ snapshot: this.state.snapshot.withChanges(moved) });
|
|
3982
4001
|
}
|
|
@@ -3987,8 +4006,14 @@ var Config = class Config {
|
|
|
3987
4006
|
* derive passes: this one and the session's. The mark covers this instance only, and any later
|
|
3988
4007
|
* write is a new config, so each edit still gets exactly one pass, as it did from the session alone.
|
|
3989
4008
|
*/
|
|
3990
|
-
derivedForEdit() {
|
|
3991
|
-
|
|
4009
|
+
derivedForEdit(action) {
|
|
4010
|
+
if (derivedInEdit.has(this)) return this;
|
|
4011
|
+
const derivation = this.rowDerivation();
|
|
4012
|
+
this.assertDerivedDropsUnreferenced({
|
|
4013
|
+
action,
|
|
4014
|
+
derivation
|
|
4015
|
+
});
|
|
4016
|
+
const derived = this.withRowsOf(derivation);
|
|
3992
4017
|
derivedInEdit.add(derived);
|
|
3993
4018
|
return derived;
|
|
3994
4019
|
}
|
|
@@ -4819,7 +4844,37 @@ var Config = class Config {
|
|
|
4819
4844
|
/** Every `kind:path` whose definition references the given entity — the reverse
|
|
4820
4845
|
* dependency graph, harvested generically from refs in each item's data. */
|
|
4821
4846
|
dependentsOf(kind, path, opts) {
|
|
4822
|
-
|
|
4847
|
+
const own = this.referrersOf(this.state.snapshot, kind, path, opts);
|
|
4848
|
+
const drawn = this.sourceDependentsOf(kind, path, opts);
|
|
4849
|
+
return drawn.length === 0 ? own : [...own, ...drawn];
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* The dependents of `kind:path` that use it only through a source: rows here that point whole at a
|
|
4853
|
+
* source entity which, in that source, points at `kind:path`. A rename's cascade can't rewrite
|
|
4854
|
+
* them, since the body that names the path is the source's.
|
|
4855
|
+
*
|
|
4856
|
+
* A pointer row's body lives in its source, so the index here holds only the pointer. Each source's
|
|
4857
|
+
* own index answers what its bodies name, and a source's bare ref means the path here, so each
|
|
4858
|
+
* referrer there comes back as the rows here pointing at it: the row the link minted, or an
|
|
4859
|
+
* extension of it. A source's pins are its own, so a pin here has none of these.
|
|
4860
|
+
*/
|
|
4861
|
+
sourceDependentsOf(kind, path, opts) {
|
|
4862
|
+
if (this.entityOf(kind)?.sourceIdentity !== void 0) return [];
|
|
4863
|
+
const { snapshot } = this.state;
|
|
4864
|
+
const own = new Set(this.referrersOf(snapshot, kind, path, opts));
|
|
4865
|
+
const found = /* @__PURE__ */ new Set();
|
|
4866
|
+
for (const slug of this.sourceSlugs()) {
|
|
4867
|
+
const source = this.sourceFor(slug);
|
|
4868
|
+
if (!source) continue;
|
|
4869
|
+
for (const referrer of source.dependentsOf(kind, path, opts)) {
|
|
4870
|
+
const pointer = ref(kindOf(referrer), pathOf(referrer), slug).__ref;
|
|
4871
|
+
for (const row of snapshot.refs.dependents(pointer)) {
|
|
4872
|
+
const body = snapshot.get(kindOf(row), pathOf(row))?.toJSON();
|
|
4873
|
+
if (isRef(body) && body.__ref === pointer && !own.has(row)) found.add(row);
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return [...found];
|
|
4823
4878
|
}
|
|
4824
4879
|
/** The inverse: what `kind:path` needs in order to resolve. `{ transitive: true }` returns the
|
|
4825
4880
|
* whole closure — what a sealed/exported copy would have to carry along with it. */
|
|
@@ -5080,7 +5135,7 @@ var Config = class Config {
|
|
|
5080
5135
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
5081
5136
|
hydrateFrom(stored, options) {
|
|
5082
5137
|
const claimed = schemaVersionOf(stored);
|
|
5083
|
-
if (claimed >
|
|
5138
|
+
if (claimed > 20260928180801) throw new SchemaVersionTooNew(claimed);
|
|
5084
5139
|
const wire = upgradeSerializedConfig(stored);
|
|
5085
5140
|
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, or port the repo once with \`uds migrate\`.`);
|
|
5086
5141
|
const leftover = wire.options;
|
|
@@ -44,7 +44,7 @@ type ConfigKind<C> = C extends {
|
|
|
44
44
|
* elements describes no gesture anyone makes, and a caller replacing one writes the whole list.
|
|
45
45
|
*/
|
|
46
46
|
type Matched = any;
|
|
47
|
-
type PartialBodyOf<E> = E extends EntityClass<infer F extends FieldsSchema, FieldsSchema, infer _K, Matched, Matched, Matched> ? DeepPartial<CreateInput<F>> : never;
|
|
47
|
+
type PartialBodyOf<E> = E extends Omit<EntityClass<infer F extends FieldsSchema, FieldsSchema, infer _K, Matched, Matched, Matched>, 'ref'> ? DeepPartial<CreateInput<F>> : never;
|
|
48
48
|
/** Optional at every depth, stopping at refs, arrays and primitives. */
|
|
49
49
|
type DeepPartial<T> = T extends Ref | readonly unknown[] ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
|
50
50
|
/**
|
|
@@ -68,7 +68,7 @@ declare function kindsOf<T extends readonly {
|
|
|
68
68
|
* mean. */
|
|
69
69
|
type RecordFor<E> = E extends {
|
|
70
70
|
readonly singleton: true;
|
|
71
|
-
} ? E extends EntityClass<infer F, FieldsSchema, infer _K, Matched, Matched, true> ? Partial<z.input<F>> : never : E extends EntityClass<infer F, infer G, infer _K, Matched, Matched, Matched> ? Record<string, AuthoredEntry<F, G>> : never;
|
|
71
|
+
} ? E extends Omit<EntityClass<infer F, FieldsSchema, infer _K, Matched, Matched, true>, 'ref'> ? Partial<z.input<F>> : never : E extends Omit<EntityClass<infer F, infer G, infer _K, Matched, Matched, Matched>, 'ref'> ? Record<string, AuthoredEntry<F, G>> : never;
|
|
72
72
|
/**
|
|
73
73
|
* What a config DRAWS ON — keyed by the accessor name of the kind whose items ARE the sources, valued
|
|
74
74
|
* by a thunk yielding the config type each one resolves to.
|
|
@@ -69,13 +69,26 @@ type GroupRead<F extends FieldsSchema, G extends FieldsSchema, GC extends GroupC
|
|
|
69
69
|
path: string;
|
|
70
70
|
meta: GroupBody<F, G> & GroupComputedValues<GC>;
|
|
71
71
|
};
|
|
72
|
+
/** An entity's op table as the type level holds it: each op's `input` schema and nothing else, which
|
|
73
|
+
* is all {@link OpInput} reads. */
|
|
74
|
+
type OpInputTable = Readonly<Record<string, {
|
|
75
|
+
readonly input?: z.ZodTypeAny;
|
|
76
|
+
}>>;
|
|
77
|
+
/** The {@link OpInputTable} of an op table as written. */
|
|
78
|
+
type OpInputsOf<S extends UserSchemas> = { readonly [V in keyof S as S[V] extends {
|
|
79
|
+
input: z.ZodTypeAny;
|
|
80
|
+
} ? V : never]: S[V] extends {
|
|
81
|
+
input: infer I extends z.ZodTypeAny;
|
|
82
|
+
} ? {
|
|
83
|
+
readonly input: I;
|
|
84
|
+
} : never };
|
|
72
85
|
type EntityClass<F extends FieldsSchema, G extends FieldsSchema,
|
|
73
86
|
/** The kind as a literal, so `ref` can narrow to the paths a consumer's config declares. Defaults
|
|
74
87
|
* to `string`, which is what every 2-argument use of this type keeps getting. */
|
|
75
88
|
K extends string = string,
|
|
76
|
-
/**
|
|
89
|
+
/** Each op's input schema, so a consumer can infer an operation's input type off the entity
|
|
77
90
|
* instead of restating it. See {@link OpInput}. */
|
|
78
|
-
S extends
|
|
91
|
+
S extends OpInputTable = OpInputTable,
|
|
79
92
|
/** The kind's `computed` map as written, so `Token.get(...).link` is typed off the function that
|
|
80
93
|
* produces it rather than restated. Defaults to none. */
|
|
81
94
|
C extends ComputedFields = Record<never, never>,
|
|
@@ -94,7 +107,8 @@ GI extends GroupInputs = Record<never, never>> = Omit<RefSchema, 'extend'> & {
|
|
|
94
107
|
* it, but methods compare bivariantly and a required parameter matches an optional one. */
|
|
95
108
|
readonly singleton: Single;
|
|
96
109
|
/**
|
|
97
|
-
* The entity's own op schemas, at the type level.
|
|
110
|
+
* The entity's own op input schemas, at the type level. The value is the full op table; the type
|
|
111
|
+
* keeps only each op's `input`.
|
|
98
112
|
*
|
|
99
113
|
* Present so `OpInput<typeof Component, 'element-insert'>` resolves. Every consumer that wrote an
|
|
100
114
|
* operation used to hand-declare its input shape — 20 files did, because the zod schema was defined
|
|
@@ -165,7 +179,7 @@ GI extends GroupInputs = Record<never, never>> = Omit<RefSchema, 'extend'> & {
|
|
|
165
179
|
* class must never do the same: its schema is the member shape, and `deriveCreateSchema` really
|
|
166
180
|
* does call zod's `extend` on it.
|
|
167
181
|
*/
|
|
168
|
-
extend<F2 extends ShapeOverride = Record<never, never>, G2 extends ShapeOverride = Record<never, never>, S2 extends UserSchemas =
|
|
182
|
+
extend<F2 extends ShapeOverride = Record<never, never>, G2 extends ShapeOverride = Record<never, never>, S2 extends UserSchemas = never>(overrides: {
|
|
169
183
|
fields?: F2;
|
|
170
184
|
groupFields?: G2;
|
|
171
185
|
subEntities?: Partial<Record<string, SubEntityClass | null>>;
|
|
@@ -176,7 +190,7 @@ GI extends GroupInputs = Record<never, never>> = Omit<RefSchema, 'extend'> & {
|
|
|
176
190
|
* from the kind can name it — and a source writer that guesses emits the base's class into a
|
|
177
191
|
* Config that never imported it. See {@link EntityKind.entityName}. */
|
|
178
192
|
entityName?: string;
|
|
179
|
-
}): EntityClass<ExtendedFields<F, F2>, ExtendedFields<G, G2>, K, S2
|
|
193
|
+
}): EntityClass<ExtendedFields<F, F2>, ExtendedFields<G, G2>, K, [S2] extends [never] ? S : OpInputsOf<S2>, C, Single, GC, GI>;
|
|
180
194
|
};
|
|
181
195
|
declare function defineEntity<F extends FieldsSchema, G extends FieldsSchema = z.ZodObject<Record<never, never>>, K extends string = string, const S extends UserSchemas = Record<never, never>, const C extends ComputedFields = Record<never, never>, Single extends boolean = false, const GC extends GroupComputedFields = Record<never, never>, const GI extends GroupInputs = Record<never, never>>(spec: {
|
|
182
196
|
kind: K;
|
|
@@ -341,7 +355,13 @@ declare function defineEntity<F extends FieldsSchema, G extends FieldsSchema = z
|
|
|
341
355
|
element?: unknown;
|
|
342
356
|
}[];
|
|
343
357
|
rewriteName?: (data: unknown, from: string, to: string) => unknown;
|
|
344
|
-
}): EntityClass<F, G, K, S
|
|
358
|
+
}): EntityClass<F, G, K, { readonly [V in keyof S as S[V] extends {
|
|
359
|
+
input: z.ZodTypeAny;
|
|
360
|
+
} ? V : never]: S[V] extends {
|
|
361
|
+
input: infer I extends z.ZodTypeAny;
|
|
362
|
+
} ? {
|
|
363
|
+
readonly input: I;
|
|
364
|
+
} : never }, C, Single, GC, GI>;
|
|
345
365
|
/**
|
|
346
366
|
* The input type of one of an entity's operations — `OpInput<typeof Component, 'element-insert'>`.
|
|
347
367
|
*
|
|
@@ -350,7 +370,7 @@ declare function defineEntity<F extends FieldsSchema, G extends FieldsSchema = z
|
|
|
350
370
|
* a field the op has no input for: the write is silently dropped, and nothing catches it until a merge.
|
|
351
371
|
*/
|
|
352
372
|
type OpInput<E extends {
|
|
353
|
-
readonly schemas:
|
|
373
|
+
readonly schemas: OpInputTable;
|
|
354
374
|
}, V extends keyof E['schemas']> = E['schemas'][V] extends {
|
|
355
375
|
input: infer I extends z.ZodTypeAny;
|
|
356
376
|
} ? z.input<I> : never;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/framework/named.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `T` itself, spelled so an interface can extend it: `interface TokenClass extends
|
|
4
|
+
* Named<typeof TokenDefinition> {}`. Declaration output refers to an interface by name, where an
|
|
5
|
+
* inferred entity type would be re-expanded, schema and all, at every place it's referenced.
|
|
6
|
+
*/
|
|
7
|
+
type Named<T> = T;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { Named };
|
package/dist/framework/plan.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ interface RenamePlan {
|
|
|
29
29
|
readonly to: string;
|
|
30
30
|
/** Every entity the cascade rewrites: a body holding a ref to the old path, or its name as a key. */
|
|
31
31
|
readonly rewrites: readonly EntityAddress[];
|
|
32
|
+
/** Rows that use the entity through a source, whose body names it there. The cascade can't rewrite
|
|
33
|
+
* them, so after the rename they name a path this config no longer holds. */
|
|
34
|
+
readonly throughSource: readonly EntityAddress[];
|
|
32
35
|
/** Why the rename would be refused. `undefined` when it would go through. */
|
|
33
36
|
readonly blocked?: string;
|
|
34
37
|
}
|
package/dist/framework/plan.js
CHANGED
|
@@ -50,10 +50,13 @@ function planRename({ config, kind, path, to }) {
|
|
|
50
50
|
path,
|
|
51
51
|
to
|
|
52
52
|
}]));
|
|
53
|
+
const throughSource = config.sourceDependentsOf(kind, path);
|
|
54
|
+
const drawn = new Set(throughSource);
|
|
53
55
|
return {
|
|
54
56
|
from: path,
|
|
55
57
|
to,
|
|
56
|
-
rewrites: addresses(config.dependentsOf(kind, path)),
|
|
58
|
+
rewrites: addresses(config.dependentsOf(kind, path).filter((ref) => !drawn.has(ref))),
|
|
59
|
+
throughSource: addresses(throughSource),
|
|
57
60
|
...blocked === void 0 ? {} : { blocked }
|
|
58
61
|
};
|
|
59
62
|
}
|
|
@@ -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 = 20260928180801;
|
|
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 = 20260928180801;
|
|
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 > 20260928180801) 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 ?? 20260928180801;
|
|
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 ?? 20260928180801;
|
|
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 ?? 20260928180801;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -12,7 +12,7 @@ declare const GROUP: unique symbol;
|
|
|
12
12
|
* `'color/text/primary'` or `color: { text: { primary } }` — so a record of these is admissible at
|
|
13
13
|
* every level, exactly as `register` flattens them.
|
|
14
14
|
*/
|
|
15
|
-
type AuthoredEntry<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<F> |
|
|
15
|
+
type AuthoredEntry<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<F> | EntryGroup<F, G> | Authored | string | number | Ref | NestedEntries<F, G>;
|
|
16
16
|
/**
|
|
17
17
|
* A record of entries under a shared prefix.
|
|
18
18
|
*
|
|
@@ -21,9 +21,11 @@ type AuthoredEntry<F extends FieldsSchema, G extends FieldsSchema> = CreateInput
|
|
|
21
21
|
* is a malformed item either way, and this is what makes the type say so rather than silently
|
|
22
22
|
* reading `{ valuee: '#fff' }` as a nested token named `valuee`.
|
|
23
23
|
*/
|
|
24
|
-
type NestedEntries<F extends FieldsSchema, G extends FieldsSchema> = {
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
type NestedEntries<F extends FieldsSchema, G extends FieldsSchema> = NestedRecord<F, G> & { readonly [K in ItemFieldKeys<F, G>]?: never };
|
|
25
|
+
/** {@link NestedEntries}' records. An interface, so the recursion resolves lazily. */
|
|
26
|
+
interface NestedRecord<F extends FieldsSchema, G extends FieldsSchema> {
|
|
27
|
+
readonly [key: string]: CreateInput<F> | EntryGroup<F, G> | Authored | Ref | NestedEntries<F, G>;
|
|
28
|
+
}
|
|
27
29
|
/** A group node — its own fields, plus the members that live under its path. */
|
|
28
30
|
type GroupBody<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<G> & {
|
|
29
31
|
/** The group's members, keyed by the segment that extends its path. Stating the prefix once is
|
|
@@ -47,7 +49,15 @@ type GroupInputHandler<I> = (args: {
|
|
|
47
49
|
type GroupInputs = Readonly<Record<string, GroupInputHandler<never>>>;
|
|
48
50
|
/** The input keys a kind's `group()` takes, typed off each handler's declared input. */
|
|
49
51
|
type GroupInputValues<GI extends GroupInputs> = { readonly [K in keyof GI]?: GI[K] extends GroupInputHandler<infer I> ? I : never };
|
|
52
|
+
/** The kind's own item fields, which never name a path segment or sit on an unmarked group. */
|
|
53
|
+
type ItemFieldKeys<F extends FieldsSchema, G extends FieldsSchema> = Exclude<keyof CreateInput<F>, keyof CreateInput<G>>;
|
|
54
|
+
/**
|
|
55
|
+
* A group body in an entry's place. It may not carry the kind's item fields: only `<Entity>.group()`
|
|
56
|
+
* marks a group, so a body with an item field is an item, and typing it as a group would let an item
|
|
57
|
+
* with a wrong field through.
|
|
58
|
+
*/
|
|
59
|
+
type EntryGroup<F extends FieldsSchema, G extends FieldsSchema> = GroupBody<F, G> & { readonly [K in ItemFieldKeys<F, G>]?: never };
|
|
50
60
|
declare function brandGroup<F extends FieldsSchema, G extends FieldsSchema>(meta: GroupBody<F, G>): GroupBody<F, G>;
|
|
51
61
|
declare function isGroupBody(value: unknown): boolean;
|
|
52
62
|
//#endregion
|
|
53
|
-
export { AuthoredEntry, GROUP, GroupBody, GroupInputValues, GroupInputs, brandGroup, isGroupBody };
|
|
63
|
+
export { AuthoredEntry, EntryGroup, GROUP, GroupBody, GroupInputValues, GroupInputs, brandGroup, isGroupBody };
|