@motion-proto/live-tokens 0.74.0 → 0.76.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/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
- package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
- package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
- package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
- package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
- package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
- package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
- package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
- package/.claude/skills/live-tokens-create-theme/SKILL.md +52 -48
- package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
- package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
- package/.claude/skills/live-tokens-set-colors/SKILL.md +47 -38
- package/.claude/skills/live-tokens-set-geometry/SKILL.md +58 -35
- package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +5 -3
- package/.claude/skills/live-tokens-set-type/SKILL.md +30 -30
- package/CHANGELOG.md +138 -0
- package/README.md +17 -7
- package/bin/check-component.mjs +91 -19
- package/bin/check-page.mjs +102 -21
- package/bin/cli.mjs +87 -113
- package/bin/contractRunner.mjs +945 -0
- package/bin/create.mjs +1 -1
- package/bin/lib/catalogue.mjs +37 -30
- package/bin/lib/findings.mjs +46 -15
- package/bin/lib/report.mjs +3 -3
- package/bin/lib/tokenVocabulary.mjs +4 -4
- package/bin/migrate-routes.mjs +5 -5
- package/bin/migrate.mjs +4 -4
- package/bin/save-theme.mjs +8 -9
- package/bin/set-colors.mjs +9 -11
- package/bin/set-geometry.mjs +7 -7
- package/bin/set-type.mjs +5 -7
- package/bin/setup-claude.mjs +110 -0
- package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
- package/dist-plugin/{chunk-7VRTBGJT.js → chunk-PDNL4NC5.js} +9 -2
- package/dist-plugin/{chunk-V3YF6CGT.js → chunk-SWXRVZKT.js} +43 -1
- package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.cts} +1 -0
- package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.ts} +1 -0
- package/dist-plugin/index.cjs +310 -147
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +218 -122
- package/dist-plugin/migrateData/index.cjs +66 -2
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +3 -3
- package/dist-plugin/setColors/index.cjs +61 -4
- package/dist-plugin/setColors/index.d.cts +1 -1
- package/dist-plugin/setColors/index.d.ts +1 -1
- package/dist-plugin/setColors/index.js +5 -5
- package/dist-plugin/setGeometry/index.cjs +107 -44
- package/dist-plugin/setGeometry/index.d.cts +5 -5
- package/dist-plugin/setGeometry/index.d.ts +5 -5
- package/dist-plugin/setGeometry/index.js +51 -45
- package/dist-plugin/setType/index.cjs +15 -0
- package/dist-plugin/setType/index.d.cts +1 -1
- package/dist-plugin/setType/index.d.ts +1 -1
- package/dist-plugin/setType/index.js +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +35 -8
- package/src/app/site.css +19 -9
- package/src/editor/bootstrap.ts +2 -0
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
- package/src/editor/component-editor/DialogEditor.svelte +4 -4
- package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
- package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
- package/src/editor/component-editor/TabBarEditor.svelte +1 -1
- package/src/editor/component-editor/TableEditor.svelte +2 -2
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
- package/src/editor/core/components/adjustAliases.ts +59 -45
- package/src/editor/core/components/aliasKinds.ts +9 -5
- package/src/editor/core/preview/themePreview.ts +9 -2
- package/src/editor/core/sketch/sketchLayer.ts +22 -0
- package/src/editor/core/store/editorStore.ts +10 -1
- package/src/editor/core/themes/buildColors.ts +3 -3
- package/src/editor/core/themes/liveStateStream.ts +26 -0
- package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
- package/src/editor/core/themes/migrations/index.ts +2 -0
- package/src/editor/core/themes/themeDocumentSync.ts +22 -11
- package/src/editor/core/themes/themeService.ts +9 -2
- package/src/editor/pages/ComponentEditorPage.svelte +17 -1
- package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
- package/src/editor/skill-atlas/SkillAtlas.svelte +75 -573
- package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
- package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
- package/src/editor/skill-atlas/edges.ts +31 -0
- package/src/editor/skill-atlas/skillSources.generated.ts +20 -19
- package/src/editor/skill-atlas/skillTrees.ts +19 -3840
- package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
- package/src/editor/skill-atlas/trees/create-component.ts +275 -0
- package/src/editor/skill-atlas/trees/create-page.ts +320 -0
- package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
- package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
- package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
- package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
- package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
- package/src/editor/skill-atlas/trees/set-type.ts +142 -0
- package/src/editor/skill-atlas/types.ts +3 -4
- package/src/editor/skill-atlas/wireLayout.ts +287 -0
- package/src/live-tokens/data/themes/autumn.json +15 -15
- package/src/live-tokens/data/themes/halloween.json +15 -15
- package/src/live-tokens/data/themes/midnight-study.json +15 -15
- package/src/live-tokens/data/themes/ocean.json +15 -15
- package/src/live-tokens/data/themes/royal-velvet.json +15 -15
- package/src/live-tokens/data/themes/sketchy.json +15 -15
- package/src/live-tokens/data/themes/spring-meadow.json +15 -15
- package/src/live-tokens/data/themes/sunset.json +15 -15
- package/src/system/components/Badge.svelte +7 -0
- package/src/system/components/Button.svelte +7 -0
- package/src/system/components/Callout.svelte +10 -6
- package/src/system/components/Card.svelte +23 -4
- package/src/system/components/CodeSnippet.svelte +4 -3
- package/src/system/components/CollapsibleSection.svelte +23 -8
- package/src/system/components/CornerBadge.svelte +6 -0
- package/src/system/components/Dialog.svelte +13 -6
- package/src/system/components/IconButton.svelte +9 -0
- package/src/system/components/Image.svelte +8 -0
- package/src/system/components/ImageLightbox.svelte +6 -0
- package/src/system/components/InlineEditActions.svelte +7 -0
- package/src/system/components/Input.svelte +7 -0
- package/src/system/components/MenuSelect.svelte +7 -0
- package/src/system/components/Notification.svelte +7 -0
- package/src/system/components/Panel.svelte +6 -0
- package/src/system/components/ProgressBar.svelte +5 -0
- package/src/system/components/RadioButton.svelte +11 -5
- package/src/system/components/SectionDivider.svelte +8 -0
- package/src/system/components/SegmentedControl.svelte +6 -0
- package/src/system/components/SideNavigation.svelte +6 -0
- package/src/system/components/Slider.svelte +7 -4
- package/src/system/components/TabBar.svelte +15 -9
- package/src/system/components/Table.svelte +8 -3
- package/src/system/components/Toggle.svelte +4 -4
- package/src/system/components/Tooltip.svelte +6 -0
- package/src/testing-js/chunk-AO7EZHYV.js +776 -0
- package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
- package/src/testing-js/chunk-FAFOAWYL.js +39 -0
- package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
- package/src/testing-js/chunk-L73N4NSO.js +23 -0
- package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
- package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
- package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
- package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
- package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
- package/src/testing-js/component-alias.contract.js +81 -0
- package/src/testing-js/component-alias.contract.js.map +1 -0
- package/src/testing-js/component-editor.contract.js +62 -0
- package/src/testing-js/component-editor.contract.js.map +1 -0
- package/src/testing-js/component-render.contract.js +568 -0
- package/src/testing-js/component-render.contract.js.map +1 -0
- package/src/testing-js/index.d.ts +293 -0
- package/src/testing-js/index.js +222 -0
- package/src/testing-js/index.js.map +1 -0
- package/src/testing-js/registry.contract.js +39 -0
- package/src/testing-js/registry.contract.js.map +1 -0
- package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
- package/src/testing-js/vitest.d.ts +3 -0
- package/src/testing-js/vitest.js +13 -0
- package/src/testing-js/vitest.js.map +1 -0
- package/template/README.md +13 -0
- package/template/_gitignore +6 -0
- package/template/package.json +3 -1
- package/template/src/pages/Home.svelte +4 -18
- package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
- package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
package/dist-plugin/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
nextAvailableName,
|
|
6
6
|
normalizeTheme,
|
|
7
7
|
versionedFileResourceServer
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PDNL4NC5.js";
|
|
9
9
|
import {
|
|
10
10
|
formatGradientValue,
|
|
11
11
|
palettesToVars,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-O6GQ6GBH.js";
|
|
17
17
|
import {
|
|
18
18
|
CURRENT_COMPONENT_SCHEMA_VERSION
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SWXRVZKT.js";
|
|
20
20
|
import {
|
|
21
21
|
TOKENS_CSS_MIGRATIONS,
|
|
22
22
|
extractGlobalRootBody,
|
|
@@ -30,12 +30,14 @@ import {
|
|
|
30
30
|
parseOklchCss
|
|
31
31
|
} from "./chunk-7TQQTHI6.js";
|
|
32
32
|
import {
|
|
33
|
-
resolveDataDirs
|
|
34
|
-
|
|
33
|
+
resolveDataDirs,
|
|
34
|
+
testDataDir,
|
|
35
|
+
testPackageDataDir
|
|
36
|
+
} from "./chunk-6WGFOJXO.js";
|
|
35
37
|
|
|
36
38
|
// vite-plugin/themeFileApi.ts
|
|
37
|
-
import
|
|
38
|
-
import
|
|
39
|
+
import fs2 from "fs";
|
|
40
|
+
import path2 from "path";
|
|
39
41
|
|
|
40
42
|
// src/editor/core/themes/migrations/2026-07-21-palette-oklch-basis.ts
|
|
41
43
|
var round = (v, dp) => {
|
|
@@ -166,18 +168,79 @@ async function dispatch(req, res, routes) {
|
|
|
166
168
|
return false;
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
// vite-plugin/files/dataTreeWatch.ts
|
|
172
|
+
import fs from "fs";
|
|
173
|
+
import path from "path";
|
|
174
|
+
function fingerprint(file) {
|
|
175
|
+
try {
|
|
176
|
+
return fs.readFileSync(file, "utf-8");
|
|
177
|
+
} catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function dataTreeWatch(opts) {
|
|
182
|
+
const debounceMs = opts.debounceMs ?? 100;
|
|
183
|
+
const ownWrites = /* @__PURE__ */ new Map();
|
|
184
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
185
|
+
let watchers = [];
|
|
186
|
+
let timer = null;
|
|
187
|
+
function noteOwnWrite(file) {
|
|
188
|
+
const resolved = path.resolve(file);
|
|
189
|
+
ownWrites.set(resolved, fingerprint(resolved));
|
|
190
|
+
}
|
|
191
|
+
function onEvent(dir, filename) {
|
|
192
|
+
if (!filename) return;
|
|
193
|
+
const file = path.resolve(dir, filename.toString());
|
|
194
|
+
if (!opts.isLive(file)) return;
|
|
195
|
+
if (ownWrites.has(file) && ownWrites.get(file) === fingerprint(file)) return;
|
|
196
|
+
ownWrites.delete(file);
|
|
197
|
+
if (timer) clearTimeout(timer);
|
|
198
|
+
timer = setTimeout(() => {
|
|
199
|
+
timer = null;
|
|
200
|
+
for (const listener of listeners) listener();
|
|
201
|
+
}, debounceMs);
|
|
202
|
+
}
|
|
203
|
+
function start() {
|
|
204
|
+
for (const dir of opts.dirs) {
|
|
205
|
+
if (!fs.existsSync(dir)) continue;
|
|
206
|
+
const watcher = fs.watch(
|
|
207
|
+
dir,
|
|
208
|
+
{ recursive: true, persistent: false },
|
|
209
|
+
(_event, filename) => onEvent(dir, filename)
|
|
210
|
+
);
|
|
211
|
+
watcher.on("error", () => watcher.close());
|
|
212
|
+
watchers.push(watcher);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function stop() {
|
|
216
|
+
for (const watcher of watchers) watcher.close();
|
|
217
|
+
watchers = [];
|
|
218
|
+
if (timer) clearTimeout(timer);
|
|
219
|
+
timer = null;
|
|
220
|
+
}
|
|
221
|
+
function subscribe(listener) {
|
|
222
|
+
if (listeners.size === 0) start();
|
|
223
|
+
listeners.add(listener);
|
|
224
|
+
return () => {
|
|
225
|
+
listeners.delete(listener);
|
|
226
|
+
if (listeners.size === 0) stop();
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return { noteOwnWrite, subscribe };
|
|
230
|
+
}
|
|
231
|
+
|
|
169
232
|
// vite-plugin/themeFileApi.ts
|
|
170
233
|
import { fileURLToPath } from "url";
|
|
171
234
|
var PKG_VERSION = (() => {
|
|
172
235
|
try {
|
|
173
|
-
let dir =
|
|
236
|
+
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
174
237
|
for (let i = 0; i < 4; i++) {
|
|
175
|
-
const p =
|
|
176
|
-
if (
|
|
177
|
-
const json = JSON.parse(
|
|
238
|
+
const p = path2.join(dir, "package.json");
|
|
239
|
+
if (fs2.existsSync(p)) {
|
|
240
|
+
const json = JSON.parse(fs2.readFileSync(p, "utf-8"));
|
|
178
241
|
if (json?.name === "@motion-proto/live-tokens") return json.version ?? "";
|
|
179
242
|
}
|
|
180
|
-
const up =
|
|
243
|
+
const up = path2.dirname(dir);
|
|
181
244
|
if (up === dir) break;
|
|
182
245
|
dir = up;
|
|
183
246
|
}
|
|
@@ -221,56 +284,64 @@ function themeFileApi(opts) {
|
|
|
221
284
|
const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
|
|
222
285
|
const THEMES_DIR = dataDirs.themesDir;
|
|
223
286
|
const SKETCH_STYLES_DIR = dataDirs.sketchStylesDir;
|
|
224
|
-
const CSS_PATH =
|
|
225
|
-
const
|
|
226
|
-
const
|
|
287
|
+
const CSS_PATH = path2.resolve(opts.tokensCssPath);
|
|
288
|
+
const ISOLATED_DATA_DIR = testDataDir();
|
|
289
|
+
const GENERATED_CSS_PATH = ISOLATED_DATA_DIR ? path2.join(ISOLATED_DATA_DIR, "tokens.generated.css") : opts.tokensGeneratedCssPath ? path2.resolve(opts.tokensGeneratedCssPath) : path2.join(dataDirs.dataDir, "tokens.generated.css");
|
|
290
|
+
const FONTS_CSS_PATH = ISOLATED_DATA_DIR ? path2.join(ISOLATED_DATA_DIR, "fonts.css") : opts.fontsCssPath ? path2.resolve(opts.fontsCssPath) : path2.join(path2.dirname(CSS_PATH), "fonts.css");
|
|
227
291
|
const API_BASE = opts.apiBase ?? "/api/live-tokens";
|
|
228
|
-
const consumerComponentDirs = opts.componentsSrcDir ? [
|
|
229
|
-
const packageComponentsDir =
|
|
230
|
-
|
|
292
|
+
const consumerComponentDirs = opts.componentsSrcDir ? [path2.resolve(opts.componentsSrcDir)] : [path2.resolve("src/components"), path2.resolve("src/system/components")];
|
|
293
|
+
const packageComponentsDir = path2.resolve(
|
|
294
|
+
path2.dirname(fileURLToPath(import.meta.url)),
|
|
231
295
|
"..",
|
|
232
296
|
"src",
|
|
233
297
|
"system",
|
|
234
298
|
"components"
|
|
235
299
|
);
|
|
236
|
-
const packageDataDir =
|
|
237
|
-
|
|
300
|
+
const packageDataDir = testPackageDataDir() ?? path2.resolve(
|
|
301
|
+
path2.dirname(fileURLToPath(import.meta.url)),
|
|
238
302
|
"..",
|
|
239
303
|
"src",
|
|
240
304
|
"live-tokens",
|
|
241
305
|
"data"
|
|
242
306
|
);
|
|
243
|
-
const packageColorsAndTypeDir =
|
|
244
|
-
const packageThemesDir =
|
|
245
|
-
const packageComponentConfigsDir =
|
|
246
|
-
const packageSketchStylesDir =
|
|
307
|
+
const packageColorsAndTypeDir = path2.join(packageDataDir, "colors-and-type");
|
|
308
|
+
const packageThemesDir = path2.join(packageDataDir, "themes");
|
|
309
|
+
const packageComponentConfigsDir = path2.join(packageDataDir, "component-configs");
|
|
310
|
+
const packageSketchStylesDir = path2.join(packageDataDir, "sketch-styles");
|
|
247
311
|
function shippedNames(dataDir, subdir) {
|
|
248
312
|
try {
|
|
249
|
-
const pkgRoot =
|
|
250
|
-
const pkg = JSON.parse(
|
|
313
|
+
const pkgRoot = path2.resolve(dataDir, "..", "..", "..");
|
|
314
|
+
const pkg = JSON.parse(fs2.readFileSync(path2.join(pkgRoot, "package.json"), "utf-8"));
|
|
251
315
|
const files = Array.isArray(pkg.files) ? pkg.files : [];
|
|
252
316
|
const owned = new RegExp(`^src/live-tokens/data/${subdir}/[^/]+\\.json$`);
|
|
253
|
-
return files.filter((f) => owned.test(f)).map((f) =>
|
|
317
|
+
return files.filter((f) => owned.test(f)).map((f) => path2.basename(f, ".json"));
|
|
254
318
|
} catch {
|
|
255
319
|
return [];
|
|
256
320
|
}
|
|
257
321
|
}
|
|
258
322
|
const COMPONENTS_SCAN_DIRS = [...consumerComponentDirs];
|
|
259
|
-
if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) &&
|
|
323
|
+
if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && fs2.existsSync(packageComponentsDir)) {
|
|
260
324
|
COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
|
|
261
325
|
}
|
|
326
|
+
const isLiveStateFile = (file) => file === path2.join(THEMES_DIR, "_active.json") || path2.basename(file) === "_working.json" && (file.startsWith(COLORS_AND_TYPE_DIR + path2.sep) || file.startsWith(COMPONENT_CONFIGS_DIR + path2.sep));
|
|
327
|
+
const liveWatch = dataTreeWatch({
|
|
328
|
+
dirs: [COLORS_AND_TYPE_DIR, COMPONENT_CONFIGS_DIR, THEMES_DIR],
|
|
329
|
+
isLive: isLiveStateFile
|
|
330
|
+
});
|
|
262
331
|
const colorsAndTypeResource = versionedFileResourceServer({
|
|
263
332
|
dir: COLORS_AND_TYPE_DIR,
|
|
264
333
|
packageDir: packageColorsAndTypeDir,
|
|
265
|
-
packageOwnedNames: shippedNames(packageDataDir, "colors-and-type")
|
|
334
|
+
packageOwnedNames: shippedNames(packageDataDir, "colors-and-type"),
|
|
335
|
+
onWrite: liveWatch.noteOwnWrite
|
|
266
336
|
});
|
|
267
337
|
const componentResourceCache = /* @__PURE__ */ new Map();
|
|
268
338
|
function componentResource(comp) {
|
|
269
339
|
let r = componentResourceCache.get(comp);
|
|
270
340
|
if (!r) {
|
|
271
341
|
r = versionedFileResourceServer({
|
|
272
|
-
dir:
|
|
273
|
-
packageDir:
|
|
342
|
+
dir: path2.join(COMPONENT_CONFIGS_DIR, comp),
|
|
343
|
+
packageDir: path2.join(packageComponentConfigsDir, comp),
|
|
344
|
+
onWrite: liveWatch.noteOwnWrite
|
|
274
345
|
});
|
|
275
346
|
componentResourceCache.set(comp, r);
|
|
276
347
|
}
|
|
@@ -278,7 +349,8 @@ function themeFileApi(opts) {
|
|
|
278
349
|
}
|
|
279
350
|
const themesResource = versionedFileResourceServer({
|
|
280
351
|
dir: THEMES_DIR,
|
|
281
|
-
packageDir: packageThemesDir
|
|
352
|
+
packageDir: packageThemesDir,
|
|
353
|
+
onWrite: liveWatch.noteOwnWrite
|
|
282
354
|
});
|
|
283
355
|
const sketchStylesResource = versionedFileResourceServer({
|
|
284
356
|
dir: SKETCH_STYLES_DIR,
|
|
@@ -359,7 +431,7 @@ function themeFileApi(opts) {
|
|
|
359
431
|
const productionThemeName = themesResource.getProductionName();
|
|
360
432
|
const productionTheme = readTheme(productionThemeName)?.theme ?? null;
|
|
361
433
|
if (themesResource.existingPath(productionThemeName) !== null && !productionTheme?.colorsAndType) {
|
|
362
|
-
const tail = `${
|
|
434
|
+
const tail = `${path2.basename(GENERATED_CSS_PATH)} was left as it was.`;
|
|
363
435
|
throw new Error(
|
|
364
436
|
unreadableThemeReason(productionThemeName) === "colors-and-type" ? `[live-tokens] ${notAThemeError(productionThemeName)} ${tail}` : `[live-tokens] Production theme "${productionThemeName}" is unreadable, so ${tail} Repair the theme file or adopt another theme.`
|
|
365
437
|
);
|
|
@@ -397,7 +469,7 @@ function themeFileApi(opts) {
|
|
|
397
469
|
}
|
|
398
470
|
}
|
|
399
471
|
let componentOverrideCount = 0;
|
|
400
|
-
if (
|
|
472
|
+
if (fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
|
|
401
473
|
const blocks = [];
|
|
402
474
|
for (const comp of listComponentNames()) {
|
|
403
475
|
const prodCfg = productionTheme?.componentConfigs[comp];
|
|
@@ -430,12 +502,12 @@ function themeFileApi(opts) {
|
|
|
430
502
|
lines.push("");
|
|
431
503
|
}
|
|
432
504
|
}
|
|
433
|
-
if (!
|
|
434
|
-
|
|
505
|
+
if (!fs2.existsSync(path2.dirname(GENERATED_CSS_PATH))) {
|
|
506
|
+
fs2.mkdirSync(path2.dirname(GENERATED_CSS_PATH), { recursive: true });
|
|
435
507
|
}
|
|
436
|
-
|
|
508
|
+
fs2.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
|
|
437
509
|
console.log(
|
|
438
|
-
`[regenerateTokensCss] Wrote ${
|
|
510
|
+
`[regenerateTokensCss] Wrote ${path2.basename(GENERATED_CSS_PATH)} (${colorsAndTypeVarCount} theme vars, ${componentOverrideCount} component overrides)`
|
|
439
511
|
);
|
|
440
512
|
}
|
|
441
513
|
function syncFontsToCss(colorsAndTypeData) {
|
|
@@ -463,18 +535,18 @@ function themeFileApi(opts) {
|
|
|
463
535
|
lines.push("");
|
|
464
536
|
}
|
|
465
537
|
const content = lines.join("\n");
|
|
466
|
-
if (!
|
|
467
|
-
|
|
538
|
+
if (!fs2.existsSync(path2.dirname(FONTS_CSS_PATH))) {
|
|
539
|
+
fs2.mkdirSync(path2.dirname(FONTS_CSS_PATH), { recursive: true });
|
|
468
540
|
}
|
|
469
|
-
|
|
470
|
-
console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${
|
|
541
|
+
fs2.writeFileSync(FONTS_CSS_PATH, content);
|
|
542
|
+
console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${path2.basename(FONTS_CSS_PATH)}`);
|
|
471
543
|
}
|
|
472
544
|
function componentNameFromFile(filePath) {
|
|
473
|
-
return
|
|
545
|
+
return path2.basename(filePath, ".svelte").toLowerCase();
|
|
474
546
|
}
|
|
475
547
|
function isThemeAwareComponent(filePath) {
|
|
476
548
|
try {
|
|
477
|
-
const source =
|
|
549
|
+
const source = fs2.readFileSync(filePath, "utf-8");
|
|
478
550
|
return /:global\(:root\)\s*\{/.test(source);
|
|
479
551
|
} catch {
|
|
480
552
|
return false;
|
|
@@ -483,10 +555,10 @@ function themeFileApi(opts) {
|
|
|
483
555
|
function listComponentSourcePaths() {
|
|
484
556
|
const byName = /* @__PURE__ */ new Map();
|
|
485
557
|
for (const dir of COMPONENTS_SCAN_DIRS) {
|
|
486
|
-
if (!
|
|
487
|
-
for (const f of
|
|
558
|
+
if (!fs2.existsSync(dir)) continue;
|
|
559
|
+
for (const f of fs2.readdirSync(dir)) {
|
|
488
560
|
if (!f.endsWith(".svelte")) continue;
|
|
489
|
-
const full =
|
|
561
|
+
const full = path2.join(dir, f);
|
|
490
562
|
if (!isThemeAwareComponent(full)) continue;
|
|
491
563
|
const name = componentNameFromFile(f);
|
|
492
564
|
if (!byName.has(name)) byName.set(name, full);
|
|
@@ -500,18 +572,18 @@ function themeFileApi(opts) {
|
|
|
500
572
|
function warnOnTokenDrift(log) {
|
|
501
573
|
let tokensCss = "";
|
|
502
574
|
try {
|
|
503
|
-
tokensCss =
|
|
575
|
+
tokensCss = fs2.readFileSync(CSS_PATH, "utf-8");
|
|
504
576
|
} catch {
|
|
505
577
|
return;
|
|
506
578
|
}
|
|
507
579
|
let generatedCss = "";
|
|
508
580
|
try {
|
|
509
|
-
generatedCss =
|
|
581
|
+
generatedCss = fs2.readFileSync(GENERATED_CSS_PATH, "utf-8");
|
|
510
582
|
} catch {
|
|
511
583
|
}
|
|
512
584
|
const componentSources = listComponentSourcePaths().map((p) => ({
|
|
513
585
|
name: componentNameFromFile(p),
|
|
514
|
-
source:
|
|
586
|
+
source: fs2.readFileSync(p, "utf-8")
|
|
515
587
|
}));
|
|
516
588
|
const missing = validateTokensCss({ tokensCss, generatedCss, componentSources });
|
|
517
589
|
if (missing.length === 0) return;
|
|
@@ -519,7 +591,7 @@ function themeFileApi(opts) {
|
|
|
519
591
|
(m) => ` ${m.token} (referenced by ${m.referencedBy.join(", ")})`
|
|
520
592
|
);
|
|
521
593
|
log(
|
|
522
|
-
`[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${
|
|
594
|
+
`[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${path2.relative(process.cwd(), CSS_PATH)}:
|
|
523
595
|
${lines.join("\n")}
|
|
524
596
|
These render as blank/empty editor slots. Run \`npx live-tokens migrate\` to reconcile.`
|
|
525
597
|
);
|
|
@@ -527,30 +599,30 @@ ${lines.join("\n")}
|
|
|
527
599
|
function autoMigrateAdditive(log) {
|
|
528
600
|
let before = "";
|
|
529
601
|
try {
|
|
530
|
-
before =
|
|
602
|
+
before = fs2.readFileSync(CSS_PATH, "utf-8");
|
|
531
603
|
} catch {
|
|
532
604
|
return;
|
|
533
605
|
}
|
|
534
606
|
const { css, applied, changed } = runAdditiveTokensCssMigrations(before);
|
|
535
607
|
if (!changed) return;
|
|
536
|
-
|
|
608
|
+
fs2.writeFileSync(CSS_PATH, css);
|
|
537
609
|
log(
|
|
538
|
-
`[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${
|
|
610
|
+
`[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${path2.relative(process.cwd(), CSS_PATH)}: ${applied.join(", ")}. Review the diff in git.`
|
|
539
611
|
);
|
|
540
612
|
}
|
|
541
613
|
function generateDefaultConfig(comp, sourcePath) {
|
|
542
|
-
if (!
|
|
614
|
+
if (!fs2.existsSync(sourcePath)) return;
|
|
543
615
|
const r = componentResource(comp);
|
|
544
616
|
r.ensureDir();
|
|
545
617
|
const defaultPath = r.filePath("default");
|
|
546
|
-
const sourceStat =
|
|
618
|
+
const sourceStat = fs2.statSync(sourcePath);
|
|
547
619
|
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
548
620
|
let existingUpdatedAt;
|
|
549
621
|
let existingAliases;
|
|
550
622
|
let existingSchemaVersion;
|
|
551
|
-
if (
|
|
623
|
+
if (fs2.existsSync(defaultPath)) {
|
|
552
624
|
try {
|
|
553
|
-
const existing = JSON.parse(
|
|
625
|
+
const existing = JSON.parse(fs2.readFileSync(defaultPath, "utf-8"));
|
|
554
626
|
if (existing.createdAt) createdAt = existing.createdAt;
|
|
555
627
|
if (typeof existing.updatedAt === "string") existingUpdatedAt = existing.updatedAt;
|
|
556
628
|
if (existing.aliases && typeof existing.aliases === "object") {
|
|
@@ -559,13 +631,13 @@ ${lines.join("\n")}
|
|
|
559
631
|
if (typeof existing.schemaVersion === "number") existingSchemaVersion = existing.schemaVersion;
|
|
560
632
|
} catch {
|
|
561
633
|
}
|
|
562
|
-
const defaultStat =
|
|
634
|
+
const defaultStat = fs2.statSync(defaultPath);
|
|
563
635
|
if (defaultStat.mtimeMs >= sourceStat.mtimeMs && existingSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION) {
|
|
564
636
|
return;
|
|
565
637
|
}
|
|
566
638
|
}
|
|
567
639
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
568
|
-
const source =
|
|
640
|
+
const source = fs2.readFileSync(sourcePath, "utf-8");
|
|
569
641
|
const body = extractGlobalRootBody(source);
|
|
570
642
|
const aliases = extractAliasDeclarations(body);
|
|
571
643
|
const aliasesUnchanged = existingAliases !== void 0 && JSON.stringify(existingAliases) === JSON.stringify(aliases);
|
|
@@ -580,14 +652,14 @@ ${lines.join("\n")}
|
|
|
580
652
|
};
|
|
581
653
|
if (aliasesUnchanged && schemaStampCurrent && existingUpdatedAt) {
|
|
582
654
|
const t = /* @__PURE__ */ new Date();
|
|
583
|
-
|
|
655
|
+
fs2.utimesSync(defaultPath, t, t);
|
|
584
656
|
return;
|
|
585
657
|
}
|
|
586
|
-
|
|
658
|
+
fs2.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
|
|
587
659
|
}
|
|
588
660
|
function ensureComponentConfigsDir() {
|
|
589
|
-
if (!
|
|
590
|
-
|
|
661
|
+
if (!fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
|
|
662
|
+
fs2.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
|
|
591
663
|
}
|
|
592
664
|
for (const sourcePath of listComponentSourcePaths()) {
|
|
593
665
|
const comp = componentNameFromFile(sourcePath);
|
|
@@ -600,14 +672,14 @@ ${lines.join("\n")}
|
|
|
600
672
|
const legacy = [];
|
|
601
673
|
const check = (dir) => {
|
|
602
674
|
for (const name of ["_active.json", "_production.json"]) {
|
|
603
|
-
const p =
|
|
604
|
-
if (
|
|
675
|
+
const p = path2.join(dir, name);
|
|
676
|
+
if (fs2.existsSync(p)) legacy.push(path2.relative(process.cwd(), p));
|
|
605
677
|
}
|
|
606
678
|
};
|
|
607
679
|
check(COLORS_AND_TYPE_DIR);
|
|
608
|
-
if (
|
|
609
|
-
for (const entry of
|
|
610
|
-
if (entry.isDirectory()) check(
|
|
680
|
+
if (fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
|
|
681
|
+
for (const entry of fs2.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
|
|
682
|
+
if (entry.isDirectory()) check(path2.join(COMPONENT_CONFIGS_DIR, entry.name));
|
|
611
683
|
}
|
|
612
684
|
}
|
|
613
685
|
return legacy;
|
|
@@ -615,19 +687,19 @@ ${lines.join("\n")}
|
|
|
615
687
|
function warnOnLegacyPointers(legacy, bakeHeld, warn) {
|
|
616
688
|
if (legacy.length === 0) return;
|
|
617
689
|
warn(
|
|
618
|
-
`[live-tokens] ${legacy.length} legacy pointer file(s) left from the pre-working-set data model, starting with ${legacy[0]}. They are no longer read. Run \`npx live-tokens migrate\` to heal the tree.` + (bakeHeld ? ` Until then this tree has named no production theme, so ${
|
|
690
|
+
`[live-tokens] ${legacy.length} legacy pointer file(s) left from the pre-working-set data model, starting with ${legacy[0]}. They are no longer read. Run \`npx live-tokens migrate\` to heal the tree.` + (bakeHeld ? ` Until then this tree has named no production theme, so ${path2.basename(GENERATED_CSS_PATH)} is left exactly as it is rather than rebuilt from the default.` : "")
|
|
619
691
|
);
|
|
620
692
|
}
|
|
621
693
|
function warnOnLegacyLayout(evidence, warn) {
|
|
622
694
|
warn(
|
|
623
|
-
`[live-tokens] This project still uses the data layout from 0.47 and earlier: ${evidence}. Since 0.48 the whole-theme theme files live in \`themes/\` and the colors and type live in \`colors-and-type/\`. Nothing in the data directory was written, the editor cannot save, and ${
|
|
695
|
+
`[live-tokens] This project still uses the data layout from 0.47 and earlier: ${evidence}. Since 0.48 the whole-theme theme files live in \`themes/\` and the colors and type live in \`colors-and-type/\`. Nothing in the data directory was written, the editor cannot save, and ${path2.basename(GENERATED_CSS_PATH)} is left exactly as it is. Run \`npx live-tokens migrate\` to move the directories and heal the tree, then restart the dev server.`
|
|
624
696
|
);
|
|
625
697
|
}
|
|
626
698
|
function warnOnUnmigratedSketchStyles(warn) {
|
|
627
|
-
const legacyDir =
|
|
628
|
-
if (!
|
|
699
|
+
const legacyDir = path2.join(dataDirs.dataDir, "sketch-presets");
|
|
700
|
+
if (!fs2.existsSync(legacyDir)) return;
|
|
629
701
|
warn(
|
|
630
|
-
`[live-tokens] Saved sketchstyles still live under the retired ${
|
|
702
|
+
`[live-tokens] Saved sketchstyles still live under the retired ${path2.basename(legacyDir)}/ directory name. Run \`npx live-tokens migrate\` to rename it to ${path2.basename(SKETCH_STYLES_DIR)}/; until then they will not show up in the Sketchstyle view.`
|
|
631
703
|
);
|
|
632
704
|
}
|
|
633
705
|
const diskThemeResolvers = {
|
|
@@ -651,7 +723,7 @@ ${lines.join("\n")}
|
|
|
651
723
|
const resolved = themesResource.existingPath(fileName);
|
|
652
724
|
if (resolved === null) return "missing";
|
|
653
725
|
try {
|
|
654
|
-
if (isColorsAndTypeShaped(JSON.parse(
|
|
726
|
+
if (isColorsAndTypeShaped(JSON.parse(fs2.readFileSync(resolved, "utf-8")))) {
|
|
655
727
|
return "colors-and-type";
|
|
656
728
|
}
|
|
657
729
|
} catch {
|
|
@@ -659,7 +731,7 @@ ${lines.join("\n")}
|
|
|
659
731
|
return "corrupt";
|
|
660
732
|
}
|
|
661
733
|
function notAThemeError(fileName) {
|
|
662
|
-
return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${
|
|
734
|
+
return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${path2.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme skill "create-theme".`;
|
|
663
735
|
}
|
|
664
736
|
function respondUnreadableTheme(res, fileName, missingError) {
|
|
665
737
|
switch (unreadableThemeReason(fileName)) {
|
|
@@ -678,18 +750,18 @@ ${lines.join("\n")}
|
|
|
678
750
|
}
|
|
679
751
|
function writeTheme(fileName, theme) {
|
|
680
752
|
themesResource.ensureDir();
|
|
681
|
-
|
|
753
|
+
fs2.writeFileSync(themesResource.filePath(fileName), JSON.stringify(theme, null, 2));
|
|
682
754
|
}
|
|
683
755
|
function migrateLocalThemes(warn) {
|
|
684
|
-
if (
|
|
685
|
-
if (!
|
|
686
|
-
for (const file of
|
|
756
|
+
if (path2.resolve(THEMES_DIR) === path2.resolve(packageThemesDir)) return;
|
|
757
|
+
if (!fs2.existsSync(THEMES_DIR)) return;
|
|
758
|
+
for (const file of fs2.readdirSync(THEMES_DIR)) {
|
|
687
759
|
if (!file.endsWith(".json") || file.startsWith("_")) continue;
|
|
688
760
|
const fileName = file.slice(0, -".json".length);
|
|
689
761
|
if (fileName === "default") continue;
|
|
690
762
|
let raw;
|
|
691
763
|
try {
|
|
692
|
-
raw = JSON.parse(
|
|
764
|
+
raw = JSON.parse(fs2.readFileSync(path2.join(THEMES_DIR, file), "utf-8"));
|
|
693
765
|
} catch {
|
|
694
766
|
continue;
|
|
695
767
|
}
|
|
@@ -710,7 +782,7 @@ ${lines.join("\n")}
|
|
|
710
782
|
function ensureDefaultTheme(warn) {
|
|
711
783
|
let existing = null;
|
|
712
784
|
try {
|
|
713
|
-
existing = JSON.parse(
|
|
785
|
+
existing = JSON.parse(fs2.readFileSync(themesResource.filePath("default"), "utf-8"));
|
|
714
786
|
} catch {
|
|
715
787
|
}
|
|
716
788
|
if (isColorsAndTypeShaped(existing)) {
|
|
@@ -747,9 +819,9 @@ ${lines.join("\n")}
|
|
|
747
819
|
themesResource.ensureDir();
|
|
748
820
|
ensureDefaultTheme(warn);
|
|
749
821
|
migrateLocalThemes(warn);
|
|
750
|
-
const productionPointerHeld = !
|
|
822
|
+
const productionPointerHeld = !fs2.existsSync(themesResource.productionPath) && listLegacyPointers().length > 0;
|
|
751
823
|
if (productionPointerHeld) {
|
|
752
|
-
if (!
|
|
824
|
+
if (!fs2.existsSync(themesResource.activePath)) themesResource.setActiveName("default");
|
|
753
825
|
} else {
|
|
754
826
|
themesResource.ensureMeta();
|
|
755
827
|
}
|
|
@@ -828,8 +900,8 @@ ${lines.join("\n")}
|
|
|
828
900
|
}
|
|
829
901
|
function clearAllWorking() {
|
|
830
902
|
colorsAndTypeResource.clearWorking();
|
|
831
|
-
if (!
|
|
832
|
-
for (const entry of
|
|
903
|
+
if (!fs2.existsSync(COMPONENT_CONFIGS_DIR)) return;
|
|
904
|
+
for (const entry of fs2.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
|
|
833
905
|
if (entry.isDirectory()) componentResource(entry.name).clearWorking();
|
|
834
906
|
}
|
|
835
907
|
}
|
|
@@ -872,6 +944,7 @@ ${lines.join("\n")}
|
|
|
872
944
|
const SKETCH_STYLES_ROUTE = `${API_BASE}/sketch-styles`;
|
|
873
945
|
const SKETCH_STYLE_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-styles/([a-z0-9\\-_]+)$`);
|
|
874
946
|
const PRODUCTION_ROUTE = `${API_BASE}/production`;
|
|
947
|
+
const EVENTS_ROUTE = `${API_BASE}/events`;
|
|
875
948
|
async function handleListColorsAndType(_ctx) {
|
|
876
949
|
const files = colorsAndTypeResource.listNames().map((fileName) => {
|
|
877
950
|
const data = colorsAndTypeResource.readJson(fileName);
|
|
@@ -956,15 +1029,15 @@ ${lines.join("\n")}
|
|
|
956
1029
|
}
|
|
957
1030
|
const body = JSON.parse(await readBody(req));
|
|
958
1031
|
body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
959
|
-
if (
|
|
1032
|
+
if (fs2.existsSync(filePath)) {
|
|
960
1033
|
try {
|
|
961
|
-
const existing = JSON.parse(
|
|
1034
|
+
const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
962
1035
|
if (existing.createdAt) body.createdAt = existing.createdAt;
|
|
963
1036
|
} catch {
|
|
964
1037
|
}
|
|
965
1038
|
}
|
|
966
1039
|
if (!body.createdAt) body.createdAt = body.updatedAt;
|
|
967
|
-
|
|
1040
|
+
fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
|
|
968
1041
|
jsonResponse(res, 200, { ok: true, fileName });
|
|
969
1042
|
return;
|
|
970
1043
|
}
|
|
@@ -973,8 +1046,8 @@ ${lines.join("\n")}
|
|
|
973
1046
|
jsonResponse(res, 403, { error: "Cannot delete the default colors and type" });
|
|
974
1047
|
return;
|
|
975
1048
|
}
|
|
976
|
-
if (
|
|
977
|
-
|
|
1049
|
+
if (fs2.existsSync(filePath)) {
|
|
1050
|
+
fs2.unlinkSync(filePath);
|
|
978
1051
|
} else if (colorsAndTypeResource.existingPath(fileName)) {
|
|
979
1052
|
jsonResponse(res, 403, {
|
|
980
1053
|
error: "Cannot delete colors and type shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
|
|
@@ -1061,16 +1134,16 @@ ${lines.join("\n")}
|
|
|
1061
1134
|
body.component = comp;
|
|
1062
1135
|
body.name = body.name || name;
|
|
1063
1136
|
body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1064
|
-
if (
|
|
1137
|
+
if (fs2.existsSync(configPath)) {
|
|
1065
1138
|
try {
|
|
1066
|
-
const existing = JSON.parse(
|
|
1139
|
+
const existing = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
1067
1140
|
if (existing.createdAt) body.createdAt = existing.createdAt;
|
|
1068
1141
|
} catch {
|
|
1069
1142
|
}
|
|
1070
1143
|
}
|
|
1071
1144
|
if (!body.createdAt) body.createdAt = body.updatedAt;
|
|
1072
1145
|
r.ensureDir();
|
|
1073
|
-
|
|
1146
|
+
fs2.writeFileSync(configPath, JSON.stringify(body, null, 2));
|
|
1074
1147
|
jsonResponse(res, 200, { ok: true, fileName: name });
|
|
1075
1148
|
return;
|
|
1076
1149
|
}
|
|
@@ -1079,7 +1152,7 @@ ${lines.join("\n")}
|
|
|
1079
1152
|
jsonResponse(res, 403, { error: "Cannot delete default config" });
|
|
1080
1153
|
return;
|
|
1081
1154
|
}
|
|
1082
|
-
if (
|
|
1155
|
+
if (fs2.existsSync(configPath)) fs2.unlinkSync(configPath);
|
|
1083
1156
|
jsonResponse(res, 200, { ok: true });
|
|
1084
1157
|
return;
|
|
1085
1158
|
}
|
|
@@ -1087,7 +1160,7 @@ ${lines.join("\n")}
|
|
|
1087
1160
|
async function handleListComponentConfigs({ params, res }) {
|
|
1088
1161
|
const [comp] = params;
|
|
1089
1162
|
const r = componentResource(comp);
|
|
1090
|
-
if (!
|
|
1163
|
+
if (!fs2.existsSync(r.dir)) {
|
|
1091
1164
|
jsonResponse(res, 404, { error: "Component not found" });
|
|
1092
1165
|
return;
|
|
1093
1166
|
}
|
|
@@ -1175,9 +1248,9 @@ ${lines.join("\n")}
|
|
|
1175
1248
|
const body = JSON.parse(await readBody(req));
|
|
1176
1249
|
const { theme } = normalizeTheme(body, diskThemeResolvers);
|
|
1177
1250
|
theme.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1178
|
-
if (
|
|
1251
|
+
if (fs2.existsSync(filePath)) {
|
|
1179
1252
|
try {
|
|
1180
|
-
const existing = JSON.parse(
|
|
1253
|
+
const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
1181
1254
|
if (existing.createdAt) theme.createdAt = existing.createdAt;
|
|
1182
1255
|
} catch {
|
|
1183
1256
|
}
|
|
@@ -1199,7 +1272,7 @@ ${lines.join("\n")}
|
|
|
1199
1272
|
});
|
|
1200
1273
|
return;
|
|
1201
1274
|
}
|
|
1202
|
-
if (
|
|
1275
|
+
if (fs2.existsSync(filePath)) {
|
|
1203
1276
|
const deletingActive = themesResource.getActiveName() === fileName;
|
|
1204
1277
|
const liveColors = deletingActive ? resolveLiveColorsAndType(activeTheme()) : null;
|
|
1205
1278
|
const liveComponents = {};
|
|
@@ -1209,7 +1282,7 @@ ${lines.join("\n")}
|
|
|
1209
1282
|
if (resolved) liveComponents[comp] = resolved.data;
|
|
1210
1283
|
}
|
|
1211
1284
|
}
|
|
1212
|
-
|
|
1285
|
+
fs2.unlinkSync(filePath);
|
|
1213
1286
|
if (themesResource.existingPath(fileName) === null && deletingActive) {
|
|
1214
1287
|
themesResource.setActiveName("default");
|
|
1215
1288
|
}
|
|
@@ -1256,30 +1329,50 @@ ${lines.join("\n")}
|
|
|
1256
1329
|
return;
|
|
1257
1330
|
}
|
|
1258
1331
|
clearAllWorking();
|
|
1259
|
-
const knownComponents = listComponentNames();
|
|
1260
1332
|
themesResource.setActiveName(fileName);
|
|
1261
|
-
const
|
|
1262
|
-
for (const comp of knownComponents) {
|
|
1263
|
-
const resolved = resolveLiveComponentConfig(comp, theme);
|
|
1264
|
-
if (resolved) resolvedConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
|
|
1265
|
-
}
|
|
1266
|
-
const resolvedColorsAndType = resolveLiveColorsAndType(theme);
|
|
1333
|
+
const knownComponents = listComponentNames();
|
|
1267
1334
|
const skippedComponents = Object.keys(theme.componentConfigs).filter(
|
|
1268
1335
|
(comp) => !knownComponents.includes(comp)
|
|
1269
1336
|
);
|
|
1270
1337
|
jsonResponse(res, 200, {
|
|
1271
1338
|
ok: true,
|
|
1272
|
-
|
|
1273
|
-
colorsAndType: resolvedColorsAndType && {
|
|
1274
|
-
...resolvedColorsAndType.data,
|
|
1275
|
-
_fileName: fileName,
|
|
1276
|
-
_source: resolvedColorsAndType.source
|
|
1277
|
-
},
|
|
1278
|
-
componentConfigs: resolvedConfigs,
|
|
1339
|
+
...resolveLiveState(theme, fileName),
|
|
1279
1340
|
skippedComponents,
|
|
1280
1341
|
filled
|
|
1281
1342
|
});
|
|
1282
1343
|
}
|
|
1344
|
+
function resolveLiveState(theme, fileName) {
|
|
1345
|
+
const componentConfigs = {};
|
|
1346
|
+
for (const comp of listComponentNames()) {
|
|
1347
|
+
const resolved = resolveLiveComponentConfig(comp, theme);
|
|
1348
|
+
if (resolved) componentConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
|
|
1349
|
+
}
|
|
1350
|
+
const colorsAndType = resolveLiveColorsAndType(theme);
|
|
1351
|
+
return {
|
|
1352
|
+
fileName,
|
|
1353
|
+
theme: { ...theme, _fileName: fileName },
|
|
1354
|
+
colorsAndType: colorsAndType && { ...colorsAndType.data, _fileName: fileName, _source: colorsAndType.source },
|
|
1355
|
+
componentConfigs
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
async function handleEvents({ req, res }) {
|
|
1359
|
+
res.statusCode = 200;
|
|
1360
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
1361
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
1362
|
+
res.setHeader("Connection", "keep-alive");
|
|
1363
|
+
res.write(": connected\n\n");
|
|
1364
|
+
const unsubscribe = liveWatch.subscribe(() => {
|
|
1365
|
+
const activeFile = themesResource.getActiveName();
|
|
1366
|
+
const read = readTheme(activeFile);
|
|
1367
|
+
if (!read) return;
|
|
1368
|
+
const state = resolveLiveState(read.theme, activeFile);
|
|
1369
|
+
res.write(`event: live-state
|
|
1370
|
+
data: ${JSON.stringify(state)}
|
|
1371
|
+
|
|
1372
|
+
`);
|
|
1373
|
+
});
|
|
1374
|
+
req.on("close", unsubscribe);
|
|
1375
|
+
}
|
|
1283
1376
|
async function handleExportTheme({ params, res }) {
|
|
1284
1377
|
const [fileName] = params;
|
|
1285
1378
|
if (rejectReservedName(res, fileName)) return;
|
|
@@ -1440,22 +1533,22 @@ ${lines.join("\n")}
|
|
|
1440
1533
|
}
|
|
1441
1534
|
body.name = String(body.name || fileName);
|
|
1442
1535
|
body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1443
|
-
if (
|
|
1536
|
+
if (fs2.existsSync(filePath)) {
|
|
1444
1537
|
try {
|
|
1445
|
-
const existing = JSON.parse(
|
|
1538
|
+
const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
1446
1539
|
if (existing.createdAt) body.createdAt = existing.createdAt;
|
|
1447
1540
|
} catch {
|
|
1448
1541
|
}
|
|
1449
1542
|
}
|
|
1450
1543
|
if (!body.createdAt) body.createdAt = body.updatedAt;
|
|
1451
1544
|
sketchStylesResource.ensureDir();
|
|
1452
|
-
|
|
1545
|
+
fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
|
|
1453
1546
|
jsonResponse(res, 200, { ok: true, fileName });
|
|
1454
1547
|
return;
|
|
1455
1548
|
}
|
|
1456
1549
|
if (req.method === "DELETE") {
|
|
1457
|
-
if (
|
|
1458
|
-
|
|
1550
|
+
if (fs2.existsSync(filePath)) {
|
|
1551
|
+
fs2.unlinkSync(filePath);
|
|
1459
1552
|
} else if (sketchStylesResource.existingPath(fileName)) {
|
|
1460
1553
|
jsonResponse(res, 403, {
|
|
1461
1554
|
error: "Cannot delete a sketchstyle shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
|
|
@@ -1551,12 +1644,13 @@ ${lines.join("\n")}
|
|
|
1551
1644
|
{ method: "PUT", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
|
|
1552
1645
|
{ method: "DELETE", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
|
|
1553
1646
|
{ method: "POST", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: methodNotAllowed },
|
|
1647
|
+
{ method: "GET", pattern: EVENTS_ROUTE, handler: handleEvents },
|
|
1554
1648
|
{ method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptTheme },
|
|
1555
1649
|
{ method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
|
|
1556
1650
|
{ method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
|
|
1557
1651
|
{ method: "DELETE", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed }
|
|
1558
1652
|
];
|
|
1559
|
-
const isEditorOwnedJson = (file) => file.endsWith(".json") &&
|
|
1653
|
+
const isEditorOwnedJson = (file) => file.endsWith(".json") && path2.resolve(file).startsWith(dataDirs.dataDir + path2.sep);
|
|
1560
1654
|
return {
|
|
1561
1655
|
name: "theme-file-api",
|
|
1562
1656
|
config() {
|
|
@@ -1584,8 +1678,10 @@ ${lines.join("\n")}
|
|
|
1584
1678
|
const { productionPointerHeld } = ensureThemesDir((msg) => server.config.logger.warn(msg));
|
|
1585
1679
|
const openTheme = activeTheme();
|
|
1586
1680
|
if (openTheme) pruneMatchingWorking(openTheme);
|
|
1587
|
-
if (!productionPointerHeld || !
|
|
1588
|
-
if (opts.autoMigrate
|
|
1681
|
+
if (!productionPointerHeld || !fs2.existsSync(GENERATED_CSS_PATH)) regenerateTokensCss();
|
|
1682
|
+
if (opts.autoMigrate && !ISOLATED_DATA_DIR) {
|
|
1683
|
+
autoMigrateAdditive((msg) => server.config.logger.info(msg));
|
|
1684
|
+
}
|
|
1589
1685
|
warnOnTokenDrift((msg) => server.config.logger.warn(msg));
|
|
1590
1686
|
warnOnLegacyPointers(
|
|
1591
1687
|
listLegacyPointers(),
|
|
@@ -1608,7 +1704,7 @@ ${lines.join("\n")}
|
|
|
1608
1704
|
},
|
|
1609
1705
|
handleHotUpdate(ctx) {
|
|
1610
1706
|
if (legacyLayout) return;
|
|
1611
|
-
const normalized =
|
|
1707
|
+
const normalized = path2.resolve(ctx.file);
|
|
1612
1708
|
if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
|
|
1613
1709
|
if (!normalized.endsWith(".svelte")) return;
|
|
1614
1710
|
if (!isThemeAwareComponent(normalized)) return;
|