nxds-cli 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +281 -46
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// ../claude-design/src/theme-fields.ts
|
|
4
|
+
var isExportThemeFlag = (flag) => flag !== "mode" && flag !== "icons";
|
|
5
|
+
function shellValue(value) {
|
|
6
|
+
if (/^[\w.-]+$/.test(value)) return value;
|
|
7
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
8
|
+
}
|
|
9
|
+
function formatThemeFlags(flags) {
|
|
10
|
+
return flags.map(({ flag, value }) => `--${flag} ${shellValue(value)}`).join(" ");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// ../core/src/token-source/ui-scale.ts
|
|
14
|
+
var UI_SCALES = {
|
|
15
|
+
small: { spacing: 0.9, text: 12 / 14, icon: 14 / 16 },
|
|
16
|
+
default: { spacing: 1, text: 1, icon: 1 },
|
|
17
|
+
large: { spacing: 1.1, text: 16 / 14, icon: 18 / 16 },
|
|
18
|
+
larger: { spacing: 1.25, text: 18 / 14, icon: 20 / 16 }
|
|
19
|
+
};
|
|
20
|
+
var NON_DEFAULT_UI_SCALES = Object.keys(UI_SCALES).filter((scale) => scale !== "default");
|
|
21
|
+
var TEXT_SIZES = [12, 13, 14, 15, 16];
|
|
22
|
+
var MIN_TEXT_PX = 8;
|
|
23
|
+
|
|
3
24
|
// ../../node_modules/culori/src/rgb/parseNumber.js
|
|
4
25
|
var parseNumber = (color, len) => {
|
|
5
26
|
if (typeof color !== "number") return;
|
|
@@ -3838,6 +3859,13 @@ var BASE_TONE_OPTIONS = [
|
|
|
3838
3859
|
{ value: "slate", label: "Slate", color: "#717376" },
|
|
3839
3860
|
{ value: "gray", label: "Gray", color: "#707274" }
|
|
3840
3861
|
];
|
|
3862
|
+
var UI_SCALE_OPTIONS = [
|
|
3863
|
+
{ value: "small", label: "Small" },
|
|
3864
|
+
{ value: "default", label: "Default" },
|
|
3865
|
+
{ value: "large", label: "Large" },
|
|
3866
|
+
{ value: "larger", label: "Larger" }
|
|
3867
|
+
];
|
|
3868
|
+
var TEXT_SIZE_OPTIONS = TEXT_SIZES.map((value) => ({ value, label: `${value}px` }));
|
|
3841
3869
|
var DENSITY_OPTIONS = [
|
|
3842
3870
|
{ value: "tight", label: "Tight" },
|
|
3843
3871
|
{ value: "compact", label: "Compact" },
|
|
@@ -3871,6 +3899,8 @@ var DEFAULT_NXDS_APPEARANCE = {
|
|
|
3871
3899
|
surfaceTone: "zinc",
|
|
3872
3900
|
lightContrast: 50,
|
|
3873
3901
|
darkContrast: 50,
|
|
3902
|
+
uiScale: "default",
|
|
3903
|
+
textSize: 14,
|
|
3874
3904
|
density: "default",
|
|
3875
3905
|
corners: "subtle",
|
|
3876
3906
|
elevation: "quiet",
|
|
@@ -3879,18 +3909,21 @@ var DEFAULT_NXDS_APPEARANCE = {
|
|
|
3879
3909
|
uiFont: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
3880
3910
|
headingFont: null,
|
|
3881
3911
|
codeFont: 'ui-monospace, "SF Mono", Menlo, monospace',
|
|
3882
|
-
uiFontSize: 14,
|
|
3883
3912
|
codeFontSize: 12,
|
|
3884
3913
|
reduceMotion: false,
|
|
3885
3914
|
pointerCursors: false,
|
|
3886
3915
|
fontSmoothing: false
|
|
3887
3916
|
}
|
|
3888
3917
|
};
|
|
3889
|
-
var FONT_SIZE_PX_MIN =
|
|
3918
|
+
var FONT_SIZE_PX_MIN = MIN_TEXT_PX;
|
|
3890
3919
|
var FONT_SIZE_PX_MAX = 32;
|
|
3891
3920
|
var SURFACE_TONES = new Set(
|
|
3892
3921
|
BASE_TONE_OPTIONS.map((option) => option.value)
|
|
3893
3922
|
);
|
|
3923
|
+
var SCALES = new Set(
|
|
3924
|
+
UI_SCALE_OPTIONS.map((option) => option.value)
|
|
3925
|
+
);
|
|
3926
|
+
var TEXT_SIZE_VALUES = new Set(TEXT_SIZES);
|
|
3894
3927
|
var DENSITIES = new Set(
|
|
3895
3928
|
DENSITY_OPTIONS.map((option) => option.value)
|
|
3896
3929
|
);
|
|
@@ -4043,20 +4076,6 @@ function contrastField(flag, key, description) {
|
|
|
4043
4076
|
})
|
|
4044
4077
|
};
|
|
4045
4078
|
}
|
|
4046
|
-
function fontSizeField(flag, key, description) {
|
|
4047
|
-
return {
|
|
4048
|
-
kind: "integer",
|
|
4049
|
-
flag,
|
|
4050
|
-
key: `prefs.${key}`,
|
|
4051
|
-
description,
|
|
4052
|
-
min: FONT_SIZE_PX_MIN,
|
|
4053
|
-
max: FONT_SIZE_PX_MAX,
|
|
4054
|
-
read: (theme) => String(theme.appearance.prefs[key]),
|
|
4055
|
-
write: (theme, value) => withPrefs(theme, {
|
|
4056
|
-
[key]: integer(flag, value, FONT_SIZE_PX_MIN, FONT_SIZE_PX_MAX)
|
|
4057
|
-
})
|
|
4058
|
-
};
|
|
4059
|
-
}
|
|
4060
4079
|
function fontField(flag, key, description, categories, fallback) {
|
|
4061
4080
|
const fonts = FONT_OPTIONS.filter(
|
|
4062
4081
|
(font) => categories.includes(font.category)
|
|
@@ -4087,6 +4106,9 @@ function fontField(flag, key, description, categories, fallback) {
|
|
|
4087
4106
|
}
|
|
4088
4107
|
};
|
|
4089
4108
|
}
|
|
4109
|
+
var TEXT_SIZES2 = TEXT_SIZE_OPTIONS.map((option) => option.value);
|
|
4110
|
+
var TEXT_SIZE_MIN = Math.min(...TEXT_SIZES2);
|
|
4111
|
+
var TEXT_SIZE_MAX = Math.max(...TEXT_SIZES2);
|
|
4090
4112
|
var DEFAULT_PREFS = DEFAULT_NXDS_APPEARANCE.prefs;
|
|
4091
4113
|
var TEXT_FONTS = ["sans", "serif"];
|
|
4092
4114
|
var NXDS_THEME_FIELDS = [
|
|
@@ -4107,6 +4129,30 @@ var NXDS_THEME_FIELDS = [
|
|
|
4107
4129
|
"neutral tone of backgrounds and borders",
|
|
4108
4130
|
BASE_TONE_OPTIONS.map((option) => option.value)
|
|
4109
4131
|
),
|
|
4132
|
+
enumField(
|
|
4133
|
+
"ui-scale",
|
|
4134
|
+
"uiScale",
|
|
4135
|
+
"size of text, icons and spacing together",
|
|
4136
|
+
UI_SCALE_OPTIONS.map((option) => option.value)
|
|
4137
|
+
),
|
|
4138
|
+
{
|
|
4139
|
+
kind: "integer",
|
|
4140
|
+
flag: "text-size",
|
|
4141
|
+
key: "textSize",
|
|
4142
|
+
description: `label text size in px at the default UI scale, ${TEXT_SIZE_MIN} to ${TEXT_SIZE_MAX}`,
|
|
4143
|
+
min: TEXT_SIZE_MIN,
|
|
4144
|
+
max: TEXT_SIZE_MAX,
|
|
4145
|
+
read: (theme) => String(theme.appearance.textSize),
|
|
4146
|
+
write: (theme, value) => withAppearance(theme, {
|
|
4147
|
+
// Every whole number from the minimum to the maximum is a text size.
|
|
4148
|
+
textSize: integer(
|
|
4149
|
+
"text-size",
|
|
4150
|
+
value,
|
|
4151
|
+
TEXT_SIZE_MIN,
|
|
4152
|
+
TEXT_SIZE_MAX
|
|
4153
|
+
)
|
|
4154
|
+
})
|
|
4155
|
+
},
|
|
4110
4156
|
enumField(
|
|
4111
4157
|
"density",
|
|
4112
4158
|
"density",
|
|
@@ -4157,8 +4203,23 @@ var NXDS_THEME_FIELDS = [
|
|
|
4157
4203
|
value: "system",
|
|
4158
4204
|
family: DEFAULT_PREFS.codeFont
|
|
4159
4205
|
}),
|
|
4160
|
-
|
|
4161
|
-
|
|
4206
|
+
{
|
|
4207
|
+
kind: "integer",
|
|
4208
|
+
flag: "code-font-size",
|
|
4209
|
+
key: "prefs.codeFontSize",
|
|
4210
|
+
description: "code text size in px",
|
|
4211
|
+
min: FONT_SIZE_PX_MIN,
|
|
4212
|
+
max: FONT_SIZE_PX_MAX,
|
|
4213
|
+
read: (theme) => String(theme.appearance.prefs.codeFontSize),
|
|
4214
|
+
write: (theme, value) => withPrefs(theme, {
|
|
4215
|
+
codeFontSize: integer(
|
|
4216
|
+
"code-font-size",
|
|
4217
|
+
value,
|
|
4218
|
+
FONT_SIZE_PX_MIN,
|
|
4219
|
+
FONT_SIZE_PX_MAX
|
|
4220
|
+
)
|
|
4221
|
+
})
|
|
4222
|
+
},
|
|
4162
4223
|
{
|
|
4163
4224
|
kind: "choice",
|
|
4164
4225
|
flag: "icons",
|
|
@@ -4543,7 +4604,7 @@ async function fetchRelease(registry, version) {
|
|
|
4543
4604
|
if (isNewerSchema(value)) {
|
|
4544
4605
|
const release = version === "latest" ? "The latest nxds release" : `nxds ${version}`;
|
|
4545
4606
|
throw new CliError(
|
|
4546
|
-
`${release} needs a newer nxds-cli than ${"0.
|
|
4607
|
+
`${release} needs a newer nxds-cli than ${"0.8.0"}. Run \`${CLI_COMMAND}\` to get the newest one.`
|
|
4547
4608
|
);
|
|
4548
4609
|
}
|
|
4549
4610
|
const invalid2 = (problems) => new CliError(
|
|
@@ -6123,14 +6184,18 @@ function report(checks) {
|
|
|
6123
6184
|
// ../claude-design/src/system-index.ts
|
|
6124
6185
|
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
6125
6186
|
var PAGE_PATHS = ["manifest.json", "api/"];
|
|
6126
|
-
function mergeSystemIndex(current, exported) {
|
|
6127
|
-
|
|
6128
|
-
|
|
6187
|
+
function mergeSystemIndex(current, exported, { retitle }) {
|
|
6188
|
+
const { theme: _theme, ...kept } = current;
|
|
6189
|
+
const merged = {
|
|
6190
|
+
...kept,
|
|
6129
6191
|
namespace: exported.namespace,
|
|
6130
6192
|
editing: exported.editing,
|
|
6131
6193
|
libraries: exported.libraries,
|
|
6132
6194
|
lastChange: exported.lastChange
|
|
6133
6195
|
};
|
|
6196
|
+
if (retitle) merged["title"] = exported.title;
|
|
6197
|
+
if (exported.theme) merged["theme"] = exported.theme;
|
|
6198
|
+
return merged;
|
|
6134
6199
|
}
|
|
6135
6200
|
function isPageGenerated(file) {
|
|
6136
6201
|
return PAGE_PATHS.some((page) => file === page || file.startsWith(page));
|
|
@@ -6179,6 +6244,7 @@ var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
|
6179
6244
|
var DEFAULT_EXPORT_DIR = "nxds-design-system";
|
|
6180
6245
|
var FETCH_TIMEOUT_MS2 = 6e4;
|
|
6181
6246
|
var dispatcher2 = new EnvHttpProxyAgent2();
|
|
6247
|
+
var THEME_FILE = "theme.js";
|
|
6182
6248
|
function redactUrl(url) {
|
|
6183
6249
|
const redacted = httpUrl(url);
|
|
6184
6250
|
if (!redacted) return "<invalid URL>";
|
|
@@ -6313,9 +6379,8 @@ function stalePaths(existing, exported) {
|
|
|
6313
6379
|
var EXPORT_NAMES = /* @__PURE__ */ new Set(["project", "files.json", "removed.json"]);
|
|
6314
6380
|
var isRootName = (name) => name !== "" && name !== "." && name !== ".." && path10.basename(name) === name && !EXPORT_NAMES.has(name);
|
|
6315
6381
|
var sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
6316
|
-
var
|
|
6317
|
-
|
|
6318
|
-
);
|
|
6382
|
+
var isEntry = (value) => typeof value?.path === "string" && typeof value.sha256 === "string";
|
|
6383
|
+
var isEntryList = (value) => Array.isArray(value) && value.every(isEntry);
|
|
6319
6384
|
function readManifest(root) {
|
|
6320
6385
|
const file = path10.join(root, "files.json");
|
|
6321
6386
|
if (!existsSync9(file)) {
|
|
@@ -6324,12 +6389,12 @@ function readManifest(root) {
|
|
|
6324
6389
|
);
|
|
6325
6390
|
}
|
|
6326
6391
|
const value = readJson(file);
|
|
6327
|
-
if (!isEntryList(value?.project) || !isEntryList(value.root)) {
|
|
6392
|
+
if (!isEntryList(value?.project) || !isEntryList(value.root) || !(value.theme === void 0 || isEntry(value.theme) && value.theme.path === THEME_FILE)) {
|
|
6328
6393
|
throw new CliError(
|
|
6329
|
-
`${file} must hold project and root, each a JSON array of { path, sha256 } entries.`
|
|
6394
|
+
`${file} must hold project and root, each a JSON array of { path, sha256 } entries, and may hold theme, the { path, sha256 } entry for ${THEME_FILE}.`
|
|
6330
6395
|
);
|
|
6331
6396
|
}
|
|
6332
|
-
return { project: value.project, root: value.root };
|
|
6397
|
+
return { project: value.project, root: value.root, theme: value.theme };
|
|
6333
6398
|
}
|
|
6334
6399
|
function readEntries(dir, entries, prefix) {
|
|
6335
6400
|
const files = /* @__PURE__ */ new Map();
|
|
@@ -6373,7 +6438,8 @@ function readRelease(root) {
|
|
|
6373
6438
|
}
|
|
6374
6439
|
return {
|
|
6375
6440
|
files: readEntries(projectDir, manifest.project, "project/"),
|
|
6376
|
-
rootFiles: readEntries(root, manifest.root, "")
|
|
6441
|
+
rootFiles: readEntries(root, manifest.root, ""),
|
|
6442
|
+
themeModule: manifest.theme ? readEntries(root, [manifest.theme], "").get(THEME_FILE) : void 0
|
|
6377
6443
|
};
|
|
6378
6444
|
}
|
|
6379
6445
|
function droppedRootFiles(out, rootFiles) {
|
|
@@ -6417,13 +6483,132 @@ function writeManifest(out, files, rootFiles) {
|
|
|
6417
6483
|
`
|
|
6418
6484
|
);
|
|
6419
6485
|
}
|
|
6420
|
-
function
|
|
6486
|
+
function readIndex(file) {
|
|
6487
|
+
const index = readJson(file);
|
|
6488
|
+
if (typeof index !== "object" || index === null || Array.isArray(index)) {
|
|
6489
|
+
throw new UsageError(`${file} must be a system's design-system.json.`);
|
|
6490
|
+
}
|
|
6491
|
+
return index;
|
|
6492
|
+
}
|
|
6493
|
+
function storedTheme(index, file) {
|
|
6494
|
+
const theme = index["theme"];
|
|
6495
|
+
if (theme === void 0) return {};
|
|
6496
|
+
if (typeof theme !== "object" || theme === null || Array.isArray(theme) || !Object.values(theme).every((value) => typeof value === "string")) {
|
|
6497
|
+
throw new UsageError(
|
|
6498
|
+
`${file}: "theme" must be an object of theme flag values, such as {"corners": "round"}. Fix it, or remove it to export the default theme.`
|
|
6499
|
+
);
|
|
6500
|
+
}
|
|
6501
|
+
return theme;
|
|
6502
|
+
}
|
|
6503
|
+
function layeredTheme(stored, passed) {
|
|
6504
|
+
const flags = { ...stored, ...passed };
|
|
6505
|
+
for (const [flag, value] of Object.entries(passed)) {
|
|
6506
|
+
if (value === "") delete flags[flag];
|
|
6507
|
+
}
|
|
6508
|
+
return flags;
|
|
6509
|
+
}
|
|
6510
|
+
var noFlagError = (flag, version) => new UsageError(
|
|
6511
|
+
`nxds ${version} has no --${flag}. Pass --release latest to export a release that has it.`
|
|
6512
|
+
);
|
|
6513
|
+
function noThemeModuleError(theme, { passed, indexFile, version }) {
|
|
6514
|
+
const flag = Object.keys(theme).find((name) => name in passed);
|
|
6515
|
+
if (flag !== void 0) return noFlagError(flag, version);
|
|
6516
|
+
return new UsageError(
|
|
6517
|
+
`${indexFile} has a theme, and nxds ${version} can't theme an export. Pass --release latest to keep the theme.`
|
|
6518
|
+
);
|
|
6519
|
+
}
|
|
6520
|
+
function assertThemeFlags(flags, taken, { passed, indexFile, version }) {
|
|
6521
|
+
for (const flag of Object.keys(flags)) {
|
|
6522
|
+
if (taken.includes(flag)) continue;
|
|
6523
|
+
if (flag in passed) throw noFlagError(flag, version);
|
|
6524
|
+
if (flag === "mode" || flag === "icons") {
|
|
6525
|
+
throw new UsageError(
|
|
6526
|
+
`${indexFile} theme: a system carries Light and Dark and one icon library, so it has no "${flag}". Remove it from "theme".`
|
|
6527
|
+
);
|
|
6528
|
+
}
|
|
6529
|
+
throw new UsageError(
|
|
6530
|
+
`${indexFile} theme: "${flag}" isn't a theme flag nxds ${version} takes. Remove it from "theme".`
|
|
6531
|
+
);
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
var isThemeModule = (value) => typeof value === "object" && value !== null && value.api === 1 && Array.isArray(value.flags) && typeof value.render === "function" && typeof value.title === "function";
|
|
6535
|
+
async function importTheme(bytes, version) {
|
|
6536
|
+
let imported;
|
|
6537
|
+
try {
|
|
6538
|
+
imported = await import(`data:text/javascript;base64,${bytes.toString("base64")}`);
|
|
6539
|
+
} catch (error) {
|
|
6540
|
+
throw new CliError(
|
|
6541
|
+
`nxds ${version}'s theme.js failed to load (${error.message}). Report it at https://github.com/nexuslabs-ai/nxds/issues.`
|
|
6542
|
+
);
|
|
6543
|
+
}
|
|
6544
|
+
if (!isThemeModule(imported.default)) {
|
|
6545
|
+
throw new CliError(
|
|
6546
|
+
`nxds ${version}'s theme.js is newer than this nxds-cli. Run \`npx nxds-cli@latest\` to get the newest one.`
|
|
6547
|
+
);
|
|
6548
|
+
}
|
|
6549
|
+
return imported.default;
|
|
6550
|
+
}
|
|
6551
|
+
var isRendered = (value) => {
|
|
6552
|
+
const rendered = value;
|
|
6553
|
+
return typeof rendered?.guide === "function" && typeof rendered.index?.title === "string" && typeof rendered.index.theme === "object" && ["tokens.json", "tokens.css", "README.md"].every(
|
|
6554
|
+
(file) => typeof rendered.project?.[file] === "string"
|
|
6555
|
+
);
|
|
6556
|
+
};
|
|
6557
|
+
function themeError(error, { passed, indexFile, version }) {
|
|
6558
|
+
const { message, flag } = error;
|
|
6559
|
+
if (typeof flag === "string" && flag in passed) {
|
|
6560
|
+
return new UsageError(message);
|
|
6561
|
+
}
|
|
6562
|
+
if (typeof flag === "string" && indexFile !== void 0) {
|
|
6563
|
+
return new UsageError(
|
|
6564
|
+
`${indexFile} theme: ${message} Pass --${flag} <value> to change it, or --${flag}= to reset it.`
|
|
6565
|
+
);
|
|
6566
|
+
}
|
|
6567
|
+
return new CliError(`nxds ${version}'s theme.js failed: ${message}`);
|
|
6568
|
+
}
|
|
6569
|
+
function renderTheme(theme, flags, source) {
|
|
6570
|
+
const { version } = source;
|
|
6571
|
+
let rendered;
|
|
6572
|
+
try {
|
|
6573
|
+
rendered = theme.render(flags);
|
|
6574
|
+
} catch (error) {
|
|
6575
|
+
throw themeError(error, source);
|
|
6576
|
+
}
|
|
6577
|
+
if (!isRendered(rendered)) {
|
|
6578
|
+
throw new CliError(
|
|
6579
|
+
`nxds ${version}'s theme.js rendered no token files, README or setup guide.`
|
|
6580
|
+
);
|
|
6581
|
+
}
|
|
6582
|
+
return rendered;
|
|
6583
|
+
}
|
|
6584
|
+
function storedThemeTitle(stored, module, defaultTitle) {
|
|
6585
|
+
if (Object.keys(stored).length === 0) return defaultTitle;
|
|
6586
|
+
try {
|
|
6587
|
+
return module?.title(stored);
|
|
6588
|
+
} catch {
|
|
6589
|
+
return void 0;
|
|
6590
|
+
}
|
|
6591
|
+
}
|
|
6592
|
+
function exportedIndex(files) {
|
|
6421
6593
|
const exported = files.get("design-system.json");
|
|
6422
6594
|
if (!exported) throw new CliError("The release has no design-system.json.");
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6595
|
+
return JSON.parse(exported.toString("utf8"));
|
|
6596
|
+
}
|
|
6597
|
+
var jsonBytes = (value) => Buffer.from(`${JSON.stringify(value, null, 2)}
|
|
6598
|
+
`);
|
|
6599
|
+
function applyTheme(rendered, files, rootFiles) {
|
|
6600
|
+
const { project } = rendered;
|
|
6601
|
+
files.set("tokens.json", Buffer.from(project["tokens.json"]));
|
|
6602
|
+
files.set("tokens.css", Buffer.from(project["tokens.css"]));
|
|
6603
|
+
files.set("README.md", Buffer.from(project["README.md"]));
|
|
6604
|
+
files.set(
|
|
6605
|
+
"design-system.json",
|
|
6606
|
+
jsonBytes({ ...exportedIndex(files), ...rendered.index })
|
|
6426
6607
|
);
|
|
6608
|
+
rootFiles.set("SETUP.md", Buffer.from(rendered.guide(files.size)));
|
|
6609
|
+
}
|
|
6610
|
+
function mergeIndex(files, current, currentFile, retitle) {
|
|
6611
|
+
const merged = mergeSystemIndex(current, exportedIndex(files), { retitle });
|
|
6427
6612
|
const errors = validateIndex(merged);
|
|
6428
6613
|
if (errors.length > 0) {
|
|
6429
6614
|
throw new UsageError(
|
|
@@ -6431,11 +6616,7 @@ function mergeIndex(files, currentFile) {
|
|
|
6431
6616
|
${errors.map((error) => ` ${error}`).join("\n")}`
|
|
6432
6617
|
);
|
|
6433
6618
|
}
|
|
6434
|
-
files.set(
|
|
6435
|
-
"design-system.json",
|
|
6436
|
-
Buffer.from(`${JSON.stringify(merged, null, 2)}
|
|
6437
|
-
`)
|
|
6438
|
-
);
|
|
6619
|
+
files.set("design-system.json", jsonBytes(merged));
|
|
6439
6620
|
}
|
|
6440
6621
|
function writeProject(out, files) {
|
|
6441
6622
|
mkdirSync2(out, { recursive: true });
|
|
@@ -6492,8 +6673,31 @@ async function exportClaudeDesign(cwd, options) {
|
|
|
6492
6673
|
options.release ?? "latest"
|
|
6493
6674
|
);
|
|
6494
6675
|
try {
|
|
6495
|
-
const { files, rootFiles } = readRelease(pkg.root);
|
|
6496
|
-
|
|
6676
|
+
const { files, rootFiles, themeModule } = readRelease(pkg.root);
|
|
6677
|
+
const indexFile = options.index && path10.resolve(cwd, options.index);
|
|
6678
|
+
const current = indexFile ? readIndex(indexFile) : void 0;
|
|
6679
|
+
const passed = options.theme;
|
|
6680
|
+
const stored = current && indexFile ? storedTheme(current, indexFile) : {};
|
|
6681
|
+
const theme = layeredTheme(stored, passed);
|
|
6682
|
+
const source = {
|
|
6683
|
+
passed,
|
|
6684
|
+
indexFile: options.index,
|
|
6685
|
+
version: pkg.version
|
|
6686
|
+
};
|
|
6687
|
+
const defaultTitle = exportedIndex(files).title;
|
|
6688
|
+
const module = themeModule && (Object.keys(theme).length > 0 || Object.keys(stored).length > 0) ? await importTheme(themeModule, pkg.version) : void 0;
|
|
6689
|
+
let themed = {};
|
|
6690
|
+
if (Object.keys(theme).length > 0) {
|
|
6691
|
+
if (!module) throw noThemeModuleError(theme, source);
|
|
6692
|
+
assertThemeFlags(theme, module.flags, source);
|
|
6693
|
+
const rendered = renderTheme(module, theme, source);
|
|
6694
|
+
applyTheme(rendered, files, rootFiles);
|
|
6695
|
+
themed = rendered.index.theme;
|
|
6696
|
+
}
|
|
6697
|
+
if (current && indexFile) {
|
|
6698
|
+
const retitle = current["title"] === storedThemeTitle(stored, module, defaultTitle);
|
|
6699
|
+
mergeIndex(files, current, indexFile, retitle);
|
|
6700
|
+
}
|
|
6497
6701
|
const exported = new Set(
|
|
6498
6702
|
[...files.keys()].map((file) => `project/${file}`)
|
|
6499
6703
|
);
|
|
@@ -6514,6 +6718,11 @@ async function exportClaudeDesign(cwd, options) {
|
|
|
6514
6718
|
const lines2 = [
|
|
6515
6719
|
`Exported nxds ${pkg.version} as a Claude Design System: ${files.size} files in ${path10.join(relative, "project")}.`
|
|
6516
6720
|
];
|
|
6721
|
+
if (Object.keys(themed).length > 0) {
|
|
6722
|
+
lines2.push(
|
|
6723
|
+
`Themed with ${formatThemeFlags(Object.entries(themed).map(([flag, value]) => ({ flag, value })))}.`
|
|
6724
|
+
);
|
|
6725
|
+
}
|
|
6517
6726
|
if (rootFiles.has("coverage.md")) {
|
|
6518
6727
|
lines2.push(
|
|
6519
6728
|
`The props the canvas can't set are in ${path10.join(relative, "coverage.md")}.`
|
|
@@ -6537,6 +6746,7 @@ async function exportClaudeDesign(cwd, options) {
|
|
|
6537
6746
|
lines: lines2,
|
|
6538
6747
|
data: {
|
|
6539
6748
|
version: pkg.version,
|
|
6749
|
+
theme: themed,
|
|
6540
6750
|
out,
|
|
6541
6751
|
files: files.size,
|
|
6542
6752
|
removed,
|
|
@@ -6976,7 +7186,7 @@ function program(done, write) {
|
|
|
6976
7186
|
// Errors are printed once, by `main`, as text or JSON.
|
|
6977
7187
|
outputError: () => {
|
|
6978
7188
|
}
|
|
6979
|
-
}).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.
|
|
7189
|
+
}).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.8.0", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
|
|
6980
7190
|
new Option(
|
|
6981
7191
|
"--registry <url|path>",
|
|
6982
7192
|
"where to get nxds releases (default: https://nxds.dev/r)"
|
|
@@ -7058,13 +7268,13 @@ Docs: https://nxds.dev/getting-started/install`
|
|
|
7058
7268
|
const { cwd, registry } = context(command);
|
|
7059
7269
|
done(await diff(cwd, registry, items));
|
|
7060
7270
|
});
|
|
7061
|
-
cli.command("export").description(
|
|
7062
|
-
"export nxds as a Claude Design System folder, ready to publish"
|
|
7271
|
+
const exportCommand = cli.command("export").description(
|
|
7272
|
+
"export nxds as a Claude Design System folder, ready to publish. Theme flags set the system's theme, as they do for init; with --index, one left out keeps the system's value, and an empty one, such as --density=, resets it"
|
|
7063
7273
|
).addArgument(
|
|
7064
7274
|
new Argument("<target>", "what to export").choices(["claude-design"])
|
|
7065
7275
|
).option("--out <path>", `folder to write (default: ${DEFAULT_EXPORT_DIR})`).option("--release <version>", "nxds release to export (default: latest)").option(
|
|
7066
7276
|
"--index <path>",
|
|
7067
|
-
"the system's current design-system.json, to keep its title
|
|
7277
|
+
"the system's current design-system.json, to keep its title, creation date and theme"
|
|
7068
7278
|
).option(
|
|
7069
7279
|
"--existing <path>",
|
|
7070
7280
|
"a JSON list of the system's current file paths, to list the ones this release removes"
|
|
@@ -7076,9 +7286,34 @@ Docs: https://nxds.dev/getting-started/install`
|
|
|
7076
7286
|
"--npm-registry <url>",
|
|
7077
7287
|
`npm registry to download from (default: ${DEFAULT_NPM_REGISTRY})`
|
|
7078
7288
|
).env("npm_config_registry")
|
|
7079
|
-
)
|
|
7289
|
+
);
|
|
7290
|
+
const exportThemeOptions = NXDS_THEME_FIELDS.filter(
|
|
7291
|
+
(field) => isExportThemeFlag(field.flag)
|
|
7292
|
+
).map((field) => {
|
|
7293
|
+
const option = new Option(`--${field.flag} <value>`, field.description);
|
|
7294
|
+
exportCommand.addOption(option);
|
|
7295
|
+
return { flag: field.flag, key: option.attributeName() };
|
|
7296
|
+
});
|
|
7297
|
+
exportCommand.action(async (_target, _options, command) => {
|
|
7298
|
+
const options = command.opts();
|
|
7299
|
+
const theme = Object.fromEntries(
|
|
7300
|
+
exportThemeOptions.flatMap(({ flag, key }) => {
|
|
7301
|
+
const value = options[key];
|
|
7302
|
+
return value === void 0 ? [] : [[flag, value]];
|
|
7303
|
+
})
|
|
7304
|
+
);
|
|
7305
|
+
const { out, release, source, npmRegistry, index, existing, overwrite } = command.opts();
|
|
7080
7306
|
done(
|
|
7081
|
-
await exportClaudeDesign(cwdOf(command),
|
|
7307
|
+
await exportClaudeDesign(cwdOf(command), {
|
|
7308
|
+
out,
|
|
7309
|
+
release,
|
|
7310
|
+
source,
|
|
7311
|
+
npmRegistry,
|
|
7312
|
+
index,
|
|
7313
|
+
existing,
|
|
7314
|
+
overwrite,
|
|
7315
|
+
theme
|
|
7316
|
+
})
|
|
7082
7317
|
);
|
|
7083
7318
|
});
|
|
7084
7319
|
cli.command("doctor").description("check that nxds is wired up correctly").action(async (_options, command) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nxds-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Install nxds components, blocks and setup into your app.",
|
|
6
6
|
"keywords": [
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"@types/semver": "^7.8.0",
|
|
46
46
|
"tsup": "^8.5.1",
|
|
47
47
|
"typescript": "^5.9.3",
|
|
48
|
-
"@nxds/catalog": "0.0.
|
|
49
|
-
"@nxds/claude-design": "0.
|
|
50
|
-
"@nxds/core": "0.
|
|
48
|
+
"@nxds/catalog": "0.0.3",
|
|
49
|
+
"@nxds/claude-design": "0.17.0",
|
|
50
|
+
"@nxds/core": "0.14.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|