onsystem 0.7.0 → 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/README.md +1 -1
- package/dist/cli.js +397 -70
- package/dist/{config-1XSTYI44.d.ts → config-kYGiD5oW.d.ts} +7 -0
- package/dist/{design-system-C4bhqLLw.js → design-system-Dmcv7eHR.js} +1086 -76
- package/dist/eslint-worker.d.ts +1 -1
- package/dist/eslint-worker.js +3 -5
- package/dist/eslint.js +1 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.js +2 -2
- package/dist/{stdio-BojAQ6JP.js → stdio-MTS6QAgo.js} +30 -7
- package/dist/{workspace-Z0tZf_Dv.js → workspace-CM1RyqZA.js} +1 -1
- package/package.json +1 -1
- package/schema.json +1 -1
package/dist/eslint-worker.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as DesignSystemModel, i as ResolvedConfig } from "./config-
|
|
1
|
+
import { h as DesignSystemModel, i as ResolvedConfig } from "./config-kYGiD5oW.js";
|
|
2
2
|
import { MessagePort } from "node:worker_threads";
|
|
3
3
|
//#region src/eslint/worker.d.ts
|
|
4
4
|
export interface LoadRequest {
|
package/dist/eslint-worker.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as loadTarget } from "./workspace-
|
|
1
|
+
import { Q as excludedBy, Tt as relativePath, i as componentFiles, r as buildModel } from "./design-system-Dmcv7eHR.js";
|
|
2
|
+
import { r as loadTarget } from "./workspace-CM1RyqZA.js";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { parentPort } from "node:worker_threads";
|
|
@@ -14,8 +14,6 @@ const warned = /* @__PURE__ */ new Set();
|
|
|
14
14
|
/** How long a loaded design system is trusted before its files are looked at again. */
|
|
15
15
|
const FRESH_MS = 2e3;
|
|
16
16
|
const targets = /* @__PURE__ */ new Map();
|
|
17
|
-
/** The default test and story patterns: the recommended config ignores those files itself. */
|
|
18
|
-
const TEST_PATTERNS = /* @__PURE__ */ new Set([DEFAULT_TEST_EXCLUDE, DEFAULT_TEST_FOLDERS]);
|
|
19
17
|
const projects = /* @__PURE__ */ new Map();
|
|
20
18
|
function realPath(file) {
|
|
21
19
|
try {
|
|
@@ -65,7 +63,7 @@ async function load(request) {
|
|
|
65
63
|
projects.set(config.root, project);
|
|
66
64
|
}
|
|
67
65
|
const relative = relativePath(config.root, request.file);
|
|
68
|
-
const excluded = config
|
|
66
|
+
const excluded = excludedBy(config, relative, { includeTests: true });
|
|
69
67
|
if (excluded) return { skip: `excluded by "${excluded}"` };
|
|
70
68
|
if (!config.includeDesignSystem && project.own.has(realPath(request.file))) return { skip: "one of the design system’s own component files" };
|
|
71
69
|
const { version } = project;
|
package/dist/eslint.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as DEFAULT_SEVERITY, K as DEFAULT_TEST_EXCLUDE, Tt as relativePath, _ as NAME, k as RULES, q as DEFAULT_TEST_FOLDERS, t as DesignSystem, v as VERSION } from "./design-system-Dmcv7eHR.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-
|
|
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-kYGiD5oW.js";
|
|
2
2
|
import ts from "typescript";
|
|
3
3
|
import { Oklch } from "culori";
|
|
4
4
|
import { McpServer, Transport } from "@modelcontextprotocol/server";
|
|
@@ -541,11 +541,24 @@ export declare class DesignSystem {
|
|
|
541
541
|
private readonly searchIndex;
|
|
542
542
|
/**
|
|
543
543
|
* The components the tools offer: all of them, except a library's (MUI's) where the project
|
|
544
|
-
* has its own of that name, a wrapper the team means to be used
|
|
545
|
-
*
|
|
544
|
+
* has its own of that name, a wrapper the team means to be used, and the helpers in a
|
|
545
|
+
* registry folder's `lib/` (signoff-ui's `Img` and icons). The rules still check code that
|
|
546
|
+
* imports either directly against them.
|
|
546
547
|
*/
|
|
547
548
|
private readonly offered;
|
|
549
|
+
/** The design systems the rules rank, with the registry folders a config lists. */
|
|
550
|
+
private readonly sources;
|
|
548
551
|
constructor(model: DesignSystemModel, config: ResolvedConfig);
|
|
552
|
+
/**
|
|
553
|
+
* The shadcn registry a component was copied from (`@signoff-ui`), when its folder is one
|
|
554
|
+
* components.json names: a read-only design system, whose code is the registry's.
|
|
555
|
+
*/
|
|
556
|
+
registryOf(component: ComponentInfo): {
|
|
557
|
+
registry: string;
|
|
558
|
+
folder: string;
|
|
559
|
+
} | undefined;
|
|
560
|
+
/** A component in a registry folder's `lib/`: an internal of its items, not one of them. */
|
|
561
|
+
private registryHelper;
|
|
549
562
|
get root(): string;
|
|
550
563
|
get components(): ComponentInfo[];
|
|
551
564
|
get tokens(): Token[];
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-
|
|
1
|
+
import { A as TokenIndex, B as parseDoc, I as parseDtcgTokens, L as parseDesignMd, M as mergeTokens, N as toDesignMd, P as toDtcg, R as parseCssTokens, V as extractComponents, X as configJsonSchema, Y as RULE_IDS, Z as defineConfig, a as fingerprint, d as searchComponents, et as loadConfig, f as applyFixes, g as formatDiagnostics, it as findVariantDefinitions, j as loadTokens, k as RULES, n as DesignSystemHost, o as loadDesignSystem, p as checkSource, r as buildModel, t as DesignSystem, v as VERSION, z as attachDocs } from "./design-system-Dmcv7eHR.js";
|
|
2
|
+
import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-MTS6QAgo.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 {
|
|
2
|
-
import { n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-
|
|
1
|
+
import { Ct as isInside, Dt as defaultProjectConfig, F as TOKEN_CATEGORIES, G as DEFAULT_SEVERITY, H as CONFIG_FILES, J as LEGACY_CONFIG_FILES, Q as excludedBy, St as SCRIPT_FILE, Tt as relativePath, Y as RULE_IDS, _ as NAME, at as LIBRARIES, bt as truncate, ct as notReadYet, d as searchComponents, et as loadConfig, ft as detectProject, m as uncheckedNotice, n as DesignSystemHost, ot as LIBRARY_IDS, pt as findDesignSystemPackage, rt as formatPx, st as libraryTitle, u as buildSearchIndex, v as VERSION, vt as closest, xt as unique, yt as plural } from "./design-system-Dmcv7eHR.js";
|
|
2
|
+
import { n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-CM1RyqZA.js";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -47,7 +47,10 @@ function explainProject(ds, cwd, indent = "") {
|
|
|
47
47
|
field("importPath", importPaths(ds));
|
|
48
48
|
field("libraries", config.libraryIds === void 0 ? `every library onsystem reads (${LIBRARY_IDS.join(", ")})` : config.libraryIds !== false && config.libraryIds.length ? config.libraryIds.join(", ") : `none ("libraries": ${JSON.stringify(config.libraryIds)})`);
|
|
49
49
|
if (config.tailwindConfig) field("tailwind", display(config.root, config.tailwindConfig));
|
|
50
|
-
if (config.designSystems)
|
|
50
|
+
if (config.designSystems) {
|
|
51
|
+
const ranked = config.designSystems.filter((d) => !d.registry).length > 1;
|
|
52
|
+
field("primary", config.designSystems.map((d, i) => `${i ? "then " : ""}${d.source}${d.registry ? ", read-only" : ranked ? ` (${d.imports} imports)` : ""}`).join("; "));
|
|
53
|
+
}
|
|
51
54
|
const changed = RULE_IDS.filter((id) => config.rules[id].severity !== DEFAULT_SEVERITY[id]);
|
|
52
55
|
field("rules", `${RULE_IDS.map((id) => `${id} ${config.rules[id].severity}`).join(", ")}${changed.length ? ` (changed: ${changed.join(", ")})` : ""}`);
|
|
53
56
|
if (config.overrides?.length) for (const override of config.overrides) field("override", `${override.files.join(", ")}: ${Object.entries(override.rules).map(([id, rule]) => `${id} ${rule.severity}`).join(", ")}`);
|
|
@@ -236,7 +239,7 @@ function renderComponentList(ds, project) {
|
|
|
236
239
|
const parts = ds.components.length - roots.length;
|
|
237
240
|
const lines = [`${plural(roots.length, "component")}${parts ? ` (+${plural(parts, "part")})` : ""}${project ? ` in ${project}` : ""}. Call get_component before using one.`, ""];
|
|
238
241
|
const own = roots.filter((c) => !c.library);
|
|
239
|
-
for (const component of own) lines.push(...listItem(component));
|
|
242
|
+
for (const component of own) lines.push(...listItem(component, registryNote(ds, component)));
|
|
240
243
|
for (const library of new Set(roots.flatMap((c) => c.library ? [c.library] : []))) {
|
|
241
244
|
if (own.length) lines.push("");
|
|
242
245
|
lines.push(`From ${library} (import { Name } from "${library}"):`, "");
|
|
@@ -244,6 +247,11 @@ function renderComponentList(ds, project) {
|
|
|
244
247
|
}
|
|
245
248
|
return lines.join("\n");
|
|
246
249
|
}
|
|
250
|
+
/** ` (from @signoff-ui, read-only)` for a component copied from a shadcn registry. */
|
|
251
|
+
function registryNote(ds, component) {
|
|
252
|
+
const from = ds.registryOf(component);
|
|
253
|
+
return from ? ` (from ${from.registry}, read-only)` : "";
|
|
254
|
+
}
|
|
247
255
|
function listItem(component, note = "", withImport = true) {
|
|
248
256
|
const element = component.element ? ` <${component.element}>` : "";
|
|
249
257
|
const lines = [`${component.name}${element}${note} — ${firstSentence(component.description) || "No description."}`];
|
|
@@ -376,6 +384,8 @@ function renderComponent(ds, component, origin) {
|
|
|
376
384
|
].filter(Boolean);
|
|
377
385
|
lines.push(facts.join(" · "));
|
|
378
386
|
if (origin) lines.push(`From ${origin.package}, used by ${listOf$1(origin.projects)}.`);
|
|
387
|
+
const registry = ds.registryOf(component);
|
|
388
|
+
if (registry) lines.push(`Installed from the shadcn registry ${registry.registry} into ${registry.folder}: use it as it is. Its code is the registry's, so change it upstream, not here; \`npx shadcn add --overwrite\` replaces the file.`);
|
|
379
389
|
lines.push("", "## Props");
|
|
380
390
|
if (!component.props.length && !component.inherits.length) lines.push("No props.");
|
|
381
391
|
for (const prop of component.props) lines.push(renderProp(prop));
|
|
@@ -565,6 +575,10 @@ const MAX_CODE = 1e6;
|
|
|
565
575
|
/** Diagnostics check_ui returns by default: a 3,000-line file can have thousands, more than a context holds. */
|
|
566
576
|
const DEFAULT_LIMIT = 50;
|
|
567
577
|
const MAX_LIMIT = 1e3;
|
|
578
|
+
/** check_ui's answer for a path or filename that is not JS or TS. */
|
|
579
|
+
function notScript(name) {
|
|
580
|
+
return errorResult(`check_ui checks .tsx, .jsx, .ts and .js files; ${name} is not one, so it was not checked.`);
|
|
581
|
+
}
|
|
568
582
|
/**
|
|
569
583
|
* An integer, without the ±9007199254740991 bounds zod adds to the JSON Schema,
|
|
570
584
|
* which every client would otherwise read in each tool definition.
|
|
@@ -999,7 +1013,7 @@ function createServer({ getDesignSystem, getProjects }) {
|
|
|
999
1013
|
description: "Lint TSX/JSX against the design system. Reports hardcoded colors, spacing and radius (with the nearest token), native elements that have a design-system component, unknown components, props and variant values, and icon-only buttons without an accessible name. Each diagnostic has line/column, a rule id, a message and a suggested fix. Run it on every snippet or file you write and fix all errors. Pass `code` for unsaved code, or `path` for a file in the project.",
|
|
1000
1014
|
inputSchema: z.object({
|
|
1001
1015
|
code: z.string().max(MAX_CODE).optional().describe(`TSX/JSX source to check (up to ${MAX_CODE.toLocaleString("en")} characters).`),
|
|
1002
|
-
path: z.string().max(MAX_PATH).optional().describe("Path of a file to check: relative to the project root (the monorepo root, when served from there), or absolute."),
|
|
1016
|
+
path: z.string().max(MAX_PATH).optional().describe("Path of a .tsx, .jsx, .ts or .js file to check: relative to the project root (the monorepo root, when served from there), or absolute."),
|
|
1003
1017
|
filename: z.string().max(MAX_PATH).optional().describe("Name to report `code` under; a .jsx extension parses it as JSX. At a monorepo root, the path the code will be saved under, which picks the project whose design system checks it. When the server was started outside your project, pass it as an absolute path: the project is found from it."),
|
|
1004
1018
|
limit: z.number().int().min(1).max(MAX_LIMIT).default(DEFAULT_LIMIT).describe(`Most diagnostics to return, errors first (default ${DEFAULT_LIMIT}). The counts and byRule cover all of them.`)
|
|
1005
1019
|
}),
|
|
@@ -1014,7 +1028,7 @@ function createServer({ getDesignSystem, getProjects }) {
|
|
|
1014
1028
|
errors: int(),
|
|
1015
1029
|
warnings: int()
|
|
1016
1030
|
})).describe("Every finding per rule, shown or not."),
|
|
1017
|
-
skipped: z.string().optional().describe("Why the file was not checked: it renders an image (next/og) or an email."),
|
|
1031
|
+
skipped: z.string().optional().describe("Why the file was not checked: it renders an image (next/og) or an email, or the config's `exclude` leaves it out."),
|
|
1018
1032
|
unchecked: z.object({
|
|
1019
1033
|
names: z.array(z.string()),
|
|
1020
1034
|
modules: z.array(z.string())
|
|
@@ -1024,6 +1038,7 @@ function createServer({ getDesignSystem, getProjects }) {
|
|
|
1024
1038
|
annotations: READ_ONLY
|
|
1025
1039
|
}, async ({ code, path: filePath, filename, limit }) => {
|
|
1026
1040
|
if (code === void 0 && !filePath) return errorResult("Pass either `code` or `path`.");
|
|
1041
|
+
if (code !== void 0 && filename !== void 0 && !SCRIPT_FILE.test(filename)) return notScript(filename);
|
|
1027
1042
|
const routeBy = code === void 0 ? filePath : filename ?? void 0;
|
|
1028
1043
|
const set = await getProjects?.(routeBy);
|
|
1029
1044
|
let ds;
|
|
@@ -1048,6 +1063,7 @@ function createServer({ getDesignSystem, getProjects }) {
|
|
|
1048
1063
|
const absolute = path.resolve(base, filePath);
|
|
1049
1064
|
const outside = errorResult(`${filePath} is outside the project root (${base}).`);
|
|
1050
1065
|
if (!isInside(base, absolute)) return outside;
|
|
1066
|
+
if (!SCRIPT_FILE.test(absolute)) return notScript(filePath);
|
|
1051
1067
|
try {
|
|
1052
1068
|
const [root, real] = await Promise.all([fsp.realpath(base), fsp.realpath(absolute)]);
|
|
1053
1069
|
if (!isInside(root, real)) return outside;
|
|
@@ -1071,7 +1087,14 @@ function createServer({ getDesignSystem, getProjects }) {
|
|
|
1071
1087
|
file = relativePath(ds.root, absolute);
|
|
1072
1088
|
shown = relativePath(base, absolute);
|
|
1073
1089
|
}
|
|
1074
|
-
const
|
|
1090
|
+
const excluded = (filename !== void 0 || code === void 0) && !path.isAbsolute(file) ? excludedBy(ds.config, file) : void 0;
|
|
1091
|
+
const checked = excluded ? {
|
|
1092
|
+
file,
|
|
1093
|
+
diagnostics: [],
|
|
1094
|
+
errorCount: 0,
|
|
1095
|
+
warningCount: 0,
|
|
1096
|
+
skipped: `It is left out by "${excluded}" in the config's exclude, as in check, the ESLint plugin and the Claude Code hook.`
|
|
1097
|
+
} : ds.check(source, file);
|
|
1075
1098
|
const result = file === shown ? checked : {
|
|
1076
1099
|
...checked,
|
|
1077
1100
|
file: shown
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as hasOwnConfig, Ct as isInside, H as CONFIG_FILES, J as LEGACY_CONFIG_FILES, Tt as relativePath, _t as workspacePatterns, et as loadConfig, gt as workspacePackageDirs, ht as isWorkspaceRoot, i as componentFiles, pt as findDesignSystemPackage, tt as loadConfigWith, ut as PackageFinder } from "./design-system-Dmcv7eHR.js";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import os from "node:os";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onsystem",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
]
|
|
23
23
|
},
|
|
24
24
|
"exclude": {
|
|
25
|
-
"description": "Globs to
|
|
25
|
+
"description": "Globs for files to leave out, relative to the root: `check` in folders and globs, the ESLint plugin, the Claude Code hook and check_ui leave them out, and finding components skips them. A folder (`app/legacy`) covers everything in it. Adds to the defaults (node_modules, .d.ts files, tests and stories); a pattern that starts with `!` takes out the default it names, such as `!**/*.d.ts`.",
|
|
26
26
|
"type": "array",
|
|
27
27
|
"items": {
|
|
28
28
|
"type": "string"
|