rafters 0.0.79 → 0.0.81
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/index.js +1570 -1310
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a2, b2) => (typeof require !== "undefined" ? require : a2)[b2]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
9
15
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
16
|
};
|
|
11
17
|
var __export = (target, all) => {
|
|
@@ -80,9 +86,9 @@ var require_escape_html = __commonJS({
|
|
|
80
86
|
import { Command } from "commander";
|
|
81
87
|
|
|
82
88
|
// src/commands/add.ts
|
|
83
|
-
import { existsSync as
|
|
84
|
-
import { access, mkdir as
|
|
85
|
-
import { dirname, join as
|
|
89
|
+
import { existsSync as existsSync4 } from "fs";
|
|
90
|
+
import { access, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
91
|
+
import { dirname, join as join8 } from "path";
|
|
86
92
|
|
|
87
93
|
// ../design-tokens/src/exporters/dtcg.ts
|
|
88
94
|
function categoryToDTCGType(category, token) {
|
|
@@ -1253,34 +1259,59 @@ ${themeBody}`;
|
|
|
1253
1259
|
}
|
|
1254
1260
|
}
|
|
1255
1261
|
function postProcessDocSheet(css) {
|
|
1262
|
+
const csstree3 = __require("css-tree");
|
|
1263
|
+
const ast = csstree3.parse(css);
|
|
1256
1264
|
const parts = [];
|
|
1257
|
-
|
|
1258
|
-
const
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1265
|
+
let hasHostContainer = false;
|
|
1266
|
+
const atruleNames = /* @__PURE__ */ new Set(["layer", "property", "keyframes"]);
|
|
1267
|
+
csstree3.walk(ast, {
|
|
1268
|
+
visit: "Atrule",
|
|
1269
|
+
enter(node) {
|
|
1270
|
+
if (!atruleNames.has(node.name)) return;
|
|
1271
|
+
if (node.name === "layer") {
|
|
1272
|
+
const prelude = node.prelude ? csstree3.generate(node.prelude) : "";
|
|
1273
|
+
if (prelude === "theme" && node.block) {
|
|
1274
|
+
let content = csstree3.generate(node.block);
|
|
1275
|
+
content = content.replace(/^\{/, "").replace(/\}$/, "");
|
|
1276
|
+
content = rewriteRootToHost(content);
|
|
1277
|
+
if (!hasHostContainer) {
|
|
1278
|
+
parts.push(`:host{container-type:inline-size}${content}`);
|
|
1279
|
+
hasHostContainer = true;
|
|
1280
|
+
} else {
|
|
1281
|
+
parts.push(content);
|
|
1282
|
+
}
|
|
1283
|
+
} else if (/^(base|components|utilities)/.test(prelude) && node.block) {
|
|
1284
|
+
parts.push(csstree3.generate(node));
|
|
1285
|
+
} else if (prelude.startsWith("properties") && node.block) {
|
|
1286
|
+
let block = csstree3.generate(node);
|
|
1287
|
+
block = rewritePropertiesSelector(block);
|
|
1288
|
+
parts.push(block);
|
|
1277
1289
|
}
|
|
1290
|
+
} else {
|
|
1291
|
+
parts.push(csstree3.generate(node));
|
|
1278
1292
|
}
|
|
1279
1293
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1294
|
+
});
|
|
1295
|
+
csstree3.walk(ast, {
|
|
1296
|
+
visit: "Rule",
|
|
1297
|
+
enter(node, _item, list) {
|
|
1298
|
+
if (list !== ast.children) return;
|
|
1299
|
+
let block = csstree3.generate(node);
|
|
1300
|
+
block = rewriteRootToHost(block);
|
|
1301
|
+
parts.push(block);
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1282
1304
|
return parts.join("");
|
|
1283
1305
|
}
|
|
1306
|
+
function rewriteRootToHost(css) {
|
|
1307
|
+
return css.replace(/:root\s*,\s*:host/g, ":host").replace(/:root\[data-theme/g, ":host[data-theme").replace(/:root(?=[{\s,[])/g, ":host");
|
|
1308
|
+
}
|
|
1309
|
+
function rewritePropertiesSelector(css) {
|
|
1310
|
+
return css.replace(
|
|
1311
|
+
/\*\s*,\s*:?:?before\s*,\s*:?:?after\s*,\s*:?:?backdrop/g,
|
|
1312
|
+
":host,*,::before,::after"
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1284
1315
|
|
|
1285
1316
|
// ../design-tokens/src/exporters/typescript.ts
|
|
1286
1317
|
function tokenValueToTS(token) {
|
|
@@ -27299,194 +27330,23 @@ function generateBaseSystem(config2 = {}) {
|
|
|
27299
27330
|
};
|
|
27300
27331
|
}
|
|
27301
27332
|
|
|
27302
|
-
// ../design-tokens/src/
|
|
27303
|
-
var
|
|
27304
|
-
|
|
27305
|
-
|
|
27306
|
-
|
|
27307
|
-
// Provenance. Optional by design: absent means unknown, which is what every
|
|
27308
|
-
// override written before this field existed actually is.
|
|
27309
|
-
kind: OverrideKindSchema.optional()
|
|
27310
|
-
});
|
|
27311
|
-
var BindingSchema2 = external_exports.object({
|
|
27312
|
-
plugin: external_exports.string(),
|
|
27313
|
-
input: external_exports.unknown()
|
|
27314
|
-
});
|
|
27315
|
-
var NodeSchema = external_exports.object({
|
|
27316
|
-
name: external_exports.string(),
|
|
27317
|
-
value: external_exports.unknown(),
|
|
27318
|
-
binding: BindingSchema2.optional(),
|
|
27319
|
-
userOverride: UserOverrideSchema.optional()
|
|
27320
|
-
});
|
|
27321
|
-
var CircularDependencyError = class extends Error {
|
|
27322
|
-
constructor(cycle) {
|
|
27323
|
-
super(`Circular dependency: ${cycle.join(" -> ")}`);
|
|
27324
|
-
this.cycle = cycle;
|
|
27325
|
-
this.name = "CircularDependencyError";
|
|
27326
|
-
}
|
|
27327
|
-
};
|
|
27328
|
-
var UnknownPluginError = class extends Error {
|
|
27329
|
-
constructor(pluginName) {
|
|
27330
|
-
super(`Unknown plugin: ${pluginName}`);
|
|
27331
|
-
this.pluginName = pluginName;
|
|
27332
|
-
this.name = "UnknownPluginError";
|
|
27333
|
-
}
|
|
27334
|
-
};
|
|
27335
|
-
var TokenGraph = class {
|
|
27336
|
-
nodes = /* @__PURE__ */ new Map();
|
|
27337
|
-
plugins = /* @__PURE__ */ new Map();
|
|
27338
|
-
snapshot = null;
|
|
27339
|
-
constructor(plugins = []) {
|
|
27340
|
-
for (const plugin of plugins) this.plugins.set(plugin.name, plugin);
|
|
27341
|
-
}
|
|
27342
|
-
registerPlugin(plugin) {
|
|
27343
|
-
this.plugins.set(plugin.name, plugin);
|
|
27344
|
-
}
|
|
27345
|
-
set(name, value, options) {
|
|
27346
|
-
this.takeSnapshot();
|
|
27347
|
-
const existing = this.nodes.get(name);
|
|
27348
|
-
const next = {
|
|
27349
|
-
name,
|
|
27350
|
-
value,
|
|
27351
|
-
userOverride: {
|
|
27352
|
-
previousValue: existing?.value,
|
|
27353
|
-
reason: options.reason,
|
|
27354
|
-
...options.context ? { context: options.context } : {},
|
|
27355
|
-
...options.kind ? { kind: options.kind } : {}
|
|
27356
|
-
},
|
|
27357
|
-
...existing?.binding ? { binding: existing.binding } : {}
|
|
27358
|
-
};
|
|
27359
|
-
this.nodes.set(name, next);
|
|
27360
|
-
this.cascadeFrom(name);
|
|
27361
|
-
}
|
|
27362
|
-
// Hydrate a node from persisted state. No cascade fires; the caller
|
|
27363
|
-
// (registry constructor) is responsible for ordering: leaves first, then
|
|
27364
|
-
// bindings. userOverride / binding are preserved verbatim from the persisted
|
|
27365
|
-
// token so that the anchor + re-derivation hook both survive reload.
|
|
27366
|
-
seed(name, value, extras) {
|
|
27367
|
-
this.nodes.set(name, {
|
|
27368
|
-
name,
|
|
27369
|
-
value,
|
|
27370
|
-
...extras?.userOverride ? { userOverride: extras.userOverride } : {},
|
|
27371
|
-
...extras?.binding ? { binding: extras.binding } : {}
|
|
27372
|
-
});
|
|
27373
|
-
}
|
|
27374
|
-
bind(name, pluginName, input) {
|
|
27375
|
-
const plugin = this.requirePlugin(pluginName);
|
|
27376
|
-
plugin.inputSchema.parse(input);
|
|
27377
|
-
const directDeps = plugin.dependsOn(input);
|
|
27378
|
-
this.assertNoCycle(name, directDeps);
|
|
27379
|
-
this.takeSnapshot();
|
|
27380
|
-
const value = plugin.transform(input, (n2) => this.get(n2));
|
|
27381
|
-
plugin.outputSchema.parse(value);
|
|
27382
|
-
this.nodes.set(name, { name, value, binding: { plugin: pluginName, input } });
|
|
27383
|
-
this.cascadeFrom(name);
|
|
27384
|
-
}
|
|
27385
|
-
get(name) {
|
|
27386
|
-
return this.nodes.get(name)?.value;
|
|
27387
|
-
}
|
|
27388
|
-
node(name) {
|
|
27389
|
-
return this.nodes.get(name);
|
|
27390
|
-
}
|
|
27391
|
-
undo() {
|
|
27392
|
-
if (!this.snapshot) return;
|
|
27393
|
-
this.nodes = this.snapshot;
|
|
27394
|
-
this.snapshot = null;
|
|
27395
|
-
}
|
|
27396
|
-
has(name) {
|
|
27397
|
-
return this.nodes.has(name);
|
|
27398
|
-
}
|
|
27399
|
-
list(filter) {
|
|
27400
|
-
const all = Array.from(this.nodes.values());
|
|
27401
|
-
if (!filter?.namespace) return all;
|
|
27402
|
-
const prefix = filter.namespace;
|
|
27403
|
-
return all.filter(
|
|
27404
|
-
(n2) => n2.name === prefix || n2.name.startsWith(`${prefix}-`) || n2.name.startsWith(`${prefix}.`)
|
|
27405
|
-
);
|
|
27406
|
-
}
|
|
27407
|
-
size() {
|
|
27408
|
-
return this.nodes.size;
|
|
27409
|
-
}
|
|
27410
|
-
requirePlugin(pluginName) {
|
|
27411
|
-
const plugin = this.plugins.get(pluginName);
|
|
27412
|
-
if (!plugin) throw new UnknownPluginError(pluginName);
|
|
27413
|
-
return plugin;
|
|
27414
|
-
}
|
|
27415
|
-
takeSnapshot() {
|
|
27416
|
-
this.snapshot = /* @__PURE__ */ new Map();
|
|
27417
|
-
for (const [k, v] of this.nodes) this.snapshot.set(k, structuredClone(v));
|
|
27418
|
-
}
|
|
27419
|
-
cascadeFrom(changed) {
|
|
27420
|
-
const dependents = this.collectDependents(changed);
|
|
27421
|
-
if (dependents.size === 0) return;
|
|
27422
|
-
const ordered = this.topoSort(dependents);
|
|
27423
|
-
for (const name of ordered) {
|
|
27424
|
-
const node = this.nodes.get(name);
|
|
27425
|
-
if (!node || node.userOverride || !node.binding) continue;
|
|
27426
|
-
const plugin = this.requirePlugin(node.binding.plugin);
|
|
27427
|
-
const value = plugin.transform(node.binding.input, (n2) => this.get(n2));
|
|
27428
|
-
plugin.outputSchema.parse(value);
|
|
27429
|
-
this.nodes.set(name, { ...node, value });
|
|
27430
|
-
}
|
|
27431
|
-
}
|
|
27432
|
-
collectDependents(changed) {
|
|
27433
|
-
const out = /* @__PURE__ */ new Set();
|
|
27434
|
-
const queue = [changed];
|
|
27435
|
-
while (queue.length > 0) {
|
|
27436
|
-
const current = queue.shift();
|
|
27437
|
-
for (const [name, node] of this.nodes) {
|
|
27438
|
-
if (out.has(name) || !node.binding) continue;
|
|
27439
|
-
const plugin = this.plugins.get(node.binding.plugin);
|
|
27440
|
-
if (!plugin) continue;
|
|
27441
|
-
if (plugin.dependsOn(node.binding.input).includes(current)) {
|
|
27442
|
-
out.add(name);
|
|
27443
|
-
queue.push(name);
|
|
27444
|
-
}
|
|
27445
|
-
}
|
|
27446
|
-
}
|
|
27447
|
-
return out;
|
|
27448
|
-
}
|
|
27449
|
-
topoSort(names) {
|
|
27450
|
-
const sorted = [];
|
|
27451
|
-
const visited = /* @__PURE__ */ new Set();
|
|
27452
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
27453
|
-
const visit = (name, path) => {
|
|
27454
|
-
if (visited.has(name)) return;
|
|
27455
|
-
if (visiting.has(name)) throw new CircularDependencyError([...path, name]);
|
|
27456
|
-
visiting.add(name);
|
|
27457
|
-
const node = this.nodes.get(name);
|
|
27458
|
-
if (node?.binding) {
|
|
27459
|
-
const plugin = this.plugins.get(node.binding.plugin);
|
|
27460
|
-
if (plugin) {
|
|
27461
|
-
for (const dep of plugin.dependsOn(node.binding.input)) {
|
|
27462
|
-
if (names.has(dep)) visit(dep, [...path, name]);
|
|
27463
|
-
}
|
|
27464
|
-
}
|
|
27465
|
-
}
|
|
27466
|
-
visiting.delete(name);
|
|
27467
|
-
visited.add(name);
|
|
27468
|
-
sorted.push(name);
|
|
27469
|
-
};
|
|
27470
|
-
for (const name of names) visit(name, []);
|
|
27471
|
-
return sorted;
|
|
27472
|
-
}
|
|
27473
|
-
assertNoCycle(name, directDeps) {
|
|
27474
|
-
const visited = /* @__PURE__ */ new Set();
|
|
27475
|
-
const dfs = (current, path) => {
|
|
27476
|
-
if (current === name) throw new CircularDependencyError([...path, current]);
|
|
27477
|
-
if (visited.has(current)) return;
|
|
27478
|
-
visited.add(current);
|
|
27479
|
-
const node = this.nodes.get(current);
|
|
27480
|
-
if (!node?.binding) return;
|
|
27481
|
-
const plugin = this.plugins.get(node.binding.plugin);
|
|
27482
|
-
if (!plugin) return;
|
|
27483
|
-
for (const dep of plugin.dependsOn(node.binding.input)) {
|
|
27484
|
-
dfs(dep, [...path, current]);
|
|
27485
|
-
}
|
|
27486
|
-
};
|
|
27487
|
-
for (const dep of directDeps) dfs(dep, [name]);
|
|
27333
|
+
// ../design-tokens/src/importers/adapter.ts
|
|
27334
|
+
var adapters = /* @__PURE__ */ new Map();
|
|
27335
|
+
function register2(adapter) {
|
|
27336
|
+
if (adapters.has(adapter.name)) {
|
|
27337
|
+
throw new Error(`DesignSystemAdapter "${adapter.name}" is already registered.`);
|
|
27488
27338
|
}
|
|
27489
|
-
|
|
27339
|
+
adapters.set(adapter.name, adapter);
|
|
27340
|
+
}
|
|
27341
|
+
function getAdapter(name) {
|
|
27342
|
+
const adapter = adapters.get(name);
|
|
27343
|
+
if (adapter !== void 0) return adapter;
|
|
27344
|
+
const known = getAvailableAdapters();
|
|
27345
|
+
throw new Error(`Unknown design system adapter "${name}". Valid values: ${known.join(", ")}.`);
|
|
27346
|
+
}
|
|
27347
|
+
function getAvailableAdapters() {
|
|
27348
|
+
return [...adapters.keys()].sort();
|
|
27349
|
+
}
|
|
27490
27350
|
|
|
27491
27351
|
// ../design-tokens/src/importers/shadcn.ts
|
|
27492
27352
|
import * as csstree from "css-tree";
|
|
@@ -27654,46 +27514,6 @@ function classifyDeclarations(declarations) {
|
|
|
27654
27514
|
return { byNamespace: buckets, unclassified };
|
|
27655
27515
|
}
|
|
27656
27516
|
|
|
27657
|
-
// ../design-tokens/src/importers/color.ts
|
|
27658
|
-
function importColorFamily(name, seedPosition, seed) {
|
|
27659
|
-
const seedIndex = POSITION_TO_INDEX[seedPosition];
|
|
27660
|
-
if (seedIndex === void 0) {
|
|
27661
|
-
throw new Error(`importColorFamily: unknown scale position "${seedPosition}"`);
|
|
27662
|
-
}
|
|
27663
|
-
const built = buildColorValue(seed, { token: name });
|
|
27664
|
-
if (built.scale.length !== SCALE_POSITIONS.length) {
|
|
27665
|
-
throw new Error(
|
|
27666
|
-
`importColorFamily: buildColorValue returned ${built.scale.length} positions, expected ${SCALE_POSITIONS.length}`
|
|
27667
|
-
);
|
|
27668
|
-
}
|
|
27669
|
-
const scale2 = [...built.scale];
|
|
27670
|
-
scale2[seedIndex] = seed;
|
|
27671
|
-
const value = { ...built, name, scale: scale2 };
|
|
27672
|
-
const tokens = [
|
|
27673
|
-
{
|
|
27674
|
-
name,
|
|
27675
|
-
namespace: "color",
|
|
27676
|
-
category: "color",
|
|
27677
|
-
value,
|
|
27678
|
-
userOverride: null,
|
|
27679
|
-
containerQueryAware: true
|
|
27680
|
-
}
|
|
27681
|
-
];
|
|
27682
|
-
for (const [i, pos] of SCALE_POSITIONS.entries()) {
|
|
27683
|
-
const oklch2 = value.scale[i];
|
|
27684
|
-
if (!oklch2) continue;
|
|
27685
|
-
tokens.push({
|
|
27686
|
-
name: `${name}-${pos}`,
|
|
27687
|
-
namespace: "color",
|
|
27688
|
-
category: "color",
|
|
27689
|
-
value: oklchToCSS(oklch2),
|
|
27690
|
-
userOverride: null,
|
|
27691
|
-
containerQueryAware: true
|
|
27692
|
-
});
|
|
27693
|
-
}
|
|
27694
|
-
return tokens;
|
|
27695
|
-
}
|
|
27696
|
-
|
|
27697
27517
|
// ../design-tokens/src/importers/colors.ts
|
|
27698
27518
|
function colorsFromClassification(classification) {
|
|
27699
27519
|
const result = [];
|
|
@@ -27728,9 +27548,14 @@ var GENERIC_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
27728
27548
|
"revert",
|
|
27729
27549
|
"revert-layer"
|
|
27730
27550
|
]);
|
|
27551
|
+
var SOURCE_PRIORITY = {
|
|
27552
|
+
declaration: 0,
|
|
27553
|
+
google: 1,
|
|
27554
|
+
"font-face": 2
|
|
27555
|
+
};
|
|
27731
27556
|
function detectFonts(css) {
|
|
27732
27557
|
const found = /* @__PURE__ */ new Map();
|
|
27733
|
-
const accept = (name, stack, sourceDeclName) => {
|
|
27558
|
+
const accept = (name, stack, source, sourceDeclName) => {
|
|
27734
27559
|
if (name === null) return;
|
|
27735
27560
|
const canonical = normalizeFamilyName(name);
|
|
27736
27561
|
if (canonical === "" || GENERIC_KEYWORDS.has(canonical.toLowerCase())) return;
|
|
@@ -27740,30 +27565,33 @@ function detectFonts(css) {
|
|
|
27740
27565
|
found.set(key, {
|
|
27741
27566
|
name: canonical,
|
|
27742
27567
|
stack,
|
|
27568
|
+
source,
|
|
27743
27569
|
...sourceDeclName && { sourceDeclName }
|
|
27744
27570
|
});
|
|
27745
27571
|
return;
|
|
27746
27572
|
}
|
|
27573
|
+
const mergedSource = SOURCE_PRIORITY[source] > SOURCE_PRIORITY[existing.source] ? source : existing.source;
|
|
27747
27574
|
const mergedStack = stack.length > existing.stack.length ? stack : existing.stack;
|
|
27748
27575
|
const mergedDeclName = existing.sourceDeclName ?? sourceDeclName;
|
|
27749
27576
|
found.set(key, {
|
|
27750
27577
|
name: existing.name,
|
|
27751
27578
|
stack: mergedStack,
|
|
27579
|
+
source: mergedSource,
|
|
27752
27580
|
...mergedDeclName && { sourceDeclName: mergedDeclName }
|
|
27753
27581
|
});
|
|
27754
27582
|
};
|
|
27755
27583
|
for (const family of extractGoogleFontFamilies(css)) {
|
|
27756
|
-
accept(family, quoteIfNeeded(family));
|
|
27584
|
+
accept(family, quoteIfNeeded(family), "google");
|
|
27757
27585
|
}
|
|
27758
27586
|
for (const family of extractFontFaceFamilies(css)) {
|
|
27759
|
-
accept(family, quoteIfNeeded(family));
|
|
27587
|
+
accept(family, quoteIfNeeded(family), "font-face");
|
|
27760
27588
|
}
|
|
27761
27589
|
const rootDecls = extractShadcnRoot(css);
|
|
27762
27590
|
const themeDecls = extractThemeBlocks2(css);
|
|
27763
27591
|
for (const decl of [...rootDecls, ...themeDecls]) {
|
|
27764
27592
|
if (!decl.name.startsWith("font-")) continue;
|
|
27765
27593
|
const first = firstFamilyFromStack(decl.value);
|
|
27766
|
-
accept(first, decl.value.trim(), decl.name);
|
|
27594
|
+
accept(first, decl.value.trim(), "declaration", decl.name);
|
|
27767
27595
|
}
|
|
27768
27596
|
return Array.from(found.values());
|
|
27769
27597
|
}
|
|
@@ -27838,8 +27666,271 @@ function quoteIfNeeded(name) {
|
|
|
27838
27666
|
return `"${name}"`;
|
|
27839
27667
|
}
|
|
27840
27668
|
|
|
27841
|
-
// ../design-tokens/src/importers/
|
|
27842
|
-
|
|
27669
|
+
// ../design-tokens/src/importers/shadcn-adapter.ts
|
|
27670
|
+
var sharedDetection = {
|
|
27671
|
+
detectFonts(css) {
|
|
27672
|
+
return [...detectFonts(css)];
|
|
27673
|
+
},
|
|
27674
|
+
detectColors(css) {
|
|
27675
|
+
const declarations = extractShadcnRoot(css);
|
|
27676
|
+
const classification = classifyDeclarations(declarations);
|
|
27677
|
+
return [...colorsFromClassification(classification)];
|
|
27678
|
+
},
|
|
27679
|
+
detectSpacing(css) {
|
|
27680
|
+
const value = detectSpacingBase(css);
|
|
27681
|
+
return value !== null ? { base: value } : {};
|
|
27682
|
+
},
|
|
27683
|
+
detectRadius(css) {
|
|
27684
|
+
const value = detectRadiusBase(css);
|
|
27685
|
+
return value !== null ? { base: value } : {};
|
|
27686
|
+
},
|
|
27687
|
+
detectFocusRing(css) {
|
|
27688
|
+
const value = detectFocusRingWidth(css);
|
|
27689
|
+
return value !== null ? { width: value } : {};
|
|
27690
|
+
},
|
|
27691
|
+
detectFontSize(css) {
|
|
27692
|
+
const value = detectFontSizeBase(css);
|
|
27693
|
+
return value !== null ? { base: value } : {};
|
|
27694
|
+
}
|
|
27695
|
+
};
|
|
27696
|
+
var shadcnAdapter = { name: "shadcn", ...sharedDetection };
|
|
27697
|
+
register2(shadcnAdapter);
|
|
27698
|
+
|
|
27699
|
+
// ../design-tokens/src/importers/tailwind-adapter.ts
|
|
27700
|
+
var tailwindAdapter = { name: "tailwind", ...sharedDetection };
|
|
27701
|
+
register2(tailwindAdapter);
|
|
27702
|
+
|
|
27703
|
+
// ../design-tokens/src/graph.ts
|
|
27704
|
+
var UserOverrideSchema = external_exports.object({
|
|
27705
|
+
previousValue: external_exports.unknown(),
|
|
27706
|
+
reason: external_exports.string(),
|
|
27707
|
+
context: external_exports.string().optional(),
|
|
27708
|
+
// Provenance. Optional by design: absent means unknown, which is what every
|
|
27709
|
+
// override written before this field existed actually is.
|
|
27710
|
+
kind: OverrideKindSchema.optional()
|
|
27711
|
+
});
|
|
27712
|
+
var BindingSchema2 = external_exports.object({
|
|
27713
|
+
plugin: external_exports.string(),
|
|
27714
|
+
input: external_exports.unknown()
|
|
27715
|
+
});
|
|
27716
|
+
var NodeSchema = external_exports.object({
|
|
27717
|
+
name: external_exports.string(),
|
|
27718
|
+
value: external_exports.unknown(),
|
|
27719
|
+
binding: BindingSchema2.optional(),
|
|
27720
|
+
userOverride: UserOverrideSchema.optional()
|
|
27721
|
+
});
|
|
27722
|
+
var CircularDependencyError = class extends Error {
|
|
27723
|
+
constructor(cycle) {
|
|
27724
|
+
super(`Circular dependency: ${cycle.join(" -> ")}`);
|
|
27725
|
+
this.cycle = cycle;
|
|
27726
|
+
this.name = "CircularDependencyError";
|
|
27727
|
+
}
|
|
27728
|
+
};
|
|
27729
|
+
var UnknownPluginError = class extends Error {
|
|
27730
|
+
constructor(pluginName) {
|
|
27731
|
+
super(`Unknown plugin: ${pluginName}`);
|
|
27732
|
+
this.pluginName = pluginName;
|
|
27733
|
+
this.name = "UnknownPluginError";
|
|
27734
|
+
}
|
|
27735
|
+
};
|
|
27736
|
+
var TokenGraph = class {
|
|
27737
|
+
nodes = /* @__PURE__ */ new Map();
|
|
27738
|
+
plugins = /* @__PURE__ */ new Map();
|
|
27739
|
+
snapshot = null;
|
|
27740
|
+
constructor(plugins = []) {
|
|
27741
|
+
for (const plugin of plugins) this.plugins.set(plugin.name, plugin);
|
|
27742
|
+
}
|
|
27743
|
+
registerPlugin(plugin) {
|
|
27744
|
+
this.plugins.set(plugin.name, plugin);
|
|
27745
|
+
}
|
|
27746
|
+
set(name, value, options) {
|
|
27747
|
+
this.takeSnapshot();
|
|
27748
|
+
const existing = this.nodes.get(name);
|
|
27749
|
+
const next = {
|
|
27750
|
+
name,
|
|
27751
|
+
value,
|
|
27752
|
+
userOverride: {
|
|
27753
|
+
previousValue: existing?.value,
|
|
27754
|
+
reason: options.reason,
|
|
27755
|
+
...options.context ? { context: options.context } : {},
|
|
27756
|
+
...options.kind ? { kind: options.kind } : {}
|
|
27757
|
+
},
|
|
27758
|
+
...existing?.binding ? { binding: existing.binding } : {}
|
|
27759
|
+
};
|
|
27760
|
+
this.nodes.set(name, next);
|
|
27761
|
+
this.cascadeFrom(name);
|
|
27762
|
+
}
|
|
27763
|
+
// Hydrate a node from persisted state. No cascade fires; the caller
|
|
27764
|
+
// (registry constructor) is responsible for ordering: leaves first, then
|
|
27765
|
+
// bindings. userOverride / binding are preserved verbatim from the persisted
|
|
27766
|
+
// token so that the anchor + re-derivation hook both survive reload.
|
|
27767
|
+
seed(name, value, extras) {
|
|
27768
|
+
this.nodes.set(name, {
|
|
27769
|
+
name,
|
|
27770
|
+
value,
|
|
27771
|
+
...extras?.userOverride ? { userOverride: extras.userOverride } : {},
|
|
27772
|
+
...extras?.binding ? { binding: extras.binding } : {}
|
|
27773
|
+
});
|
|
27774
|
+
}
|
|
27775
|
+
bind(name, pluginName, input) {
|
|
27776
|
+
const plugin = this.requirePlugin(pluginName);
|
|
27777
|
+
plugin.inputSchema.parse(input);
|
|
27778
|
+
const directDeps = plugin.dependsOn(input);
|
|
27779
|
+
this.assertNoCycle(name, directDeps);
|
|
27780
|
+
this.takeSnapshot();
|
|
27781
|
+
const value = plugin.transform(input, (n2) => this.get(n2));
|
|
27782
|
+
plugin.outputSchema.parse(value);
|
|
27783
|
+
this.nodes.set(name, { name, value, binding: { plugin: pluginName, input } });
|
|
27784
|
+
this.cascadeFrom(name);
|
|
27785
|
+
}
|
|
27786
|
+
get(name) {
|
|
27787
|
+
return this.nodes.get(name)?.value;
|
|
27788
|
+
}
|
|
27789
|
+
node(name) {
|
|
27790
|
+
return this.nodes.get(name);
|
|
27791
|
+
}
|
|
27792
|
+
undo() {
|
|
27793
|
+
if (!this.snapshot) return;
|
|
27794
|
+
this.nodes = this.snapshot;
|
|
27795
|
+
this.snapshot = null;
|
|
27796
|
+
}
|
|
27797
|
+
has(name) {
|
|
27798
|
+
return this.nodes.has(name);
|
|
27799
|
+
}
|
|
27800
|
+
list(filter) {
|
|
27801
|
+
const all = Array.from(this.nodes.values());
|
|
27802
|
+
if (!filter?.namespace) return all;
|
|
27803
|
+
const prefix = filter.namespace;
|
|
27804
|
+
return all.filter(
|
|
27805
|
+
(n2) => n2.name === prefix || n2.name.startsWith(`${prefix}-`) || n2.name.startsWith(`${prefix}.`)
|
|
27806
|
+
);
|
|
27807
|
+
}
|
|
27808
|
+
size() {
|
|
27809
|
+
return this.nodes.size;
|
|
27810
|
+
}
|
|
27811
|
+
requirePlugin(pluginName) {
|
|
27812
|
+
const plugin = this.plugins.get(pluginName);
|
|
27813
|
+
if (!plugin) throw new UnknownPluginError(pluginName);
|
|
27814
|
+
return plugin;
|
|
27815
|
+
}
|
|
27816
|
+
takeSnapshot() {
|
|
27817
|
+
this.snapshot = /* @__PURE__ */ new Map();
|
|
27818
|
+
for (const [k, v] of this.nodes) this.snapshot.set(k, structuredClone(v));
|
|
27819
|
+
}
|
|
27820
|
+
cascadeFrom(changed) {
|
|
27821
|
+
const dependents = this.collectDependents(changed);
|
|
27822
|
+
if (dependents.size === 0) return;
|
|
27823
|
+
const ordered = this.topoSort(dependents);
|
|
27824
|
+
for (const name of ordered) {
|
|
27825
|
+
const node = this.nodes.get(name);
|
|
27826
|
+
if (!node || node.userOverride || !node.binding) continue;
|
|
27827
|
+
const plugin = this.requirePlugin(node.binding.plugin);
|
|
27828
|
+
const value = plugin.transform(node.binding.input, (n2) => this.get(n2));
|
|
27829
|
+
plugin.outputSchema.parse(value);
|
|
27830
|
+
this.nodes.set(name, { ...node, value });
|
|
27831
|
+
}
|
|
27832
|
+
}
|
|
27833
|
+
collectDependents(changed) {
|
|
27834
|
+
const out = /* @__PURE__ */ new Set();
|
|
27835
|
+
const queue = [changed];
|
|
27836
|
+
while (queue.length > 0) {
|
|
27837
|
+
const current = queue.shift();
|
|
27838
|
+
for (const [name, node] of this.nodes) {
|
|
27839
|
+
if (out.has(name) || !node.binding) continue;
|
|
27840
|
+
const plugin = this.plugins.get(node.binding.plugin);
|
|
27841
|
+
if (!plugin) continue;
|
|
27842
|
+
if (plugin.dependsOn(node.binding.input).includes(current)) {
|
|
27843
|
+
out.add(name);
|
|
27844
|
+
queue.push(name);
|
|
27845
|
+
}
|
|
27846
|
+
}
|
|
27847
|
+
}
|
|
27848
|
+
return out;
|
|
27849
|
+
}
|
|
27850
|
+
topoSort(names) {
|
|
27851
|
+
const sorted = [];
|
|
27852
|
+
const visited = /* @__PURE__ */ new Set();
|
|
27853
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
27854
|
+
const visit = (name, path) => {
|
|
27855
|
+
if (visited.has(name)) return;
|
|
27856
|
+
if (visiting.has(name)) throw new CircularDependencyError([...path, name]);
|
|
27857
|
+
visiting.add(name);
|
|
27858
|
+
const node = this.nodes.get(name);
|
|
27859
|
+
if (node?.binding) {
|
|
27860
|
+
const plugin = this.plugins.get(node.binding.plugin);
|
|
27861
|
+
if (plugin) {
|
|
27862
|
+
for (const dep of plugin.dependsOn(node.binding.input)) {
|
|
27863
|
+
if (names.has(dep)) visit(dep, [...path, name]);
|
|
27864
|
+
}
|
|
27865
|
+
}
|
|
27866
|
+
}
|
|
27867
|
+
visiting.delete(name);
|
|
27868
|
+
visited.add(name);
|
|
27869
|
+
sorted.push(name);
|
|
27870
|
+
};
|
|
27871
|
+
for (const name of names) visit(name, []);
|
|
27872
|
+
return sorted;
|
|
27873
|
+
}
|
|
27874
|
+
assertNoCycle(name, directDeps) {
|
|
27875
|
+
const visited = /* @__PURE__ */ new Set();
|
|
27876
|
+
const dfs = (current, path) => {
|
|
27877
|
+
if (current === name) throw new CircularDependencyError([...path, current]);
|
|
27878
|
+
if (visited.has(current)) return;
|
|
27879
|
+
visited.add(current);
|
|
27880
|
+
const node = this.nodes.get(current);
|
|
27881
|
+
if (!node?.binding) return;
|
|
27882
|
+
const plugin = this.plugins.get(node.binding.plugin);
|
|
27883
|
+
if (!plugin) return;
|
|
27884
|
+
for (const dep of plugin.dependsOn(node.binding.input)) {
|
|
27885
|
+
dfs(dep, [...path, current]);
|
|
27886
|
+
}
|
|
27887
|
+
};
|
|
27888
|
+
for (const dep of directDeps) dfs(dep, [name]);
|
|
27889
|
+
}
|
|
27890
|
+
};
|
|
27891
|
+
|
|
27892
|
+
// ../design-tokens/src/importers/color.ts
|
|
27893
|
+
function importColorFamily(name, seedPosition, seed) {
|
|
27894
|
+
const seedIndex = POSITION_TO_INDEX[seedPosition];
|
|
27895
|
+
if (seedIndex === void 0) {
|
|
27896
|
+
throw new Error(`importColorFamily: unknown scale position "${seedPosition}"`);
|
|
27897
|
+
}
|
|
27898
|
+
const built = buildColorValue(seed, { token: name });
|
|
27899
|
+
if (built.scale.length !== SCALE_POSITIONS.length) {
|
|
27900
|
+
throw new Error(
|
|
27901
|
+
`importColorFamily: buildColorValue returned ${built.scale.length} positions, expected ${SCALE_POSITIONS.length}`
|
|
27902
|
+
);
|
|
27903
|
+
}
|
|
27904
|
+
const scale2 = [...built.scale];
|
|
27905
|
+
scale2[seedIndex] = seed;
|
|
27906
|
+
const value = { ...built, name, scale: scale2 };
|
|
27907
|
+
const tokens = [
|
|
27908
|
+
{
|
|
27909
|
+
name,
|
|
27910
|
+
namespace: "color",
|
|
27911
|
+
category: "color",
|
|
27912
|
+
value,
|
|
27913
|
+
userOverride: null,
|
|
27914
|
+
containerQueryAware: true
|
|
27915
|
+
}
|
|
27916
|
+
];
|
|
27917
|
+
for (const [i, pos] of SCALE_POSITIONS.entries()) {
|
|
27918
|
+
const oklch2 = value.scale[i];
|
|
27919
|
+
if (!oklch2) continue;
|
|
27920
|
+
tokens.push({
|
|
27921
|
+
name: `${name}-${pos}`,
|
|
27922
|
+
namespace: "color",
|
|
27923
|
+
category: "color",
|
|
27924
|
+
value: oklchToCSS(oklch2),
|
|
27925
|
+
userOverride: null,
|
|
27926
|
+
containerQueryAware: true
|
|
27927
|
+
});
|
|
27928
|
+
}
|
|
27929
|
+
return tokens;
|
|
27930
|
+
}
|
|
27931
|
+
|
|
27932
|
+
// ../design-tokens/src/importers/sense.ts
|
|
27933
|
+
function senseShadcnCss(css) {
|
|
27843
27934
|
const declarations = extractShadcnRoot(css);
|
|
27844
27935
|
const classification = classifyDeclarations(declarations);
|
|
27845
27936
|
const byNamespace = Object.fromEntries(
|
|
@@ -29330,912 +29421,566 @@ function isPathField(value) {
|
|
|
29330
29421
|
return typeof value === "string" || Array.isArray(value);
|
|
29331
29422
|
}
|
|
29332
29423
|
|
|
29333
|
-
// src/commands/
|
|
29424
|
+
// src/commands/init.ts
|
|
29425
|
+
import { existsSync as existsSync3 } from "fs";
|
|
29426
|
+
import { copyFile, mkdir as mkdir2, readFile as readFile3, rm, writeFile as writeFile2 } from "fs/promises";
|
|
29427
|
+
import { createRequire } from "module";
|
|
29428
|
+
import { join as join7, relative as relative2 } from "path";
|
|
29429
|
+
import { checkbox, confirm, select } from "@inquirer/prompts";
|
|
29334
29430
|
var REGISTRY_PLUGINS = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
|
|
29335
|
-
async function
|
|
29336
|
-
const
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
registry2 = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS);
|
|
29340
|
-
} catch {
|
|
29341
|
-
return;
|
|
29342
|
-
}
|
|
29343
|
-
if (registry2.size() === 0) return;
|
|
29344
|
-
try {
|
|
29345
|
-
await regenerateOutputs(registry2, {
|
|
29346
|
-
outputDir: paths.output,
|
|
29347
|
-
exports: config2.exports,
|
|
29348
|
-
contentSources: resolveContentSources(cwd, config2),
|
|
29349
|
-
darkMode: config2.darkMode ?? "class",
|
|
29350
|
-
includeImport: !config2.shadcn
|
|
29351
|
-
});
|
|
29352
|
-
} catch (err) {
|
|
29353
|
-
log({
|
|
29354
|
-
event: "add:regen-failed",
|
|
29355
|
-
message: `Output regeneration failed: ${err instanceof Error ? err.message : String(err)}`
|
|
29356
|
-
});
|
|
29357
|
-
}
|
|
29431
|
+
async function backupCss(cssPath) {
|
|
29432
|
+
const backupPath = cssPath.replace(/\.css$/, ".backup.css");
|
|
29433
|
+
await copyFile(cssPath, backupPath);
|
|
29434
|
+
return backupPath;
|
|
29358
29435
|
}
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
|
|
29362
|
-
|
|
29363
|
-
|
|
29364
|
-
|
|
29365
|
-
|
|
29436
|
+
function cleanSourceCssBlocks(content) {
|
|
29437
|
+
function parseBlocks(src) {
|
|
29438
|
+
const blocks = [];
|
|
29439
|
+
let depth = 0;
|
|
29440
|
+
const headerStack = [];
|
|
29441
|
+
let segmentStart = 0;
|
|
29442
|
+
for (let i = 0; i < src.length; i++) {
|
|
29443
|
+
const ch = src.charAt(i);
|
|
29444
|
+
if (ch === "{") {
|
|
29445
|
+
headerStack.push(segmentStart);
|
|
29446
|
+
depth++;
|
|
29447
|
+
if (depth >= 1) {
|
|
29448
|
+
blocks.push({
|
|
29449
|
+
headerStart: segmentStart,
|
|
29450
|
+
bodyStart: i + 1,
|
|
29451
|
+
end: -1,
|
|
29452
|
+
header: src.slice(segmentStart, i).trim()
|
|
29453
|
+
});
|
|
29454
|
+
}
|
|
29455
|
+
segmentStart = i + 1;
|
|
29456
|
+
} else if (ch === "}") {
|
|
29457
|
+
depth--;
|
|
29458
|
+
const open = blocks.slice().reverse().find((b2) => b2.end === -1);
|
|
29459
|
+
if (open) open.end = i + 1;
|
|
29460
|
+
headerStack.pop();
|
|
29461
|
+
segmentStart = i + 1;
|
|
29462
|
+
} else if (ch === ";") {
|
|
29463
|
+
segmentStart = i + 1;
|
|
29464
|
+
}
|
|
29465
|
+
}
|
|
29466
|
+
return blocks.filter((b2) => b2.end !== -1);
|
|
29366
29467
|
}
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
|
|
29371
|
-
|
|
29372
|
-
|
|
29373
|
-
|
|
29374
|
-
|
|
29375
|
-
const
|
|
29376
|
-
|
|
29468
|
+
function isContentEmpty(body) {
|
|
29469
|
+
return body.replace(/\/\*[\s\S]*?\*\//g, "").trim().length === 0;
|
|
29470
|
+
}
|
|
29471
|
+
let out = content;
|
|
29472
|
+
for (let pass = 0; pass < 10; pass++) {
|
|
29473
|
+
const blocks = parseBlocks(out);
|
|
29474
|
+
let edited = false;
|
|
29475
|
+
for (const block of blocks.sort((a2, b2) => b2.headerStart - a2.headerStart)) {
|
|
29476
|
+
const header = block.header;
|
|
29477
|
+
if (/^@theme\s+inline$/.test(header)) {
|
|
29478
|
+
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29479
|
+
edited = true;
|
|
29480
|
+
break;
|
|
29481
|
+
}
|
|
29482
|
+
if (header === ":root" || /(^|,)\s*:root\s*$/.test(header)) {
|
|
29483
|
+
const body = out.slice(block.bodyStart, block.end - 1);
|
|
29484
|
+
const cleanedBody = body.replace(/--[\w-]+\s*:[^;{}]*;?/g, "");
|
|
29485
|
+
if (isContentEmpty(cleanedBody)) {
|
|
29486
|
+
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29487
|
+
edited = true;
|
|
29488
|
+
break;
|
|
29489
|
+
}
|
|
29490
|
+
if (cleanedBody !== body) {
|
|
29491
|
+
out = out.slice(0, block.bodyStart) + cleanedBody + out.slice(block.end - 1);
|
|
29492
|
+
edited = true;
|
|
29493
|
+
break;
|
|
29494
|
+
}
|
|
29495
|
+
continue;
|
|
29496
|
+
}
|
|
29497
|
+
if (header.startsWith("@media") || header.startsWith("@supports")) {
|
|
29498
|
+
const body = out.slice(block.bodyStart, block.end - 1);
|
|
29499
|
+
if (isContentEmpty(body)) {
|
|
29500
|
+
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29501
|
+
edited = true;
|
|
29502
|
+
break;
|
|
29503
|
+
}
|
|
29504
|
+
}
|
|
29377
29505
|
}
|
|
29378
|
-
|
|
29506
|
+
if (!edited) break;
|
|
29379
29507
|
}
|
|
29508
|
+
return out.replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n");
|
|
29380
29509
|
}
|
|
29381
|
-
function
|
|
29382
|
-
|
|
29510
|
+
async function stripImportedDeclarations(cwd, cssPath, importedNames) {
|
|
29511
|
+
if (importedNames.length === 0) return;
|
|
29512
|
+
const fullPath = join7(cwd, cssPath);
|
|
29513
|
+
const content = await readFile3(fullPath, "utf-8");
|
|
29514
|
+
const pattern = new RegExp(importedNames.map((n2) => `^\\s*--${n2}[^;]*;\\s*$`).join("|"), "gm");
|
|
29515
|
+
const cleaned = cleanSourceCssBlocks(content.replace(pattern, ""));
|
|
29516
|
+
const collapsed = cleaned.replace(/\n{3,}/g, "\n\n");
|
|
29517
|
+
await writeFile2(fullPath, collapsed);
|
|
29383
29518
|
}
|
|
29384
|
-
|
|
29385
|
-
|
|
29386
|
-
|
|
29519
|
+
function migrateConfig(raw) {
|
|
29520
|
+
if ("shadcn" in raw && !("source" in raw)) {
|
|
29521
|
+
if (raw.shadcn === true) {
|
|
29522
|
+
raw.source = "shadcn";
|
|
29523
|
+
}
|
|
29524
|
+
delete raw.shadcn;
|
|
29525
|
+
}
|
|
29526
|
+
return raw;
|
|
29387
29527
|
}
|
|
29388
|
-
function
|
|
29389
|
-
|
|
29390
|
-
const
|
|
29391
|
-
|
|
29392
|
-
|
|
29393
|
-
|
|
29394
|
-
|
|
29395
|
-
|
|
29396
|
-
|
|
29397
|
-
|
|
29528
|
+
async function updateMainCss(cwd, cssPath, themePath) {
|
|
29529
|
+
const fullCssPath = join7(cwd, cssPath);
|
|
29530
|
+
const cssContent = await readFile3(fullCssPath, "utf-8");
|
|
29531
|
+
const cssDir = join7(cwd, cssPath, "..");
|
|
29532
|
+
const themeFullPath = join7(cwd, themePath);
|
|
29533
|
+
const relativeThemePath = relative2(cssDir, themeFullPath);
|
|
29534
|
+
if (cssContent.includes(".rafters/output/rafters.css")) {
|
|
29535
|
+
log({ event: "init:css_already_imported", cssPath });
|
|
29536
|
+
return;
|
|
29537
|
+
}
|
|
29538
|
+
await backupCss(fullCssPath);
|
|
29539
|
+
let newContent;
|
|
29540
|
+
if (cssContent.includes('@import "tailwindcss"')) {
|
|
29541
|
+
newContent = cssContent.replace('@import "tailwindcss";', `@import "${relativeThemePath}";`);
|
|
29542
|
+
} else if (cssContent.includes("@import 'tailwindcss'")) {
|
|
29543
|
+
newContent = cssContent.replace("@import 'tailwindcss';", `@import "${relativeThemePath}";`);
|
|
29544
|
+
} else {
|
|
29545
|
+
newContent = `@import "${relativeThemePath}";
|
|
29546
|
+
|
|
29547
|
+
${cssContent}`;
|
|
29548
|
+
}
|
|
29549
|
+
await writeFile2(fullCssPath, newContent);
|
|
29550
|
+
log({
|
|
29551
|
+
event: "init:css_updated",
|
|
29552
|
+
cssPath,
|
|
29553
|
+
themePath: relativeThemePath
|
|
29554
|
+
});
|
|
29398
29555
|
}
|
|
29399
|
-
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
|
|
29404
|
-
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29556
|
+
function isInteractive() {
|
|
29557
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
29558
|
+
}
|
|
29559
|
+
function resolveSourceCssPath(cwd, framework, detectedFramework, projectCssPath, shadcnCssPath, emit) {
|
|
29560
|
+
if (shadcnCssPath) {
|
|
29561
|
+
if (existsSync3(join7(cwd, shadcnCssPath))) return shadcnCssPath;
|
|
29562
|
+
const fallback = framework === detectedFramework ? projectCssPath : findCssPath(cwd, framework);
|
|
29563
|
+
emit({
|
|
29564
|
+
event: "init:shadcn_css_missing",
|
|
29565
|
+
configuredPath: shadcnCssPath,
|
|
29566
|
+
fallbackPath: fallback,
|
|
29567
|
+
message: "components.json points at a CSS file that does not exist. Falling back to the framework canonical location."
|
|
29408
29568
|
});
|
|
29569
|
+
return fallback;
|
|
29409
29570
|
}
|
|
29410
|
-
|
|
29411
|
-
return untracked;
|
|
29571
|
+
return framework === detectedFramework ? projectCssPath : findCssPath(cwd, framework);
|
|
29412
29572
|
}
|
|
29413
|
-
function
|
|
29414
|
-
return
|
|
29573
|
+
function slugifyFontName(name) {
|
|
29574
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
29415
29575
|
}
|
|
29416
|
-
|
|
29417
|
-
|
|
29418
|
-
|
|
29419
|
-
|
|
29420
|
-
|
|
29421
|
-
|
|
29576
|
+
function isFontStackValue(value) {
|
|
29577
|
+
if (typeof value !== "string") return false;
|
|
29578
|
+
if (value.startsWith("var(")) return false;
|
|
29579
|
+
if (/[,'"]/.test(value)) return true;
|
|
29580
|
+
return /\b(sans-serif|serif|monospace|cursive|fantasy|system-ui|ui-(?:sans-serif|serif|monospace|rounded))\b/.test(
|
|
29581
|
+
value
|
|
29582
|
+
);
|
|
29422
29583
|
}
|
|
29423
|
-
|
|
29424
|
-
|
|
29425
|
-
|
|
29426
|
-
|
|
29427
|
-
|
|
29428
|
-
|
|
29429
|
-
return { files: [...matched, ...shared], fallback: false };
|
|
29430
|
-
}
|
|
29431
|
-
if (REACT_FALLBACK_TARGETS.has(target)) {
|
|
29432
|
-
const fallbackFiles = files.filter((f) => f.path.endsWith(".tsx"));
|
|
29433
|
-
if (fallbackFiles.length > 0) {
|
|
29434
|
-
return { files: [...fallbackFiles, ...shared], fallback: true };
|
|
29584
|
+
async function resolveFramework(detected, flag, agentMode) {
|
|
29585
|
+
if (flag) {
|
|
29586
|
+
if (!isSelectableFramework(flag)) {
|
|
29587
|
+
throw new Error(
|
|
29588
|
+
`Unknown --framework "${flag}". Valid values: ${SELECTABLE_FRAMEWORKS.join(", ")}.`
|
|
29589
|
+
);
|
|
29435
29590
|
}
|
|
29591
|
+
return flag;
|
|
29436
29592
|
}
|
|
29437
|
-
if (
|
|
29438
|
-
|
|
29439
|
-
|
|
29440
|
-
|
|
29441
|
-
|
|
29442
|
-
|
|
29443
|
-
|
|
29444
|
-
|
|
29445
|
-
function selectCompositeFiles(files, target) {
|
|
29446
|
-
return files.filter((file2) => {
|
|
29447
|
-
const gate = TARGET_GATED_COMPOSITE_FILES.find((g2) => file2.path.endsWith(g2.suffix));
|
|
29448
|
-
return gate ? gate.target === target : true;
|
|
29593
|
+
if (detected !== "unknown") return detected;
|
|
29594
|
+
if (agentMode || !isInteractive()) return "unknown";
|
|
29595
|
+
const picked = await select({
|
|
29596
|
+
message: "Couldn't auto-detect your framework. Which one is this?",
|
|
29597
|
+
choices: SELECTABLE_FRAMEWORKS.map((value) => ({
|
|
29598
|
+
name: FRAMEWORK_SPECS[value].label ?? value,
|
|
29599
|
+
value
|
|
29600
|
+
}))
|
|
29449
29601
|
});
|
|
29602
|
+
return picked;
|
|
29450
29603
|
}
|
|
29451
|
-
|
|
29452
|
-
|
|
29453
|
-
|
|
29454
|
-
const { components, primitives, composites: composites2, rules, substrate } = config2.installed;
|
|
29455
|
-
const bucketByType = {
|
|
29456
|
-
ui: components,
|
|
29457
|
-
primitive: primitives,
|
|
29458
|
-
composite: composites2 ?? [],
|
|
29459
|
-
rule: rules ?? [],
|
|
29460
|
-
substrate: substrate ?? []
|
|
29461
|
-
};
|
|
29462
|
-
return bucketByType[item.type].includes(item.name);
|
|
29463
|
-
}
|
|
29464
|
-
function isInstalledOnDisk(config2, item, cwd) {
|
|
29465
|
-
if (!isAlreadyInstalled(config2, item)) return false;
|
|
29466
|
-
const filesToCheck = item.type === "ui" ? selectFilesForFramework(item.files, getComponentTarget(config2)).files : item.files;
|
|
29467
|
-
for (const file2 of filesToCheck) {
|
|
29468
|
-
if (fileExists(cwd, transformPath(file2.path, config2, cwd))) return true;
|
|
29469
|
-
}
|
|
29470
|
-
return false;
|
|
29471
|
-
}
|
|
29472
|
-
function trackInstalled(config2, items) {
|
|
29473
|
-
if (!config2.installed) {
|
|
29474
|
-
config2.installed = { components: [], primitives: [], composites: [], rules: [] };
|
|
29604
|
+
async function promptExportFormats(existingConfig) {
|
|
29605
|
+
if (!isInteractive()) {
|
|
29606
|
+
return existingConfig ?? DEFAULT_EXPORTS;
|
|
29475
29607
|
}
|
|
29476
|
-
const
|
|
29477
|
-
|
|
29478
|
-
|
|
29479
|
-
|
|
29480
|
-
|
|
29481
|
-
|
|
29482
|
-
|
|
29483
|
-
|
|
29484
|
-
|
|
29485
|
-
|
|
29486
|
-
|
|
29487
|
-
|
|
29488
|
-
|
|
29489
|
-
if (!bucket.includes(item.name)) bucket.push(item.name);
|
|
29490
|
-
}
|
|
29491
|
-
installed.components.sort();
|
|
29492
|
-
installed.primitives.sort();
|
|
29493
|
-
installed.composites.sort();
|
|
29494
|
-
installed.rules.sort();
|
|
29495
|
-
installed.substrate.sort();
|
|
29496
|
-
}
|
|
29497
|
-
function rootFor(field, cwd, fallback) {
|
|
29498
|
-
return field === void 0 ? fallback : resolveRoot(field, cwd, fallback);
|
|
29499
|
-
}
|
|
29500
|
-
function transformPath(registryPath, config2, cwd = process.cwd()) {
|
|
29501
|
-
if (!config2) return registryPath;
|
|
29502
|
-
const replacements = [
|
|
29503
|
-
["components/ui/", config2.componentsPath, "components/ui"],
|
|
29504
|
-
["lib/primitives/", config2.primitivesPath, "lib/primitives"],
|
|
29505
|
-
["composites/", config2.compositesPath, "composites"],
|
|
29506
|
-
["rules/", config2.rulesPath, "lib/rules"]
|
|
29608
|
+
const choices = EXPORT_CHOICES.map((choice) => ({
|
|
29609
|
+
name: choice.name,
|
|
29610
|
+
value: choice.value,
|
|
29611
|
+
checked: existingConfig ? existingConfig[choice.value] : choice.checked
|
|
29612
|
+
}));
|
|
29613
|
+
const allChoices = [
|
|
29614
|
+
...choices,
|
|
29615
|
+
...FUTURE_EXPORTS.map((choice) => ({
|
|
29616
|
+
name: `${choice.name} (${choice.disabled})`,
|
|
29617
|
+
value: choice.value,
|
|
29618
|
+
checked: false,
|
|
29619
|
+
disabled: true
|
|
29620
|
+
}))
|
|
29507
29621
|
];
|
|
29508
|
-
|
|
29509
|
-
|
|
29510
|
-
|
|
29622
|
+
const selections = await checkbox({
|
|
29623
|
+
message: "What would you like to export?",
|
|
29624
|
+
choices: allChoices,
|
|
29625
|
+
required: true
|
|
29626
|
+
});
|
|
29627
|
+
return selectionsToConfig(selections);
|
|
29628
|
+
}
|
|
29629
|
+
function isTailwindCliInstalled() {
|
|
29630
|
+
const require2 = createRequire(import.meta.url);
|
|
29631
|
+
try {
|
|
29632
|
+
require2.resolve("@tailwindcss/cli/package.json");
|
|
29633
|
+
return true;
|
|
29634
|
+
} catch (err) {
|
|
29635
|
+
if (err instanceof Error && "code" in err && err.code === "MODULE_NOT_FOUND") {
|
|
29636
|
+
return false;
|
|
29511
29637
|
}
|
|
29638
|
+
throw err;
|
|
29512
29639
|
}
|
|
29513
|
-
return registryPath;
|
|
29514
|
-
}
|
|
29515
|
-
function substrateProjectPath(registryPath, config2, cwd = process.cwd()) {
|
|
29516
|
-
const componentsResolved = rootFor(config2?.componentsPath, cwd, "components/ui");
|
|
29517
|
-
const sourceRoot = componentsResolved.replace(/\/?components\/ui$/, "");
|
|
29518
|
-
return sourceRoot ? join7(sourceRoot, registryPath) : registryPath;
|
|
29519
|
-
}
|
|
29520
|
-
function fileExists(cwd, relativePath) {
|
|
29521
|
-
return existsSync3(join7(cwd, relativePath));
|
|
29522
29640
|
}
|
|
29523
|
-
function
|
|
29524
|
-
|
|
29525
|
-
|
|
29526
|
-
|
|
29527
|
-
const primitivesPath = rootFor(config2?.primitivesPath, cwd, "lib/primitives");
|
|
29528
|
-
const stripSourceRoot = (p2) => p2.replace(/^(src|app)\//, "");
|
|
29529
|
-
const aliasComponents = stripSourceRoot(componentsPath);
|
|
29530
|
-
const aliasPrimitives = stripSourceRoot(primitivesPath);
|
|
29531
|
-
transformed = transformed.replace(
|
|
29532
|
-
/from\s+['"]\.\.\/\.\.\/primitives\/([^'"]+)['"]/g,
|
|
29533
|
-
`from '@/${aliasPrimitives}/$1'`
|
|
29534
|
-
);
|
|
29535
|
-
transformed = transformed.replace(
|
|
29536
|
-
/from\s+['"]\.\.\/primitives\/([^'"]+)['"]/g,
|
|
29537
|
-
`from '@/${aliasPrimitives}/$1'`
|
|
29538
|
-
);
|
|
29539
|
-
const substrateOwnDir = fileType === "substrate" && installPath ? stripSourceRoot(dirname(installPath)) : null;
|
|
29540
|
-
const aliasSibling = fileType === "primitive" ? aliasPrimitives : substrateOwnDir ?? aliasComponents;
|
|
29541
|
-
transformed = transformed.replace(/from\s+['"]\.\/([^'"]+)['"]/g, `from '@/${aliasSibling}/$1'`);
|
|
29542
|
-
if (substrateKinds.length > 0) {
|
|
29543
|
-
const kindAlternation = substrateKinds.join("|");
|
|
29544
|
-
transformed = transformed.replace(
|
|
29545
|
-
new RegExp(`from\\s+['"](?:\\.\\./){1,2}(${kindAlternation})/([^'"]+)['"]`, "g"),
|
|
29546
|
-
"from '@/$1/$2'"
|
|
29641
|
+
async function ensureTailwindCli(cwd) {
|
|
29642
|
+
if (!isInteractive() || isAgentMode()) {
|
|
29643
|
+
throw new Error(
|
|
29644
|
+
"Standalone CSS export requires @tailwindcss/cli. Install it as a dev dependency in your project."
|
|
29547
29645
|
);
|
|
29548
29646
|
}
|
|
29549
|
-
|
|
29550
|
-
/
|
|
29551
|
-
|
|
29552
|
-
);
|
|
29553
|
-
|
|
29554
|
-
/
|
|
29555
|
-
`from '@/${aliasComponents}/$1'`
|
|
29556
|
-
);
|
|
29557
|
-
return transformed;
|
|
29558
|
-
}
|
|
29559
|
-
async function installItem(cwd, item, options, config2, substrateKinds = []) {
|
|
29560
|
-
const installedFiles = [];
|
|
29561
|
-
let skipped = false;
|
|
29562
|
-
let filesToInstall = item.files;
|
|
29563
|
-
if (item.type === "ui") {
|
|
29564
|
-
const target = getComponentTarget(config2);
|
|
29565
|
-
const selection = selectFilesForFramework(item.files, target);
|
|
29566
|
-
filesToInstall = selection.files;
|
|
29567
|
-
if (selection.fallback) {
|
|
29568
|
-
log({
|
|
29569
|
-
event: "add:fallback",
|
|
29570
|
-
component: item.name,
|
|
29571
|
-
target,
|
|
29572
|
-
message: `No ${targetToExtension(target)} version available for ${item.name}. Installing React version.`
|
|
29573
|
-
});
|
|
29574
|
-
}
|
|
29575
|
-
const hasComponentFile = selection.files.some((f) => !isSharedFile(f.path));
|
|
29576
|
-
if (!hasComponentFile) {
|
|
29577
|
-
throw new Error(
|
|
29578
|
-
`No ${targetToExtension(target)} version available for "${item.name}" and no compatible fallback exists.`
|
|
29579
|
-
);
|
|
29580
|
-
}
|
|
29581
|
-
} else if (item.type === "composite") {
|
|
29582
|
-
filesToInstall = selectCompositeFiles(item.files, getComponentTarget(config2));
|
|
29647
|
+
const shouldInstall = await confirm({
|
|
29648
|
+
message: "Standalone CSS requires @tailwindcss/cli. Install it now?",
|
|
29649
|
+
default: true
|
|
29650
|
+
});
|
|
29651
|
+
if (!shouldInstall) {
|
|
29652
|
+
throw new Error("Standalone CSS export requires @tailwindcss/cli.");
|
|
29583
29653
|
}
|
|
29584
|
-
|
|
29585
|
-
|
|
29586
|
-
|
|
29587
|
-
|
|
29588
|
-
|
|
29589
|
-
log({
|
|
29590
|
-
event: "add:skip",
|
|
29591
|
-
component: item.name,
|
|
29592
|
-
file: projectPath2,
|
|
29593
|
-
reason: "exists"
|
|
29594
|
-
});
|
|
29595
|
-
skipped = true;
|
|
29596
|
-
continue;
|
|
29597
|
-
}
|
|
29598
|
-
}
|
|
29599
|
-
await mkdir2(dirname(targetPath), { recursive: true });
|
|
29600
|
-
const fileType = item.type === "primitive" ? "primitive" : item.type === "substrate" ? "substrate" : "component";
|
|
29601
|
-
const transformedContent = transformFileContent(file2.content, config2, fileType, cwd, {
|
|
29602
|
-
substrateKinds,
|
|
29603
|
-
installPath: file2.path
|
|
29604
|
-
});
|
|
29605
|
-
await writeFile2(targetPath, transformedContent, "utf-8");
|
|
29606
|
-
installedFiles.push(projectPath2);
|
|
29654
|
+
await updateDependencies([], ["@tailwindcss/cli"], { cwd });
|
|
29655
|
+
if (!isTailwindCliInstalled()) {
|
|
29656
|
+
throw new Error(
|
|
29657
|
+
"@tailwindcss/cli was installed but cannot be resolved. Try installing at the workspace root."
|
|
29658
|
+
);
|
|
29607
29659
|
}
|
|
29608
|
-
return {
|
|
29609
|
-
installed: installedFiles.length > 0,
|
|
29610
|
-
skipped,
|
|
29611
|
-
files: installedFiles
|
|
29612
|
-
};
|
|
29613
29660
|
}
|
|
29614
|
-
async function
|
|
29615
|
-
|
|
29616
|
-
|
|
29617
|
-
|
|
29618
|
-
|
|
29619
|
-
const client = new RegistryClient(resolveRegistryUrl(options, config2));
|
|
29620
|
-
let folder;
|
|
29621
|
-
const firstArg = components[0];
|
|
29622
|
-
if (firstArg && FOLDER_NAMES.has(firstArg)) {
|
|
29623
|
-
folder = firstArg;
|
|
29624
|
-
components = components.slice(1);
|
|
29625
|
-
}
|
|
29626
|
-
if (options.list) {
|
|
29627
|
-
const availableComponents = await client.listComponents();
|
|
29628
|
-
const availableComposites = await client.listComposites();
|
|
29629
|
-
if (options.agent) {
|
|
29630
|
-
log({
|
|
29631
|
-
event: "add:list",
|
|
29632
|
-
components: availableComponents,
|
|
29633
|
-
composites: availableComposites
|
|
29634
|
-
});
|
|
29635
|
-
} else {
|
|
29636
|
-
console.log("Available components:\n");
|
|
29637
|
-
for (const comp of availableComponents) {
|
|
29638
|
-
console.log(` ${comp.name} ${comp.description ?? ""}`);
|
|
29639
|
-
}
|
|
29640
|
-
if (availableComposites.length > 0) {
|
|
29641
|
-
console.log("\nAvailable composites:\n");
|
|
29642
|
-
for (const comp of availableComposites) {
|
|
29643
|
-
console.log(` ${comp.name} ${comp.description ?? ""}`);
|
|
29644
|
-
}
|
|
29645
|
-
}
|
|
29646
|
-
}
|
|
29647
|
-
return;
|
|
29661
|
+
async function generateOutputs(cwd, paths, registry2, exports, source, darkMode = "class", config2) {
|
|
29662
|
+
const contentSources = config2 ? resolveContentSources(cwd, config2) : [];
|
|
29663
|
+
if (exports.compiled && !isTailwindCliInstalled()) {
|
|
29664
|
+
log({ event: "init:prompting_exports" });
|
|
29665
|
+
await ensureTailwindCli(cwd);
|
|
29648
29666
|
}
|
|
29649
|
-
|
|
29650
|
-
|
|
29651
|
-
error46("Project not initialized. Run `rafters init` first.");
|
|
29652
|
-
process.exitCode = 1;
|
|
29653
|
-
return;
|
|
29667
|
+
if (exports.compiled) {
|
|
29668
|
+
log({ event: "init:compiling_css" });
|
|
29654
29669
|
}
|
|
29655
|
-
|
|
29656
|
-
|
|
29670
|
+
return regenerateOutputs(registry2, {
|
|
29671
|
+
outputDir: paths.output,
|
|
29672
|
+
exports,
|
|
29673
|
+
contentSources,
|
|
29674
|
+
darkMode,
|
|
29675
|
+
includeImport: source !== "shadcn"
|
|
29676
|
+
});
|
|
29677
|
+
}
|
|
29678
|
+
async function regenerateFromExisting(cwd, paths, source, isAgentMode2, framework) {
|
|
29679
|
+
log({ event: "init:regenerate", cwd });
|
|
29680
|
+
let existingConfig = null;
|
|
29681
|
+
try {
|
|
29682
|
+
const configContent = await readFile3(paths.config, "utf-8");
|
|
29683
|
+
existingConfig = migrateConfig(
|
|
29684
|
+
JSON.parse(configContent)
|
|
29685
|
+
);
|
|
29686
|
+
} catch {
|
|
29657
29687
|
}
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
|
|
29661
|
-
|
|
29662
|
-
|
|
29663
|
-
|
|
29664
|
-
|
|
29665
|
-
}
|
|
29666
|
-
const trackedNames = getInstalledNames(config2);
|
|
29667
|
-
untrackedNames = await discoverUntrackedNames(cwd, config2, client, trackedNames);
|
|
29668
|
-
const candidates = [.../* @__PURE__ */ new Set([...trackedNames, ...untrackedNames])].sort();
|
|
29669
|
-
if (candidates.length === 0) {
|
|
29670
|
-
error46("No installed components found. Use 'rafters add <component>' to install first.");
|
|
29671
|
-
process.exitCode = 1;
|
|
29672
|
-
return;
|
|
29673
|
-
}
|
|
29674
|
-
if (untrackedNames.length > 0) {
|
|
29675
|
-
log({
|
|
29676
|
-
event: "add:untracked",
|
|
29677
|
-
components: untrackedNames,
|
|
29678
|
-
message: `Found ${untrackedNames.length} component(s) on disk the config never tracked: ${untrackedNames.join(", ")}. Refreshing and tracking them.`
|
|
29679
|
-
});
|
|
29680
|
-
}
|
|
29681
|
-
components = candidates;
|
|
29688
|
+
if (framework !== "unknown" && existingConfig) {
|
|
29689
|
+
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
29690
|
+
existingConfig.framework = framework;
|
|
29691
|
+
existingConfig.componentsPath = frameworkPaths.components;
|
|
29692
|
+
existingConfig.primitivesPath = frameworkPaths.primitives;
|
|
29693
|
+
existingConfig.compositesPath = frameworkPaths.composites;
|
|
29694
|
+
existingConfig.rulesPath = frameworkPaths.rules;
|
|
29682
29695
|
}
|
|
29683
|
-
|
|
29684
|
-
|
|
29685
|
-
|
|
29686
|
-
if (
|
|
29687
|
-
|
|
29688
|
-
process.exitCode = 1;
|
|
29689
|
-
return;
|
|
29696
|
+
await rm(join7(paths.tokens, "elevation.rafters.json"), { force: true });
|
|
29697
|
+
await rm(join7(paths.tokens, "fill.rafters.json"), { force: true });
|
|
29698
|
+
const registry2 = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS);
|
|
29699
|
+
if (registry2.size() === 0) {
|
|
29700
|
+
throw new Error("No tokens found. Cannot regenerate without existing tokens.");
|
|
29690
29701
|
}
|
|
29702
|
+
const namespaces = [...new Set(registry2.list().map((t) => t.namespace))];
|
|
29691
29703
|
log({
|
|
29692
|
-
event: "
|
|
29693
|
-
|
|
29694
|
-
|
|
29695
|
-
overwrite: options.overwrite ?? false
|
|
29704
|
+
event: "init:loaded",
|
|
29705
|
+
tokenCount: registry2.size(),
|
|
29706
|
+
namespaces
|
|
29696
29707
|
});
|
|
29697
|
-
|
|
29698
|
-
|
|
29699
|
-
|
|
29700
|
-
|
|
29701
|
-
|
|
29702
|
-
|
|
29703
|
-
|
|
29704
|
-
seen.add(itemName);
|
|
29705
|
-
allItems.push(composite);
|
|
29706
|
-
for (const dep of composite.primitives) {
|
|
29707
|
-
if (!seen.has(dep)) {
|
|
29708
|
-
const depItems = await client.resolveDependencies(dep, seen);
|
|
29709
|
-
allItems.push(...depItems);
|
|
29710
|
-
}
|
|
29711
|
-
}
|
|
29712
|
-
}
|
|
29713
|
-
} else {
|
|
29714
|
-
const items = await client.resolveDependencies(itemName, seen);
|
|
29715
|
-
allItems.push(...items);
|
|
29716
|
-
}
|
|
29717
|
-
} catch (err) {
|
|
29718
|
-
if (err instanceof Error) {
|
|
29719
|
-
error46(err.message);
|
|
29720
|
-
} else {
|
|
29721
|
-
error46(`Failed to fetch "${itemName}"`);
|
|
29722
|
-
}
|
|
29723
|
-
process.exitCode = 1;
|
|
29724
|
-
return;
|
|
29708
|
+
let exports;
|
|
29709
|
+
if (isAgentMode2) {
|
|
29710
|
+
exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
|
|
29711
|
+
log({ event: "init:exports_default", exports });
|
|
29712
|
+
} else {
|
|
29713
|
+
if (isInteractive()) {
|
|
29714
|
+
log({ event: "init:prompting_exports" });
|
|
29725
29715
|
}
|
|
29716
|
+
exports = await promptExportFormats(existingConfig?.exports);
|
|
29717
|
+
log({ event: "init:exports_selected", exports });
|
|
29726
29718
|
}
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
|
|
29734
|
-
|
|
29735
|
-
|
|
29736
|
-
|
|
29737
|
-
|
|
29738
|
-
|
|
29739
|
-
|
|
29740
|
-
|
|
29741
|
-
|
|
29742
|
-
|
|
29743
|
-
|
|
29744
|
-
|
|
29745
|
-
|
|
29746
|
-
|
|
29747
|
-
|
|
29748
|
-
|
|
29749
|
-
|
|
29750
|
-
|
|
29751
|
-
|
|
29752
|
-
|
|
29753
|
-
}
|
|
29754
|
-
}
|
|
29755
|
-
|
|
29756
|
-
const result = await installItem(cwd, item, options, config2, substrateKinds);
|
|
29757
|
-
if (result.installed) {
|
|
29758
|
-
written.push(item.name);
|
|
29759
|
-
installedItems.push(item);
|
|
29760
|
-
if (item.type === "ui") {
|
|
29761
|
-
const selection = selectFilesForFramework(item.files, target);
|
|
29762
|
-
filteredItems.push({ ...item, files: selection.files });
|
|
29763
|
-
} else {
|
|
29764
|
-
filteredItems.push(item);
|
|
29765
|
-
}
|
|
29766
|
-
log({
|
|
29767
|
-
event: "add:installed",
|
|
29768
|
-
component: item.name,
|
|
29769
|
-
type: item.type,
|
|
29770
|
-
files: result.files
|
|
29771
|
-
});
|
|
29772
|
-
}
|
|
29773
|
-
if (result.skipped && !result.installed) {
|
|
29774
|
-
skipped.push(item.name);
|
|
29775
|
-
installedItems.push(item);
|
|
29776
|
-
}
|
|
29777
|
-
} catch (err) {
|
|
29778
|
-
failed.push(item.name);
|
|
29779
|
-
if (err instanceof Error) {
|
|
29780
|
-
log({
|
|
29781
|
-
event: "add:warning",
|
|
29782
|
-
component: item.name,
|
|
29783
|
-
message: err.message
|
|
29784
|
-
});
|
|
29785
|
-
}
|
|
29786
|
-
}
|
|
29719
|
+
await mkdir2(paths.output, { recursive: true });
|
|
29720
|
+
const outputs = await generateOutputs(
|
|
29721
|
+
cwd,
|
|
29722
|
+
paths,
|
|
29723
|
+
registry2,
|
|
29724
|
+
exports,
|
|
29725
|
+
source,
|
|
29726
|
+
"class",
|
|
29727
|
+
existingConfig
|
|
29728
|
+
);
|
|
29729
|
+
if (existingConfig) {
|
|
29730
|
+
existingConfig.exports = exports;
|
|
29731
|
+
await writeFile2(paths.config, JSON.stringify(existingConfig, null, 2));
|
|
29732
|
+
} else {
|
|
29733
|
+
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
29734
|
+
const newConfig = {
|
|
29735
|
+
framework,
|
|
29736
|
+
componentsPath: frameworkPaths.components,
|
|
29737
|
+
primitivesPath: frameworkPaths.primitives,
|
|
29738
|
+
compositesPath: frameworkPaths.composites,
|
|
29739
|
+
rulesPath: frameworkPaths.rules,
|
|
29740
|
+
cssPath: null,
|
|
29741
|
+
...source ? { source } : {},
|
|
29742
|
+
intent: "efficient",
|
|
29743
|
+
fonts: { path: null, imports: [] },
|
|
29744
|
+
exports,
|
|
29745
|
+
installed: { components: [], primitives: [], composites: [], rules: [] }
|
|
29746
|
+
};
|
|
29747
|
+
await writeFile2(paths.config, JSON.stringify(newConfig, null, 2));
|
|
29787
29748
|
}
|
|
29788
|
-
|
|
29789
|
-
|
|
29790
|
-
|
|
29791
|
-
|
|
29792
|
-
|
|
29793
|
-
|
|
29794
|
-
|
|
29749
|
+
log({
|
|
29750
|
+
event: "init:complete",
|
|
29751
|
+
outputs,
|
|
29752
|
+
path: paths.output
|
|
29753
|
+
});
|
|
29754
|
+
}
|
|
29755
|
+
async function resetToDefaults(cwd, paths, source, isAgentMode2, framework) {
|
|
29756
|
+
log({ event: "init:reset", cwd });
|
|
29757
|
+
let existingConfig = null;
|
|
29795
29758
|
try {
|
|
29796
|
-
|
|
29797
|
-
|
|
29798
|
-
|
|
29799
|
-
|
|
29800
|
-
|
|
29801
|
-
message: `Failed to process dependencies: ${message}`,
|
|
29802
|
-
dependencies: [],
|
|
29803
|
-
suggestion: "Check package.json and try installing dependencies manually."
|
|
29804
|
-
});
|
|
29759
|
+
const configContent = await readFile3(paths.config, "utf-8");
|
|
29760
|
+
existingConfig = migrateConfig(
|
|
29761
|
+
JSON.parse(configContent)
|
|
29762
|
+
);
|
|
29763
|
+
} catch {
|
|
29805
29764
|
}
|
|
29806
|
-
if (
|
|
29765
|
+
if (framework !== "unknown" && existingConfig) {
|
|
29766
|
+
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
29767
|
+
existingConfig.framework = framework;
|
|
29768
|
+
existingConfig.componentsPath = frameworkPaths.components;
|
|
29769
|
+
existingConfig.primitivesPath = frameworkPaths.primitives;
|
|
29770
|
+
existingConfig.compositesPath = frameworkPaths.composites;
|
|
29771
|
+
existingConfig.rulesPath = frameworkPaths.rules;
|
|
29772
|
+
}
|
|
29773
|
+
let existingTokens = [];
|
|
29774
|
+
try {
|
|
29775
|
+
existingTokens = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS).list();
|
|
29776
|
+
} catch {
|
|
29777
|
+
}
|
|
29778
|
+
const overriddenTokens = existingTokens.filter((t) => t.userOverride);
|
|
29779
|
+
if (overriddenTokens.length > 0) {
|
|
29780
|
+
const backup = {
|
|
29781
|
+
resetAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29782
|
+
reason: "rafters init --reset",
|
|
29783
|
+
overrides: overriddenTokens.map((t) => ({
|
|
29784
|
+
name: t.name,
|
|
29785
|
+
value: t.value,
|
|
29786
|
+
userOverride: t.userOverride,
|
|
29787
|
+
namespace: t.namespace
|
|
29788
|
+
}))
|
|
29789
|
+
};
|
|
29790
|
+
await mkdir2(paths.output, { recursive: true });
|
|
29791
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
29792
|
+
const backupPath = join7(paths.output, `reset-${timestamp}.json`);
|
|
29793
|
+
await writeFile2(backupPath, JSON.stringify(backup, null, 2));
|
|
29807
29794
|
log({
|
|
29808
|
-
event: "
|
|
29809
|
-
|
|
29810
|
-
|
|
29811
|
-
skipped: depsResult.skipped
|
|
29795
|
+
event: "init:reset_backup",
|
|
29796
|
+
path: backupPath,
|
|
29797
|
+
overrideCount: overriddenTokens.length
|
|
29812
29798
|
});
|
|
29813
29799
|
}
|
|
29814
|
-
|
|
29815
|
-
|
|
29816
|
-
|
|
29817
|
-
|
|
29818
|
-
} else
|
|
29800
|
+
let exports;
|
|
29801
|
+
if (isAgentMode2) {
|
|
29802
|
+
exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
|
|
29803
|
+
log({ event: "init:exports_default", exports });
|
|
29804
|
+
} else {
|
|
29805
|
+
if (isInteractive()) {
|
|
29806
|
+
log({ event: "init:prompting_exports" });
|
|
29807
|
+
}
|
|
29808
|
+
exports = await promptExportFormats(existingConfig?.exports);
|
|
29809
|
+
log({ event: "init:exports_selected", exports });
|
|
29810
|
+
}
|
|
29811
|
+
const system = generateBaseSystem({});
|
|
29812
|
+
const registry2 = new TokenRegistry(system.allTokens, REGISTRY_PLUGINS);
|
|
29813
|
+
log({
|
|
29814
|
+
event: "init:reset_generated",
|
|
29815
|
+
tokenCount: registry2.size()
|
|
29816
|
+
});
|
|
29817
|
+
await rm(paths.tokens, { recursive: true, force: true });
|
|
29818
|
+
await mkdir2(paths.tokens, { recursive: true });
|
|
29819
|
+
saveRegistryToDir(paths.tokens, registry2);
|
|
29820
|
+
const allTokensToSave = registry2.list();
|
|
29821
|
+
const namespaceCount = new Set(allTokensToSave.map((t) => t.namespace)).size;
|
|
29822
|
+
log({
|
|
29823
|
+
event: "init:registry_saved",
|
|
29824
|
+
path: paths.tokens,
|
|
29825
|
+
namespaceCount
|
|
29826
|
+
});
|
|
29827
|
+
await mkdir2(paths.output, { recursive: true });
|
|
29828
|
+
const outputs = await generateOutputs(
|
|
29829
|
+
cwd,
|
|
29830
|
+
paths,
|
|
29831
|
+
registry2,
|
|
29832
|
+
exports,
|
|
29833
|
+
source,
|
|
29834
|
+
"class",
|
|
29835
|
+
existingConfig
|
|
29836
|
+
);
|
|
29837
|
+
if (existingConfig) {
|
|
29838
|
+
existingConfig.exports = exports;
|
|
29839
|
+
await writeFile2(paths.config, JSON.stringify(existingConfig, null, 2));
|
|
29840
|
+
} else {
|
|
29841
|
+
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
29819
29842
|
const newConfig = {
|
|
29820
|
-
framework
|
|
29821
|
-
componentsPath:
|
|
29822
|
-
primitivesPath:
|
|
29823
|
-
compositesPath:
|
|
29824
|
-
rulesPath:
|
|
29843
|
+
framework,
|
|
29844
|
+
componentsPath: frameworkPaths.components,
|
|
29845
|
+
primitivesPath: frameworkPaths.primitives,
|
|
29846
|
+
compositesPath: frameworkPaths.composites,
|
|
29847
|
+
rulesPath: frameworkPaths.rules,
|
|
29825
29848
|
cssPath: null,
|
|
29826
|
-
|
|
29827
|
-
|
|
29849
|
+
...source ? { source } : {},
|
|
29850
|
+
intent: "efficient",
|
|
29851
|
+
fonts: { path: null, imports: [] },
|
|
29852
|
+
exports,
|
|
29828
29853
|
installed: { components: [], primitives: [], composites: [], rules: [] }
|
|
29829
29854
|
};
|
|
29830
|
-
|
|
29831
|
-
await saveConfig(cwd, newConfig);
|
|
29832
|
-
await regenerateAfterInstall(cwd, newConfig);
|
|
29855
|
+
await writeFile2(paths.config, JSON.stringify(newConfig, null, 2));
|
|
29833
29856
|
}
|
|
29834
29857
|
log({
|
|
29835
|
-
event: "
|
|
29836
|
-
|
|
29837
|
-
|
|
29838
|
-
untracked: untrackedNames.length,
|
|
29839
|
-
failed: failed.length,
|
|
29840
|
-
components: written,
|
|
29841
|
-
skippedComponents: skipped,
|
|
29842
|
-
untrackedComponents: untrackedNames,
|
|
29843
|
-
failedComponents: failed
|
|
29858
|
+
event: "init:complete",
|
|
29859
|
+
outputs,
|
|
29860
|
+
path: paths.output
|
|
29844
29861
|
});
|
|
29845
|
-
|
|
29846
|
-
|
|
29847
|
-
|
|
29848
|
-
|
|
29862
|
+
}
|
|
29863
|
+
async function init(options) {
|
|
29864
|
+
setAgentMode(options.agent ?? false);
|
|
29865
|
+
const isAgentMode2 = options.agent ?? false;
|
|
29866
|
+
const cwd = process.cwd();
|
|
29867
|
+
const paths = getRaftersPaths(cwd);
|
|
29868
|
+
log({ event: "init:start", cwd });
|
|
29869
|
+
const project = await detectProject(cwd);
|
|
29870
|
+
const { framework: detectedFramework, shadcn, tailwindVersion, astroHasReact } = project;
|
|
29871
|
+
const source = shadcn ? "shadcn" : void 0;
|
|
29872
|
+
log({
|
|
29873
|
+
event: "init:detected",
|
|
29874
|
+
framework: detectedFramework,
|
|
29875
|
+
tailwindVersion,
|
|
29876
|
+
hasShadcn: !!shadcn
|
|
29877
|
+
});
|
|
29878
|
+
const framework = await resolveFramework(detectedFramework, options.framework, isAgentMode2);
|
|
29879
|
+
if (framework !== detectedFramework) {
|
|
29849
29880
|
log({
|
|
29850
|
-
event: "
|
|
29851
|
-
|
|
29852
|
-
|
|
29881
|
+
event: "init:framework_resolved",
|
|
29882
|
+
detected: detectedFramework,
|
|
29883
|
+
resolved: framework,
|
|
29884
|
+
source: options.framework ? "flag" : "prompt"
|
|
29853
29885
|
});
|
|
29854
|
-
error46("Component already exists. Use --update to re-fetch from registry.");
|
|
29855
|
-
process.exitCode = 1;
|
|
29856
29886
|
}
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
// src/commands/init.ts
|
|
29860
|
-
import { existsSync as existsSync4 } from "fs";
|
|
29861
|
-
import { copyFile, mkdir as mkdir3, readFile as readFile4, rm, writeFile as writeFile3 } from "fs/promises";
|
|
29862
|
-
import { createRequire } from "module";
|
|
29863
|
-
import { join as join8, relative as relative2 } from "path";
|
|
29864
|
-
import { checkbox, confirm, select } from "@inquirer/prompts";
|
|
29865
|
-
var REGISTRY_PLUGINS2 = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
|
|
29866
|
-
async function backupCss(cssPath) {
|
|
29867
|
-
const backupPath = cssPath.replace(/\.css$/, ".backup.css");
|
|
29868
|
-
await copyFile(cssPath, backupPath);
|
|
29869
|
-
return backupPath;
|
|
29870
|
-
}
|
|
29871
|
-
function cleanSourceCssBlocks(content) {
|
|
29872
|
-
function parseBlocks(src) {
|
|
29873
|
-
const blocks = [];
|
|
29874
|
-
let depth = 0;
|
|
29875
|
-
const headerStack = [];
|
|
29876
|
-
let segmentStart = 0;
|
|
29877
|
-
for (let i = 0; i < src.length; i++) {
|
|
29878
|
-
const ch = src.charAt(i);
|
|
29879
|
-
if (ch === "{") {
|
|
29880
|
-
headerStack.push(segmentStart);
|
|
29881
|
-
depth++;
|
|
29882
|
-
if (depth >= 1) {
|
|
29883
|
-
blocks.push({
|
|
29884
|
-
headerStart: segmentStart,
|
|
29885
|
-
bodyStart: i + 1,
|
|
29886
|
-
end: -1,
|
|
29887
|
-
header: src.slice(segmentStart, i).trim()
|
|
29888
|
-
});
|
|
29889
|
-
}
|
|
29890
|
-
segmentStart = i + 1;
|
|
29891
|
-
} else if (ch === "}") {
|
|
29892
|
-
depth--;
|
|
29893
|
-
const open = blocks.slice().reverse().find((b2) => b2.end === -1);
|
|
29894
|
-
if (open) open.end = i + 1;
|
|
29895
|
-
headerStack.pop();
|
|
29896
|
-
segmentStart = i + 1;
|
|
29897
|
-
} else if (ch === ";") {
|
|
29898
|
-
segmentStart = i + 1;
|
|
29899
|
-
}
|
|
29900
|
-
}
|
|
29901
|
-
return blocks.filter((b2) => b2.end !== -1);
|
|
29887
|
+
if (isTailwindV3(tailwindVersion)) {
|
|
29888
|
+
throw new Error("Tailwind v3 detected. Rafters requires Tailwind v4.");
|
|
29902
29889
|
}
|
|
29903
|
-
|
|
29904
|
-
|
|
29890
|
+
const raftersExists = existsSync3(paths.root);
|
|
29891
|
+
if (options.reset && !raftersExists) {
|
|
29892
|
+
throw new Error("Nothing to reset. No .rafters/ directory found.");
|
|
29905
29893
|
}
|
|
29906
|
-
|
|
29907
|
-
|
|
29908
|
-
|
|
29909
|
-
let edited = false;
|
|
29910
|
-
for (const block of blocks.sort((a2, b2) => b2.headerStart - a2.headerStart)) {
|
|
29911
|
-
const header = block.header;
|
|
29912
|
-
if (/^@theme\s+inline$/.test(header)) {
|
|
29913
|
-
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29914
|
-
edited = true;
|
|
29915
|
-
break;
|
|
29916
|
-
}
|
|
29917
|
-
if (header === ":root" || /(^|,)\s*:root\s*$/.test(header)) {
|
|
29918
|
-
const body = out.slice(block.bodyStart, block.end - 1);
|
|
29919
|
-
const cleanedBody = body.replace(/--[\w-]+\s*:[^;{}]*;?/g, "");
|
|
29920
|
-
if (isContentEmpty(cleanedBody)) {
|
|
29921
|
-
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29922
|
-
edited = true;
|
|
29923
|
-
break;
|
|
29924
|
-
}
|
|
29925
|
-
if (cleanedBody !== body) {
|
|
29926
|
-
out = out.slice(0, block.bodyStart) + cleanedBody + out.slice(block.end - 1);
|
|
29927
|
-
edited = true;
|
|
29928
|
-
break;
|
|
29929
|
-
}
|
|
29930
|
-
continue;
|
|
29931
|
-
}
|
|
29932
|
-
if (header.startsWith("@media") || header.startsWith("@supports")) {
|
|
29933
|
-
const body = out.slice(block.bodyStart, block.end - 1);
|
|
29934
|
-
if (isContentEmpty(body)) {
|
|
29935
|
-
out = out.slice(0, block.headerStart) + out.slice(block.end);
|
|
29936
|
-
edited = true;
|
|
29937
|
-
break;
|
|
29938
|
-
}
|
|
29939
|
-
}
|
|
29940
|
-
}
|
|
29941
|
-
if (!edited) break;
|
|
29894
|
+
if (raftersExists && options.reset) {
|
|
29895
|
+
await resetToDefaults(cwd, paths, source, isAgentMode2, framework);
|
|
29896
|
+
return;
|
|
29942
29897
|
}
|
|
29943
|
-
|
|
29944
|
-
|
|
29945
|
-
|
|
29946
|
-
|
|
29947
|
-
|
|
29948
|
-
|
|
29949
|
-
|
|
29950
|
-
const cleaned = cleanSourceCssBlocks(content.replace(pattern, ""));
|
|
29951
|
-
const collapsed = cleaned.replace(/\n{3,}/g, "\n\n");
|
|
29952
|
-
await writeFile3(fullPath, collapsed);
|
|
29953
|
-
}
|
|
29954
|
-
async function updateMainCss(cwd, cssPath, themePath) {
|
|
29955
|
-
const fullCssPath = join8(cwd, cssPath);
|
|
29956
|
-
const cssContent = await readFile4(fullCssPath, "utf-8");
|
|
29957
|
-
const cssDir = join8(cwd, cssPath, "..");
|
|
29958
|
-
const themeFullPath = join8(cwd, themePath);
|
|
29959
|
-
const relativeThemePath = relative2(cssDir, themeFullPath);
|
|
29960
|
-
if (cssContent.includes(".rafters/output/rafters.css")) {
|
|
29961
|
-
log({ event: "init:css_already_imported", cssPath });
|
|
29898
|
+
if (raftersExists && !options.rebuild) {
|
|
29899
|
+
throw new Error(
|
|
29900
|
+
".rafters/ directory already exists. Use --rebuild to regenerate output files, or --reset to start from defaults."
|
|
29901
|
+
);
|
|
29902
|
+
}
|
|
29903
|
+
if (raftersExists && options.rebuild) {
|
|
29904
|
+
await regenerateFromExisting(cwd, paths, source, isAgentMode2, framework);
|
|
29962
29905
|
return;
|
|
29963
29906
|
}
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
|
|
29968
|
-
} else if (cssContent.includes("@import 'tailwindcss'")) {
|
|
29969
|
-
newContent = cssContent.replace("@import 'tailwindcss';", `@import "${relativeThemePath}";`);
|
|
29907
|
+
let exports;
|
|
29908
|
+
if (isAgentMode2) {
|
|
29909
|
+
exports = DEFAULT_EXPORTS;
|
|
29910
|
+
log({ event: "init:exports_default", exports });
|
|
29970
29911
|
} else {
|
|
29971
|
-
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
29976
|
-
log({
|
|
29977
|
-
event: "init:css_updated",
|
|
29978
|
-
cssPath,
|
|
29979
|
-
themePath: relativeThemePath
|
|
29980
|
-
});
|
|
29981
|
-
}
|
|
29982
|
-
function isInteractive() {
|
|
29983
|
-
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
29984
|
-
}
|
|
29985
|
-
function resolveSourceCssPath(cwd, framework, detectedFramework, projectCssPath, shadcnCssPath, emit) {
|
|
29986
|
-
if (shadcnCssPath) {
|
|
29987
|
-
if (existsSync4(join8(cwd, shadcnCssPath))) return shadcnCssPath;
|
|
29988
|
-
const fallback = framework === detectedFramework ? projectCssPath : findCssPath(cwd, framework);
|
|
29989
|
-
emit({
|
|
29990
|
-
event: "init:shadcn_css_missing",
|
|
29991
|
-
configuredPath: shadcnCssPath,
|
|
29992
|
-
fallbackPath: fallback,
|
|
29993
|
-
message: "components.json points at a CSS file that does not exist. Falling back to the framework canonical location."
|
|
29994
|
-
});
|
|
29995
|
-
return fallback;
|
|
29912
|
+
if (isInteractive()) {
|
|
29913
|
+
log({ event: "init:prompting_exports" });
|
|
29914
|
+
}
|
|
29915
|
+
exports = await promptExportFormats();
|
|
29916
|
+
log({ event: "init:exports_selected", exports });
|
|
29996
29917
|
}
|
|
29997
|
-
|
|
29998
|
-
}
|
|
29999
|
-
|
|
30000
|
-
|
|
30001
|
-
|
|
30002
|
-
|
|
30003
|
-
|
|
30004
|
-
|
|
30005
|
-
|
|
30006
|
-
return /\b(sans-serif|serif|monospace|cursive|fantasy|system-ui|ui-(?:sans-serif|serif|monospace|rounded))\b/.test(
|
|
30007
|
-
value
|
|
29918
|
+
const adapter = getAdapter(source ?? "tailwind");
|
|
29919
|
+
const baseConfig = {};
|
|
29920
|
+
const sourceCssPathForBase = resolveSourceCssPath(
|
|
29921
|
+
cwd,
|
|
29922
|
+
framework,
|
|
29923
|
+
detectedFramework,
|
|
29924
|
+
project.cssPath,
|
|
29925
|
+
shadcn?.tailwind?.css,
|
|
29926
|
+
log
|
|
30008
29927
|
);
|
|
30009
|
-
|
|
30010
|
-
|
|
30011
|
-
|
|
30012
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
|
|
29928
|
+
if (sourceCssPathForBase !== null) {
|
|
29929
|
+
try {
|
|
29930
|
+
const cssForBase = await readFile3(join7(cwd, sourceCssPathForBase), "utf-8");
|
|
29931
|
+
const baseSlots = [
|
|
29932
|
+
{
|
|
29933
|
+
detect: () => adapter.detectSpacing(cssForBase).base,
|
|
29934
|
+
field: "baseSpacingUnit",
|
|
29935
|
+
event: "init:import_spacing_applied",
|
|
29936
|
+
eventKey: "baseSpacingUnit"
|
|
29937
|
+
},
|
|
29938
|
+
{
|
|
29939
|
+
detect: () => adapter.detectRadius(cssForBase).base,
|
|
29940
|
+
field: "baseRadiusOverride",
|
|
29941
|
+
event: "init:import_radius_applied",
|
|
29942
|
+
eventKey: "baseRadius"
|
|
29943
|
+
},
|
|
29944
|
+
{
|
|
29945
|
+
detect: () => adapter.detectFontSize(cssForBase).base,
|
|
29946
|
+
field: "baseFontSizeOverride",
|
|
29947
|
+
event: "init:import_font_size_applied",
|
|
29948
|
+
eventKey: "baseFontSize"
|
|
29949
|
+
},
|
|
29950
|
+
{
|
|
29951
|
+
detect: () => adapter.detectFocusRing(cssForBase).width,
|
|
29952
|
+
field: "focusRingWidthOverride",
|
|
29953
|
+
event: "init:import_focus_ring_applied",
|
|
29954
|
+
eventKey: "focusRingWidth"
|
|
29955
|
+
}
|
|
29956
|
+
// Motion duration is intentionally not imported -- rafters' motion
|
|
29957
|
+
// system is research-backed and most projects' `--duration-base`
|
|
29958
|
+
// values are unresearched defaults. See importers/bases.ts for the
|
|
29959
|
+
// policy note; designers can `rafters set motion-duration-base ...`
|
|
29960
|
+
// after init to override explicitly.
|
|
29961
|
+
];
|
|
29962
|
+
for (const slot of baseSlots) {
|
|
29963
|
+
const value = slot.detect();
|
|
29964
|
+
if (value === void 0) continue;
|
|
29965
|
+
baseConfig[slot.field] = value;
|
|
29966
|
+
log({
|
|
29967
|
+
event: slot.event,
|
|
29968
|
+
cssPath: sourceCssPathForBase,
|
|
29969
|
+
[slot.eventKey]: value
|
|
29970
|
+
});
|
|
29971
|
+
}
|
|
29972
|
+
} catch (err) {
|
|
29973
|
+
if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) throw err;
|
|
30016
29974
|
}
|
|
30017
|
-
return flag;
|
|
30018
29975
|
}
|
|
30019
|
-
|
|
30020
|
-
|
|
30021
|
-
|
|
30022
|
-
|
|
30023
|
-
|
|
30024
|
-
name: FRAMEWORK_SPECS[value].label ?? value,
|
|
30025
|
-
value
|
|
30026
|
-
}))
|
|
29976
|
+
const system = generateBaseSystem(baseConfig);
|
|
29977
|
+
const registry2 = new TokenRegistry(system.allTokens, REGISTRY_PLUGINS);
|
|
29978
|
+
log({
|
|
29979
|
+
event: "init:generated",
|
|
29980
|
+
tokenCount: registry2.size()
|
|
30027
29981
|
});
|
|
30028
|
-
|
|
30029
|
-
}
|
|
30030
|
-
async function promptExportFormats(existingConfig) {
|
|
30031
|
-
if (!isInteractive()) {
|
|
30032
|
-
return existingConfig ?? DEFAULT_EXPORTS;
|
|
30033
|
-
}
|
|
30034
|
-
const choices = EXPORT_CHOICES.map((choice) => ({
|
|
30035
|
-
name: choice.name,
|
|
30036
|
-
value: choice.value,
|
|
30037
|
-
checked: existingConfig ? existingConfig[choice.value] : choice.checked
|
|
30038
|
-
}));
|
|
30039
|
-
const allChoices = [
|
|
30040
|
-
...choices,
|
|
30041
|
-
...FUTURE_EXPORTS.map((choice) => ({
|
|
30042
|
-
name: `${choice.name} (${choice.disabled})`,
|
|
30043
|
-
value: choice.value,
|
|
30044
|
-
checked: false,
|
|
30045
|
-
disabled: true
|
|
30046
|
-
}))
|
|
30047
|
-
];
|
|
30048
|
-
const selections = await checkbox({
|
|
30049
|
-
message: "What would you like to export?",
|
|
30050
|
-
choices: allChoices,
|
|
30051
|
-
required: true
|
|
30052
|
-
});
|
|
30053
|
-
return selectionsToConfig(selections);
|
|
30054
|
-
}
|
|
30055
|
-
function isTailwindCliInstalled() {
|
|
30056
|
-
const require2 = createRequire(import.meta.url);
|
|
30057
|
-
try {
|
|
30058
|
-
require2.resolve("@tailwindcss/cli/package.json");
|
|
30059
|
-
return true;
|
|
30060
|
-
} catch (err) {
|
|
30061
|
-
if (err instanceof Error && "code" in err && err.code === "MODULE_NOT_FOUND") {
|
|
30062
|
-
return false;
|
|
30063
|
-
}
|
|
30064
|
-
throw err;
|
|
30065
|
-
}
|
|
30066
|
-
}
|
|
30067
|
-
async function ensureTailwindCli(cwd) {
|
|
30068
|
-
if (!isInteractive() || isAgentMode()) {
|
|
30069
|
-
throw new Error(
|
|
30070
|
-
"Standalone CSS export requires @tailwindcss/cli. Install it as a dev dependency in your project."
|
|
30071
|
-
);
|
|
30072
|
-
}
|
|
30073
|
-
const shouldInstall = await confirm({
|
|
30074
|
-
message: "Standalone CSS requires @tailwindcss/cli. Install it now?",
|
|
30075
|
-
default: true
|
|
30076
|
-
});
|
|
30077
|
-
if (!shouldInstall) {
|
|
30078
|
-
throw new Error("Standalone CSS export requires @tailwindcss/cli.");
|
|
30079
|
-
}
|
|
30080
|
-
await updateDependencies([], ["@tailwindcss/cli"], { cwd });
|
|
30081
|
-
if (!isTailwindCliInstalled()) {
|
|
30082
|
-
throw new Error(
|
|
30083
|
-
"@tailwindcss/cli was installed but cannot be resolved. Try installing at the workspace root."
|
|
30084
|
-
);
|
|
30085
|
-
}
|
|
30086
|
-
}
|
|
30087
|
-
async function generateOutputs(cwd, paths, registry2, exports, shadcn, darkMode = "class", config2) {
|
|
30088
|
-
const contentSources = config2 ? resolveContentSources(cwd, config2) : [];
|
|
30089
|
-
if (exports.compiled && !isTailwindCliInstalled()) {
|
|
30090
|
-
log({ event: "init:prompting_exports" });
|
|
30091
|
-
await ensureTailwindCli(cwd);
|
|
30092
|
-
}
|
|
30093
|
-
if (exports.compiled) {
|
|
30094
|
-
log({ event: "init:compiling_css" });
|
|
30095
|
-
}
|
|
30096
|
-
return regenerateOutputs(registry2, {
|
|
30097
|
-
outputDir: paths.output,
|
|
30098
|
-
exports,
|
|
30099
|
-
contentSources,
|
|
30100
|
-
darkMode,
|
|
30101
|
-
includeImport: !shadcn
|
|
30102
|
-
});
|
|
30103
|
-
}
|
|
30104
|
-
async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode2, framework) {
|
|
30105
|
-
log({ event: "init:regenerate", cwd });
|
|
30106
|
-
let existingConfig = null;
|
|
30107
|
-
try {
|
|
30108
|
-
const configContent = await readFile4(paths.config, "utf-8");
|
|
30109
|
-
existingConfig = JSON.parse(configContent);
|
|
30110
|
-
} catch {
|
|
30111
|
-
}
|
|
30112
|
-
if (framework !== "unknown" && existingConfig) {
|
|
30113
|
-
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
30114
|
-
existingConfig.framework = framework;
|
|
30115
|
-
existingConfig.componentsPath = frameworkPaths.components;
|
|
30116
|
-
existingConfig.primitivesPath = frameworkPaths.primitives;
|
|
30117
|
-
existingConfig.compositesPath = frameworkPaths.composites;
|
|
30118
|
-
existingConfig.rulesPath = frameworkPaths.rules;
|
|
30119
|
-
}
|
|
30120
|
-
await rm(join8(paths.tokens, "elevation.rafters.json"), { force: true });
|
|
30121
|
-
await rm(join8(paths.tokens, "fill.rafters.json"), { force: true });
|
|
30122
|
-
const registry2 = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS2);
|
|
30123
|
-
if (registry2.size() === 0) {
|
|
30124
|
-
throw new Error("No tokens found. Cannot regenerate without existing tokens.");
|
|
30125
|
-
}
|
|
30126
|
-
const namespaces = [...new Set(registry2.list().map((t) => t.namespace))];
|
|
30127
|
-
log({
|
|
30128
|
-
event: "init:loaded",
|
|
30129
|
-
tokenCount: registry2.size(),
|
|
30130
|
-
namespaces
|
|
30131
|
-
});
|
|
30132
|
-
let exports;
|
|
30133
|
-
if (isAgentMode2) {
|
|
30134
|
-
exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
|
|
30135
|
-
log({ event: "init:exports_default", exports });
|
|
30136
|
-
} else {
|
|
30137
|
-
if (isInteractive()) {
|
|
30138
|
-
log({ event: "init:prompting_exports" });
|
|
30139
|
-
}
|
|
30140
|
-
exports = await promptExportFormats(existingConfig?.exports);
|
|
30141
|
-
log({ event: "init:exports_selected", exports });
|
|
30142
|
-
}
|
|
30143
|
-
await mkdir3(paths.output, { recursive: true });
|
|
30144
|
-
const outputs = await generateOutputs(
|
|
30145
|
-
cwd,
|
|
30146
|
-
paths,
|
|
30147
|
-
registry2,
|
|
30148
|
-
exports,
|
|
30149
|
-
shadcn,
|
|
30150
|
-
"class",
|
|
30151
|
-
existingConfig
|
|
30152
|
-
);
|
|
30153
|
-
if (existingConfig) {
|
|
30154
|
-
existingConfig.exports = exports;
|
|
30155
|
-
await writeFile3(paths.config, JSON.stringify(existingConfig, null, 2));
|
|
30156
|
-
} else {
|
|
30157
|
-
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
30158
|
-
const newConfig = {
|
|
30159
|
-
framework,
|
|
30160
|
-
componentsPath: frameworkPaths.components,
|
|
30161
|
-
primitivesPath: frameworkPaths.primitives,
|
|
30162
|
-
compositesPath: frameworkPaths.composites,
|
|
30163
|
-
rulesPath: frameworkPaths.rules,
|
|
30164
|
-
cssPath: null,
|
|
30165
|
-
shadcn: !!shadcn,
|
|
30166
|
-
exports,
|
|
30167
|
-
installed: { components: [], primitives: [], composites: [], rules: [] }
|
|
30168
|
-
};
|
|
30169
|
-
await writeFile3(paths.config, JSON.stringify(newConfig, null, 2));
|
|
30170
|
-
}
|
|
30171
|
-
log({
|
|
30172
|
-
event: "init:complete",
|
|
30173
|
-
outputs,
|
|
30174
|
-
path: paths.output
|
|
30175
|
-
});
|
|
30176
|
-
}
|
|
30177
|
-
async function resetToDefaults(cwd, paths, shadcn, isAgentMode2, framework) {
|
|
30178
|
-
log({ event: "init:reset", cwd });
|
|
30179
|
-
let existingConfig = null;
|
|
30180
|
-
try {
|
|
30181
|
-
const configContent = await readFile4(paths.config, "utf-8");
|
|
30182
|
-
existingConfig = JSON.parse(configContent);
|
|
30183
|
-
} catch {
|
|
30184
|
-
}
|
|
30185
|
-
if (framework !== "unknown" && existingConfig) {
|
|
30186
|
-
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
30187
|
-
existingConfig.framework = framework;
|
|
30188
|
-
existingConfig.componentsPath = frameworkPaths.components;
|
|
30189
|
-
existingConfig.primitivesPath = frameworkPaths.primitives;
|
|
30190
|
-
existingConfig.compositesPath = frameworkPaths.composites;
|
|
30191
|
-
existingConfig.rulesPath = frameworkPaths.rules;
|
|
30192
|
-
}
|
|
30193
|
-
let existingTokens = [];
|
|
30194
|
-
try {
|
|
30195
|
-
existingTokens = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS2).list();
|
|
30196
|
-
} catch {
|
|
30197
|
-
}
|
|
30198
|
-
const overriddenTokens = existingTokens.filter((t) => t.userOverride);
|
|
30199
|
-
if (overriddenTokens.length > 0) {
|
|
30200
|
-
const backup = {
|
|
30201
|
-
resetAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30202
|
-
reason: "rafters init --reset",
|
|
30203
|
-
overrides: overriddenTokens.map((t) => ({
|
|
30204
|
-
name: t.name,
|
|
30205
|
-
value: t.value,
|
|
30206
|
-
userOverride: t.userOverride,
|
|
30207
|
-
namespace: t.namespace
|
|
30208
|
-
}))
|
|
30209
|
-
};
|
|
30210
|
-
await mkdir3(paths.output, { recursive: true });
|
|
30211
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
30212
|
-
const backupPath = join8(paths.output, `reset-${timestamp}.json`);
|
|
30213
|
-
await writeFile3(backupPath, JSON.stringify(backup, null, 2));
|
|
30214
|
-
log({
|
|
30215
|
-
event: "init:reset_backup",
|
|
30216
|
-
path: backupPath,
|
|
30217
|
-
overrideCount: overriddenTokens.length
|
|
30218
|
-
});
|
|
30219
|
-
}
|
|
30220
|
-
let exports;
|
|
30221
|
-
if (isAgentMode2) {
|
|
30222
|
-
exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
|
|
30223
|
-
log({ event: "init:exports_default", exports });
|
|
30224
|
-
} else {
|
|
30225
|
-
if (isInteractive()) {
|
|
30226
|
-
log({ event: "init:prompting_exports" });
|
|
30227
|
-
}
|
|
30228
|
-
exports = await promptExportFormats(existingConfig?.exports);
|
|
30229
|
-
log({ event: "init:exports_selected", exports });
|
|
30230
|
-
}
|
|
30231
|
-
const system = generateBaseSystem({});
|
|
30232
|
-
const registry2 = new TokenRegistry(system.allTokens, REGISTRY_PLUGINS2);
|
|
30233
|
-
log({
|
|
30234
|
-
event: "init:reset_generated",
|
|
30235
|
-
tokenCount: registry2.size()
|
|
30236
|
-
});
|
|
30237
|
-
await rm(paths.tokens, { recursive: true, force: true });
|
|
30238
|
-
await mkdir3(paths.tokens, { recursive: true });
|
|
29982
|
+
await mkdir2(paths.tokens, { recursive: true });
|
|
29983
|
+
await mkdir2(paths.output, { recursive: true });
|
|
30239
29984
|
saveRegistryToDir(paths.tokens, registry2);
|
|
30240
29985
|
const allTokensToSave = registry2.list();
|
|
30241
29986
|
const namespaceCount = new Set(allTokensToSave.map((t) => t.namespace)).size;
|
|
@@ -30244,183 +29989,26 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode2, framework) {
|
|
|
30244
29989
|
path: paths.tokens,
|
|
30245
29990
|
namespaceCount
|
|
30246
29991
|
});
|
|
30247
|
-
await
|
|
30248
|
-
|
|
29992
|
+
const outputs = await generateOutputs(cwd, paths, registry2, exports, source);
|
|
29993
|
+
let detectedCssPath = null;
|
|
29994
|
+
detectedCssPath = resolveSourceCssPath(
|
|
30249
29995
|
cwd,
|
|
30250
|
-
|
|
30251
|
-
|
|
30252
|
-
|
|
30253
|
-
shadcn,
|
|
30254
|
-
|
|
30255
|
-
existingConfig
|
|
29996
|
+
framework,
|
|
29997
|
+
detectedFramework,
|
|
29998
|
+
project.cssPath,
|
|
29999
|
+
shadcn?.tailwind?.css,
|
|
30000
|
+
log
|
|
30256
30001
|
);
|
|
30257
|
-
if (
|
|
30258
|
-
|
|
30259
|
-
|
|
30260
|
-
|
|
30261
|
-
|
|
30262
|
-
|
|
30263
|
-
|
|
30264
|
-
|
|
30265
|
-
|
|
30266
|
-
|
|
30267
|
-
rulesPath: frameworkPaths.rules,
|
|
30268
|
-
cssPath: null,
|
|
30269
|
-
shadcn: !!shadcn,
|
|
30270
|
-
exports,
|
|
30271
|
-
installed: { components: [], primitives: [], composites: [], rules: [] }
|
|
30272
|
-
};
|
|
30273
|
-
await writeFile3(paths.config, JSON.stringify(newConfig, null, 2));
|
|
30274
|
-
}
|
|
30275
|
-
log({
|
|
30276
|
-
event: "init:complete",
|
|
30277
|
-
outputs,
|
|
30278
|
-
path: paths.output
|
|
30279
|
-
});
|
|
30280
|
-
}
|
|
30281
|
-
async function init(options) {
|
|
30282
|
-
setAgentMode(options.agent ?? false);
|
|
30283
|
-
const isAgentMode2 = options.agent ?? false;
|
|
30284
|
-
const cwd = process.cwd();
|
|
30285
|
-
const paths = getRaftersPaths(cwd);
|
|
30286
|
-
log({ event: "init:start", cwd });
|
|
30287
|
-
const project = await detectProject(cwd);
|
|
30288
|
-
const { framework: detectedFramework, shadcn, tailwindVersion, astroHasReact } = project;
|
|
30289
|
-
log({
|
|
30290
|
-
event: "init:detected",
|
|
30291
|
-
framework: detectedFramework,
|
|
30292
|
-
tailwindVersion,
|
|
30293
|
-
hasShadcn: !!shadcn
|
|
30294
|
-
});
|
|
30295
|
-
const framework = await resolveFramework(detectedFramework, options.framework, isAgentMode2);
|
|
30296
|
-
if (framework !== detectedFramework) {
|
|
30297
|
-
log({
|
|
30298
|
-
event: "init:framework_resolved",
|
|
30299
|
-
detected: detectedFramework,
|
|
30300
|
-
resolved: framework,
|
|
30301
|
-
source: options.framework ? "flag" : "prompt"
|
|
30302
|
-
});
|
|
30303
|
-
}
|
|
30304
|
-
if (isTailwindV3(tailwindVersion)) {
|
|
30305
|
-
throw new Error("Tailwind v3 detected. Rafters requires Tailwind v4.");
|
|
30306
|
-
}
|
|
30307
|
-
const raftersExists = existsSync4(paths.root);
|
|
30308
|
-
if (options.reset && !raftersExists) {
|
|
30309
|
-
throw new Error("Nothing to reset. No .rafters/ directory found.");
|
|
30310
|
-
}
|
|
30311
|
-
if (raftersExists && options.reset) {
|
|
30312
|
-
await resetToDefaults(cwd, paths, shadcn, isAgentMode2, framework);
|
|
30313
|
-
return;
|
|
30314
|
-
}
|
|
30315
|
-
if (raftersExists && !options.rebuild) {
|
|
30316
|
-
throw new Error(
|
|
30317
|
-
".rafters/ directory already exists. Use --rebuild to regenerate output files, or --reset to start from defaults."
|
|
30318
|
-
);
|
|
30319
|
-
}
|
|
30320
|
-
if (raftersExists && options.rebuild) {
|
|
30321
|
-
await regenerateFromExisting(cwd, paths, shadcn, isAgentMode2, framework);
|
|
30322
|
-
return;
|
|
30323
|
-
}
|
|
30324
|
-
let exports;
|
|
30325
|
-
if (isAgentMode2) {
|
|
30326
|
-
exports = DEFAULT_EXPORTS;
|
|
30327
|
-
log({ event: "init:exports_default", exports });
|
|
30328
|
-
} else {
|
|
30329
|
-
if (isInteractive()) {
|
|
30330
|
-
log({ event: "init:prompting_exports" });
|
|
30331
|
-
}
|
|
30332
|
-
exports = await promptExportFormats();
|
|
30333
|
-
log({ event: "init:exports_selected", exports });
|
|
30334
|
-
}
|
|
30335
|
-
const baseConfig = {};
|
|
30336
|
-
const sourceCssPathForBase = resolveSourceCssPath(
|
|
30337
|
-
cwd,
|
|
30338
|
-
framework,
|
|
30339
|
-
detectedFramework,
|
|
30340
|
-
project.cssPath,
|
|
30341
|
-
shadcn?.tailwind?.css,
|
|
30342
|
-
log
|
|
30343
|
-
);
|
|
30344
|
-
if (sourceCssPathForBase !== null) {
|
|
30345
|
-
try {
|
|
30346
|
-
const cssForBase = await readFile4(join8(cwd, sourceCssPathForBase), "utf-8");
|
|
30347
|
-
const baseSlots = [
|
|
30348
|
-
{
|
|
30349
|
-
detect: detectSpacingBase,
|
|
30350
|
-
field: "baseSpacingUnit",
|
|
30351
|
-
event: "init:import_spacing_applied",
|
|
30352
|
-
eventKey: "baseSpacingUnit"
|
|
30353
|
-
},
|
|
30354
|
-
{
|
|
30355
|
-
detect: detectRadiusBase,
|
|
30356
|
-
field: "baseRadiusOverride",
|
|
30357
|
-
event: "init:import_radius_applied",
|
|
30358
|
-
eventKey: "baseRadius"
|
|
30359
|
-
},
|
|
30360
|
-
{
|
|
30361
|
-
detect: detectFontSizeBase,
|
|
30362
|
-
field: "baseFontSizeOverride",
|
|
30363
|
-
event: "init:import_font_size_applied",
|
|
30364
|
-
eventKey: "baseFontSize"
|
|
30365
|
-
},
|
|
30366
|
-
{
|
|
30367
|
-
detect: detectFocusRingWidth,
|
|
30368
|
-
field: "focusRingWidthOverride",
|
|
30369
|
-
event: "init:import_focus_ring_applied",
|
|
30370
|
-
eventKey: "focusRingWidth"
|
|
30371
|
-
}
|
|
30372
|
-
// Motion duration is intentionally not imported -- rafters' motion
|
|
30373
|
-
// system is research-backed and most projects' `--duration-base`
|
|
30374
|
-
// values are unresearched defaults. See importers/bases.ts for the
|
|
30375
|
-
// policy note; designers can `rafters set motion-duration-base ...`
|
|
30376
|
-
// after init to override explicitly.
|
|
30377
|
-
];
|
|
30378
|
-
for (const slot of baseSlots) {
|
|
30379
|
-
const value = slot.detect(cssForBase);
|
|
30380
|
-
if (value === null) continue;
|
|
30381
|
-
baseConfig[slot.field] = value;
|
|
30382
|
-
log({ event: slot.event, cssPath: sourceCssPathForBase, [slot.eventKey]: value });
|
|
30383
|
-
}
|
|
30384
|
-
} catch (err) {
|
|
30385
|
-
if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) throw err;
|
|
30386
|
-
}
|
|
30387
|
-
}
|
|
30388
|
-
const system = generateBaseSystem(baseConfig);
|
|
30389
|
-
const registry2 = new TokenRegistry(system.allTokens, REGISTRY_PLUGINS2);
|
|
30390
|
-
log({
|
|
30391
|
-
event: "init:generated",
|
|
30392
|
-
tokenCount: registry2.size()
|
|
30393
|
-
});
|
|
30394
|
-
await mkdir3(paths.tokens, { recursive: true });
|
|
30395
|
-
await mkdir3(paths.output, { recursive: true });
|
|
30396
|
-
saveRegistryToDir(paths.tokens, registry2);
|
|
30397
|
-
const allTokensToSave = registry2.list();
|
|
30398
|
-
const namespaceCount = new Set(allTokensToSave.map((t) => t.namespace)).size;
|
|
30399
|
-
log({
|
|
30400
|
-
event: "init:registry_saved",
|
|
30401
|
-
path: paths.tokens,
|
|
30402
|
-
namespaceCount
|
|
30403
|
-
});
|
|
30404
|
-
const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
|
|
30405
|
-
let detectedCssPath = null;
|
|
30406
|
-
detectedCssPath = resolveSourceCssPath(
|
|
30407
|
-
cwd,
|
|
30408
|
-
framework,
|
|
30409
|
-
detectedFramework,
|
|
30410
|
-
project.cssPath,
|
|
30411
|
-
shadcn?.tailwind?.css,
|
|
30412
|
-
log
|
|
30413
|
-
);
|
|
30414
|
-
if (!shadcn && exports.tailwind) {
|
|
30415
|
-
if (detectedCssPath) {
|
|
30416
|
-
await updateMainCss(cwd, detectedCssPath, ".rafters/output/rafters.css");
|
|
30417
|
-
} else {
|
|
30418
|
-
log({
|
|
30419
|
-
event: "init:css_not_found",
|
|
30420
|
-
message: 'No main CSS file found. Add @import ".rafters/output/rafters.css" manually.',
|
|
30421
|
-
searchedLocations: FRAMEWORK_SPECS[framework].cssLocations
|
|
30422
|
-
});
|
|
30423
|
-
}
|
|
30002
|
+
if (source !== "shadcn" && exports.tailwind) {
|
|
30003
|
+
if (detectedCssPath) {
|
|
30004
|
+
await updateMainCss(cwd, detectedCssPath, ".rafters/output/rafters.css");
|
|
30005
|
+
} else {
|
|
30006
|
+
log({
|
|
30007
|
+
event: "init:css_not_found",
|
|
30008
|
+
message: 'No main CSS file found. Add @import ".rafters/output/rafters.css" manually.',
|
|
30009
|
+
searchedLocations: FRAMEWORK_SPECS[framework].cssLocations
|
|
30010
|
+
});
|
|
30011
|
+
}
|
|
30424
30012
|
}
|
|
30425
30013
|
let componentTarget = frameworkToTarget(framework);
|
|
30426
30014
|
if (framework === "astro" && astroHasReact && isInteractive() && !isAgentMode2) {
|
|
@@ -30441,14 +30029,16 @@ async function init(options) {
|
|
|
30441
30029
|
const frameworkPaths = FRAMEWORK_SPECS[framework].components;
|
|
30442
30030
|
const config2 = {
|
|
30443
30031
|
framework,
|
|
30032
|
+
...source ? { source } : {},
|
|
30444
30033
|
componentTarget,
|
|
30445
30034
|
componentsPath: frameworkPaths.components,
|
|
30446
30035
|
primitivesPath: frameworkPaths.primitives,
|
|
30447
30036
|
compositesPath: frameworkPaths.composites,
|
|
30448
30037
|
rulesPath: frameworkPaths.rules,
|
|
30449
30038
|
cssPath: detectedCssPath,
|
|
30450
|
-
shadcn: !!shadcn,
|
|
30451
30039
|
exports,
|
|
30040
|
+
intent: "efficient",
|
|
30041
|
+
fonts: { path: null, imports: [] },
|
|
30452
30042
|
installed: {
|
|
30453
30043
|
components: [],
|
|
30454
30044
|
primitives: [],
|
|
@@ -30456,11 +30046,11 @@ async function init(options) {
|
|
|
30456
30046
|
rules: []
|
|
30457
30047
|
}
|
|
30458
30048
|
};
|
|
30459
|
-
await
|
|
30049
|
+
await writeFile2(paths.config, JSON.stringify(config2, null, 2));
|
|
30460
30050
|
if (detectedCssPath) {
|
|
30461
30051
|
let sourceCss = null;
|
|
30462
30052
|
try {
|
|
30463
|
-
sourceCss = await
|
|
30053
|
+
sourceCss = await readFile3(join7(cwd, detectedCssPath), "utf-8");
|
|
30464
30054
|
} catch (err) {
|
|
30465
30055
|
if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) throw err;
|
|
30466
30056
|
}
|
|
@@ -30473,7 +30063,7 @@ async function init(options) {
|
|
|
30473
30063
|
...summary
|
|
30474
30064
|
});
|
|
30475
30065
|
const classification = classifyDeclarations(extractShadcnRoot(sourceCss));
|
|
30476
|
-
const colorDecls =
|
|
30066
|
+
const colorDecls = adapter.detectColors(sourceCss);
|
|
30477
30067
|
const nonColorDecls = [
|
|
30478
30068
|
...classification.byNamespace.typography,
|
|
30479
30069
|
...classification.byNamespace.spacing,
|
|
@@ -30517,7 +30107,7 @@ async function init(options) {
|
|
|
30517
30107
|
}
|
|
30518
30108
|
}
|
|
30519
30109
|
saveRegistryToDir(paths.tokens, registry2);
|
|
30520
|
-
await generateOutputs(cwd, paths, registry2, exports,
|
|
30110
|
+
await generateOutputs(cwd, paths, registry2, exports, source);
|
|
30521
30111
|
const importedNames = [
|
|
30522
30112
|
...toImportColors.map((c4) => c4.name),
|
|
30523
30113
|
...toImportNonColors.map((d2) => d2.name)
|
|
@@ -30549,7 +30139,10 @@ async function init(options) {
|
|
|
30549
30139
|
familySeeds.set(baseName, { seed: oklch2, seedPosition });
|
|
30550
30140
|
}
|
|
30551
30141
|
}
|
|
30552
|
-
const families = Array.from(familySeeds, ([name, info]) => ({
|
|
30142
|
+
const families = Array.from(familySeeds, ([name, info]) => ({
|
|
30143
|
+
name,
|
|
30144
|
+
...info
|
|
30145
|
+
}));
|
|
30553
30146
|
if (families.length > 0) {
|
|
30554
30147
|
for (const family of families) {
|
|
30555
30148
|
for (const t of importColorFamily(family.name, family.seedPosition, family.seed)) {
|
|
@@ -30592,7 +30185,10 @@ async function init(options) {
|
|
|
30592
30185
|
if (!family) continue;
|
|
30593
30186
|
const position = isAgentMode2 ? family.seedPosition : await select({
|
|
30594
30187
|
message: `Which position in "${familyChoice}" for "${role}"?`,
|
|
30595
|
-
choices: SCALE_POSITIONS.map((p2) => ({
|
|
30188
|
+
choices: SCALE_POSITIONS.map((p2) => ({
|
|
30189
|
+
name: p2,
|
|
30190
|
+
value: p2
|
|
30191
|
+
})),
|
|
30596
30192
|
default: family.seedPosition
|
|
30597
30193
|
});
|
|
30598
30194
|
registry2.set(
|
|
@@ -30605,7 +30201,7 @@ async function init(options) {
|
|
|
30605
30201
|
assignments.push({ role, family: familyChoice, position });
|
|
30606
30202
|
}
|
|
30607
30203
|
saveRegistryToDir(paths.tokens, registry2);
|
|
30608
|
-
await generateOutputs(cwd, paths, registry2, exports,
|
|
30204
|
+
await generateOutputs(cwd, paths, registry2, exports, source);
|
|
30609
30205
|
const themeImportedNames = families.flatMap(
|
|
30610
30206
|
(f) => SCALE_POSITIONS.map((p2) => `color-${f.name}-${p2}`).concat([`color-${f.name}`])
|
|
30611
30207
|
);
|
|
@@ -30621,7 +30217,7 @@ async function init(options) {
|
|
|
30621
30217
|
}
|
|
30622
30218
|
}
|
|
30623
30219
|
if (sourceCss !== null) {
|
|
30624
|
-
const detectedFonts = detectFonts(sourceCss);
|
|
30220
|
+
const detectedFonts = adapter.detectFonts(sourceCss);
|
|
30625
30221
|
if (detectedFonts.length > 0) {
|
|
30626
30222
|
const typographyTokens = registry2.list({ namespace: "typography" });
|
|
30627
30223
|
const baseFamilyNames = new Set(
|
|
@@ -30696,27 +30292,564 @@ async function init(options) {
|
|
|
30696
30292
|
registry2.set(base, font.stack, { reason });
|
|
30697
30293
|
}
|
|
30698
30294
|
}
|
|
30699
|
-
fontAssignments.push({ role, family: font.name });
|
|
30295
|
+
fontAssignments.push({ role, family: font.name });
|
|
30296
|
+
}
|
|
30297
|
+
if (fontAssignments.length > 0 || definedFonts.length > 0) {
|
|
30298
|
+
saveRegistryToDir(paths.tokens, registry2);
|
|
30299
|
+
await generateOutputs(cwd, paths, registry2, exports, source);
|
|
30300
|
+
log({
|
|
30301
|
+
event: "init:import_fonts_applied",
|
|
30302
|
+
cssPath: detectedCssPath,
|
|
30303
|
+
fontsDetected: detectedFonts.map((f) => f.name),
|
|
30304
|
+
assignments: fontAssignments,
|
|
30305
|
+
...definedFonts.length > 0 ? { definedFonts } : {}
|
|
30306
|
+
});
|
|
30307
|
+
}
|
|
30308
|
+
}
|
|
30309
|
+
}
|
|
30310
|
+
}
|
|
30311
|
+
log({
|
|
30312
|
+
event: "init:complete",
|
|
30313
|
+
outputs: [...outputs, "config.rafters.json"],
|
|
30314
|
+
path: paths.output
|
|
30315
|
+
});
|
|
30316
|
+
}
|
|
30317
|
+
|
|
30318
|
+
// src/commands/add.ts
|
|
30319
|
+
var REGISTRY_PLUGINS2 = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
|
|
30320
|
+
async function regenerateAfterInstall(cwd, config2) {
|
|
30321
|
+
const paths = getRaftersPaths(cwd);
|
|
30322
|
+
let registry2;
|
|
30323
|
+
try {
|
|
30324
|
+
registry2 = loadRegistryFromDir(paths.tokens, REGISTRY_PLUGINS2);
|
|
30325
|
+
} catch {
|
|
30326
|
+
return;
|
|
30327
|
+
}
|
|
30328
|
+
if (registry2.size() === 0) return;
|
|
30329
|
+
try {
|
|
30330
|
+
await regenerateOutputs(registry2, {
|
|
30331
|
+
outputDir: paths.output,
|
|
30332
|
+
exports: config2.exports,
|
|
30333
|
+
contentSources: resolveContentSources(cwd, config2),
|
|
30334
|
+
darkMode: config2.darkMode ?? "class",
|
|
30335
|
+
includeImport: config2.source !== "shadcn"
|
|
30336
|
+
});
|
|
30337
|
+
} catch (err) {
|
|
30338
|
+
log({
|
|
30339
|
+
event: "add:regen-failed",
|
|
30340
|
+
message: `Output regeneration failed: ${err instanceof Error ? err.message : String(err)}`
|
|
30341
|
+
});
|
|
30342
|
+
}
|
|
30343
|
+
}
|
|
30344
|
+
async function isInitialized(cwd) {
|
|
30345
|
+
const paths = getRaftersPaths(cwd);
|
|
30346
|
+
try {
|
|
30347
|
+
await access(paths.root);
|
|
30348
|
+
return true;
|
|
30349
|
+
} catch {
|
|
30350
|
+
return false;
|
|
30351
|
+
}
|
|
30352
|
+
}
|
|
30353
|
+
async function loadConfig(cwd) {
|
|
30354
|
+
const paths = getRaftersPaths(cwd);
|
|
30355
|
+
try {
|
|
30356
|
+
const content = await readFile4(paths.config, "utf-8");
|
|
30357
|
+
return migrateConfig(
|
|
30358
|
+
JSON.parse(content)
|
|
30359
|
+
);
|
|
30360
|
+
} catch (err) {
|
|
30361
|
+
if (existsSync4(paths.config)) {
|
|
30362
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30363
|
+
log({
|
|
30364
|
+
event: "add:warning",
|
|
30365
|
+
message: `Failed to load config: ${message}`
|
|
30366
|
+
});
|
|
30367
|
+
}
|
|
30368
|
+
return null;
|
|
30369
|
+
}
|
|
30370
|
+
}
|
|
30371
|
+
function resolveRegistryUrl(options, config2) {
|
|
30372
|
+
return options.registryUrl ?? config2?.registryUrl;
|
|
30373
|
+
}
|
|
30374
|
+
async function saveConfig(cwd, config2) {
|
|
30375
|
+
const paths = getRaftersPaths(cwd);
|
|
30376
|
+
await writeFile3(paths.config, JSON.stringify(config2, null, 2));
|
|
30377
|
+
}
|
|
30378
|
+
function getInstalledNames(config2) {
|
|
30379
|
+
if (!config2?.installed) return [];
|
|
30380
|
+
const names = /* @__PURE__ */ new Set([
|
|
30381
|
+
...config2.installed.components,
|
|
30382
|
+
...config2.installed.primitives,
|
|
30383
|
+
...config2.installed.composites ?? [],
|
|
30384
|
+
...config2.installed.rules ?? [],
|
|
30385
|
+
...config2.installed.substrate ?? []
|
|
30386
|
+
]);
|
|
30387
|
+
return [...names].sort();
|
|
30388
|
+
}
|
|
30389
|
+
async function discoverUntrackedNames(cwd, config2, client, tracked) {
|
|
30390
|
+
let index = null;
|
|
30391
|
+
try {
|
|
30392
|
+
index = await client.fetchIndex();
|
|
30393
|
+
} catch (err) {
|
|
30394
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30395
|
+
log({
|
|
30396
|
+
event: "add:warning",
|
|
30397
|
+
message: `Could not read the registry index to reconcile on-disk components (${message}). Updating tracked components only.`
|
|
30398
|
+
});
|
|
30399
|
+
}
|
|
30400
|
+
const { untracked } = buildUpdateCandidates(tracked, index, readInstallRoots(cwd, config2));
|
|
30401
|
+
return untracked;
|
|
30402
|
+
}
|
|
30403
|
+
function getComponentTarget(config2) {
|
|
30404
|
+
return resolveComponentTarget(config2);
|
|
30405
|
+
}
|
|
30406
|
+
var SHARED_EXTENSIONS = /* @__PURE__ */ new Set([".behavior.ts", ".classes.ts"]);
|
|
30407
|
+
function isSharedFile(path) {
|
|
30408
|
+
for (const ext of SHARED_EXTENSIONS) {
|
|
30409
|
+
if (path.endsWith(ext)) return true;
|
|
30410
|
+
}
|
|
30411
|
+
return false;
|
|
30412
|
+
}
|
|
30413
|
+
var REACT_FALLBACK_TARGETS = /* @__PURE__ */ new Set(["astro", "vue", "svelte"]);
|
|
30414
|
+
function selectFilesForFramework(files, target) {
|
|
30415
|
+
const preferredExt = targetToExtension(target);
|
|
30416
|
+
const shared = files.filter((f) => isSharedFile(f.path));
|
|
30417
|
+
const matched = files.filter((f) => f.path.endsWith(preferredExt));
|
|
30418
|
+
if (matched.length > 0) {
|
|
30419
|
+
return { files: [...matched, ...shared], fallback: false };
|
|
30420
|
+
}
|
|
30421
|
+
if (REACT_FALLBACK_TARGETS.has(target)) {
|
|
30422
|
+
const fallbackFiles = files.filter((f) => f.path.endsWith(".tsx"));
|
|
30423
|
+
if (fallbackFiles.length > 0) {
|
|
30424
|
+
return { files: [...fallbackFiles, ...shared], fallback: true };
|
|
30425
|
+
}
|
|
30426
|
+
}
|
|
30427
|
+
if (target !== "react" && !REACT_FALLBACK_TARGETS.has(target)) {
|
|
30428
|
+
return { files: shared, fallback: false };
|
|
30429
|
+
}
|
|
30430
|
+
return { files, fallback: false };
|
|
30431
|
+
}
|
|
30432
|
+
var TARGET_GATED_COMPOSITE_FILES = [{ suffix: "Composite.astro", target: "astro" }];
|
|
30433
|
+
function selectCompositeFiles(files, target) {
|
|
30434
|
+
return files.filter((file2) => {
|
|
30435
|
+
const gate = TARGET_GATED_COMPOSITE_FILES.find((g2) => file2.path.endsWith(g2.suffix));
|
|
30436
|
+
return gate ? gate.target === target : true;
|
|
30437
|
+
});
|
|
30438
|
+
}
|
|
30439
|
+
var FOLDER_NAMES = /* @__PURE__ */ new Set(["composites"]);
|
|
30440
|
+
function isAlreadyInstalled(config2, item) {
|
|
30441
|
+
if (!config2?.installed) return false;
|
|
30442
|
+
const { components, primitives, composites: composites2, rules, substrate } = config2.installed;
|
|
30443
|
+
const bucketByType = {
|
|
30444
|
+
ui: components,
|
|
30445
|
+
primitive: primitives,
|
|
30446
|
+
composite: composites2 ?? [],
|
|
30447
|
+
rule: rules ?? [],
|
|
30448
|
+
substrate: substrate ?? []
|
|
30449
|
+
};
|
|
30450
|
+
return bucketByType[item.type].includes(item.name);
|
|
30451
|
+
}
|
|
30452
|
+
function isInstalledOnDisk(config2, item, cwd) {
|
|
30453
|
+
if (!isAlreadyInstalled(config2, item)) return false;
|
|
30454
|
+
const filesToCheck = item.type === "ui" ? selectFilesForFramework(item.files, getComponentTarget(config2)).files : item.files;
|
|
30455
|
+
for (const file2 of filesToCheck) {
|
|
30456
|
+
if (fileExists(cwd, transformPath(file2.path, config2, cwd))) return true;
|
|
30457
|
+
}
|
|
30458
|
+
return false;
|
|
30459
|
+
}
|
|
30460
|
+
function trackInstalled(config2, items) {
|
|
30461
|
+
if (!config2.installed) {
|
|
30462
|
+
config2.installed = {
|
|
30463
|
+
components: [],
|
|
30464
|
+
primitives: [],
|
|
30465
|
+
composites: [],
|
|
30466
|
+
rules: []
|
|
30467
|
+
};
|
|
30468
|
+
}
|
|
30469
|
+
const installed = config2.installed;
|
|
30470
|
+
if (!installed.composites) installed.composites = [];
|
|
30471
|
+
if (!installed.rules) installed.rules = [];
|
|
30472
|
+
if (!installed.substrate) installed.substrate = [];
|
|
30473
|
+
const bucketByType = {
|
|
30474
|
+
ui: installed.components,
|
|
30475
|
+
primitive: installed.primitives,
|
|
30476
|
+
composite: installed.composites,
|
|
30477
|
+
rule: installed.rules,
|
|
30478
|
+
substrate: installed.substrate
|
|
30479
|
+
};
|
|
30480
|
+
for (const item of items) {
|
|
30481
|
+
const bucket = bucketByType[item.type];
|
|
30482
|
+
if (!bucket.includes(item.name)) bucket.push(item.name);
|
|
30483
|
+
}
|
|
30484
|
+
installed.components.sort();
|
|
30485
|
+
installed.primitives.sort();
|
|
30486
|
+
installed.composites.sort();
|
|
30487
|
+
installed.rules.sort();
|
|
30488
|
+
installed.substrate.sort();
|
|
30489
|
+
}
|
|
30490
|
+
function rootFor(field, cwd, fallback) {
|
|
30491
|
+
return field === void 0 ? fallback : resolveRoot(field, cwd, fallback);
|
|
30492
|
+
}
|
|
30493
|
+
function transformPath(registryPath, config2, cwd = process.cwd()) {
|
|
30494
|
+
if (!config2) return registryPath;
|
|
30495
|
+
const replacements = [
|
|
30496
|
+
["components/ui/", config2.componentsPath, "components/ui"],
|
|
30497
|
+
["lib/primitives/", config2.primitivesPath, "lib/primitives"],
|
|
30498
|
+
["composites/", config2.compositesPath, "composites"],
|
|
30499
|
+
["rules/", config2.rulesPath, "lib/rules"]
|
|
30500
|
+
];
|
|
30501
|
+
for (const [prefix, field, fallback] of replacements) {
|
|
30502
|
+
if (registryPath.startsWith(prefix)) {
|
|
30503
|
+
return registryPath.replace(prefix, `${rootFor(field, cwd, fallback)}/`);
|
|
30504
|
+
}
|
|
30505
|
+
}
|
|
30506
|
+
return registryPath;
|
|
30507
|
+
}
|
|
30508
|
+
function substrateProjectPath(registryPath, config2, cwd = process.cwd()) {
|
|
30509
|
+
const componentsResolved = rootFor(config2?.componentsPath, cwd, "components/ui");
|
|
30510
|
+
const sourceRoot = componentsResolved.replace(/\/?components\/ui$/, "");
|
|
30511
|
+
return sourceRoot ? join8(sourceRoot, registryPath) : registryPath;
|
|
30512
|
+
}
|
|
30513
|
+
function fileExists(cwd, relativePath) {
|
|
30514
|
+
return existsSync4(join8(cwd, relativePath));
|
|
30515
|
+
}
|
|
30516
|
+
function transformFileContent(content, config2, fileType = "component", cwd = process.cwd(), opts = {}) {
|
|
30517
|
+
const { substrateKinds = [], installPath } = opts;
|
|
30518
|
+
let transformed = content;
|
|
30519
|
+
const componentsPath = rootFor(config2?.componentsPath, cwd, "components/ui");
|
|
30520
|
+
const primitivesPath = rootFor(config2?.primitivesPath, cwd, "lib/primitives");
|
|
30521
|
+
const stripSourceRoot = (p2) => p2.replace(/^(src|app)\//, "");
|
|
30522
|
+
const aliasComponents = stripSourceRoot(componentsPath);
|
|
30523
|
+
const aliasPrimitives = stripSourceRoot(primitivesPath);
|
|
30524
|
+
transformed = transformed.replace(
|
|
30525
|
+
/from\s+['"]\.\.\/\.\.\/primitives\/([^'"]+)['"]/g,
|
|
30526
|
+
`from '@/${aliasPrimitives}/$1'`
|
|
30527
|
+
);
|
|
30528
|
+
transformed = transformed.replace(
|
|
30529
|
+
/from\s+['"]\.\.\/primitives\/([^'"]+)['"]/g,
|
|
30530
|
+
`from '@/${aliasPrimitives}/$1'`
|
|
30531
|
+
);
|
|
30532
|
+
const substrateOwnDir = fileType === "substrate" && installPath ? stripSourceRoot(dirname(installPath)) : null;
|
|
30533
|
+
const aliasSibling = fileType === "primitive" ? aliasPrimitives : substrateOwnDir ?? aliasComponents;
|
|
30534
|
+
transformed = transformed.replace(/from\s+['"]\.\/([^'"]+)['"]/g, `from '@/${aliasSibling}/$1'`);
|
|
30535
|
+
if (substrateKinds.length > 0) {
|
|
30536
|
+
const kindAlternation = substrateKinds.join("|");
|
|
30537
|
+
transformed = transformed.replace(
|
|
30538
|
+
new RegExp(`from\\s+['"](?:\\.\\./){1,2}(${kindAlternation})/([^'"]+)['"]`, "g"),
|
|
30539
|
+
"from '@/$1/$2'"
|
|
30540
|
+
);
|
|
30541
|
+
}
|
|
30542
|
+
transformed = transformed.replace(
|
|
30543
|
+
/from\s+['"]\.\.\/([^/'"]+)\/\1([^'"]*)['"]/g,
|
|
30544
|
+
`from '@/${aliasComponents}/$1$2'`
|
|
30545
|
+
);
|
|
30546
|
+
transformed = transformed.replace(
|
|
30547
|
+
/from\s+['"]\.\.\/([^'"]+)['"]/g,
|
|
30548
|
+
`from '@/${aliasComponents}/$1'`
|
|
30549
|
+
);
|
|
30550
|
+
return transformed;
|
|
30551
|
+
}
|
|
30552
|
+
async function installItem(cwd, item, options, config2, substrateKinds = []) {
|
|
30553
|
+
const installedFiles = [];
|
|
30554
|
+
let skipped = false;
|
|
30555
|
+
let filesToInstall = item.files;
|
|
30556
|
+
if (item.type === "ui") {
|
|
30557
|
+
const target = getComponentTarget(config2);
|
|
30558
|
+
const selection = selectFilesForFramework(item.files, target);
|
|
30559
|
+
filesToInstall = selection.files;
|
|
30560
|
+
if (selection.fallback) {
|
|
30561
|
+
log({
|
|
30562
|
+
event: "add:fallback",
|
|
30563
|
+
component: item.name,
|
|
30564
|
+
target,
|
|
30565
|
+
message: `No ${targetToExtension(target)} version available for ${item.name}. Installing React version.`
|
|
30566
|
+
});
|
|
30567
|
+
}
|
|
30568
|
+
const hasComponentFile = selection.files.some((f) => !isSharedFile(f.path));
|
|
30569
|
+
if (!hasComponentFile) {
|
|
30570
|
+
throw new Error(
|
|
30571
|
+
`No ${targetToExtension(target)} version available for "${item.name}" and no compatible fallback exists.`
|
|
30572
|
+
);
|
|
30573
|
+
}
|
|
30574
|
+
} else if (item.type === "composite") {
|
|
30575
|
+
filesToInstall = selectCompositeFiles(item.files, getComponentTarget(config2));
|
|
30576
|
+
}
|
|
30577
|
+
for (const file2 of filesToInstall) {
|
|
30578
|
+
const projectPath2 = item.type === "substrate" ? substrateProjectPath(file2.path, config2, cwd) : transformPath(file2.path, config2, cwd);
|
|
30579
|
+
const targetPath = join8(cwd, projectPath2);
|
|
30580
|
+
if (fileExists(cwd, projectPath2)) {
|
|
30581
|
+
if (!options.overwrite) {
|
|
30582
|
+
log({
|
|
30583
|
+
event: "add:skip",
|
|
30584
|
+
component: item.name,
|
|
30585
|
+
file: projectPath2,
|
|
30586
|
+
reason: "exists"
|
|
30587
|
+
});
|
|
30588
|
+
skipped = true;
|
|
30589
|
+
continue;
|
|
30590
|
+
}
|
|
30591
|
+
}
|
|
30592
|
+
await mkdir3(dirname(targetPath), { recursive: true });
|
|
30593
|
+
const fileType = item.type === "primitive" ? "primitive" : item.type === "substrate" ? "substrate" : "component";
|
|
30594
|
+
const transformedContent = transformFileContent(file2.content, config2, fileType, cwd, {
|
|
30595
|
+
substrateKinds,
|
|
30596
|
+
installPath: file2.path
|
|
30597
|
+
});
|
|
30598
|
+
await writeFile3(targetPath, transformedContent, "utf-8");
|
|
30599
|
+
installedFiles.push(projectPath2);
|
|
30600
|
+
}
|
|
30601
|
+
return {
|
|
30602
|
+
installed: installedFiles.length > 0,
|
|
30603
|
+
skipped,
|
|
30604
|
+
files: installedFiles
|
|
30605
|
+
};
|
|
30606
|
+
}
|
|
30607
|
+
async function add(componentArgs, options) {
|
|
30608
|
+
setAgentMode(options.agent ?? false);
|
|
30609
|
+
let components = componentArgs;
|
|
30610
|
+
const cwd = process.cwd();
|
|
30611
|
+
const config2 = await loadConfig(cwd);
|
|
30612
|
+
const client = new RegistryClient(resolveRegistryUrl(options, config2));
|
|
30613
|
+
let folder;
|
|
30614
|
+
const firstArg = components[0];
|
|
30615
|
+
if (firstArg && FOLDER_NAMES.has(firstArg)) {
|
|
30616
|
+
folder = firstArg;
|
|
30617
|
+
components = components.slice(1);
|
|
30618
|
+
}
|
|
30619
|
+
if (options.list) {
|
|
30620
|
+
const availableComponents = await client.listComponents();
|
|
30621
|
+
const availableComposites = await client.listComposites();
|
|
30622
|
+
if (options.agent) {
|
|
30623
|
+
log({
|
|
30624
|
+
event: "add:list",
|
|
30625
|
+
components: availableComponents,
|
|
30626
|
+
composites: availableComposites
|
|
30627
|
+
});
|
|
30628
|
+
} else {
|
|
30629
|
+
console.log("Available components:\n");
|
|
30630
|
+
for (const comp of availableComponents) {
|
|
30631
|
+
console.log(` ${comp.name} ${comp.description ?? ""}`);
|
|
30632
|
+
}
|
|
30633
|
+
if (availableComposites.length > 0) {
|
|
30634
|
+
console.log("\nAvailable composites:\n");
|
|
30635
|
+
for (const comp of availableComposites) {
|
|
30636
|
+
console.log(` ${comp.name} ${comp.description ?? ""}`);
|
|
30637
|
+
}
|
|
30638
|
+
}
|
|
30639
|
+
}
|
|
30640
|
+
return;
|
|
30641
|
+
}
|
|
30642
|
+
const initialized = await isInitialized(cwd);
|
|
30643
|
+
if (!initialized) {
|
|
30644
|
+
error46("Project not initialized. Run `rafters init` first.");
|
|
30645
|
+
process.exitCode = 1;
|
|
30646
|
+
return;
|
|
30647
|
+
}
|
|
30648
|
+
if (options.update) {
|
|
30649
|
+
options.overwrite = true;
|
|
30650
|
+
}
|
|
30651
|
+
let untrackedNames = [];
|
|
30652
|
+
if (options.updateAll) {
|
|
30653
|
+
options.overwrite = true;
|
|
30654
|
+
if (!config2) {
|
|
30655
|
+
error46("No rafters config found. Run 'rafters init' first.");
|
|
30656
|
+
process.exitCode = 1;
|
|
30657
|
+
return;
|
|
30658
|
+
}
|
|
30659
|
+
const trackedNames = getInstalledNames(config2);
|
|
30660
|
+
untrackedNames = await discoverUntrackedNames(cwd, config2, client, trackedNames);
|
|
30661
|
+
const candidates = [.../* @__PURE__ */ new Set([...trackedNames, ...untrackedNames])].sort();
|
|
30662
|
+
if (candidates.length === 0) {
|
|
30663
|
+
error46("No installed components found. Use 'rafters add <component>' to install first.");
|
|
30664
|
+
process.exitCode = 1;
|
|
30665
|
+
return;
|
|
30666
|
+
}
|
|
30667
|
+
if (untrackedNames.length > 0) {
|
|
30668
|
+
log({
|
|
30669
|
+
event: "add:untracked",
|
|
30670
|
+
components: untrackedNames,
|
|
30671
|
+
message: `Found ${untrackedNames.length} component(s) on disk the config never tracked: ${untrackedNames.join(", ")}. Refreshing and tracking them.`
|
|
30672
|
+
});
|
|
30673
|
+
}
|
|
30674
|
+
components = candidates;
|
|
30675
|
+
}
|
|
30676
|
+
if (folder === "composites" && components.length === 0) {
|
|
30677
|
+
components = ["composites"];
|
|
30678
|
+
}
|
|
30679
|
+
if (components.length === 0) {
|
|
30680
|
+
error46("No components specified. Usage: rafters add <component...>");
|
|
30681
|
+
process.exitCode = 1;
|
|
30682
|
+
return;
|
|
30683
|
+
}
|
|
30684
|
+
log({
|
|
30685
|
+
event: "add:start",
|
|
30686
|
+
cwd,
|
|
30687
|
+
components,
|
|
30688
|
+
overwrite: options.overwrite ?? false
|
|
30689
|
+
});
|
|
30690
|
+
const allItems = [];
|
|
30691
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30692
|
+
for (const itemName of components) {
|
|
30693
|
+
try {
|
|
30694
|
+
if (folder === "composites") {
|
|
30695
|
+
if (!seen.has(itemName)) {
|
|
30696
|
+
const composite = await client.fetchComposite(itemName);
|
|
30697
|
+
seen.add(itemName);
|
|
30698
|
+
allItems.push(composite);
|
|
30699
|
+
for (const dep of composite.primitives) {
|
|
30700
|
+
if (!seen.has(dep)) {
|
|
30701
|
+
const depItems = await client.resolveDependencies(dep, seen);
|
|
30702
|
+
allItems.push(...depItems);
|
|
30703
|
+
}
|
|
30704
|
+
}
|
|
30700
30705
|
}
|
|
30701
|
-
|
|
30702
|
-
|
|
30703
|
-
|
|
30704
|
-
|
|
30705
|
-
|
|
30706
|
-
|
|
30707
|
-
|
|
30708
|
-
|
|
30709
|
-
|
|
30710
|
-
|
|
30706
|
+
} else {
|
|
30707
|
+
const items = await client.resolveDependencies(itemName, seen);
|
|
30708
|
+
allItems.push(...items);
|
|
30709
|
+
}
|
|
30710
|
+
} catch (err) {
|
|
30711
|
+
if (err instanceof Error) {
|
|
30712
|
+
error46(err.message);
|
|
30713
|
+
} else {
|
|
30714
|
+
error46(`Failed to fetch "${itemName}"`);
|
|
30715
|
+
}
|
|
30716
|
+
process.exitCode = 1;
|
|
30717
|
+
return;
|
|
30718
|
+
}
|
|
30719
|
+
}
|
|
30720
|
+
const substrateKinds = [
|
|
30721
|
+
...new Set(
|
|
30722
|
+
allItems.filter((item) => item.type === "substrate").map((item) => item.files[0]?.path.split("/")[0]).filter((segment) => Boolean(segment))
|
|
30723
|
+
)
|
|
30724
|
+
];
|
|
30725
|
+
const written = [];
|
|
30726
|
+
const skipped = [];
|
|
30727
|
+
const failed = [];
|
|
30728
|
+
const installedItems = [];
|
|
30729
|
+
const filteredItems = [];
|
|
30730
|
+
const target = getComponentTarget(config2);
|
|
30731
|
+
for (const item of allItems) {
|
|
30732
|
+
if (!options.overwrite && isAlreadyInstalled(config2, item)) {
|
|
30733
|
+
if (isInstalledOnDisk(config2, item, cwd)) {
|
|
30734
|
+
log({
|
|
30735
|
+
event: "add:skip",
|
|
30736
|
+
component: item.name,
|
|
30737
|
+
reason: "already installed"
|
|
30738
|
+
});
|
|
30739
|
+
skipped.push(item.name);
|
|
30740
|
+
continue;
|
|
30741
|
+
}
|
|
30742
|
+
log({
|
|
30743
|
+
event: "add:warning",
|
|
30744
|
+
component: item.name,
|
|
30745
|
+
message: "Config tracks this as installed but no files found on disk -- reinstalling."
|
|
30746
|
+
});
|
|
30747
|
+
}
|
|
30748
|
+
try {
|
|
30749
|
+
const result = await installItem(cwd, item, options, config2, substrateKinds);
|
|
30750
|
+
if (result.installed) {
|
|
30751
|
+
written.push(item.name);
|
|
30752
|
+
installedItems.push(item);
|
|
30753
|
+
if (item.type === "ui") {
|
|
30754
|
+
const selection = selectFilesForFramework(item.files, target);
|
|
30755
|
+
filteredItems.push({ ...item, files: selection.files });
|
|
30756
|
+
} else {
|
|
30757
|
+
filteredItems.push(item);
|
|
30711
30758
|
}
|
|
30759
|
+
log({
|
|
30760
|
+
event: "add:installed",
|
|
30761
|
+
component: item.name,
|
|
30762
|
+
type: item.type,
|
|
30763
|
+
files: result.files
|
|
30764
|
+
});
|
|
30765
|
+
}
|
|
30766
|
+
if (result.skipped && !result.installed) {
|
|
30767
|
+
skipped.push(item.name);
|
|
30768
|
+
installedItems.push(item);
|
|
30769
|
+
}
|
|
30770
|
+
} catch (err) {
|
|
30771
|
+
failed.push(item.name);
|
|
30772
|
+
if (err instanceof Error) {
|
|
30773
|
+
log({
|
|
30774
|
+
event: "add:warning",
|
|
30775
|
+
component: item.name,
|
|
30776
|
+
message: err.message
|
|
30777
|
+
});
|
|
30712
30778
|
}
|
|
30713
30779
|
}
|
|
30714
30780
|
}
|
|
30781
|
+
const emptyDeps = {
|
|
30782
|
+
installed: [],
|
|
30783
|
+
skipped: [],
|
|
30784
|
+
devInstalled: [],
|
|
30785
|
+
failed: []
|
|
30786
|
+
};
|
|
30787
|
+
let depsResult = emptyDeps;
|
|
30788
|
+
try {
|
|
30789
|
+
depsResult = await installRegistryDependencies(filteredItems, cwd, {
|
|
30790
|
+
target
|
|
30791
|
+
});
|
|
30792
|
+
} catch (err) {
|
|
30793
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30794
|
+
log({
|
|
30795
|
+
event: "add:deps:install-failed",
|
|
30796
|
+
message: `Failed to process dependencies: ${message}`,
|
|
30797
|
+
dependencies: [],
|
|
30798
|
+
suggestion: "Check package.json and try installing dependencies manually."
|
|
30799
|
+
});
|
|
30800
|
+
}
|
|
30801
|
+
if (depsResult.installed.length > 0 || depsResult.skipped.length > 0) {
|
|
30802
|
+
log({
|
|
30803
|
+
event: "add:dependencies",
|
|
30804
|
+
dependencies: depsResult.installed,
|
|
30805
|
+
devDependencies: depsResult.devInstalled,
|
|
30806
|
+
skipped: depsResult.skipped
|
|
30807
|
+
});
|
|
30808
|
+
}
|
|
30809
|
+
if (installedItems.length > 0 && config2) {
|
|
30810
|
+
trackInstalled(config2, installedItems);
|
|
30811
|
+
await saveConfig(cwd, config2);
|
|
30812
|
+
await regenerateAfterInstall(cwd, config2);
|
|
30813
|
+
} else if (installedItems.length > 0 && !config2) {
|
|
30814
|
+
const newConfig = {
|
|
30815
|
+
framework: "unknown",
|
|
30816
|
+
componentsPath: "components/ui",
|
|
30817
|
+
primitivesPath: "lib/primitives",
|
|
30818
|
+
compositesPath: "composites",
|
|
30819
|
+
rulesPath: "lib/rules",
|
|
30820
|
+
cssPath: null,
|
|
30821
|
+
intent: "efficient",
|
|
30822
|
+
fonts: { path: null, imports: [] },
|
|
30823
|
+
exports: DEFAULT_EXPORTS,
|
|
30824
|
+
installed: { components: [], primitives: [], composites: [], rules: [] }
|
|
30825
|
+
};
|
|
30826
|
+
trackInstalled(newConfig, installedItems);
|
|
30827
|
+
await saveConfig(cwd, newConfig);
|
|
30828
|
+
await regenerateAfterInstall(cwd, newConfig);
|
|
30829
|
+
}
|
|
30715
30830
|
log({
|
|
30716
|
-
event: "
|
|
30717
|
-
|
|
30718
|
-
|
|
30831
|
+
event: "add:complete",
|
|
30832
|
+
written: written.length,
|
|
30833
|
+
skipped: skipped.length,
|
|
30834
|
+
untracked: untrackedNames.length,
|
|
30835
|
+
failed: failed.length,
|
|
30836
|
+
components: written,
|
|
30837
|
+
skippedComponents: skipped,
|
|
30838
|
+
untrackedComponents: untrackedNames,
|
|
30839
|
+
failedComponents: failed
|
|
30719
30840
|
});
|
|
30841
|
+
if (failed.length > 0) {
|
|
30842
|
+
process.exitCode = 1;
|
|
30843
|
+
}
|
|
30844
|
+
if (!options.updateAll && skipped.length > 0 && written.length === 0) {
|
|
30845
|
+
log({
|
|
30846
|
+
event: "add:hint",
|
|
30847
|
+
message: "Some components were skipped. Use --update to re-fetch, or --update-all to refresh everything.",
|
|
30848
|
+
skipped
|
|
30849
|
+
});
|
|
30850
|
+
error46("Component already exists. Use --update to re-fetch from registry.");
|
|
30851
|
+
process.exitCode = 1;
|
|
30852
|
+
}
|
|
30720
30853
|
}
|
|
30721
30854
|
|
|
30722
30855
|
// src/commands/mcp.ts
|
|
@@ -30891,7 +31024,7 @@ function fuzzyScore(query, target) {
|
|
|
30891
31024
|
|
|
30892
31025
|
// ../composites/src/registry.ts
|
|
30893
31026
|
var composites = /* @__PURE__ */ new Map();
|
|
30894
|
-
function
|
|
31027
|
+
function register3(composite) {
|
|
30895
31028
|
const { id } = composite.manifest;
|
|
30896
31029
|
if (composites.has(id)) {
|
|
30897
31030
|
throw new Error(`Composite "${id}" is already registered`);
|
|
@@ -31233,7 +31366,10 @@ var RaftersToolHandler = class {
|
|
|
31233
31366
|
text: JSON.stringify({
|
|
31234
31367
|
error: "workspace parameter required",
|
|
31235
31368
|
suggestion: "Multiple workspaces are available. Pass `workspace` with one of the names below.",
|
|
31236
|
-
workspaces: this.workspaces.map((w) => ({
|
|
31369
|
+
workspaces: this.workspaces.map((w) => ({
|
|
31370
|
+
name: w.name,
|
|
31371
|
+
root: w.root
|
|
31372
|
+
}))
|
|
31237
31373
|
})
|
|
31238
31374
|
}
|
|
31239
31375
|
]
|
|
@@ -31270,7 +31406,7 @@ var RaftersToolHandler = class {
|
|
|
31270
31406
|
const { registry: registry2 } = await discoverFromDirs(...dirs);
|
|
31271
31407
|
for (const composite of registry2.values()) {
|
|
31272
31408
|
try {
|
|
31273
|
-
|
|
31409
|
+
register3(composite);
|
|
31274
31410
|
} catch {
|
|
31275
31411
|
}
|
|
31276
31412
|
}
|
|
@@ -31298,7 +31434,9 @@ var RaftersToolHandler = class {
|
|
|
31298
31434
|
const paths = getRaftersPaths(workspaceRoot);
|
|
31299
31435
|
let config2 = null;
|
|
31300
31436
|
try {
|
|
31301
|
-
config2 =
|
|
31437
|
+
config2 = migrateConfig(
|
|
31438
|
+
JSON.parse(await readFile6(paths.config, "utf-8"))
|
|
31439
|
+
);
|
|
31302
31440
|
} catch {
|
|
31303
31441
|
}
|
|
31304
31442
|
if (!config2?.compositesPath) {
|
|
@@ -31342,7 +31480,9 @@ var RaftersToolHandler = class {
|
|
|
31342
31480
|
// are listed -- the array is empty when nothing is constrained.
|
|
31343
31481
|
blockRules: c4.blocks.filter((b2) => b2.rules && b2.rules.length > 0).map((b2) => ({ id: b2.id, type: b2.type, rules: b2.rules }))
|
|
31344
31482
|
}));
|
|
31345
|
-
return {
|
|
31483
|
+
return {
|
|
31484
|
+
content: [{ type: "text", text: JSON.stringify({ composites: result }, null, 2) }]
|
|
31485
|
+
};
|
|
31346
31486
|
}
|
|
31347
31487
|
async handlePattern(args) {
|
|
31348
31488
|
const { solves, query, workspace } = args;
|
|
@@ -31389,7 +31529,9 @@ var RaftersToolHandler = class {
|
|
|
31389
31529
|
cognitiveLoad: c4.manifest.cognitiveLoad,
|
|
31390
31530
|
usagePatterns: c4.manifest.usagePatterns
|
|
31391
31531
|
}));
|
|
31392
|
-
return {
|
|
31532
|
+
return {
|
|
31533
|
+
content: [{ type: "text", text: JSON.stringify({ patterns }, null, 2) }]
|
|
31534
|
+
};
|
|
31393
31535
|
}
|
|
31394
31536
|
async handleComponent(componentName) {
|
|
31395
31537
|
try {
|
|
@@ -31508,8 +31650,8 @@ import { existsSync as existsSync8 } from "fs";
|
|
|
31508
31650
|
import { resolve as resolve6 } from "path";
|
|
31509
31651
|
|
|
31510
31652
|
// ../studio/src/api/vite-plugin.ts
|
|
31511
|
-
import { readFile as readFile7 } from "fs/promises";
|
|
31512
|
-
import { join as join14 } from "path";
|
|
31653
|
+
import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
31654
|
+
import { isAbsolute as isAbsolute3, join as join14 } from "path";
|
|
31513
31655
|
var REGISTRY_PLUGINS3 = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
|
|
31514
31656
|
var STUDIO_REASON_DEFAULT = "studio interactive edit";
|
|
31515
31657
|
var TokenResponseSchema = external_exports.object({
|
|
@@ -31537,13 +31679,52 @@ var ColorBuildOptionsSchema = external_exports.object({
|
|
|
31537
31679
|
var projectPath = process.env.RAFTERS_PROJECT_PATH || process.cwd();
|
|
31538
31680
|
var outputDir = join14(projectPath, ".rafters", "output");
|
|
31539
31681
|
var configPath = join14(projectPath, ".rafters", "config.rafters.json");
|
|
31540
|
-
|
|
31682
|
+
var FontsConfigSchema = external_exports.object({
|
|
31683
|
+
path: external_exports.union([external_exports.string(), external_exports.null()]).optional(),
|
|
31684
|
+
imports: external_exports.array(external_exports.string()).optional()
|
|
31685
|
+
});
|
|
31686
|
+
var RaftersConfigSchema = external_exports.object({
|
|
31687
|
+
intent: external_exports.string().optional(),
|
|
31688
|
+
fonts: FontsConfigSchema.optional(),
|
|
31689
|
+
source: external_exports.string().optional(),
|
|
31690
|
+
darkMode: external_exports.enum(["class", "media"]).optional(),
|
|
31691
|
+
framework: external_exports.string().optional(),
|
|
31692
|
+
cssPath: external_exports.union([external_exports.string(), external_exports.null()]).optional(),
|
|
31693
|
+
exports: external_exports.record(external_exports.string(), external_exports.boolean()).optional()
|
|
31694
|
+
}).passthrough();
|
|
31695
|
+
var KNOWN_INTENTS = ["efficient"];
|
|
31696
|
+
async function readRaftersConfig() {
|
|
31541
31697
|
try {
|
|
31542
|
-
|
|
31698
|
+
const raw = JSON.parse(await readFile7(configPath, "utf8"));
|
|
31699
|
+
if ("shadcn" in raw && !("source" in raw)) {
|
|
31700
|
+
if (raw.shadcn === true) raw.source = "shadcn";
|
|
31701
|
+
delete raw.shadcn;
|
|
31702
|
+
}
|
|
31703
|
+
const result = RaftersConfigSchema.safeParse(raw);
|
|
31704
|
+
if (!result.success) {
|
|
31705
|
+
console.log(`[rafters] Config validation failed: ${result.error.message}`);
|
|
31706
|
+
return null;
|
|
31707
|
+
}
|
|
31708
|
+
return result.data;
|
|
31543
31709
|
} catch {
|
|
31544
31710
|
return null;
|
|
31545
31711
|
}
|
|
31546
31712
|
}
|
|
31713
|
+
function validateFontsPath(path) {
|
|
31714
|
+
if (path === null || path === void 0) return null;
|
|
31715
|
+
if (isAbsolute3(path)) return "fonts path must be relative";
|
|
31716
|
+
return null;
|
|
31717
|
+
}
|
|
31718
|
+
function validateIntent(intent) {
|
|
31719
|
+
if (!KNOWN_INTENTS.includes(intent)) {
|
|
31720
|
+
return `unknown intent "${intent}". Known: ${KNOWN_INTENTS.join(", ")}`;
|
|
31721
|
+
}
|
|
31722
|
+
return null;
|
|
31723
|
+
}
|
|
31724
|
+
async function loadStudioConfig() {
|
|
31725
|
+
const raw = await readRaftersConfig();
|
|
31726
|
+
return raw;
|
|
31727
|
+
}
|
|
31547
31728
|
var SetTokenMessageSchema = external_exports.object({
|
|
31548
31729
|
name: external_exports.string().min(1),
|
|
31549
31730
|
value: external_exports.union([external_exports.string(), ColorValueSchema, ColorReferenceSchema]),
|
|
@@ -31942,7 +32123,7 @@ function studioApiPlugin() {
|
|
|
31942
32123
|
exports,
|
|
31943
32124
|
contentSources: config2 ? resolveContentSources(projectPath, config2) : [],
|
|
31944
32125
|
darkMode: config2?.darkMode ?? "class",
|
|
31945
|
-
includeImport:
|
|
32126
|
+
includeImport: config2?.source !== "shadcn"
|
|
31946
32127
|
},
|
|
31947
32128
|
{ notify: () => server.ws.send({ type: "custom", event: "rafters:css-updated" }) }
|
|
31948
32129
|
);
|
|
@@ -32060,6 +32241,85 @@ function studioApiPlugin() {
|
|
|
32060
32241
|
client.send("rafters:token-updated", { ok: false, error: String(error47) });
|
|
32061
32242
|
}
|
|
32062
32243
|
});
|
|
32244
|
+
server.ws.on("rafters:get-config", async (_rawData, client) => {
|
|
32245
|
+
const config2 = await readRaftersConfig();
|
|
32246
|
+
if (!config2) {
|
|
32247
|
+
client.send("rafters:config", {
|
|
32248
|
+
ok: false,
|
|
32249
|
+
error: `config not found at ${configPath}`
|
|
32250
|
+
});
|
|
32251
|
+
return;
|
|
32252
|
+
}
|
|
32253
|
+
client.send("rafters:config", { ok: true, config: config2 });
|
|
32254
|
+
});
|
|
32255
|
+
server.ws.on("rafters:set-intent", async (rawData, client) => {
|
|
32256
|
+
const parsed = external_exports.object({ intent: external_exports.string().min(1) }).safeParse(rawData);
|
|
32257
|
+
if (!parsed.success) {
|
|
32258
|
+
client.send("rafters:intent-updated", {
|
|
32259
|
+
ok: false,
|
|
32260
|
+
error: `Invalid message: ${parsed.error.message}`
|
|
32261
|
+
});
|
|
32262
|
+
return;
|
|
32263
|
+
}
|
|
32264
|
+
const { intent } = parsed.data;
|
|
32265
|
+
const intentError = validateIntent(intent);
|
|
32266
|
+
if (intentError) {
|
|
32267
|
+
client.send("rafters:intent-updated", { ok: false, error: intentError });
|
|
32268
|
+
return;
|
|
32269
|
+
}
|
|
32270
|
+
const config2 = await readRaftersConfig();
|
|
32271
|
+
if (!config2) {
|
|
32272
|
+
client.send("rafters:intent-updated", {
|
|
32273
|
+
ok: false,
|
|
32274
|
+
error: `config not found at ${configPath}`
|
|
32275
|
+
});
|
|
32276
|
+
return;
|
|
32277
|
+
}
|
|
32278
|
+
const updated = { ...config2, intent };
|
|
32279
|
+
try {
|
|
32280
|
+
await writeFile4(configPath, JSON.stringify(updated, null, 2));
|
|
32281
|
+
client.send("rafters:intent-updated", { ok: true, intent });
|
|
32282
|
+
} catch (error47) {
|
|
32283
|
+
console.log(`[rafters] Intent update failed: ${error47}`);
|
|
32284
|
+
client.send("rafters:intent-updated", { ok: false, error: String(error47) });
|
|
32285
|
+
}
|
|
32286
|
+
});
|
|
32287
|
+
server.ws.on("rafters:set-fonts", async (rawData, client) => {
|
|
32288
|
+
const parsed = FontsConfigSchema.safeParse(rawData);
|
|
32289
|
+
if (!parsed.success) {
|
|
32290
|
+
client.send("rafters:fonts-updated", {
|
|
32291
|
+
ok: false,
|
|
32292
|
+
error: `Invalid message: ${parsed.error.message}`
|
|
32293
|
+
});
|
|
32294
|
+
return;
|
|
32295
|
+
}
|
|
32296
|
+
const fontsData = parsed.data;
|
|
32297
|
+
const pathError = validateFontsPath(fontsData.path);
|
|
32298
|
+
if (pathError) {
|
|
32299
|
+
client.send("rafters:fonts-updated", { ok: false, error: pathError });
|
|
32300
|
+
return;
|
|
32301
|
+
}
|
|
32302
|
+
const config2 = await readRaftersConfig();
|
|
32303
|
+
if (!config2) {
|
|
32304
|
+
client.send("rafters:fonts-updated", {
|
|
32305
|
+
ok: false,
|
|
32306
|
+
error: `config not found at ${configPath}`
|
|
32307
|
+
});
|
|
32308
|
+
return;
|
|
32309
|
+
}
|
|
32310
|
+
const existing = config2.fonts ?? {};
|
|
32311
|
+
const fonts = { ...existing };
|
|
32312
|
+
if (fontsData.path !== void 0) fonts.path = fontsData.path;
|
|
32313
|
+
if (fontsData.imports !== void 0) fonts.imports = fontsData.imports;
|
|
32314
|
+
const updated = { ...config2, fonts };
|
|
32315
|
+
try {
|
|
32316
|
+
await writeFile4(configPath, JSON.stringify(updated, null, 2));
|
|
32317
|
+
client.send("rafters:fonts-updated", { ok: true, fonts });
|
|
32318
|
+
} catch (error47) {
|
|
32319
|
+
console.log(`[rafters] Fonts update failed: ${error47}`);
|
|
32320
|
+
client.send("rafters:fonts-updated", { ok: false, error: String(error47) });
|
|
32321
|
+
}
|
|
32322
|
+
});
|
|
32063
32323
|
server.middlewares.use(async (req, res, next) => {
|
|
32064
32324
|
let pathname;
|
|
32065
32325
|
try {
|