onsystem 0.11.1 → 0.12.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/cli.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { $ as DEFAULT_TOKENS, A as unrecordedRules, At as relativePath, B as statusKinds, C as countBaseline, D as pruneBaseline, Dt as isInside, E as onLines, Et as SCRIPT_FILE, It as unique, J as ConfigError, L as toDesignMd, M as writeBaseline, O as readBaseline, Ot as matchesGlob, Pt as plural, R as toDtcg, Rt as readProjectConfig, S as applyBaseline, St as isDesignSystemName, T as goneFiles, Y as DEFAULT_DOCS, _ as formatDiagnostics, _t as PACKAGE_FIELD, b as BASELINE_FILE, bt as detectProject, c as silentLogger, et as FALLBACK_TOKENS, g as escapeData, gt as notReadYet, h as uncheckedNotice, ht as libraryTitle, i as componentFiles, j as updateBaseline, jt as toPosix, k as rulesRun, l as stderrLogger, o as loadDesignSystem, ot as excludedBy, q as CONFIG_FILES, rt as RULE_IDS, s as tokenFiles, tt as LEGACY_CONFIG_FILES, ut as rulesFor, v as NAME, w as findMoves, x as LEGACY_BASELINE_FILE, y as VERSION, yt as declaredConfig } from "./design-system-D7ppJYbd.js";
3
- import { a as notReadNotices, i as missingDependencies, o as explainProject, s as librariesLeftOut, t as serveStdio } from "./stdio-c3Y34to3.js";
4
- import { r as loadTarget } from "./workspace-DUgzMLGs.js";
2
+ import { $ as DEFAULT_TOKENS, A as unrecordedRules, At as relativePath, B as statusKinds, C as countBaseline, D as pruneBaseline, Dt as isInside, E as onLines, Et as SCRIPT_FILE, It as unique, J as ConfigError, L as toDesignMd, M as writeBaseline, O as readBaseline, Ot as matchesGlob, Pt as plural, R as toDtcg, Rt as readProjectConfig, S as applyBaseline, St as isDesignSystemName, T as goneFiles, Y as DEFAULT_DOCS, _ as formatDiagnostics, _t as PACKAGE_FIELD, b as BASELINE_FILE, bt as detectProject, c as silentLogger, et as FALLBACK_TOKENS, g as escapeData, gt as notReadYet, h as uncheckedNotice, ht as libraryTitle, i as componentFiles, j as updateBaseline, jt as toPosix, k as rulesRun, l as stderrLogger, o as loadDesignSystem, ot as excludedBy, q as CONFIG_FILES, rt as RULE_IDS, s as tokenFiles, st as hasOwnConfig, tt as LEGACY_CONFIG_FILES, ut as rulesFor, v as NAME, w as findMoves, x as LEGACY_BASELINE_FILE, y as VERSION, yt as declaredConfig } from "./design-system-jpX0zFNy.js";
3
+ import { a as notReadNotices, i as missingDependencies, o as explainProject, s as librariesLeftOut, t as serveStdio } from "./stdio-DKayvYuq.js";
4
+ import { a as samePath, n as hasProjectMarker, r as loadTarget } from "./workspace-DH5RWgR2.js";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import { escapePath, glob } from "tinyglobby";
8
8
  import ts from "typescript";
9
+ import os from "node:os";
9
10
  import fsp from "node:fs/promises";
10
11
  import { spawnSync } from "node:child_process";
11
12
  import readline from "node:readline/promises";
@@ -192,7 +193,8 @@ async function init(configOptions, options, io, runCheck) {
192
193
  "--update-baseline",
193
194
  ...options.cache ? [] : ["--no-cache"]
194
195
  ], checkIo);
195
- if (recorded.stdout) io.stdout(recorded.stdout);
196
+ const shown = relativePath(io.cwd, path.join(root, "onsystem.baseline.json")) || "onsystem.baseline.json";
197
+ if (recorded.stdout) io.stdout(recorded.stdout.replace(` → ${BASELINE_FILE}`, ` → ${shown}`));
196
198
  baselineWritten = fs.existsSync(path.join(root, BASELINE_FILE));
197
199
  } else io.stdout(`No baseline written; \`${NAME} check . --update-baseline\` records one later.`);
198
200
  }
@@ -723,19 +725,24 @@ project: each file is checked against the design system of the nearest folder
723
725
  with a config, components.json or package.json, and inspect lists every project.
724
726
 
725
727
  Options
726
- --root <dir> Project root (default: the config file's directory, or cwd)
727
- --config <file> Config file (default: onsystem.config.{json,ts,mjs,js})
728
+ --root <dir> Project root (default: the config file's directory, or
729
+ cwd; from a folder with no config, components.json,
730
+ package.json or project.json, the nearest folder above
731
+ it with one)
732
+ --config <file> Config file (default: onsystem.config.{json,ts,mts,js,mjs})
728
733
  --components <glob> Component sources, repeatable (default: found through
729
734
  components.json or a workspace package, else
730
735
  components/ui/**/*.{tsx,jsx} and src/components/ui/...)
731
- --tokens <file> Token file (DTCG .json or CSS), repeatable
736
+ --tokens <file> Token file (DTCG .json, CSS or DESIGN.md), repeatable
732
737
  --docs <glob> Component docs (Markdown/MDX), repeatable
733
738
  --no-cache Ignore the on-disk extraction cache
734
739
  --no-watch serve: do not reload when files change
735
740
  --format <format> check: pretty | json | github | sarif (default: pretty);
741
+ inspect: pretty | json (default: pretty);
736
742
  export: dtcg | design-md
737
743
  --out <file> export: write to this file instead of stdout
738
744
  --max-warnings <n> check: exit 1 when there are more than n warnings
745
+ (--max-warnings=-1: no limit)
739
746
  --update-baseline check: record the current findings as accepted, and exit 0
740
747
  --prune-baseline check: drop baseline entries that no longer occur, and
741
748
  accept nothing new
@@ -803,6 +810,7 @@ async function main(argv, io = defaultIo) {
803
810
  args: argv,
804
811
  allowPositionals: true,
805
812
  allowNegative: true,
813
+ tokens: true,
806
814
  options: {
807
815
  root: { type: "string" },
808
816
  config: { type: "string" },
@@ -886,7 +894,7 @@ async function main(argv, io = defaultIo) {
886
894
  io.stderr(`${error.message}\n\nRun ${NAME} --help for usage.`);
887
895
  return 2;
888
896
  }
889
- const { values, positionals } = parsed;
897
+ const { values, positionals, tokens } = parsed;
890
898
  if (values.help) {
891
899
  io.stdout(HELP);
892
900
  return 0;
@@ -900,11 +908,34 @@ async function main(argv, io = defaultIo) {
900
908
  io.stdout(HELP);
901
909
  return 0;
902
910
  }
911
+ const ignored = /* @__PURE__ */ new Set();
912
+ for (const token of tokens) {
913
+ if (token.kind !== "option") continue;
914
+ const commands = COMMAND_OPTIONS[token.name];
915
+ if (!commands || !isCommand(command) || commands.includes(command)) continue;
916
+ const owners = listOf(commands, commands.length);
917
+ if (command !== "serve") {
918
+ io.stderr(`${command}: ${token.rawName} is an option of ${owners} only. Run ${NAME} --help for usage.`);
919
+ return 2;
920
+ }
921
+ if (!ignored.has(token.rawName)) {
922
+ ignored.add(token.rawName);
923
+ io.stderr(`serve: ${token.rawName} is an option of ${owners} only, so it is ignored.`);
924
+ }
925
+ }
903
926
  let root = values.root;
904
927
  if (root !== void 0 && /\$\{[^}]*\}/.test(root)) {
905
928
  io.stderr(`--root "${root}" holds a variable the client did not expand; using the working directory instead${command === "serve" ? ", or the client's roots when it holds no project" : ""}.`);
906
929
  root = void 0;
907
930
  }
931
+ const given = [
932
+ values.config,
933
+ values.components,
934
+ values.tokens,
935
+ values.docs
936
+ ];
937
+ let walkedUp;
938
+ if (root === void 0 && command !== "serve" && given.every((v) => v === void 0)) root = walkedUp = enclosingProject(io.cwd);
908
939
  const configOptions = {
909
940
  cwd: io.cwd,
910
941
  root,
@@ -926,7 +957,7 @@ async function main(argv, io = defaultIo) {
926
957
  ...io.transport ? { transport: io.transport } : {}
927
958
  });
928
959
  return 0;
929
- case "check": return await check(rest, configOptions, values, io);
960
+ case "check": return await check(rest, configOptions, values, io, walkedUp);
930
961
  case "inspect": return await inspect(configOptions, values, io);
931
962
  case "export": return await exportTokens(configOptions, values, io);
932
963
  case "init": return await init(configOptions, {
@@ -956,11 +987,79 @@ async function main(argv, io = defaultIo) {
956
987
  io.stderr(error.message);
957
988
  return 2;
958
989
  }
990
+ if (command === "init" && error.name === "AbortError") {
991
+ io.stderr("\ninit: cancelled; nothing after that question was done.");
992
+ return 130;
993
+ }
959
994
  io.stderr(error.stack ?? String(error));
960
995
  return 2;
961
996
  }
962
997
  }
963
- async function check(patterns, configOptions, values, io) {
998
+ const COMMANDS = [
999
+ "serve",
1000
+ "check",
1001
+ "inspect",
1002
+ "export",
1003
+ "init"
1004
+ ];
1005
+ function isCommand(name) {
1006
+ return COMMANDS.includes(name);
1007
+ }
1008
+ /**
1009
+ * The options that `--help` gives to some commands only (`check:` in its text), by parser name.
1010
+ * The others apply to every command. test/cli-docs.test.ts holds the two together.
1011
+ */
1012
+ const COMMAND_OPTIONS = {
1013
+ watch: ["serve"],
1014
+ format: [
1015
+ "check",
1016
+ "inspect",
1017
+ "export"
1018
+ ],
1019
+ out: ["export"],
1020
+ "max-warnings": ["check"],
1021
+ "update-baseline": ["check"],
1022
+ "prune-baseline": ["check"],
1023
+ baseline: ["check"],
1024
+ "ignore-baseline": ["check"],
1025
+ "include-design-system": ["check"],
1026
+ "include-tests": ["check"],
1027
+ "skip-excluded": ["check"],
1028
+ "quiet-without-design-system": ["check"],
1029
+ "require-design-system": ["check"],
1030
+ explain: ["inspect"],
1031
+ yes: ["init"],
1032
+ force: ["init"]
1033
+ };
1034
+ /**
1035
+ * The project around `cwd` when `cwd` is none: the nearest folder above it with a config, a
1036
+ * components.json, a package.json or a project.json, relative to `cwd` (`../..`), as a command
1037
+ * that names it with `--root` would. Undefined when `cwd` has one of those or a baseline (a run
1038
+ * from there recorded it), when `cwd` is the home folder, or when no folder up to the home folder
1039
+ * or the filesystem root, neither of which counts, has one. Undefined, too, when `cwd` has a
1040
+ * folder zero config reads components from (a design system with no package.json) and the
1041
+ * project above would not read it: `cwd` is not the project's `src` or `app` folder, which hold
1042
+ * its own code, and the project has no components.json or config to say where its components are.
1043
+ */
1044
+ function enclosingProject(cwd) {
1045
+ const has = (dir, name) => fs.existsSync(path.join(dir, name));
1046
+ if (hasProjectMarker(cwd) || ["onsystem.baseline.json", "design-system-mcp.baseline.json"].some((f) => has(cwd, f))) return;
1047
+ const home = os.homedir();
1048
+ const never = (dir) => samePath(dir, home) || dir === path.dirname(dir);
1049
+ if (samePath(cwd, home)) return void 0;
1050
+ let above = path.dirname(cwd);
1051
+ while (!never(above) && !hasProjectMarker(above)) above = path.dirname(above);
1052
+ if (never(above)) return void 0;
1053
+ const ownComponents = ["components/ui", "src/components/ui"].some((f) => has(cwd, f));
1054
+ const readAbove = ["src", "app"].some((name) => samePath(cwd, path.join(above, name))) || has(above, "components.json") || hasOwnConfig(above);
1055
+ if (ownComponents && !readAbove) return void 0;
1056
+ return path.relative(cwd, above);
1057
+ }
1058
+ /**
1059
+ * `walkedUp`: the root, relative to the working directory, when the run took the project around
1060
+ * the working directory as its root (`enclosingProject`).
1061
+ */
1062
+ async function check(patterns, configOptions, values, io, walkedUp) {
964
1063
  if (values["quiet-without-design-system"] && values["require-design-system"]) {
965
1064
  io.stderr("check: pass --quiet-without-design-system or --require-design-system, not both");
966
1065
  return 2;
@@ -983,15 +1082,22 @@ async function check(patterns, configOptions, values, io) {
983
1082
  io.stderr(`check: unknown --format "${format}" (pretty, json, github, sarif)`);
984
1083
  return 2;
985
1084
  }
986
- const maxWarnings = values["max-warnings"] === void 0 ? void 0 : Number(values["max-warnings"]);
987
- if (maxWarnings !== void 0 && !Number.isInteger(maxWarnings)) {
988
- io.stderr("check: --max-warnings expects an integer");
1085
+ const given = values["max-warnings"];
1086
+ if (given !== void 0 && !/^-?\d+$/.test(given)) {
1087
+ io.stderr(`check: --max-warnings expects a whole number (--max-warnings=-1 for no limit), not "${given}"`);
989
1088
  return 2;
990
1089
  }
1090
+ const maxWarnings = given === void 0 || Number(given) < 0 ? void 0 : Number(given);
1091
+ const where = walkedUp === void 0 ? void 0 : toPosix(walkedUp);
1092
+ if (where !== void 0 && !values["quiet-without-design-system"]) {
1093
+ const text = `Checking the project in ${where}`;
1094
+ if (format === "pretty") io.stdout(text);
1095
+ else io.stderr(text);
1096
+ }
991
1097
  const target = await loadTarget(configOptions);
992
1098
  warnDeprecated(target.config.deprecations, format, io);
993
1099
  warnDeprecated(configWarnings(target), format, io);
994
- const selection = target.workspace ? await selectInWorkspace(target.workspace, patterns, values, format, io) : await selectInProject(target.config, patterns, values, format, io);
1100
+ const selection = target.workspace ? await selectInWorkspace(target.workspace, patterns, values, format, io) : await selectInProject(target.config, patterns, values, format, io, where);
995
1101
  if (typeof selection === "number") return selection;
996
1102
  const command = (flag) => checkCommand(patterns, configOptions, values, flag);
997
1103
  if ("noMatch" in selection) {
@@ -1302,8 +1408,11 @@ function jsxNotice(selection, cwd, command) {
1302
1408
  const check = command(selection.jsxGlobs.map(shellQuote).join(" "));
1303
1409
  return files.length === 1 ? `${files[0] ?? ""} has JSX, but folders are checked for .tsx and .jsx files, so it was not checked. Name it to check it: \`${check}\`.` : `${files.length.toLocaleString("en-US")} .js files have JSX (${listOf(files)}), but folders are checked for .tsx and .jsx files, so they were not checked. Name them to check them: \`${check}\`.`;
1304
1410
  }
1305
- /** One project: the root's config and design system for every file. */
1306
- async function selectInProject(config, patterns, values, format, io) {
1411
+ /**
1412
+ * One project: the root's config and design system for every file. `where`: the root as the
1413
+ * notices name it, when the run is not from there.
1414
+ */
1415
+ async function selectInProject(config, patterns, values, format, io, where) {
1307
1416
  const ds = await loadDesignSystem(config, {
1308
1417
  cache: values.cache,
1309
1418
  logger: silentLogger
@@ -1344,7 +1453,7 @@ async function selectInProject(config, patterns, values, format, io) {
1344
1453
  printNoResults(format, io);
1345
1454
  return 0;
1346
1455
  }
1347
- const notice = ds.notice();
1456
+ const notice = ds.notice(where);
1348
1457
  if (notice && values["require-design-system"] && !ds.hasDesignSystem()) {
1349
1458
  io.stderr(`check --require-design-system: ${notice}`);
1350
1459
  for (const text of notReadNotices([{ ds }])) io.stderr(text);
@@ -1393,6 +1502,7 @@ async function selectInWorkspace(workspace, patterns, values, format, io) {
1393
1502
  if (!found) throw new Error(`No project for ${file}`);
1394
1503
  return found;
1395
1504
  };
1505
+ const shown = (p) => relativePath(io.cwd, p.root) || ".";
1396
1506
  const designSystems = /* @__PURE__ */ new Map();
1397
1507
  const load = (p) => {
1398
1508
  let ds = designSystems.get(p.root);
@@ -1463,7 +1573,13 @@ async function selectInWorkspace(workspace, patterns, values, format, io) {
1463
1573
  }
1464
1574
  if (!complete) {
1465
1575
  const packages = workspace.projects.length + workspace.others.length;
1466
- io.stderr(`check --require-design-system: no workspace package has a design system with components and color tokens (${plural(packages, "package")} looked at). See ${DOCS}/troubleshooting`);
1576
+ const lacking = /* @__PURE__ */ new Map();
1577
+ for (const p of workspace.projects) {
1578
+ const gap = missingFrom(await load(p));
1579
+ if (gap) lacking.set(gap.what, [...lacking.get(gap.what) ?? [], shown(p)]);
1580
+ }
1581
+ const why = [...lacking].map(([what, dirs]) => `; ${what} in ${listOf(dirs)}`).join("");
1582
+ io.stderr(`check --require-design-system: no workspace package has a design system with components and color tokens (${plural(packages, "package")} looked at${why}). See ${DOCS}/troubleshooting`);
1467
1583
  return 2;
1468
1584
  }
1469
1585
  }
@@ -1481,7 +1597,7 @@ async function selectInWorkspace(workspace, patterns, values, format, io) {
1481
1597
  ds,
1482
1598
  dirs: []
1483
1599
  };
1484
- gap.dirs.push(p.dir);
1600
+ gap.dirs.push(shown(p));
1485
1601
  gaps.set(notice, gap);
1486
1602
  }
1487
1603
  const notices = [...gaps.values()].map(({ ds, dirs }) => ds.notice(listOf(dirs)) ?? "");
@@ -1489,7 +1605,7 @@ async function selectInWorkspace(workspace, patterns, values, format, io) {
1489
1605
  const ds = loaded.get(p.root);
1490
1606
  return ds ? [{
1491
1607
  ds,
1492
- dir: p.dir
1608
+ dir: shown(p)
1493
1609
  }] : [];
1494
1610
  });
1495
1611
  notices.push(...notReadNotices(checkedProjects));
@@ -1514,6 +1630,11 @@ function listOf(items, max = 3) {
1514
1630
  return `${items.slice(0, max).join(", ")} and ${items.length - max} more`;
1515
1631
  }
1516
1632
  async function inspect(configOptions, values, io) {
1633
+ const format = values.format ?? "pretty";
1634
+ if (!["pretty", "json"].includes(format)) {
1635
+ io.stderr(`inspect: unknown --format "${format}" (pretty, json)`);
1636
+ return 2;
1637
+ }
1517
1638
  const target = await loadTarget(configOptions);
1518
1639
  const { config } = target;
1519
1640
  warnDeprecated(config.deprecations, "pretty", io);
@@ -1552,6 +1673,8 @@ async function inspect(configOptions, values, io) {
1552
1673
  }
1553
1674
  lines.push("", `Tokens (${model.tokens.length})`);
1554
1675
  for (const [category, n] of tokenCounts(model)) lines.push(` ${category.padEnd(18)} ${n}`);
1676
+ const gap = missingFrom(ds);
1677
+ if (gap) lines.push("", `${gap.found}: check will not run ${gap.rules}. See ${DOCS}/configuration`);
1555
1678
  if (model.warnings.length) {
1556
1679
  lines.push("", "Warnings");
1557
1680
  for (const warning of model.warnings) lines.push(` ${warning}`);
@@ -1563,6 +1686,30 @@ async function inspect(configOptions, values, io) {
1563
1686
  return 0;
1564
1687
  }
1565
1688
  /**
1689
+ * What a design system lacks for `check` to run all its rules, as `DesignSystem.notice()` says
1690
+ * after a check: components, color tokens or both. Undefined when it has both.
1691
+ */
1692
+ function missingFrom(ds) {
1693
+ const components = ds.model.components.length > 0;
1694
+ const colors = ds.tokenIndex.has("color");
1695
+ if (components && colors) return void 0;
1696
+ if (components) return {
1697
+ what: "no color tokens",
1698
+ found: "No color tokens found",
1699
+ rules: "no-hardcoded-color"
1700
+ };
1701
+ if (colors) return {
1702
+ what: "no components",
1703
+ found: "No design-system components found",
1704
+ rules: "the component rules"
1705
+ };
1706
+ return {
1707
+ what: "no components or color tokens",
1708
+ found: "No design system found (no components or color tokens)",
1709
+ rules: "the component rules or no-hardcoded-color"
1710
+ };
1711
+ }
1712
+ /**
1566
1713
  * `MUI (@mui/material 9.4.0): 149 components from its type declarations`, per library the
1567
1714
  * project depends on, including those the config's `libraries` leaves out.
1568
1715
  */
@@ -1664,8 +1811,9 @@ async function inspectWorkspace(workspace, values, io) {
1664
1811
  const { model } = ds;
1665
1812
  const roots = ds.roots();
1666
1813
  const tokens = [...tokenCounts(model)].map(([category, n]) => `${category} ${n}`);
1814
+ const gap = missingFrom(ds);
1667
1815
  const own = project.config.configFile && (project.config.configFile !== workspace.configFile || project.config.designSystemPackage) ? `${displayPath(workspace.root, project.config.configFile)}${declaredBy(project.config, (f) => displayPath(workspace.root, f))}` : void 0;
1668
- lines.push("", `${project.dir}${project.name ? ` (${project.name})` : ""}`, ...own ? [` config ${own}`] : [], ...project.config.detected ? [` detected ${project.config.detected}`] : [], ...describeLibraries(project.config, model, io.cwd).map((line) => ` library ${line}`), ` files ${plural(model.stats.files.components, "component file")}, ${plural(model.stats.files.tokens, "token file")}, ${plural(model.stats.files.docs, "doc")}`, ` components ${roots.length} + ${ds.components.length - roots.length} parts${roots.length ? `: ${listNames(roots.map((c) => c.name))}` : ""}`, ` tokens ${tokens.length ? tokens.join(", ") : "none"}`, ...model.warnings.length ? [` warnings ${model.warnings.length}: ${model.warnings[0] ?? ""}`] : []);
1816
+ lines.push("", `${project.dir}${project.name ? ` (${project.name})` : ""}`, ...own ? [` config ${own}`] : [], ...project.config.detected ? [` detected ${project.config.detected}`] : [], ...describeLibraries(project.config, model, io.cwd).map((line) => ` library ${line}`), ` files ${plural(model.stats.files.components, "component file")}, ${plural(model.stats.files.tokens, "token file")}, ${plural(model.stats.files.docs, "doc")}`, ` components ${roots.length} + ${ds.components.length - roots.length} parts${roots.length ? `: ${listNames(roots.map((c) => c.name))}` : ""}`, ` tokens ${tokens.length ? tokens.join(", ") : "none"}`, ...gap ? [` missing ${gap.what.replace(/^no /, "")}: check will not run ${gap.rules}`] : [], ...model.warnings.length ? [` warnings ${model.warnings.length}: ${model.warnings[0] ?? ""}`] : []);
1669
1817
  }
1670
1818
  if (!loaded.length) lines.push("", `No workspace package has a design system that zero config finds. See ${DOCS}/troubleshooting`);
1671
1819
  if (workspace.others.length) lines.push("", `Without a design system (${workspace.others.length}): ${listNames(workspace.others)}`);
@@ -12346,7 +12346,7 @@ function isObject(value) {
12346
12346
  // package.json
12347
12347
  var name = "onsystem";
12348
12348
  // src/version.ts
12349
- const VERSION = "0.11.1";
12349
+ const VERSION = "0.12.0";
12350
12350
  const NAME = name;
12351
12351
  // src/lint/sarif.ts
12352
12352
  const SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";
@@ -12481,7 +12481,7 @@ function formatDiagnostics(results, format, options = {}) {
12481
12481
  const lines = results.flatMap((result) => {
12482
12482
  const file = options.uri ? options.uri(result.file) : result.file;
12483
12483
  return result.diagnostics.map((d) => {
12484
- return `::${d.severity === "error" ? "error" : "warning"} ${`file=${escapeProperty(file)},line=${d.line},col=${d.column},endLine=${d.endLine},endColumn=${d.endColumn},title=${escapeProperty(d.ruleId)}`}::${escapeData(d.message)}`;
12484
+ return `::${d.severity === "error" ? "error" : "warning"} ${`file=${escapeProperty(file)},line=${d.line},col=${d.column},endLine=${d.endLine},endColumn=${d.endColumn},title=${escapeProperty(`onsystem: ${d.ruleId}`)}`}::${escapeData(d.message)}`;
12485
12485
  });
12486
12486
  });
12487
12487
  if (fixedHint) lines.push(`::notice title=onsystem baseline::${escapeData(fixedHint)}`);
@@ -12992,7 +12992,7 @@ const STEMMED_SYNONYMS = new Map(Object.entries({
12992
12992
  surface: ["card"],
12993
12993
  section: ["card"],
12994
12994
  dropdown: ["select", "menu"],
12995
- picker: ["select"],
12995
+ picker: ["select", "calendar"],
12996
12996
  combobox: ["select"],
12997
12997
  notification: ["toast", "alert"],
12998
12998
  snackbar: ["toast"],
@@ -13002,7 +13002,20 @@ const STEMMED_SYNONYMS = new Map(Object.entries({
13002
13002
  loader: ["spinner", "skeleton"],
13003
13003
  loading: ["spinner", "skeleton"],
13004
13004
  divider: ["separator"],
13005
- avatar: ["avatar"]
13005
+ profile: ["avatar"],
13006
+ initials: ["avatar"],
13007
+ headshot: ["avatar"],
13008
+ gravatar: ["avatar"],
13009
+ offcanvas: ["sheet"],
13010
+ slideover: ["sheet"],
13011
+ expandable: ["accordion"],
13012
+ faq: ["accordion"],
13013
+ multiline: ["textarea"],
13014
+ range: ["slider"],
13015
+ date: ["calendar"],
13016
+ schedule: ["calendar"],
13017
+ palette: ["command"],
13018
+ cmdk: ["command"]
13006
13019
  }).map(([word, related]) => [stemmer(word), related.map((r) => stemmer(r))]));
13007
13020
  /** Query terms plus synonyms; synonyms carry a lower weight. */
13008
13021
  function expandQuery(query) {
@@ -1,5 +1,5 @@
1
- import { At as relativePath, a as fingerprint, i as componentFiles, ot as excludedBy, r as buildModel } from "./design-system-D7ppJYbd.js";
2
- import { r as loadTarget } from "./workspace-DUgzMLGs.js";
1
+ import { At as relativePath, a as fingerprint, i as componentFiles, ot as excludedBy, r as buildModel } from "./design-system-jpX0zFNy.js";
2
+ import { r as loadTarget } from "./workspace-DH5RWgR2.js";
3
3
  import { createHash } from "node:crypto";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
package/dist/eslint.js CHANGED
@@ -1,4 +1,4 @@
1
- import { At as relativePath, N as RULES, Q as DEFAULT_TEST_FOLDERS, X as DEFAULT_SEVERITY, Z as DEFAULT_TEST_EXCLUDE, m as checkSource, rt as RULE_IDS, t as DesignSystem, ut as rulesFor, v as NAME, y as VERSION } from "./design-system-D7ppJYbd.js";
1
+ import { At as relativePath, N as RULES, Q as DEFAULT_TEST_FOLDERS, X as DEFAULT_SEVERITY, Z as DEFAULT_TEST_EXCLUDE, m as checkSource, rt as RULE_IDS, t as DesignSystem, ut as rulesFor, v as NAME, y as VERSION } from "./design-system-jpX0zFNy.js";
2
2
  import path from "node:path";
3
3
  import { MessageChannel, Worker, receiveMessageOnPort } from "node:worker_threads";
4
4
  // src/eslint/bridge.ts
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { F as loadTokens, G as parseDoc, H as parseDesignMd, I as mergeTokens, K as extractComponents, L as toDesignMd, N as RULES, P as TokenIndex, R as toDtcg, U as parseCssTokens, V as parseDtcgTokens, W as attachDocs, _ as formatDiagnostics, a as fingerprint, at as defineConfig, ct as loadConfig, f as searchComponents, ft as findVariantDefinitions, it as configJsonSchema, m as checkSource, n as DesignSystemHost, o as loadDesignSystem, p as applyFixes, r as buildModel, rt as RULE_IDS, t as DesignSystem, y as VERSION } from "./design-system-D7ppJYbd.js";
2
- import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-c3Y34to3.js";
1
+ import { F as loadTokens, G as parseDoc, H as parseDesignMd, I as mergeTokens, K as extractComponents, L as toDesignMd, N as RULES, P as TokenIndex, R as toDtcg, U as parseCssTokens, V as parseDtcgTokens, W as attachDocs, _ as formatDiagnostics, a as fingerprint, at as defineConfig, ct as loadConfig, f as searchComponents, ft as findVariantDefinitions, it as configJsonSchema, m as checkSource, n as DesignSystemHost, o as loadDesignSystem, p as applyFixes, r as buildModel, rt as RULE_IDS, t as DesignSystem, y as VERSION } from "./design-system-jpX0zFNy.js";
2
+ import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-DKayvYuq.js";
3
3
  export { DesignSystem, DesignSystemHost, INSTRUCTIONS, RULES, RULE_IDS, TokenIndex, VERSION, applyFixes, attachDocs, buildModel, checkSource, configJsonSchema, createServer, defineConfig, extractComponents, findVariantDefinitions, fingerprint, formatDiagnostics, loadConfig, loadDesignSystem, loadTokens, mergeTokens, parseCssTokens, parseDesignMd, parseDoc, parseDtcgTokens, searchComponents, serveStdio, toDesignMd, toDtcg };
@@ -1,5 +1,5 @@
1
- import { At as relativePath, Ct as isWorkspaceRoot, Dt as isInside, Et as SCRIPT_FILE, Ft as truncate, It as unique, J as ConfigError, Lt as defaultProjectConfig, Mt as closest, Nt as json, Pt as plural, X as DEFAULT_SEVERITY, bt as detectProject, ct as loadConfig, d as descriptionOf, dt as formatPx, f as searchComponents, gt as notReadYet, h as uncheckedNotice, ht as libraryTitle, kt as pathOf, mt as LIBRARY_IDS, n as DesignSystemHost, ot as excludedBy, pt as LIBRARIES, q as CONFIG_FILES, r as buildModel, rt as RULE_IDS, tt as LEGACY_CONFIG_FILES, u as buildSearchIndex, v as NAME, xt as findDesignSystemPackage, y as VERSION, z as TOKEN_CATEGORIES } from "./design-system-D7ppJYbd.js";
2
- import { i as projectDirOf, n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-DUgzMLGs.js";
1
+ import { At as relativePath, Ct as isWorkspaceRoot, Dt as isInside, Et as SCRIPT_FILE, Ft as truncate, It as unique, J as ConfigError, Lt as defaultProjectConfig, Mt as closest, Nt as json, Pt as plural, X as DEFAULT_SEVERITY, bt as detectProject, ct as loadConfig, d as descriptionOf, dt as formatPx, f as searchComponents, gt as notReadYet, h as uncheckedNotice, ht as libraryTitle, kt as pathOf, mt as LIBRARY_IDS, n as DesignSystemHost, ot as excludedBy, pt as LIBRARIES, q as CONFIG_FILES, r as buildModel, rt as RULE_IDS, tt as LEGACY_CONFIG_FILES, u as buildSearchIndex, v as NAME, xt as findDesignSystemPackage, y as VERSION, z as TOKEN_CATEGORIES } from "./design-system-jpX0zFNy.js";
2
+ import { i as projectDirOf, n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-DH5RWgR2.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -1,4 +1,4 @@
1
- import { At as relativePath, Ct as isWorkspaceRoot, Dt as isInside, Tt as workspacePatterns, ct as loadConfig, i as componentFiles, lt as loadConfigWith, nt as PROJECT_MARKERS, st as hasOwnConfig, vt as PackageFinder, wt as workspacePackageDirs, xt as findDesignSystemPackage } from "./design-system-D7ppJYbd.js";
1
+ import { At as relativePath, Ct as isWorkspaceRoot, Dt as isInside, Tt as workspacePatterns, ct as loadConfig, i as componentFiles, lt as loadConfigWith, nt as PROJECT_MARKERS, st as hasOwnConfig, vt as PackageFinder, wt as workspacePackageDirs, xt as findDesignSystemPackage } from "./design-system-jpX0zFNy.js";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import os from "node:os";
@@ -194,6 +194,7 @@ function findProjectRoot(target, home = os.homedir()) {
194
194
  for (let up = dir; up !== path.dirname(up); up = path.dirname(up)) if (!skipped(up) && isWorkspaceRoot(up)) return up;
195
195
  return dir;
196
196
  }
197
+ /** Whether `a` and `b` are the same folder, as the platform compares paths (case-insensitive on Windows). */
197
198
  function samePath(a, b) {
198
199
  return path.relative(path.resolve(a), path.resolve(b)) === "";
199
200
  }
@@ -216,4 +217,4 @@ function isDirectory(target) {
216
217
  return false;
217
218
  }
218
219
  }
219
- export { projectDirOf as i, hasProjectMarker as n, loadTarget as r, findProjectRoot as t };
220
+ export { samePath as a, projectDirOf as i, hasProjectMarker as n, loadTarget as r, findProjectRoot as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onsystem",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "mcpName": "io.github.dgesteves/onsystem",
5
5
  "description": "Keeps coding agents on your design system: catches palette colors, native elements and APIs your system lacks, at every edit and pull request, with the fix. Set it up once in your design-system package; every app in your monorepo gets it.",
6
6
  "keywords": [
@@ -63,6 +63,7 @@
63
63
  },
64
64
  "dependencies": {
65
65
  "@modelcontextprotocol/server": "^2.3.1",
66
+ "@types/culori": "^4.0.1",
66
67
  "culori": "^4.0.2",
67
68
  "postcss": "^8.5.30",
68
69
  "stemmer": "^2.0.1",
@@ -85,7 +86,6 @@
85
86
  "@eslint/js": "^10.0.1",
86
87
  "@modelcontextprotocol/client": "^2.3.1",
87
88
  "@modelcontextprotocol/sdk": "^1.32.1",
88
- "@types/culori": "^4.0.1",
89
89
  "@types/node": "^24.19.2",
90
90
  "@vitest/coverage-istanbul": "^5.0.5",
91
91
  "ajv": "^8.20.0",