onsystem 0.9.0 → 0.10.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.
@@ -1,4 +1,4 @@
1
- import { h as DesignSystemModel, i as ResolvedConfig } from "./config-B98w8bcg.js";
1
+ import { h as DesignSystemModel, i as ResolvedConfig } from "./config-BbTW1jKU.js";
2
2
  import { MessagePort } from "node:worker_threads";
3
3
  //#region src/eslint/worker.d.ts
4
4
  export interface LoadRequest {
@@ -1,5 +1,5 @@
1
- import { At as relativePath, i as componentFiles, r as buildModel, rt as excludedBy } from "./design-system-Bykei5W0.js";
2
- import { r as loadTarget } from "./workspace-Dp1q8qZ8.js";
1
+ import { Mt as relativePath, at as excludedBy, i as componentFiles, r as buildModel } from "./design-system-D53Jxybo.js";
2
+ import { r as loadTarget } from "./workspace-DAa_08uB.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { parentPort } from "node:worker_threads";
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, t as DesignSystem, v as NAME, y as VERSION } from "./design-system-Bykei5W0.js";
1
+ import { Mt as relativePath, N as RULES, Q as DEFAULT_TEST_FOLDERS, X as DEFAULT_SEVERITY, Z as DEFAULT_TEST_EXCLUDE, t as DesignSystem, v as NAME, y as VERSION } from "./design-system-D53Jxybo.js";
2
2
  import path from "node:path";
3
3
  import { MessageChannel, Worker, receiveMessageOnPort } from "node:worker_threads";
4
4
  //#region src/eslint/bridge.ts
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as TOKEN_CATEGORIES, D as VariantInfo, E as TokenCategory, O as ImportMapping, S as SourceLocation, T as Token, _ as DocSection, a as ResolvedRule, b as PropInfo, c as configJsonSchema, d as CheckResult, f as ComponentDocs, g as Diagnostic, h as DesignSystemModel, i as ResolvedConfig, l as defineConfig, m as CompoundVariantInfo, n as LoadConfigOptions, o as RuleId, p as ComponentInfo, r as RULE_IDS, s as RuleOptions, t as Config, u as loadConfig, v as ExampleInfo, w as TextEdit, x as Severity, y as InheritedProps } from "./config-B98w8bcg.js";
1
+ import { C as TOKEN_CATEGORIES, D as VariantInfo, E as TokenCategory, O as ImportMapping, S as SourceLocation, T as Token, _ as DocSection, a as ResolvedRule, b as PropInfo, c as configJsonSchema, d as CheckResult, f as ComponentDocs, g as Diagnostic, h as DesignSystemModel, i as ResolvedConfig, l as defineConfig, m as CompoundVariantInfo, n as LoadConfigOptions, o as RuleId, p as ComponentInfo, r as RULE_IDS, s as RuleOptions, t as Config, u as loadConfig, v as ExampleInfo, w as TextEdit, x as Severity, y as InheritedProps } from "./config-BbTW1jKU.js";
2
2
  import ts from "typescript";
3
3
  import { Oklch } from "culori";
4
4
  import { McpServer, Transport } from "@modelcontextprotocol/server";
@@ -663,10 +663,10 @@ export declare class DesignSystemHost {
663
663
  /** Watches the component, token and docs locations, the config and the tsconfig chain. */
664
664
  watch(): void;
665
665
  /**
666
- * Watches the config file, the tsconfig and the tsconfigs it extends through
667
- * their directories: editors save by renaming a new file over the old one,
668
- * which ends a watch on the file. Called again after each build, so a new
669
- * `extends` target is picked up.
666
+ * Watches the config file, the config a design-system package declares, which a project with
667
+ * a config of its own reads under that one, the tsconfig and the tsconfigs it extends through
668
+ * their directories: editors save by renaming a new file over the old one, which ends a watch
669
+ * on the file. Called again after each build, so a new `extends` target is picked up.
670
670
  */
671
671
  private watchConfigFiles;
672
672
  private changed;
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 loadConfig, et as RULE_IDS, f as searchComponents, lt as findVariantDefinitions, m as checkSource, n as DesignSystemHost, nt as defineConfig, o as loadDesignSystem, p as applyFixes, r as buildModel, t as DesignSystem, tt as configJsonSchema, y as VERSION } from "./design-system-Bykei5W0.js";
2
- import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-B7u6dqLd.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, dt as findVariantDefinitions, f as searchComponents, it as defineConfig, m as checkSource, n as DesignSystemHost, nt as RULE_IDS, o as loadDesignSystem, p as applyFixes, r as buildModel, rt as configJsonSchema, st as loadConfig, t as DesignSystem, y as VERSION } from "./design-system-D53Jxybo.js";
2
+ import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-ha4IF0CU.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 { $ as LEGACY_CONFIG_FILES, At as relativePath, Ct as closest, Dt as SCRIPT_FILE, Et as unique, Mt as defaultProjectConfig, Ot as isInside, Tt as truncate, X as DEFAULT_SEVERITY, _t as detectProject, at as loadConfig, ct as formatPx, d as descriptionOf, dt as LIBRARY_IDS, et as RULE_IDS, f as searchComponents, ft as libraryTitle, h as uncheckedNotice, n as DesignSystemHost, pt as notReadYet, q as CONFIG_FILES, rt as excludedBy, u as buildSearchIndex, ut as LIBRARIES, v as NAME, vt as findDesignSystemPackage, wt as plural, y as VERSION, z as TOKEN_CATEGORIES } from "./design-system-Bykei5W0.js";
2
- import { n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-Dp1q8qZ8.js";
1
+ import { At as isInside, Dt as truncate, Et as plural, Mt as relativePath, Ot as unique, Pt as defaultProjectConfig, Tt as closest, X as DEFAULT_SEVERITY, at as excludedBy, bt as findDesignSystemPackage, d as descriptionOf, f as searchComponents, ft as LIBRARIES, h as uncheckedNotice, ht as notReadYet, kt as SCRIPT_FILE, mt as libraryTitle, n as DesignSystemHost, nt as RULE_IDS, pt as LIBRARY_IDS, q as CONFIG_FILES, st as loadConfig, tt as LEGACY_CONFIG_FILES, u as buildSearchIndex, ut as formatPx, v as NAME, y as VERSION, yt as detectProject, z as TOKEN_CATEGORIES } from "./design-system-D53Jxybo.js";
2
+ import { n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-DAa_08uB.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -19,7 +19,7 @@ function explainProject(ds, cwd, indent = "") {
19
19
  const out = (line = "") => lines.push(line ? `${indent}${line}` : "");
20
20
  out("How the design system was found");
21
21
  for (const step of packageSteps(config, cwd)) out(` ${(step.accepted ? "found" : "no").padEnd(6)} ${step.candidate}: ${step.reason}`);
22
- if (config.configured) out(` components come from ${config.configFile ? display(cwd, config.configFile) : "--components"}, so zero config did not look`);
22
+ if (config.configured) out(` components come from ${config.inherits && config.designSystemPackage ? display(cwd, config.designSystemPackage.config) : config.configFile ? `${display(cwd, config.configFile)}${over(config, cwd)}` : "--components"}, so zero config did not look`);
23
23
  else {
24
24
  const steps = [];
25
25
  detectProject(config.root, config.tsconfig, steps, config.designSystemPackage);
@@ -37,7 +37,7 @@ function explainProject(ds, cwd, indent = "") {
37
37
  out("Resolved config");
38
38
  const field = (name, value) => out(` ${name.padEnd(12)} ${value}`);
39
39
  field("root", config.root);
40
- field("config", config.configFile ? `${display(cwd, config.configFile)}${config.designSystemPackage ? ` (declared by ${config.designSystemPackage.name})` : ""}` : "(none)");
40
+ field("config", config.configFile ? `${display(cwd, config.configFile)}${over(config, cwd)}${config.designSystemPackage ? ` (declared by ${config.designSystemPackage.name})` : ""}` : "(none)");
41
41
  field("components", listOf$3(config.components) || "(none)");
42
42
  field("exclude", listOf$3(config.exclude));
43
43
  field("tokens", listOf$3(config.tokens.map((t) => `${t.path}${t.prefix ? ` (prefix ${t.prefix})` : ""}${t.fallback ? " (when nothing else is found)" : ""}`)));
@@ -111,20 +111,34 @@ function nodeModulesFor(dir) {
111
111
  if (current === path.dirname(current)) return void 0;
112
112
  }
113
113
  }
114
+ /** `, over packages/ui/onsystem.config.json` for a config read over a design-system package's. */
115
+ function over(config, cwd) {
116
+ const declared = config.designSystemPackage;
117
+ return declared && config.configFile !== declared.config ? `, over ${display(cwd, declared.config)}` : "";
118
+ }
114
119
  function display(cwd, file) {
115
120
  const rel = relativePath(cwd, file);
116
121
  return rel && !rel.startsWith("..") ? rel : file;
117
122
  }
118
123
  /**
119
- * Whether a dependency's declared config was taken on, for a project without a config of its
120
- * own: the package it came from and the others that declare one, or that none does.
124
+ * Whether a dependency's declared config was read, taken on by a project without a config of its
125
+ * own or under the one it has: the package it came from and the others that declare one, or that
126
+ * none does.
121
127
  */
122
128
  function packageSteps(config, cwd) {
123
129
  const declared = config.designSystemPackage;
124
- if (config.configFile && !declared) return [];
130
+ const candidate = "a design-system package's config";
131
+ if (config.configFile && !declared) {
132
+ const found = config.extendsOff ? findDesignSystemPackage(config.root)?.found : void 0;
133
+ if (!found) return [];
134
+ return [{
135
+ candidate,
136
+ accepted: false,
137
+ reason: `${found.name} (${found.installed ? "installed" : "a workspace package"}) declares ${display(cwd, found.config)}, not read: "extends": false in ${display(cwd, config.configFile)} reads it alone`
138
+ }];
139
+ }
125
140
  const lookup = findDesignSystemPackage(config.root);
126
141
  if (!lookup) return [];
127
- const candidate = "a design-system package's config";
128
142
  const skipped = lookup.skipped.length ? `; ${lookup.skipped.map((p) => p.name).join(", ")} ${lookup.skipped.length === 1 ? "declares one" : "declare one"} that cannot be read, skipped since installed` : "";
129
143
  if (!declared) return [{
130
144
  candidate,
@@ -134,7 +148,7 @@ function packageSteps(config, cwd) {
134
148
  return [{
135
149
  candidate,
136
150
  accepted: true,
137
- reason: `${declared.name} (${declared.installed ? "installed" : "a workspace package"}) declares ${display(cwd, declared.config)}, which this project takes on, with its paths from ${display(cwd, declared.dir)}${lookup.others.length ? `; ${lookup.others.join(", ")} also declare one, not read: one config is taken on, from the package the code imports most` : ""}${skipped}`
151
+ reason: `${declared.name} (${declared.installed ? "installed" : "a workspace package"}) declares ${display(cwd, declared.config)}, which this project ${config.configFile === declared.config ? "takes on" : `reads under ${display(cwd, config.configFile ?? "")}`}, with its paths from ${display(cwd, declared.dir)}${lookup.others.length ? `; ${lookup.others.join(", ")} also declare one, not read: one config is taken on, from the package the code imports most` : ""}${skipped}`
138
152
  }];
139
153
  }
140
154
  //#endregion
@@ -327,11 +341,16 @@ function listTail(listed) {
327
341
  if (listed.omitted) lines.push("", `${listed.omitted.toLocaleString("en-US")} more not shown: pass a higher \`limit\`, or a \`query\`.`);
328
342
  return lines;
329
343
  }
344
+ /** The shared explanation when a project has no design-system components to show. */
345
+ function noComponentsMessage(root, project, monorepo = false) {
346
+ if (monorepo) return `No design-system components found in any project of this monorepo (root: ${root}). Check the "components" globs in the config. Run \`onsystem inspect\` there to see what was looked at.`;
347
+ return `No design-system components found${project ? ` in ${project}` : ""}. Check the "components" globs in the config (root: ${root}).`;
348
+ }
330
349
  /** `project`: the folder of a workspace root's project the list is for. */
331
350
  function renderComponentList(ds, project, filter = {}) {
332
351
  const roots = ds.roots();
333
352
  const where = project ? ` in ${project}` : "";
334
- if (!roots.length) return `No components found${where}. Check the "components" globs in the config (root: ${ds.root}).`;
353
+ if (!roots.length) return noComponentsMessage(ds.root, project);
335
354
  const listed = listComponents(roots, (c) => c, filter);
336
355
  if (!listed.matched) return `No components match ${filterText(filter)}${where} (${roots.length} in all). Call list_components without filters to see them.`;
337
356
  const parts = ds.components.length - roots.length;
@@ -374,7 +393,7 @@ const PICK_PROJECT = "This is a monorepo root: pass `path`, the file you are edi
374
393
  /** Every project's components at a workspace root, grouped by the package they come from. */
375
394
  function renderCatalogList(catalog, filter = {}) {
376
395
  const roots = catalog.roots();
377
- if (!roots.length) return `No components found in any project of this monorepo (root: ${catalog.root}). Run \`onsystem inspect\` there to see what was looked at.`;
396
+ if (!roots.length) return noComponentsMessage(catalog.root, void 0, true);
378
397
  const listed = listComponents(roots, (e) => e.component, filter, (e) => e.package);
379
398
  if (!listed.matched) return `No components match ${filterText(filter)} in any project (${roots.length} in all). Call list_components without filters to see them.`;
380
399
  const packages = new Set(roots.map((e) => e.package));
@@ -1086,6 +1105,7 @@ function createServer({ getDesignSystem, getProjects }) {
1086
1105
  const matches = catalog.find(name);
1087
1106
  const [entry] = matches;
1088
1107
  if (!entry) {
1108
+ if (!catalog.roots().length) return errorResult(noComponentsMessage(catalog.root, void 0, true));
1089
1109
  const guess = catalog.suggest(name);
1090
1110
  const names = [...new Set(catalog.roots().map((e) => e.component.name))];
1091
1111
  return errorResult(`No component named "${name}" in any project.` + (guess ? ` Did you mean "${guess}"?` : "") + ` Available: ${names.join(", ")}.`);
@@ -1109,6 +1129,13 @@ function createServer({ getDesignSystem, getProjects }) {
1109
1129
  const { ds } = found;
1110
1130
  const component = ds.getComponent(name);
1111
1131
  if (!component) {
1132
+ if (!ds.roots().length) return {
1133
+ isError: true,
1134
+ content: [{
1135
+ type: "text",
1136
+ text: noComponentsMessage(ds.root, found.project?.dir)
1137
+ }]
1138
+ };
1112
1139
  const guess = ds.suggestComponent(name);
1113
1140
  return {
1114
1141
  isError: true,
@@ -1,4 +1,4 @@
1
- import { $ as LEGACY_CONFIG_FILES, At as relativePath, Ot as isInside, St as workspacePatterns, at as loadConfig, bt as isWorkspaceRoot, ht as PackageFinder, i as componentFiles, it as hasOwnConfig, ot as loadConfigWith, q as CONFIG_FILES, vt as findDesignSystemPackage, xt as workspacePackageDirs } from "./design-system-Bykei5W0.js";
1
+ import { At as isInside, Ct as workspacePackageDirs, Mt as relativePath, St as isWorkspaceRoot, _t as PackageFinder, bt as findDesignSystemPackage, ct as loadConfigWith, i as componentFiles, ot as hasOwnConfig, q as CONFIG_FILES, st as loadConfig, tt as LEGACY_CONFIG_FILES, wt as workspacePatterns } from "./design-system-D53Jxybo.js";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import os from "node:os";
@@ -121,7 +121,7 @@ async function discoverWorkspace(rootConfig, options) {
121
121
  for (const dir of workspacePackageDirs(root)) {
122
122
  const config = await loadProjectConfig(dir, root, rootConfig.configFile, options);
123
123
  const files = (await componentFiles(config)).length;
124
- const own = config.configFile !== void 0 && config.configFile !== rootConfig.configFile;
124
+ const own = config.configFile !== void 0 && config.configFile !== rootConfig.configFile || config.designSystemPackage !== void 0;
125
125
  const library = config.libraries?.some((l) => l.dir !== void 0) ?? false;
126
126
  if (files || own || library) projects.push({
127
127
  root: dir,
@@ -138,10 +138,11 @@ async function discoverWorkspace(rootConfig, options) {
138
138
  return new Workspace(root, source, projects, others, rootConfig.configFile, options, rootConfig, otherConfigs);
139
139
  }
140
140
  /**
141
- * A project's config: its own config file, else the config its design-system package declares
142
- * (a dependency with `"onsystem"` in its package.json), else the workspace root's, with paths
143
- * relative to the workspace root, else zero config. `loadConfig` from the project's folder finds
144
- * the first two the same way. CLI flags that apply to every project carry over.
141
+ * A project's config: its own config file, else the workspace root's, with paths relative to
142
+ * the workspace root, read over the config its design-system package declares (a dependency with
143
+ * `"onsystem"` in its package.json), else zero config. `loadConfig` from the project's folder
144
+ * finds its own config and the package's the same way. CLI flags that apply to every project
145
+ * carry over.
145
146
  */
146
147
  function loadProjectConfig(dir, workspaceRoot, rootConfigFile, options) {
147
148
  const shared = {
@@ -155,7 +156,7 @@ function loadProjectConfig(dir, workspaceRoot, rootConfigFile, options) {
155
156
  root: dir
156
157
  }, { packages });
157
158
  const lookup = findDesignSystemPackage(dir, packages);
158
- if (lookup?.found || lookup?.problems.length) return loadConfigWith({
159
+ if (lookup?.problems.length) return loadConfigWith({
159
160
  ...shared,
160
161
  root: dir
161
162
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onsystem",
3
- "version": "0.9.0",
3
+ "version": "0.10.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": [
package/schema.json CHANGED
@@ -7,6 +7,10 @@
7
7
  "$schema": {
8
8
  "type": "string"
9
9
  },
10
+ "extends": {
11
+ "description": "Whether this config builds on the one a design-system package declares (\"onsystem\" in the package.json of a dependency, found from the dependencies): its rules apply over the package's, and, unless it sets components of its own, what it leaves out comes from the package's (components with their importPath, docs, elements, tokens and libraries). Default: true. false reads this config alone.",
12
+ "type": "boolean"
13
+ },
10
14
  "components": {
11
15
  "description": "Globs for component source files, relative to the root.",
12
16
  "anyOf": [
@@ -103,7 +107,7 @@
103
107
  "type": "string"
104
108
  },
105
109
  "importPath": {
106
- "description": "Package name components are imported from, e.g. \"@acme/ui\", or a pattern for packages imported by path: \"@acme/ui/{path}\" is @acme/ui/primitives/button for primitives/button.tsx in the package. Default: inferred from package exports and tsconfig paths.",
110
+ "description": "Package name components are imported from, e.g. \"@acme/ui\", or a pattern for packages imported by path: \"@acme/ui/{path}\" is @acme/ui/primitives/button for primitives/button.tsx in the package. An installed dependency it names exactly, whose component sources the project does not read, is read from its type declarations (.d.ts). Default: inferred from package exports and tsconfig paths.",
107
111
  "type": "string"
108
112
  },
109
113
  "elements": {