@yahoo/uds-create-config 2.34.0 → 2.35.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/Config.d.ts +15 -0
- package/dist/Config.js +60 -9
- package/dist/Token.d.ts +12 -1
- package/dist/Token.js +25 -11
- package/dist/TokenGroup.d.ts +2 -1
- package/dist/TokenGroup.js +1 -0
- package/dist/extension.d.ts +7 -1
- package/dist/extension.js +34 -10
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -3
- package/dist/linkedNodePrefixes.d.ts +73 -0
- package/dist/linkedNodePrefixes.js +99 -0
- package/dist/refs.d.ts +20 -1
- package/dist/refs.js +17 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { slugifyLinkedName } from "./registry-aliases.js";
|
|
2
|
+
//#region src/linkedNodePrefixes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Node-scoped CSS-prefix assignment for materialized linked systems.
|
|
5
|
+
*
|
|
6
|
+
* Every linked node (`{systemId}@{version}`) regenerates its CSS at consumer
|
|
7
|
+
* build time from its sealed `config.json`, with its `prefix` overridden to a
|
|
8
|
+
* composed, collision-free identity: `<consumerPrefix>-linked-<slug>`. One
|
|
9
|
+
* prefix per NODE (not per link path) — the module graph resolves each node's
|
|
10
|
+
* files once, so its lowered class names can only carry one prefix; sharing a
|
|
11
|
+
* node between parents shares byte-identical sealed content, so sharing the
|
|
12
|
+
* prefix is correct.
|
|
13
|
+
*
|
|
14
|
+
* The assignment must be identical everywhere it's consumed (pull-time shim
|
|
15
|
+
* generation, `uds build` CSS regeneration, the bundler loaders), so every
|
|
16
|
+
* consumer derives it from the same inputs with the same pure functions:
|
|
17
|
+
* node identities from the registry tree, display names from the declaring
|
|
18
|
+
* configs' `registerLinkedSystems` entries ({@link resolveDeclaredNames}),
|
|
19
|
+
* and the consumer's own prefix. Nothing is persisted — the registry tree is
|
|
20
|
+
* the source of truth.
|
|
21
|
+
*/
|
|
22
|
+
/** CSS identifiers can't start with a digit (or a hyphen-digit pair) —
|
|
23
|
+
* prepend a letter sentinel when a candidate would. */
|
|
24
|
+
function ensureCssIdentStart(candidate) {
|
|
25
|
+
return /^[a-zA-Z_]/.test(candidate) ? candidate : `x${candidate}`;
|
|
26
|
+
}
|
|
27
|
+
/** `1.5.0` → `v1-5-0` — a CSS-safe version fragment. */
|
|
28
|
+
function versionFragment(version) {
|
|
29
|
+
return `v${version.replace(/[^a-zA-Z0-9]+/g, "-")}`;
|
|
30
|
+
}
|
|
31
|
+
function nodeKey(node) {
|
|
32
|
+
return `${node.systemId}@${node.version}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Assign each node in a linked closure its slug + composed CSS prefix,
|
|
36
|
+
* keyed by `{systemId}@{version}`.
|
|
37
|
+
*
|
|
38
|
+
* Deterministic and input-order independent: nodes are processed sorted by
|
|
39
|
+
* `(systemId, version)`. Within a slug-collision group the first sorted node
|
|
40
|
+
* keeps the bare slug; a different system appends `-x<systemId[0..8]>`; the
|
|
41
|
+
* same system at another version appends `-v<version>` — so every node in
|
|
42
|
+
* the closure gets a unique, stable prefix.
|
|
43
|
+
*
|
|
44
|
+
* `consumerPrefix` is the consuming system's own `Config.prefix`. An empty
|
|
45
|
+
* prefix is disallowed as a base (a bare `linked-…` could collide with the
|
|
46
|
+
* consumer's unprefixed classes) — the node's own uuid fragment substitutes.
|
|
47
|
+
*/
|
|
48
|
+
function assignLinkedNodePrefixes(nodes, consumerPrefix) {
|
|
49
|
+
const sorted = [...nodes].sort((a, b) => a.systemId.localeCompare(b.systemId) || a.version.localeCompare(b.version));
|
|
50
|
+
const byslug = /* @__PURE__ */ new Map();
|
|
51
|
+
for (const node of sorted) {
|
|
52
|
+
const slug = slugifyLinkedName(node.name);
|
|
53
|
+
const group = byslug.get(slug);
|
|
54
|
+
if (group) group.push(node);
|
|
55
|
+
else byslug.set(slug, [node]);
|
|
56
|
+
}
|
|
57
|
+
const out = /* @__PURE__ */ new Map();
|
|
58
|
+
const usedSlugs = /* @__PURE__ */ new Set();
|
|
59
|
+
for (const [slug, group] of byslug) {
|
|
60
|
+
const systemsInOrder = [];
|
|
61
|
+
for (const node of group) if (!systemsInOrder.includes(node.systemId)) systemsInOrder.push(node.systemId);
|
|
62
|
+
for (const node of group) {
|
|
63
|
+
const systemRank = systemsInOrder.indexOf(node.systemId);
|
|
64
|
+
const versionsOfSystem = group.filter((n) => n.systemId === node.systemId);
|
|
65
|
+
let finalSlug = slug;
|
|
66
|
+
if (systemRank > 0) finalSlug += `-x${node.systemId.slice(0, 8)}`;
|
|
67
|
+
if (versionsOfSystem.length > 1 && versionsOfSystem.indexOf(node) > 0) finalSlug += `-${versionFragment(node.version)}`;
|
|
68
|
+
const collisionBase = finalSlug;
|
|
69
|
+
let collisionIndex = 2;
|
|
70
|
+
while (usedSlugs.has(finalSlug)) {
|
|
71
|
+
finalSlug = `${collisionBase}-${collisionIndex}`;
|
|
72
|
+
collisionIndex++;
|
|
73
|
+
}
|
|
74
|
+
usedSlugs.add(finalSlug);
|
|
75
|
+
const base = ensureCssIdentStart(consumerPrefix === "" ? `x${node.systemId.slice(0, 8)}` : consumerPrefix);
|
|
76
|
+
out.set(nodeKey(node), {
|
|
77
|
+
slug: finalSlug,
|
|
78
|
+
cssPrefix: `${base}-linked-${finalSlug}`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve each node's display name from the closure's declarations. A node
|
|
86
|
+
* can be declared by several parents under different name snapshots; the
|
|
87
|
+
* winner is the declaration with the lowest `declarerKey` in sort order (the
|
|
88
|
+
* consumer's own declarations sort first as `''`), so every tool that walks
|
|
89
|
+
* the same closure derives the same names — and therefore the same slugs and
|
|
90
|
+
* CSS prefixes — without any persisted mapping.
|
|
91
|
+
*/
|
|
92
|
+
function resolveDeclaredNames(declarations) {
|
|
93
|
+
const sorted = [...declarations].sort((a, b) => a.key.localeCompare(b.key) || a.declarerKey.localeCompare(b.declarerKey));
|
|
94
|
+
const names = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const decl of sorted) if (!names.has(decl.key)) names.set(decl.key, decl.name);
|
|
96
|
+
return names;
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { assignLinkedNodePrefixes, resolveDeclaredNames };
|
package/dist/refs.d.ts
CHANGED
|
@@ -85,6 +85,18 @@ type TagName = string;
|
|
|
85
85
|
interface TokenRef<TName extends string = string> {
|
|
86
86
|
readonly __kind: 'token';
|
|
87
87
|
readonly ref: TName;
|
|
88
|
+
/**
|
|
89
|
+
* Namespace scope for refs authored in extension payloads. Absent on
|
|
90
|
+
* source-authored refs (they resolve in their own system's namespace).
|
|
91
|
+
* `'consumer'` is stamped by the extension merge on plain `token()` refs
|
|
92
|
+
* — a consumer-authored ref always means the consumer's own tokens.
|
|
93
|
+
*/
|
|
94
|
+
readonly scope?: 'consumer';
|
|
95
|
+
/** Pinned-system scope from a registry barrel's `token()` utility. */
|
|
96
|
+
readonly system?: {
|
|
97
|
+
readonly id: string;
|
|
98
|
+
readonly version: string;
|
|
99
|
+
};
|
|
88
100
|
}
|
|
89
101
|
interface TokenGroupRef<TName extends string = string> {
|
|
90
102
|
readonly __kind: 'tokenGroup';
|
|
@@ -153,6 +165,13 @@ type AnyRef = TokenRef | TokenGroupRef | CompositeRef | ModeRef | StylePropRef |
|
|
|
153
165
|
/** Doc-alignment alias kept for ergonomic import. */
|
|
154
166
|
type TokenQualifiedName = TokenName;
|
|
155
167
|
declare function token<TName extends TokenName>(ref: TName): TokenRef<TName>;
|
|
168
|
+
/**
|
|
169
|
+
* Curried factory behind a registry barrel's `token()` utility —
|
|
170
|
+
* `yahooOs.token('color/red-1')` names THAT system's token, letting a
|
|
171
|
+
* consumer mix references across pinned systems unambiguously. The plain
|
|
172
|
+
* `token()` import always means the consumer's own namespace.
|
|
173
|
+
*/
|
|
174
|
+
declare function systemToken(systemId: string, version: string): <TName extends TokenName>(ref: TName) => TokenRef<TName>;
|
|
156
175
|
declare function tokenGroup<TName extends TokenGroupName>(ref: TName): TokenGroupRef<TName>;
|
|
157
176
|
/**
|
|
158
177
|
* `composite(ref)` returns a bare `CompositeRef` plus an `.on(layer)`
|
|
@@ -182,4 +201,4 @@ declare function isComponentRef(value: unknown): value is ComponentRef;
|
|
|
182
201
|
declare function isAssetGroupRef(value: unknown): value is AssetGroupRef;
|
|
183
202
|
declare function isAssetRef(value: unknown): value is AssetRef;
|
|
184
203
|
//#endregion
|
|
185
|
-
export { AnyRef, AssetGroupName, AssetGroupRef, AssetName, AssetRef, ComponentName, ComponentRef, CompositeName, CompositeRef, CompositeRefBuilder, ModeName, ModeRef, MotionName, RegisteredAssetGroups, RegisteredComponents, RegisteredCompositeStyles, RegisteredModes, RegisteredModifiers, RegisteredMotion, RegisteredStyleProps, RegisteredTokenGroups, StylePropName, StylePropRef, TagName, TagRef, TokenGroupName, TokenGroupRef, TokenName, TokenQualifiedName, TokenRawNameRegistry, TokenRef, asset, assetGroup, component, composite, isAssetGroupRef, isAssetRef, isComponentRef, isCompositeRef, isModeRef, isStylePropRef, isTagRef, isTokenGroupRef, isTokenRef, mode, styleProp, tag, token, tokenGroup };
|
|
204
|
+
export { AnyRef, AssetGroupName, AssetGroupRef, AssetName, AssetRef, ComponentName, ComponentRef, CompositeName, CompositeRef, CompositeRefBuilder, ModeName, ModeRef, MotionName, RegisteredAssetGroups, RegisteredComponents, RegisteredCompositeStyles, RegisteredModes, RegisteredModifiers, RegisteredMotion, RegisteredStyleProps, RegisteredTokenGroups, StylePropName, StylePropRef, TagName, TagRef, TokenGroupName, TokenGroupRef, TokenName, TokenQualifiedName, TokenRawNameRegistry, TokenRef, asset, assetGroup, component, composite, isAssetGroupRef, isAssetRef, isComponentRef, isCompositeRef, isModeRef, isStylePropRef, isTagRef, isTokenGroupRef, isTokenRef, mode, styleProp, systemToken, tag, token, tokenGroup };
|
package/dist/refs.js
CHANGED
|
@@ -5,6 +5,22 @@ function token(ref) {
|
|
|
5
5
|
ref
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Curried factory behind a registry barrel's `token()` utility —
|
|
10
|
+
* `yahooOs.token('color/red-1')` names THAT system's token, letting a
|
|
11
|
+
* consumer mix references across pinned systems unambiguously. The plain
|
|
12
|
+
* `token()` import always means the consumer's own namespace.
|
|
13
|
+
*/
|
|
14
|
+
function systemToken(systemId, version) {
|
|
15
|
+
return (ref) => ({
|
|
16
|
+
__kind: "token",
|
|
17
|
+
ref,
|
|
18
|
+
system: {
|
|
19
|
+
id: systemId,
|
|
20
|
+
version
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
8
24
|
function tokenGroup(ref) {
|
|
9
25
|
return {
|
|
10
26
|
__kind: "tokenGroup",
|
|
@@ -110,4 +126,4 @@ function isAssetRef(value) {
|
|
|
110
126
|
return isRefOf(value, "asset");
|
|
111
127
|
}
|
|
112
128
|
//#endregion
|
|
113
|
-
export { asset, assetGroup, component, composite, isAssetGroupRef, isAssetRef, isComponentRef, isCompositeRef, isModeRef, isStylePropRef, isTagRef, isTokenGroupRef, isTokenRef, mode, styleProp, tag, token, tokenGroup };
|
|
129
|
+
export { asset, assetGroup, component, composite, isAssetGroupRef, isAssetRef, isComponentRef, isCompositeRef, isModeRef, isStylePropRef, isTagRef, isTokenGroupRef, isTokenRef, mode, styleProp, systemToken, tag, token, tokenGroup };
|