@kinetixui/cli 0.15.0 → 0.16.1
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 +241 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import pc9 from "picocolors";
|
|
6
6
|
|
|
7
7
|
// src/commands/add.ts
|
|
8
8
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -91,6 +91,14 @@ function assertComponentName(name) {
|
|
|
91
91
|
}
|
|
92
92
|
return name;
|
|
93
93
|
}
|
|
94
|
+
function assertThemeName(name) {
|
|
95
|
+
if (typeof name !== "string" || !/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(name)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Invalid theme name ${JSON.stringify(name)} \u2014 expected letters, digits and dashes.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return name;
|
|
101
|
+
}
|
|
94
102
|
function assertRegistryUrl(url) {
|
|
95
103
|
let parsed;
|
|
96
104
|
try {
|
|
@@ -248,6 +256,13 @@ async function doctor() {
|
|
|
248
256
|
levels.push(report("warn", `"${alias}" alias points to ${path5.relative(cwd, dir) || "."}, which doesn't exist yet.`));
|
|
249
257
|
}
|
|
250
258
|
}
|
|
259
|
+
const utilsBase = resolveAliasDir(cwd, config, "utils");
|
|
260
|
+
const utilsFile = [".ts", ".tsx", ".js", ".jsx"].map((ext) => `${utilsBase}${ext}`).find((f) => existsSync5(f));
|
|
261
|
+
if (utilsFile) {
|
|
262
|
+
levels.push(report("pass", `"utils" alias resolves to ${path5.relative(cwd, utilsFile)}`));
|
|
263
|
+
} else {
|
|
264
|
+
levels.push(report("warn", `"utils" alias points to ${path5.relative(cwd, utilsBase)}, which doesn't exist yet.`));
|
|
265
|
+
}
|
|
251
266
|
const cssPath2 = path5.join(cwd, config.srcDir ? "src" : "", config.tailwind.css);
|
|
252
267
|
if (existsSync5(cssPath2)) {
|
|
253
268
|
levels.push(report("pass", `Tailwind CSS file found at ${path5.relative(cwd, cssPath2)}`));
|
|
@@ -381,7 +396,12 @@ async function inspect(name, options) {
|
|
|
381
396
|
console.log();
|
|
382
397
|
console.log(`${pc4.dim("Type")} ${item.type}`);
|
|
383
398
|
const cwd = process.cwd();
|
|
384
|
-
|
|
399
|
+
let config = null;
|
|
400
|
+
try {
|
|
401
|
+
config = await readConfig(cwd);
|
|
402
|
+
} catch {
|
|
403
|
+
console.log(`${pc4.dim("Installed")} ${pc4.yellow("? (kinetixui.json exists but isn't valid JSON)")}`);
|
|
404
|
+
}
|
|
385
405
|
if (config) {
|
|
386
406
|
const uiDir = resolveAliasDir(cwd, config, "ui");
|
|
387
407
|
const installed = item.files.some(
|
|
@@ -412,24 +432,191 @@ async function inspect(name, options) {
|
|
|
412
432
|
console.log(`Add it: ${pc4.cyan(`npx @kinetixui/cli add ${item.name}`)}`);
|
|
413
433
|
}
|
|
414
434
|
|
|
415
|
-
// src/commands/
|
|
435
|
+
// src/commands/lint.ts
|
|
436
|
+
import { existsSync as existsSync8 } from "fs";
|
|
437
|
+
import { readdir as readdir2, readFile as readFile2 } from "fs/promises";
|
|
438
|
+
import path8 from "path";
|
|
416
439
|
import pc5 from "picocolors";
|
|
440
|
+
|
|
441
|
+
// src/lib/lint.ts
|
|
442
|
+
function stripComments(text) {
|
|
443
|
+
const noBlocks = text.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
|
|
444
|
+
return noBlocks.replace(/(^|[^:])\/\/.*$/gm, (_m, pre) => pre);
|
|
445
|
+
}
|
|
446
|
+
var HEX = "(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})";
|
|
447
|
+
var COLOR_UTILITY_PREFIXES = [
|
|
448
|
+
"bg",
|
|
449
|
+
"text",
|
|
450
|
+
"border",
|
|
451
|
+
"fill",
|
|
452
|
+
"stroke",
|
|
453
|
+
"ring",
|
|
454
|
+
"from",
|
|
455
|
+
"via",
|
|
456
|
+
"to",
|
|
457
|
+
"outline",
|
|
458
|
+
"decoration",
|
|
459
|
+
"caret",
|
|
460
|
+
"accent",
|
|
461
|
+
"shadow",
|
|
462
|
+
"divide"
|
|
463
|
+
];
|
|
464
|
+
var COLOR_PATTERNS = [
|
|
465
|
+
// bg-[#1a2b3c], text-[#fff], ring-[#1a2b3c80] …
|
|
466
|
+
new RegExp(`\\b(?:${COLOR_UTILITY_PREFIXES.join("|")})-\\[#${HEX}\\]`, "g"),
|
|
467
|
+
// style={{ color: "#1a2b3c" }} / a plain CSS declaration `color: #1a2b3c;`
|
|
468
|
+
new RegExp(`:\\s*["']?#${HEX}["']?`, "g")
|
|
469
|
+
];
|
|
470
|
+
var SPACING_UTILITY_PATTERN = "-?(?:(?:p|m)[trblxy]?|gap(?:-[xy])?|space-[xy]|inset(?:-[xy])?|top|right|bottom|left)";
|
|
471
|
+
var SPACING_VALUE = "-?[\\d.]+(?:px|rem|em|%)?";
|
|
472
|
+
var SPACING_PATTERNS = [
|
|
473
|
+
new RegExp(`\\b(?:${SPACING_UTILITY_PATTERN})-\\[${SPACING_VALUE}\\]`, "g")
|
|
474
|
+
];
|
|
475
|
+
function lineOf(text, index) {
|
|
476
|
+
let line = 1;
|
|
477
|
+
for (let i = 0; i < index; i++) if (text.charCodeAt(i) === 10) line++;
|
|
478
|
+
return line;
|
|
479
|
+
}
|
|
480
|
+
function snippetAround(text, index, length) {
|
|
481
|
+
const lineStart = text.lastIndexOf("\n", index) + 1;
|
|
482
|
+
let lineEnd = text.indexOf("\n", index);
|
|
483
|
+
if (lineEnd === -1) lineEnd = text.length;
|
|
484
|
+
return text.slice(lineStart, lineEnd).trim().slice(0, 120) || text.slice(index, index + length);
|
|
485
|
+
}
|
|
486
|
+
function lintText(file, rawText) {
|
|
487
|
+
const text = stripComments(rawText);
|
|
488
|
+
const violations = [];
|
|
489
|
+
const seen = /* @__PURE__ */ new Set();
|
|
490
|
+
const scan = (patterns, kind) => {
|
|
491
|
+
for (const pattern of patterns) {
|
|
492
|
+
pattern.lastIndex = 0;
|
|
493
|
+
let match;
|
|
494
|
+
while (match = pattern.exec(text)) {
|
|
495
|
+
const line = lineOf(text, match.index);
|
|
496
|
+
const key = `${kind}:${line}:${match.index}`;
|
|
497
|
+
if (!seen.has(key)) {
|
|
498
|
+
seen.add(key);
|
|
499
|
+
violations.push({ file, line, kind, snippet: snippetAround(text, match.index, match[0].length) });
|
|
500
|
+
}
|
|
501
|
+
if (match[0].length === 0) pattern.lastIndex++;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
scan(COLOR_PATTERNS, "color");
|
|
506
|
+
scan(SPACING_PATTERNS, "spacing");
|
|
507
|
+
violations.sort((a, b) => a.line - b.line);
|
|
508
|
+
return violations;
|
|
509
|
+
}
|
|
510
|
+
var LINT_EXTENSIONS = [".tsx", ".jsx", ".ts", ".js", ".css"];
|
|
511
|
+
|
|
512
|
+
// src/commands/lint.ts
|
|
513
|
+
var SUGGESTION = {
|
|
514
|
+
color: "consider a semantic token utility instead (e.g. bg-primary, text-foreground)",
|
|
515
|
+
spacing: "consider a token-backed spacing utility instead (e.g. p-4, gap-2)"
|
|
516
|
+
};
|
|
517
|
+
function dedupeNestedDirs(dirs) {
|
|
518
|
+
const sorted = [...new Set(dirs)].sort((a, b) => a.length - b.length);
|
|
519
|
+
const kept = [];
|
|
520
|
+
for (const dir of sorted) {
|
|
521
|
+
if (!kept.some((k) => dir === k || dir.startsWith(k + path8.sep))) kept.push(dir);
|
|
522
|
+
}
|
|
523
|
+
return kept;
|
|
524
|
+
}
|
|
525
|
+
async function collectFiles(dir) {
|
|
526
|
+
if (!existsSync8(dir)) return [];
|
|
527
|
+
const files = [];
|
|
528
|
+
const walk = async (current) => {
|
|
529
|
+
const entries = await readdir2(current, { withFileTypes: true });
|
|
530
|
+
for (const entry of entries) {
|
|
531
|
+
const full = path8.join(current, entry.name);
|
|
532
|
+
if (entry.isDirectory()) {
|
|
533
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
534
|
+
await walk(full);
|
|
535
|
+
} else if (entry.isFile() && LINT_EXTENSIONS.includes(path8.extname(entry.name))) {
|
|
536
|
+
files.push(full);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
await walk(dir);
|
|
541
|
+
return files;
|
|
542
|
+
}
|
|
543
|
+
async function lint(targetArg, options) {
|
|
544
|
+
const cwd = process.cwd();
|
|
545
|
+
let dirs;
|
|
546
|
+
if (targetArg) {
|
|
547
|
+
dirs = [path8.resolve(cwd, targetArg)];
|
|
548
|
+
} else {
|
|
549
|
+
if (!existsSync8(path8.join(cwd, CONFIG_FILE))) {
|
|
550
|
+
throw new Error(`No ${CONFIG_FILE} found \u2014 run "kinetixui init" first, or pass a path: kinetixui lint <path>`);
|
|
551
|
+
}
|
|
552
|
+
const config = await readConfig(cwd);
|
|
553
|
+
if (!config) throw new Error(`${CONFIG_FILE} exists but isn't valid JSON.`);
|
|
554
|
+
dirs = dedupeNestedDirs([resolveAliasDir(cwd, config, "components"), resolveAliasDir(cwd, config, "ui")]);
|
|
555
|
+
}
|
|
556
|
+
const seenFiles = /* @__PURE__ */ new Set();
|
|
557
|
+
const files = [];
|
|
558
|
+
for (const dir of dirs) {
|
|
559
|
+
for (const file of await collectFiles(dir)) {
|
|
560
|
+
if (!seenFiles.has(file)) {
|
|
561
|
+
seenFiles.add(file);
|
|
562
|
+
files.push(file);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (files.length === 0) {
|
|
567
|
+
console.log(pc5.dim(`No ${LINT_EXTENSIONS.join("/")} files found in ${dirs.map((d) => path8.relative(cwd, d) || ".").join(", ")}.`));
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
let totalViolations = 0;
|
|
571
|
+
let filesWithViolations = 0;
|
|
572
|
+
for (const file of files) {
|
|
573
|
+
const text = await readFile2(file, "utf8");
|
|
574
|
+
const violations = lintText(file, text);
|
|
575
|
+
if (violations.length === 0) continue;
|
|
576
|
+
filesWithViolations++;
|
|
577
|
+
const rel = path8.relative(cwd, file);
|
|
578
|
+
for (const v of violations) {
|
|
579
|
+
totalViolations++;
|
|
580
|
+
console.log(
|
|
581
|
+
`${pc5.yellow("!")} ${pc5.bold(`${rel}:${v.line}`)} \u2014 hardcoded ${v.kind}: ${pc5.dim(v.snippet)}`
|
|
582
|
+
);
|
|
583
|
+
console.log(` ${pc5.dim(SUGGESTION[v.kind])}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
console.log();
|
|
587
|
+
if (totalViolations === 0) {
|
|
588
|
+
console.log(pc5.green("\u2714"), `${files.length} file${files.length === 1 ? "" : "s"} scanned, no hardcoded colors or spacing found.`);
|
|
589
|
+
} else {
|
|
590
|
+
console.log(
|
|
591
|
+
`${totalViolations} violation${totalViolations === 1 ? "" : "s"} in ${filesWithViolations} of ${files.length} file${files.length === 1 ? "" : "s"} scanned.`
|
|
592
|
+
);
|
|
593
|
+
console.log(
|
|
594
|
+
pc5.dim(
|
|
595
|
+
"Checks unknown/deprecated tokens, accessibility violations and cross-platform inconsistencies aren't covered yet \u2014 see https://kinetixui.com/docs/cli#lint."
|
|
596
|
+
)
|
|
597
|
+
);
|
|
598
|
+
if (options.fail) process.exitCode = 1;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/commands/list.ts
|
|
603
|
+
import pc6 from "picocolors";
|
|
417
604
|
async function list(options) {
|
|
418
605
|
const items = await fetchRegistryIndex(options.registry);
|
|
419
606
|
const components = items.filter((item) => item.type === "registry:ui").sort((a, b) => a.name.localeCompare(b.name));
|
|
420
607
|
console.log(`${components.length} component(s):`);
|
|
421
608
|
console.log();
|
|
422
609
|
for (const item of components) {
|
|
423
|
-
const description = item.description ?
|
|
424
|
-
console.log(` ${
|
|
610
|
+
const description = item.description ? pc6.dim(` \u2014 ${item.description}`) : "";
|
|
611
|
+
console.log(` ${pc6.cyan(item.name)}${description}`);
|
|
425
612
|
}
|
|
426
613
|
console.log();
|
|
427
|
-
console.log(`Add one: ${
|
|
428
|
-
console.log(`Add everything: ${
|
|
614
|
+
console.log(`Add one: ${pc6.cyan("npx @kinetixui/cli add <name>")}`);
|
|
615
|
+
console.log(`Add everything: ${pc6.cyan("npx @kinetixui/cli add --all")}`);
|
|
429
616
|
}
|
|
430
617
|
|
|
431
618
|
// src/commands/parity.ts
|
|
432
|
-
import
|
|
619
|
+
import pc7 from "picocolors";
|
|
433
620
|
var PLATFORMS = ["React", "SwiftUI", "Compose", "Flutter"];
|
|
434
621
|
var PLATFORM_ABBR = {
|
|
435
622
|
React: "RE",
|
|
@@ -447,11 +634,11 @@ async function parity(names, options) {
|
|
|
447
634
|
}) : components;
|
|
448
635
|
const nameWidth = Math.max(9, ...rows.map((r) => r.name.length));
|
|
449
636
|
const header = `${"COMPONENT".padEnd(nameWidth)} ${PLATFORMS.map((p) => PLATFORM_ABBR[p]).join(" ")} STATUS`;
|
|
450
|
-
console.log(
|
|
637
|
+
console.log(pc7.dim(header));
|
|
451
638
|
for (const item of rows) {
|
|
452
639
|
const on = new Set(item.platforms ?? PLATFORMS);
|
|
453
|
-
const marks = PLATFORMS.map((p) => on.has(p) ?
|
|
454
|
-
const status = item.status ?
|
|
640
|
+
const marks = PLATFORMS.map((p) => on.has(p) ? pc7.green("\u2713 ") : pc7.dim("\u2014 "));
|
|
641
|
+
const status = item.status ? pc7.yellow(item.status) : "";
|
|
455
642
|
console.log(`${item.name.padEnd(nameWidth)} ${marks.join(" ")} ${status}`);
|
|
456
643
|
}
|
|
457
644
|
console.log();
|
|
@@ -459,10 +646,10 @@ async function parity(names, options) {
|
|
|
459
646
|
}
|
|
460
647
|
|
|
461
648
|
// src/commands/theme.ts
|
|
462
|
-
import { existsSync as
|
|
463
|
-
import { mkdir as mkdir2, readFile as
|
|
464
|
-
import
|
|
465
|
-
import
|
|
649
|
+
import { existsSync as existsSync9 } from "fs";
|
|
650
|
+
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
651
|
+
import path9 from "path";
|
|
652
|
+
import pc8 from "picocolors";
|
|
466
653
|
|
|
467
654
|
// src/lib/color-math.ts
|
|
468
655
|
function hexToRgb(hex) {
|
|
@@ -652,57 +839,59 @@ function scaffoldThemeFile(name) {
|
|
|
652
839
|
// src/commands/theme.ts
|
|
653
840
|
var THEME_DIR = "kinetixui-themes";
|
|
654
841
|
function csvPath(cwd, name) {
|
|
655
|
-
return
|
|
842
|
+
return path9.join(cwd, THEME_DIR, `${name}.csv`);
|
|
656
843
|
}
|
|
657
844
|
function cssPath(cwd, name) {
|
|
658
|
-
return
|
|
845
|
+
return path9.join(cwd, THEME_DIR, `${name}.css`);
|
|
659
846
|
}
|
|
660
847
|
async function themeCreate(name, options) {
|
|
848
|
+
assertThemeName(name);
|
|
661
849
|
const cwd = process.cwd();
|
|
662
850
|
const file = csvPath(cwd, name);
|
|
663
|
-
if (
|
|
664
|
-
throw new Error(`${
|
|
851
|
+
if (existsSync9(file) && !options.force) {
|
|
852
|
+
throw new Error(`${path9.relative(cwd, file)} already exists. Pass --force to overwrite it.`);
|
|
665
853
|
}
|
|
666
|
-
await mkdir2(
|
|
854
|
+
await mkdir2(path9.dirname(file), { recursive: true });
|
|
667
855
|
await writeFile3(file, scaffoldThemeFile(name), "utf8");
|
|
668
|
-
console.log(
|
|
856
|
+
console.log(pc8.green("\u2714"), `Wrote ${path9.relative(cwd, file)}`);
|
|
669
857
|
console.log(`Uncomment and edit the tokens you want to override, then run:`);
|
|
670
|
-
console.log(
|
|
858
|
+
console.log(pc8.dim(` kinetixui theme build ${name}`));
|
|
671
859
|
}
|
|
672
860
|
async function themeBuild(name, options) {
|
|
861
|
+
assertThemeName(name);
|
|
673
862
|
const cwd = process.cwd();
|
|
674
863
|
const src = csvPath(cwd, name);
|
|
675
|
-
if (!
|
|
676
|
-
throw new Error(`${
|
|
864
|
+
if (!existsSync9(src)) {
|
|
865
|
+
throw new Error(`${path9.relative(cwd, src)} doesn't exist. Run "kinetixui theme create ${name}" first.`);
|
|
677
866
|
}
|
|
678
|
-
const text = await
|
|
867
|
+
const text = await readFile3(src, "utf8");
|
|
679
868
|
const { values: parsed, errors, unknownTokens } = parseThemeFile(text);
|
|
680
|
-
for (const err of errors) console.log(
|
|
681
|
-
for (const unknown of unknownTokens) console.log(
|
|
869
|
+
for (const err of errors) console.log(pc8.yellow("!"), err);
|
|
870
|
+
for (const unknown of unknownTokens) console.log(pc8.yellow("!"), `"${unknown}" isn't a known token \u2014 skipped.`);
|
|
682
871
|
const values = deriveForegrounds(parsed);
|
|
683
872
|
const setCount = Object.keys(values).length;
|
|
684
873
|
if (setCount === 0) {
|
|
685
|
-
throw new Error(`No tokens set in ${
|
|
874
|
+
throw new Error(`No tokens set in ${path9.relative(cwd, src)} \u2014 nothing to build. Uncomment at least one line.`);
|
|
686
875
|
}
|
|
687
876
|
const dest = cssPath(cwd, name);
|
|
688
877
|
await writeFile3(dest, toCssBlock(values), "utf8");
|
|
689
|
-
console.log(
|
|
690
|
-
console.log(`Paste it after ${
|
|
878
|
+
console.log(pc8.green("\u2714"), `Wrote ${path9.relative(cwd, dest)} (${setCount} token${setCount === 1 ? "" : "s"})`);
|
|
879
|
+
console.log(`Paste it after ${pc8.dim('@import "@kinetixui/tokens/css";')} in your global CSS.`);
|
|
691
880
|
console.log();
|
|
692
|
-
console.log(
|
|
881
|
+
console.log(pc8.dim("WCAG AA contrast (4.5:1)"));
|
|
693
882
|
const results = checkContrast(values);
|
|
694
883
|
let failed = 0;
|
|
695
884
|
for (const { pair, ratio, pass } of results) {
|
|
696
|
-
const mark = pass ?
|
|
885
|
+
const mark = pass ? pc8.green("\u2714") : pc8.red("\u2716");
|
|
697
886
|
if (!pass) failed++;
|
|
698
|
-
console.log(`${mark} ${pair[0]} / ${pair[1]}`,
|
|
887
|
+
console.log(`${mark} ${pair[0]} / ${pair[1]}`, pc8.dim(`${ratio.toFixed(2)}:1`));
|
|
699
888
|
}
|
|
700
889
|
if (results.length === 0) {
|
|
701
|
-
console.log(
|
|
890
|
+
console.log(pc8.dim("(no checkable pairs \u2014 set at least one base + foreground, or just a base to auto-derive one)"));
|
|
702
891
|
}
|
|
703
892
|
console.log();
|
|
704
893
|
console.log("Native (SwiftUI/Compose/Flutter) theme output isn't built yet \u2014 this compiles to CSS only.");
|
|
705
|
-
console.log(
|
|
894
|
+
console.log(pc8.dim("See https://kinetixui.com/docs/cli#theme for the current scope."));
|
|
706
895
|
if (failed > 0 && options.failOnContrast) {
|
|
707
896
|
process.exitCode = 1;
|
|
708
897
|
}
|
|
@@ -711,7 +900,7 @@ async function themeBuild(name, options) {
|
|
|
711
900
|
// package.json
|
|
712
901
|
var package_default = {
|
|
713
902
|
name: "@kinetixui/cli",
|
|
714
|
-
version: "0.
|
|
903
|
+
version: "0.16.1",
|
|
715
904
|
description: "Add KinetixUI components and tokens to your project.",
|
|
716
905
|
type: "module",
|
|
717
906
|
license: "MIT",
|
|
@@ -755,7 +944,7 @@ program.command("init").description("Set up kinetixui.json and pull in the token
|
|
|
755
944
|
try {
|
|
756
945
|
await init({ registry: opts.registry, yes: opts.yes });
|
|
757
946
|
} catch (err) {
|
|
758
|
-
console.error(
|
|
947
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
759
948
|
process.exitCode = 1;
|
|
760
949
|
}
|
|
761
950
|
});
|
|
@@ -763,7 +952,7 @@ program.command("add").description("Add one or more components to your project."
|
|
|
763
952
|
try {
|
|
764
953
|
await add(components, { registry: opts.registry, overwrite: opts.overwrite, all: opts.all });
|
|
765
954
|
} catch (err) {
|
|
766
|
-
console.error(
|
|
955
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
767
956
|
process.exitCode = 1;
|
|
768
957
|
}
|
|
769
958
|
});
|
|
@@ -771,7 +960,7 @@ program.command("list").description("List every component available in the regis
|
|
|
771
960
|
try {
|
|
772
961
|
await list({ registry: opts.registry });
|
|
773
962
|
} catch (err) {
|
|
774
|
-
console.error(
|
|
963
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
775
964
|
process.exitCode = 1;
|
|
776
965
|
}
|
|
777
966
|
});
|
|
@@ -779,7 +968,7 @@ program.command("inspect").description("Show everything the registry knows about
|
|
|
779
968
|
try {
|
|
780
969
|
await inspect(name, { registry: opts.registry });
|
|
781
970
|
} catch (err) {
|
|
782
|
-
console.error(
|
|
971
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
783
972
|
process.exitCode = 1;
|
|
784
973
|
}
|
|
785
974
|
});
|
|
@@ -787,7 +976,15 @@ program.command("parity").description("Show which platforms carry each component
|
|
|
787
976
|
try {
|
|
788
977
|
await parity(components, { registry: opts.registry });
|
|
789
978
|
} catch (err) {
|
|
790
|
-
console.error(
|
|
979
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
980
|
+
process.exitCode = 1;
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
program.command("lint").description("Scan for hardcoded colors and spacing that should be semantic tokens.").argument("[path]", "directory to scan \u2014 defaults to the components/ui aliases from kinetixui.json").option("--no-fail", "exit 0 even if violations are found").action(async (target, opts) => {
|
|
984
|
+
try {
|
|
985
|
+
await lint(target, { fail: opts.fail });
|
|
986
|
+
} catch (err) {
|
|
987
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
791
988
|
process.exitCode = 1;
|
|
792
989
|
}
|
|
793
990
|
});
|
|
@@ -795,7 +992,7 @@ program.command("doctor").description("Check kinetixui.json, its aliases, and th
|
|
|
795
992
|
try {
|
|
796
993
|
await doctor();
|
|
797
994
|
} catch (err) {
|
|
798
|
-
console.error(
|
|
995
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
799
996
|
process.exitCode = 1;
|
|
800
997
|
}
|
|
801
998
|
});
|
|
@@ -804,7 +1001,7 @@ theme.command("create").description("Scaffold kinetixui-themes/<name>.csv with e
|
|
|
804
1001
|
try {
|
|
805
1002
|
await themeCreate(name, { force: opts.force });
|
|
806
1003
|
} catch (err) {
|
|
807
|
-
console.error(
|
|
1004
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
808
1005
|
process.exitCode = 1;
|
|
809
1006
|
}
|
|
810
1007
|
});
|
|
@@ -812,7 +1009,7 @@ theme.command("build").description("Compile kinetixui-themes/<name>.csv to CSS a
|
|
|
812
1009
|
try {
|
|
813
1010
|
await themeBuild(name, { failOnContrast: opts.failOnContrast });
|
|
814
1011
|
} catch (err) {
|
|
815
|
-
console.error(
|
|
1012
|
+
console.error(pc9.red("\u2716"), err.message);
|
|
816
1013
|
process.exitCode = 1;
|
|
817
1014
|
}
|
|
818
1015
|
});
|