@motion-proto/live-tokens 0.16.2 → 0.17.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/bin/cli.mjs +25 -3
- package/bin/migrate.mjs +113 -0
- package/dist-plugin/chunk-UBS57IYV.js +249 -0
- package/dist-plugin/index.cjs +200 -3
- package/dist-plugin/index.d.cts +1 -0
- package/dist-plugin/index.d.ts +1 -0
- package/dist-plugin/index.js +165 -182
- package/dist-plugin/tokensCssMigrations/index.cjs +279 -0
- package/dist-plugin/tokensCssMigrations/index.d.cts +144 -0
- package/dist-plugin/tokensCssMigrations/index.d.ts +144 -0
- package/dist-plugin/tokensCssMigrations/index.js +24 -0
- package/package.json +1 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// vite-plugin/tokensCssMigrations/index.ts
|
|
31
|
+
var tokensCssMigrations_exports = {};
|
|
32
|
+
__export(tokensCssMigrations_exports, {
|
|
33
|
+
TOKENS_CSS_MIGRATIONS: () => TOKENS_CSS_MIGRATIONS,
|
|
34
|
+
collectDefinedTokens: () => collectDefinedTokens,
|
|
35
|
+
collectReferencedTokens: () => collectReferencedTokens,
|
|
36
|
+
ensureScale: () => ensureScale,
|
|
37
|
+
readLiveTokensConfig: () => readLiveTokensConfig,
|
|
38
|
+
removeToken: () => removeToken,
|
|
39
|
+
removeTokensMatching: () => removeTokensMatching,
|
|
40
|
+
renameToken: () => renameToken,
|
|
41
|
+
runTokensCssMigrations: () => runTokensCssMigrations,
|
|
42
|
+
validateTokensCss: () => validateTokensCss
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(tokensCssMigrations_exports);
|
|
45
|
+
|
|
46
|
+
// src/editor/core/themes/parsers/globalRootBlock.ts
|
|
47
|
+
function extractGlobalRootBody(source) {
|
|
48
|
+
const re = /:global\(:root\)\s*\{([^}]*)\}/g;
|
|
49
|
+
const bodies = [];
|
|
50
|
+
let m;
|
|
51
|
+
while ((m = re.exec(source)) !== null) {
|
|
52
|
+
bodies.push(m[1]);
|
|
53
|
+
}
|
|
54
|
+
return bodies.join("\n");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// vite-plugin/tokensCssMigrations/cssTokenOps.ts
|
|
58
|
+
var DECL_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:/gi;
|
|
59
|
+
var REF_RE = /var\(\s*(--[a-z0-9-]+)/gi;
|
|
60
|
+
function collectDefinedTokens(css) {
|
|
61
|
+
const out = /* @__PURE__ */ new Set();
|
|
62
|
+
for (const m of css.matchAll(DECL_RE)) out.add(m[2]);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function collectReferencedTokens(css) {
|
|
66
|
+
const out = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const m of css.matchAll(REF_RE)) out.add(m[1]);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function ensureScale(css, opts) {
|
|
71
|
+
const defined = collectDefinedTokens(css);
|
|
72
|
+
const missing = opts.entries.filter((e) => !defined.has(e.name));
|
|
73
|
+
if (missing.length === 0) return css;
|
|
74
|
+
const lines = css.split("\n");
|
|
75
|
+
const { indent, insertAfter } = findInsertionPoint(lines, opts.anchorPrefixes ?? []);
|
|
76
|
+
const block = [];
|
|
77
|
+
if (opts.sectionComment) block.push(`${indent}/* ${opts.sectionComment} */`);
|
|
78
|
+
for (const e of missing) block.push(`${indent}${e.name}: ${e.value};`);
|
|
79
|
+
lines.splice(insertAfter + 1, 0, ...block);
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
function renameToken(css, oldName, newName) {
|
|
83
|
+
const defined = collectDefinedTokens(css);
|
|
84
|
+
if (!defined.has(oldName) || defined.has(newName)) return css;
|
|
85
|
+
const re = new RegExp(escapeRe(oldName) + "(?![a-z0-9-])", "gi");
|
|
86
|
+
return css.replace(re, newName);
|
|
87
|
+
}
|
|
88
|
+
function removeToken(css, name) {
|
|
89
|
+
const lines = css.split("\n");
|
|
90
|
+
const declRe = new RegExp("(^|[\\s;{])" + escapeRe(name) + "\\s*:");
|
|
91
|
+
const kept = lines.filter((line) => !declRe.test(line));
|
|
92
|
+
if (kept.length === lines.length) return css;
|
|
93
|
+
return kept.join("\n");
|
|
94
|
+
}
|
|
95
|
+
function removeTokensMatching(css, predicate) {
|
|
96
|
+
const lines = css.split("\n");
|
|
97
|
+
const declRe = /^\s*(--[a-z0-9-]+)\s*:/;
|
|
98
|
+
const kept = lines.filter((line) => {
|
|
99
|
+
const m = line.match(declRe);
|
|
100
|
+
return !(m && predicate(m[1]));
|
|
101
|
+
});
|
|
102
|
+
if (kept.length === lines.length) return css;
|
|
103
|
+
return kept.join("\n");
|
|
104
|
+
}
|
|
105
|
+
function findInsertionPoint(lines, anchorPrefixes) {
|
|
106
|
+
for (const prefix of anchorPrefixes) {
|
|
107
|
+
let last = -1;
|
|
108
|
+
let indent = " ";
|
|
109
|
+
for (let i = 0; i < lines.length; i++) {
|
|
110
|
+
const m = lines[i].match(/^(\s*)(--[a-z0-9-]+)\s*:/);
|
|
111
|
+
if (m && m[2].startsWith(prefix)) {
|
|
112
|
+
last = i;
|
|
113
|
+
indent = m[1] || " ";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (last !== -1) return { indent, insertAfter: last };
|
|
117
|
+
}
|
|
118
|
+
let depth = 0;
|
|
119
|
+
let inRoot = false;
|
|
120
|
+
let lastDeclIndent = " ";
|
|
121
|
+
for (let i = 0; i < lines.length; i++) {
|
|
122
|
+
const line = lines[i];
|
|
123
|
+
if (!inRoot && /(^|\s):root[^{]*\{/.test(line)) {
|
|
124
|
+
inRoot = true;
|
|
125
|
+
depth = 1;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (!inRoot) continue;
|
|
129
|
+
const declIndent = line.match(/^(\s*)--[a-z0-9-]+\s*:/);
|
|
130
|
+
if (declIndent) lastDeclIndent = declIndent[1] || " ";
|
|
131
|
+
depth += (line.match(/\{/g)?.length ?? 0) - (line.match(/\}/g)?.length ?? 0);
|
|
132
|
+
if (depth === 0) {
|
|
133
|
+
return { indent: lastDeclIndent, insertAfter: i - 1 };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { indent: " ", insertAfter: lines.length - 1 };
|
|
137
|
+
}
|
|
138
|
+
function escapeRe(s) {
|
|
139
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-05-29-typography-scale-additions.ts
|
|
143
|
+
var tokensCssMigration_2026_05_29_typographyScaleAdditions = {
|
|
144
|
+
id: "2026-05-29-typography-scale-additions",
|
|
145
|
+
description: "Add --line-height-{xs..xl}, --letter-spacing-* and --ease-out-quart scales",
|
|
146
|
+
apply(css) {
|
|
147
|
+
let out = css;
|
|
148
|
+
out = ensureScale(out, {
|
|
149
|
+
sectionComment: "Line height (t-shirt scale)",
|
|
150
|
+
anchorPrefixes: ["--line-height-", "--font-size-", "--font-weight-", "--font-"],
|
|
151
|
+
entries: [
|
|
152
|
+
{ name: "--line-height-xs", value: "1" },
|
|
153
|
+
{ name: "--line-height-sm", value: "1.25" },
|
|
154
|
+
{ name: "--line-height-md", value: "1.5" },
|
|
155
|
+
{ name: "--line-height-lg", value: "1.75" },
|
|
156
|
+
{ name: "--line-height-xl", value: "2" }
|
|
157
|
+
]
|
|
158
|
+
});
|
|
159
|
+
out = ensureScale(out, {
|
|
160
|
+
sectionComment: "Letter spacing",
|
|
161
|
+
anchorPrefixes: ["--letter-spacing-", "--line-height-", "--font-size-", "--font-"],
|
|
162
|
+
entries: [
|
|
163
|
+
{ name: "--letter-spacing-tighter", value: "-0.04em" },
|
|
164
|
+
{ name: "--letter-spacing-tight", value: "-0.02em" },
|
|
165
|
+
{ name: "--letter-spacing-normal", value: "0" },
|
|
166
|
+
{ name: "--letter-spacing-wide", value: "0.04em" },
|
|
167
|
+
{ name: "--letter-spacing-wider", value: "0.08em" }
|
|
168
|
+
]
|
|
169
|
+
});
|
|
170
|
+
out = ensureScale(out, {
|
|
171
|
+
sectionComment: "Easing",
|
|
172
|
+
anchorPrefixes: ["--ease-", "--transition-", "--duration-"],
|
|
173
|
+
entries: [{ name: "--ease-out-quart", value: "cubic-bezier(0.25, 1, 0.5, 1)" }]
|
|
174
|
+
});
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-05-29-sectiondivider-legacy-axis-cleanup.ts
|
|
180
|
+
var KEEP_SEGMENTS = /* @__PURE__ */ new Set(["lg", "md", "sm"]);
|
|
181
|
+
var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
182
|
+
id: "2026-05-29-sectiondivider-legacy-axis-cleanup",
|
|
183
|
+
description: "Remove legacy --sectiondivider-* tokens not on the lg/md/sm axis",
|
|
184
|
+
apply(css) {
|
|
185
|
+
return removeTokensMatching(css, (name) => {
|
|
186
|
+
if (!name.startsWith("--sectiondivider-")) return false;
|
|
187
|
+
const segment = name.slice("--sectiondivider-".length).split("-")[0];
|
|
188
|
+
return !KEEP_SEGMENTS.has(segment);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// vite-plugin/files/dataPaths.ts
|
|
194
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
195
|
+
var import_path = __toESM(require("path"), 1);
|
|
196
|
+
var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
197
|
+
"dataDir",
|
|
198
|
+
"themesDir",
|
|
199
|
+
"componentConfigsDir",
|
|
200
|
+
"manifestsDir",
|
|
201
|
+
"tokensCssPath"
|
|
202
|
+
]);
|
|
203
|
+
var cached = null;
|
|
204
|
+
function readLiveTokensConfig() {
|
|
205
|
+
if (cached) return cached;
|
|
206
|
+
try {
|
|
207
|
+
const configPath = import_path.default.resolve("live-tokens.config.json");
|
|
208
|
+
if (!import_fs.default.existsSync(configPath)) return cached = {};
|
|
209
|
+
const parsed = JSON.parse(import_fs.default.readFileSync(configPath, "utf-8"));
|
|
210
|
+
if (!parsed || typeof parsed !== "object") return cached = {};
|
|
211
|
+
const unknown = Object.keys(parsed).filter(
|
|
212
|
+
(k) => k !== "$schema" && !KNOWN_CONFIG_KEYS.has(k)
|
|
213
|
+
);
|
|
214
|
+
if (unknown.length > 0) {
|
|
215
|
+
console.warn(
|
|
216
|
+
`[live-tokens] Unknown key(s) in live-tokens.config.json: ${unknown.join(", ")}. Known keys: ${Array.from(KNOWN_CONFIG_KEYS).join(", ")}.`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
cached = parsed;
|
|
220
|
+
return cached;
|
|
221
|
+
} catch {
|
|
222
|
+
return cached = {};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// vite-plugin/tokensCssMigrations/index.ts
|
|
227
|
+
var TOKENS_CSS_MIGRATIONS = [
|
|
228
|
+
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
229
|
+
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup
|
|
230
|
+
];
|
|
231
|
+
function runTokensCssMigrations(css) {
|
|
232
|
+
let out = css;
|
|
233
|
+
const applied = [];
|
|
234
|
+
for (const m of TOKENS_CSS_MIGRATIONS) {
|
|
235
|
+
const next = m.apply(out);
|
|
236
|
+
if (next !== out) {
|
|
237
|
+
applied.push(m.id);
|
|
238
|
+
out = next;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { css: out, applied, changed: out !== css };
|
|
242
|
+
}
|
|
243
|
+
function validateTokensCss(input) {
|
|
244
|
+
const defined = /* @__PURE__ */ new Set([
|
|
245
|
+
...collectDefinedTokens(input.tokensCss),
|
|
246
|
+
...collectDefinedTokens(input.generatedCss ?? "")
|
|
247
|
+
]);
|
|
248
|
+
const referencedBy = /* @__PURE__ */ new Map();
|
|
249
|
+
for (const { name, source } of input.componentSources) {
|
|
250
|
+
const body = extractGlobalRootBody(source);
|
|
251
|
+
if (!body) continue;
|
|
252
|
+
for (const t of collectDefinedTokens(body)) defined.add(t);
|
|
253
|
+
for (const ref of collectReferencedTokens(body)) {
|
|
254
|
+
let set = referencedBy.get(ref);
|
|
255
|
+
if (!set) referencedBy.set(ref, set = /* @__PURE__ */ new Set());
|
|
256
|
+
set.add(name);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const missing = [];
|
|
260
|
+
for (const [token, names] of referencedBy) {
|
|
261
|
+
if (!defined.has(token)) {
|
|
262
|
+
missing.push({ token, referencedBy: [...names].sort() });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return missing.sort((a, b) => a.token.localeCompare(b.token));
|
|
266
|
+
}
|
|
267
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
268
|
+
0 && (module.exports = {
|
|
269
|
+
TOKENS_CSS_MIGRATIONS,
|
|
270
|
+
collectDefinedTokens,
|
|
271
|
+
collectReferencedTokens,
|
|
272
|
+
ensureScale,
|
|
273
|
+
readLiveTokensConfig,
|
|
274
|
+
removeToken,
|
|
275
|
+
removeTokensMatching,
|
|
276
|
+
renameToken,
|
|
277
|
+
runTokensCssMigrations,
|
|
278
|
+
validateTokensCss
|
|
279
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `tokens-css` migration: a pure, idempotent transform on the text of a
|
|
3
|
+
* consumer's `tokens.css`.
|
|
4
|
+
*
|
|
5
|
+
* Sibling to the in-browser data-file migrations in
|
|
6
|
+
* `src/editor/core/themes/migrations/` (which transform theme and
|
|
7
|
+
* component-config JSON as the editor loads them). Those run in the browser on
|
|
8
|
+
* `Record<string,string>` maps; these run in Node — from the `live-tokens
|
|
9
|
+
* migrate` CLI and the dev-plugin guardrail — on the Layer-1 CSS file the data
|
|
10
|
+
* migrations deliberately never touch.
|
|
11
|
+
*
|
|
12
|
+
* There is no `schemaVersion` here: CSS carries no version stamp, so migrations
|
|
13
|
+
* must be idempotent by presence (see `cssTokenOps`). Re-running the full set is
|
|
14
|
+
* always safe, which is what the CLI relies on.
|
|
15
|
+
*/
|
|
16
|
+
interface TokensCssMigration {
|
|
17
|
+
/** Unique id; convention: `YYYY-MM-DD-<short-name>`. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** One-line summary shown by the CLI when the migration applies. */
|
|
20
|
+
description: string;
|
|
21
|
+
/** Pure, idempotent transform on the `tokens.css` source. */
|
|
22
|
+
apply(css: string): string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Pure, idempotent text operations on a `tokens.css` declaration set.
|
|
27
|
+
*
|
|
28
|
+
* `tokens.css` is the consumer's developer-authored Layer-1 source (palettes,
|
|
29
|
+
* type/space/radius scales, motion). When the package evolves the Layer-1
|
|
30
|
+
* vocabulary — adding a scale, renaming a step — consumers' forked `tokens.css`
|
|
31
|
+
* drifts. `tokens-css` migrations reconcile that drift; these helpers are the
|
|
32
|
+
* primitives they compose.
|
|
33
|
+
*
|
|
34
|
+
* Operations are text-level (not parse-and-reserialize) so the file's comments,
|
|
35
|
+
* sectioning, and formatting survive untouched. They are idempotent **by
|
|
36
|
+
* presence**: `ensure` skips a token that already exists, `rename` only fires
|
|
37
|
+
* when the old name is present and the new one is absent, `remove` is a no-op
|
|
38
|
+
* when the name is gone. Re-running a migration therefore never double-applies,
|
|
39
|
+
* which is what lets the CLI run safely without a schema-version stamp.
|
|
40
|
+
*/
|
|
41
|
+
/** Names declared as custom properties (`--x: …;`) anywhere in the source. */
|
|
42
|
+
declare function collectDefinedTokens(css: string): Set<string>;
|
|
43
|
+
/** Names referenced via `var(--x)` anywhere in the source. */
|
|
44
|
+
declare function collectReferencedTokens(css: string): Set<string>;
|
|
45
|
+
interface ScaleEntry {
|
|
46
|
+
name: string;
|
|
47
|
+
value: string;
|
|
48
|
+
}
|
|
49
|
+
interface EnsureScaleOptions {
|
|
50
|
+
/** Tokens to guarantee exist, in the order they should appear. */
|
|
51
|
+
entries: ScaleEntry[];
|
|
52
|
+
/**
|
|
53
|
+
* Comment emitted once above the first inserted token of the group (only when
|
|
54
|
+
* at least one token is actually inserted). Written without the `/* */`.
|
|
55
|
+
*/
|
|
56
|
+
sectionComment?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Prefixes, in priority order, used to find where to insert. The block is
|
|
59
|
+
* placed after the last declaration whose name starts with one of these.
|
|
60
|
+
* Falls back to just before the closing brace of the first `:root` block.
|
|
61
|
+
*/
|
|
62
|
+
anchorPrefixes?: string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Insert any missing tokens from `entries` as one contiguous block. Tokens that
|
|
66
|
+
* already exist (by name) are left as-is. Returns the source unchanged when
|
|
67
|
+
* every entry is already present.
|
|
68
|
+
*/
|
|
69
|
+
declare function ensureScale(css: string, opts: EnsureScaleOptions): string;
|
|
70
|
+
/**
|
|
71
|
+
* Rename a token: rewrites its declaration and every `var()` reference to it.
|
|
72
|
+
* No-op unless the old name is present and the new name is absent (so a
|
|
73
|
+
* half-applied rename, or a re-run, leaves the file alone).
|
|
74
|
+
*/
|
|
75
|
+
declare function renameToken(css: string, oldName: string, newName: string): string;
|
|
76
|
+
/** Remove a token's declaration line. No-op when the name isn't declared. */
|
|
77
|
+
declare function removeToken(css: string, name: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Remove every custom-property declaration whose name satisfies `predicate`.
|
|
80
|
+
* Operates line-by-line (tokens.css is one declaration per line), so only the
|
|
81
|
+
* matched declarations are dropped — surrounding comments and structure stay.
|
|
82
|
+
* No-op when nothing matches. Use for retiring a whole retired namespace.
|
|
83
|
+
*/
|
|
84
|
+
declare function removeTokensMatching(css: string, predicate: (name: string) => boolean): string;
|
|
85
|
+
|
|
86
|
+
interface LiveTokensFileConfig {
|
|
87
|
+
dataDir?: string;
|
|
88
|
+
themesDir?: string;
|
|
89
|
+
componentConfigsDir?: string;
|
|
90
|
+
manifestsDir?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Path to the developer-authored `tokens.css`. The dev plugin takes this from
|
|
93
|
+
* its `themeFileApi({ tokensCssPath })` option; the standalone `live-tokens
|
|
94
|
+
* migrate` CLI has no plugin options, so it reads this key to locate the file.
|
|
95
|
+
*/
|
|
96
|
+
tokensCssPath?: string;
|
|
97
|
+
}
|
|
98
|
+
declare function readLiveTokensConfig(): LiveTokensFileConfig;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Registered tokens-css migrations, applied in array order. Unlike the
|
|
102
|
+
* versioned data-file migrations, ordering here is explicit (chronological) and
|
|
103
|
+
* every migration is idempotent, so the runner simply folds them left-to-right.
|
|
104
|
+
*/
|
|
105
|
+
declare const TOKENS_CSS_MIGRATIONS: TokensCssMigration[];
|
|
106
|
+
interface RunResult {
|
|
107
|
+
/** The migrated source (identical to input when nothing changed). */
|
|
108
|
+
css: string;
|
|
109
|
+
/** ids of migrations whose `apply` actually changed the source. */
|
|
110
|
+
applied: string[];
|
|
111
|
+
/** True when `css` differs from the input. */
|
|
112
|
+
changed: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** Fold every registered migration over `css`. Pure and idempotent. */
|
|
115
|
+
declare function runTokensCssMigrations(css: string): RunResult;
|
|
116
|
+
interface ComponentSource {
|
|
117
|
+
name: string;
|
|
118
|
+
source: string;
|
|
119
|
+
}
|
|
120
|
+
interface MissingToken {
|
|
121
|
+
/** The undefined `--token` a component references. */
|
|
122
|
+
token: string;
|
|
123
|
+
/** Component names whose `:global(:root)` block references it. */
|
|
124
|
+
referencedBy: string[];
|
|
125
|
+
}
|
|
126
|
+
interface ValidateInput {
|
|
127
|
+
/** Contents of the consumer's developer-authored `tokens.css`. */
|
|
128
|
+
tokensCss: string;
|
|
129
|
+
/** Contents of the editor-owned `tokens.generated.css`, if present. */
|
|
130
|
+
generatedCss?: string;
|
|
131
|
+
/** Component `.svelte` sources to scan for `:global(:root)` references. */
|
|
132
|
+
componentSources: ComponentSource[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Find primitives that components reference but the runtime never defines.
|
|
136
|
+
*
|
|
137
|
+
* "Defined" is the union of: tokens declared in `tokens.css`, in the generated
|
|
138
|
+
* sidecar, and in any component's own `:global(:root)` block (so component →
|
|
139
|
+
* component references don't false-positive). Anything referenced but not in
|
|
140
|
+
* that union is drift — the symptom the consumer sees as blank editor slots.
|
|
141
|
+
*/
|
|
142
|
+
declare function validateTokensCss(input: ValidateInput): MissingToken[];
|
|
143
|
+
|
|
144
|
+
export { type ComponentSource, type MissingToken, type RunResult, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, ensureScale, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runTokensCssMigrations, validateTokensCss };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `tokens-css` migration: a pure, idempotent transform on the text of a
|
|
3
|
+
* consumer's `tokens.css`.
|
|
4
|
+
*
|
|
5
|
+
* Sibling to the in-browser data-file migrations in
|
|
6
|
+
* `src/editor/core/themes/migrations/` (which transform theme and
|
|
7
|
+
* component-config JSON as the editor loads them). Those run in the browser on
|
|
8
|
+
* `Record<string,string>` maps; these run in Node — from the `live-tokens
|
|
9
|
+
* migrate` CLI and the dev-plugin guardrail — on the Layer-1 CSS file the data
|
|
10
|
+
* migrations deliberately never touch.
|
|
11
|
+
*
|
|
12
|
+
* There is no `schemaVersion` here: CSS carries no version stamp, so migrations
|
|
13
|
+
* must be idempotent by presence (see `cssTokenOps`). Re-running the full set is
|
|
14
|
+
* always safe, which is what the CLI relies on.
|
|
15
|
+
*/
|
|
16
|
+
interface TokensCssMigration {
|
|
17
|
+
/** Unique id; convention: `YYYY-MM-DD-<short-name>`. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** One-line summary shown by the CLI when the migration applies. */
|
|
20
|
+
description: string;
|
|
21
|
+
/** Pure, idempotent transform on the `tokens.css` source. */
|
|
22
|
+
apply(css: string): string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Pure, idempotent text operations on a `tokens.css` declaration set.
|
|
27
|
+
*
|
|
28
|
+
* `tokens.css` is the consumer's developer-authored Layer-1 source (palettes,
|
|
29
|
+
* type/space/radius scales, motion). When the package evolves the Layer-1
|
|
30
|
+
* vocabulary — adding a scale, renaming a step — consumers' forked `tokens.css`
|
|
31
|
+
* drifts. `tokens-css` migrations reconcile that drift; these helpers are the
|
|
32
|
+
* primitives they compose.
|
|
33
|
+
*
|
|
34
|
+
* Operations are text-level (not parse-and-reserialize) so the file's comments,
|
|
35
|
+
* sectioning, and formatting survive untouched. They are idempotent **by
|
|
36
|
+
* presence**: `ensure` skips a token that already exists, `rename` only fires
|
|
37
|
+
* when the old name is present and the new one is absent, `remove` is a no-op
|
|
38
|
+
* when the name is gone. Re-running a migration therefore never double-applies,
|
|
39
|
+
* which is what lets the CLI run safely without a schema-version stamp.
|
|
40
|
+
*/
|
|
41
|
+
/** Names declared as custom properties (`--x: …;`) anywhere in the source. */
|
|
42
|
+
declare function collectDefinedTokens(css: string): Set<string>;
|
|
43
|
+
/** Names referenced via `var(--x)` anywhere in the source. */
|
|
44
|
+
declare function collectReferencedTokens(css: string): Set<string>;
|
|
45
|
+
interface ScaleEntry {
|
|
46
|
+
name: string;
|
|
47
|
+
value: string;
|
|
48
|
+
}
|
|
49
|
+
interface EnsureScaleOptions {
|
|
50
|
+
/** Tokens to guarantee exist, in the order they should appear. */
|
|
51
|
+
entries: ScaleEntry[];
|
|
52
|
+
/**
|
|
53
|
+
* Comment emitted once above the first inserted token of the group (only when
|
|
54
|
+
* at least one token is actually inserted). Written without the `/* */`.
|
|
55
|
+
*/
|
|
56
|
+
sectionComment?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Prefixes, in priority order, used to find where to insert. The block is
|
|
59
|
+
* placed after the last declaration whose name starts with one of these.
|
|
60
|
+
* Falls back to just before the closing brace of the first `:root` block.
|
|
61
|
+
*/
|
|
62
|
+
anchorPrefixes?: string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Insert any missing tokens from `entries` as one contiguous block. Tokens that
|
|
66
|
+
* already exist (by name) are left as-is. Returns the source unchanged when
|
|
67
|
+
* every entry is already present.
|
|
68
|
+
*/
|
|
69
|
+
declare function ensureScale(css: string, opts: EnsureScaleOptions): string;
|
|
70
|
+
/**
|
|
71
|
+
* Rename a token: rewrites its declaration and every `var()` reference to it.
|
|
72
|
+
* No-op unless the old name is present and the new name is absent (so a
|
|
73
|
+
* half-applied rename, or a re-run, leaves the file alone).
|
|
74
|
+
*/
|
|
75
|
+
declare function renameToken(css: string, oldName: string, newName: string): string;
|
|
76
|
+
/** Remove a token's declaration line. No-op when the name isn't declared. */
|
|
77
|
+
declare function removeToken(css: string, name: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Remove every custom-property declaration whose name satisfies `predicate`.
|
|
80
|
+
* Operates line-by-line (tokens.css is one declaration per line), so only the
|
|
81
|
+
* matched declarations are dropped — surrounding comments and structure stay.
|
|
82
|
+
* No-op when nothing matches. Use for retiring a whole retired namespace.
|
|
83
|
+
*/
|
|
84
|
+
declare function removeTokensMatching(css: string, predicate: (name: string) => boolean): string;
|
|
85
|
+
|
|
86
|
+
interface LiveTokensFileConfig {
|
|
87
|
+
dataDir?: string;
|
|
88
|
+
themesDir?: string;
|
|
89
|
+
componentConfigsDir?: string;
|
|
90
|
+
manifestsDir?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Path to the developer-authored `tokens.css`. The dev plugin takes this from
|
|
93
|
+
* its `themeFileApi({ tokensCssPath })` option; the standalone `live-tokens
|
|
94
|
+
* migrate` CLI has no plugin options, so it reads this key to locate the file.
|
|
95
|
+
*/
|
|
96
|
+
tokensCssPath?: string;
|
|
97
|
+
}
|
|
98
|
+
declare function readLiveTokensConfig(): LiveTokensFileConfig;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Registered tokens-css migrations, applied in array order. Unlike the
|
|
102
|
+
* versioned data-file migrations, ordering here is explicit (chronological) and
|
|
103
|
+
* every migration is idempotent, so the runner simply folds them left-to-right.
|
|
104
|
+
*/
|
|
105
|
+
declare const TOKENS_CSS_MIGRATIONS: TokensCssMigration[];
|
|
106
|
+
interface RunResult {
|
|
107
|
+
/** The migrated source (identical to input when nothing changed). */
|
|
108
|
+
css: string;
|
|
109
|
+
/** ids of migrations whose `apply` actually changed the source. */
|
|
110
|
+
applied: string[];
|
|
111
|
+
/** True when `css` differs from the input. */
|
|
112
|
+
changed: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** Fold every registered migration over `css`. Pure and idempotent. */
|
|
115
|
+
declare function runTokensCssMigrations(css: string): RunResult;
|
|
116
|
+
interface ComponentSource {
|
|
117
|
+
name: string;
|
|
118
|
+
source: string;
|
|
119
|
+
}
|
|
120
|
+
interface MissingToken {
|
|
121
|
+
/** The undefined `--token` a component references. */
|
|
122
|
+
token: string;
|
|
123
|
+
/** Component names whose `:global(:root)` block references it. */
|
|
124
|
+
referencedBy: string[];
|
|
125
|
+
}
|
|
126
|
+
interface ValidateInput {
|
|
127
|
+
/** Contents of the consumer's developer-authored `tokens.css`. */
|
|
128
|
+
tokensCss: string;
|
|
129
|
+
/** Contents of the editor-owned `tokens.generated.css`, if present. */
|
|
130
|
+
generatedCss?: string;
|
|
131
|
+
/** Component `.svelte` sources to scan for `:global(:root)` references. */
|
|
132
|
+
componentSources: ComponentSource[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Find primitives that components reference but the runtime never defines.
|
|
136
|
+
*
|
|
137
|
+
* "Defined" is the union of: tokens declared in `tokens.css`, in the generated
|
|
138
|
+
* sidecar, and in any component's own `:global(:root)` block (so component →
|
|
139
|
+
* component references don't false-positive). Anything referenced but not in
|
|
140
|
+
* that union is drift — the symptom the consumer sees as blank editor slots.
|
|
141
|
+
*/
|
|
142
|
+
declare function validateTokensCss(input: ValidateInput): MissingToken[];
|
|
143
|
+
|
|
144
|
+
export { type ComponentSource, type MissingToken, type RunResult, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, ensureScale, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runTokensCssMigrations, validateTokensCss };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TOKENS_CSS_MIGRATIONS,
|
|
3
|
+
collectDefinedTokens,
|
|
4
|
+
collectReferencedTokens,
|
|
5
|
+
ensureScale,
|
|
6
|
+
readLiveTokensConfig,
|
|
7
|
+
removeToken,
|
|
8
|
+
removeTokensMatching,
|
|
9
|
+
renameToken,
|
|
10
|
+
runTokensCssMigrations,
|
|
11
|
+
validateTokensCss
|
|
12
|
+
} from "../chunk-UBS57IYV.js";
|
|
13
|
+
export {
|
|
14
|
+
TOKENS_CSS_MIGRATIONS,
|
|
15
|
+
collectDefinedTokens,
|
|
16
|
+
collectReferencedTokens,
|
|
17
|
+
ensureScale,
|
|
18
|
+
readLiveTokensConfig,
|
|
19
|
+
removeToken,
|
|
20
|
+
removeTokensMatching,
|
|
21
|
+
renameToken,
|
|
22
|
+
runTokensCssMigrations,
|
|
23
|
+
validateTokensCss
|
|
24
|
+
};
|