onsystem 0.10.2 → 0.11.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 +20 -7
- package/dist/{design-system-rl__N6tw.js → design-system-Csqts7Eq.js} +213 -29
- package/dist/eslint-worker.d.ts +2 -0
- package/dist/eslint-worker.js +119 -30
- package/dist/eslint.js +54 -12
- package/dist/index.d.ts +26 -5
- package/dist/index.js +2 -2
- package/dist/{stdio-CkczPt_1.js → stdio-0TpyqZaD.js} +32 -9
- package/dist/{workspace-INef0Yqt.js → workspace-Dbxubo9n.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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-
|
|
3
|
-
import { a as notReadNotices, i as missingDependencies, o as explainProject, s as librariesLeftOut, t as serveStdio } from "./stdio-
|
|
4
|
-
import { r as loadTarget } from "./workspace-
|
|
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-Csqts7Eq.js";
|
|
3
|
+
import { a as notReadNotices, i as missingDependencies, o as explainProject, s as librariesLeftOut, t as serveStdio } from "./stdio-0TpyqZaD.js";
|
|
4
|
+
import { r as loadTarget } from "./workspace-Dbxubo9n.js";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { escapePath, glob } from "tinyglobby";
|
|
@@ -324,7 +324,9 @@ function readManifest(root) {
|
|
|
324
324
|
/**
|
|
325
325
|
* Declares the config in the package's package.json, `"onsystem": "./onsystem.config.json"`,
|
|
326
326
|
* and adds it to `files` when the package lists the files it publishes, so apps that install it
|
|
327
|
-
* get it too. Writes ONSYSTEM.md for the apps' teams unless one exists
|
|
327
|
+
* get it too. Writes ONSYSTEM.md for the apps' teams unless one exists, and adds it to `files`
|
|
328
|
+
* as well, for the teams of apps that install the package, unless `files` leaves it out
|
|
329
|
+
* (`!ONSYSTEM.md`). Returns what it wrote.
|
|
328
330
|
*/
|
|
329
331
|
function declarePackage(root, manifest, name, force, notes) {
|
|
330
332
|
const written = [];
|
|
@@ -336,15 +338,18 @@ function declarePackage(root, manifest, name, force, notes) {
|
|
|
336
338
|
changed = true;
|
|
337
339
|
}
|
|
338
340
|
const files = Array.isArray(json.files) ? json.files : void 0;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
+
const added = [];
|
|
342
|
+
for (const file of [CONFIG_FILE, GUIDE_FILE]) {
|
|
343
|
+
if (!files || ships(files, file) || file === "ONSYSTEM.md" && excludes(files, file)) continue;
|
|
344
|
+
files.push(file);
|
|
345
|
+
added.push(file);
|
|
341
346
|
changed = true;
|
|
342
347
|
}
|
|
343
348
|
if (changed) {
|
|
344
349
|
fs.writeFileSync(manifest.file, `${JSON.stringify(json, null, manifest.indent)}${manifest.newline ? "\n" : ""}`);
|
|
345
350
|
written.push("package.json");
|
|
346
351
|
}
|
|
347
|
-
notes.push(`This is a design-system package: package.json declares its config ("${PACKAGE_FIELD}": "${value}"${
|
|
352
|
+
notes.push(`This is a design-system package: package.json declares its config ("${PACKAGE_FIELD}": "${value}"${added.length ? `, with ${added.join(" and ")} added to "files"` : ""}), which every app that depends on ${name} reads, under its own config when it has one.`);
|
|
348
353
|
const guide = path.join(root, GUIDE_FILE);
|
|
349
354
|
if (force || !fs.existsSync(guide)) {
|
|
350
355
|
fs.writeFileSync(guide, consumerGuide(name));
|
|
@@ -625,6 +630,14 @@ function aliasFolder(alias, project) {
|
|
|
625
630
|
}
|
|
626
631
|
}
|
|
627
632
|
}
|
|
633
|
+
/** Whether npm's `files` list leaves `file` out with a negated entry: `!ONSYSTEM.md`, `!*.md`. */
|
|
634
|
+
function excludes(files, file) {
|
|
635
|
+
return files.some((entry) => {
|
|
636
|
+
if (typeof entry !== "string" || !entry.startsWith("!")) return false;
|
|
637
|
+
const pattern = entry.slice(1).replace(/^\.?\//, "");
|
|
638
|
+
return pattern === file || matchesGlob(file, pattern);
|
|
639
|
+
});
|
|
640
|
+
}
|
|
628
641
|
/** Whether npm's `files` list publishes `file`, a path relative to the package. */
|
|
629
642
|
function ships(files, file) {
|
|
630
643
|
return files.some((entry) => {
|
|
@@ -387,7 +387,7 @@ function moduleFile(base, extensions = MODULE_EXTENSIONS, within) {
|
|
|
387
387
|
base,
|
|
388
388
|
...extensions.map((ext) => `${base}${ext}`),
|
|
389
389
|
...extensions.map((ext) => path.join(base, `index${ext}`))
|
|
390
|
-
].find((file) => isFile$
|
|
390
|
+
].find((file) => isFile$2(file) && !/(?:^|[\\/])node_modules[\\/]/.test(within ? path.relative(within, file) : file));
|
|
391
391
|
}
|
|
392
392
|
const BUILD_CONFIGS = [
|
|
393
393
|
"tsup",
|
|
@@ -580,7 +580,7 @@ function reexports(source) {
|
|
|
580
580
|
barrel
|
|
581
581
|
};
|
|
582
582
|
}
|
|
583
|
-
function isFile$
|
|
583
|
+
function isFile$2(file) {
|
|
584
584
|
try {
|
|
585
585
|
return fs.statSync(file).isFile();
|
|
586
586
|
} catch {
|
|
@@ -985,7 +985,7 @@ function fromComponentsJson(root, dir, json, project, packages, note = ignore) {
|
|
|
985
985
|
*/
|
|
986
986
|
function withAppStylesheets(root, named) {
|
|
987
987
|
if (named.every((file) => isInside(root, file))) return named;
|
|
988
|
-
const own = APP_STYLESHEETS.map((f) => path.join(root, f)).filter(isFile);
|
|
988
|
+
const own = APP_STYLESHEETS.map((f) => path.join(root, f)).filter(isFile$1);
|
|
989
989
|
if (!own.length) return named;
|
|
990
990
|
const imported = new Set(importedStylesheets(own, stylesheetResolver(root)));
|
|
991
991
|
return [...own, ...named.filter((file) => !imported.has(file))];
|
|
@@ -1145,7 +1145,7 @@ function fromPackage(root, dir, pkg, note = ignore, installed = false) {
|
|
|
1145
1145
|
for (const mapping of mappings) {
|
|
1146
1146
|
const file = path.resolve(root, mapping.target);
|
|
1147
1147
|
if (installed && isCompiledExport(dir, file)) continue;
|
|
1148
|
-
if (mapping.target.includes("*") || !SCRIPT_FILE$1.test(file) || !isFile(file)) {
|
|
1148
|
+
if (mapping.target.includes("*") || !SCRIPT_FILE$1.test(file) || !isFile$1(file)) {
|
|
1149
1149
|
add(mapping, COMPONENT_FILE.test(mapping.target));
|
|
1150
1150
|
continue;
|
|
1151
1151
|
}
|
|
@@ -1460,7 +1460,7 @@ function stylesheetResolver(root, { importPath } = {}) {
|
|
|
1460
1460
|
}
|
|
1461
1461
|
return designSystems.get(name);
|
|
1462
1462
|
};
|
|
1463
|
-
const stylesheet = (file, within) => [file, `${file}.css`].find((f) => f.endsWith(".css") && (within === void 0 || isInside(within, f) && !isBuildOutput(within, f)) && !/(?:^|[\\/])node_modules[\\/]/.test(within === void 0 ? f : path.relative(within, f)) && isFile(f));
|
|
1463
|
+
const stylesheet = (file, within) => [file, `${file}.css`].find((f) => f.endsWith(".css") && (within === void 0 || isInside(within, f) && !isBuildOutput(within, f)) && !/(?:^|[\\/])node_modules[\\/]/.test(within === void 0 ? f : path.relative(within, f)) && isFile$1(f));
|
|
1464
1464
|
return (specifier, fromFile) => {
|
|
1465
1465
|
if (/^(?:[a-z][\w+.-]*:|\/)/i.test(specifier)) return void 0;
|
|
1466
1466
|
const relative = stylesheet(path.resolve(path.dirname(fromFile), specifier), installedPackageOf(fromFile));
|
|
@@ -1491,7 +1491,7 @@ function installedStylesheet(dir, subpath) {
|
|
|
1491
1491
|
if (!match) return void 0;
|
|
1492
1492
|
const target = exportTargets(match.value, APP_CONDITIONS).map((t) => t.replaceAll("*", match.middle)).find((t) => t.endsWith(".css"));
|
|
1493
1493
|
const file = target === void 0 ? void 0 : path.resolve(dir, target);
|
|
1494
|
-
return file && isInside(dir, file) && !isBuildOutput(dir, file) && isFile(file) ? file : null;
|
|
1494
|
+
return file && isInside(dir, file) && !isBuildOutput(dir, file) && isFile$1(file) ? file : null;
|
|
1495
1495
|
}
|
|
1496
1496
|
/**
|
|
1497
1497
|
* The folder of `name` installed from a registry, when zero config reads it as a design system:
|
|
@@ -1521,12 +1521,15 @@ function installedPackageOf(file) {
|
|
|
1521
1521
|
function exportedFile(dir, subpath, accept) {
|
|
1522
1522
|
for (const { middle, value } of exportMatches(dir, subpath)) for (const target of exportTargets(value)) {
|
|
1523
1523
|
const file = path.resolve(dir, target.replaceAll("*", middle));
|
|
1524
|
-
if (isInside(dir, file) && accept(file) && isFile(file)) return file;
|
|
1524
|
+
if (isInside(dir, file) && accept(file) && isFile$1(file)) return file;
|
|
1525
1525
|
}
|
|
1526
1526
|
}
|
|
1527
1527
|
/**
|
|
1528
1528
|
* The entries of package `dir`'s `exports` that map `subpath`, with what their `*` stands for:
|
|
1529
|
-
* an exact subpath first, then the
|
|
1529
|
+
* an exact subpath first, then the patterns, as Node.js orders them (`PATTERN_KEY_COMPARE`): the
|
|
1530
|
+
* longest prefix before the `*` first, then the longest key, so `./components/*.js` comes before
|
|
1531
|
+
* `./components/*` for `./components/tip.js`. A pattern has one `*`, which stands for at least
|
|
1532
|
+
* one character.
|
|
1530
1533
|
*/
|
|
1531
1534
|
function exportMatches(dir, subpath) {
|
|
1532
1535
|
const exports = readJson$1(path.join(dir, "package.json"))?.exports;
|
|
@@ -1538,22 +1541,35 @@ function exportMatches(dir, subpath) {
|
|
|
1538
1541
|
if (key === subpath) matches.push({
|
|
1539
1542
|
middle: "",
|
|
1540
1543
|
value,
|
|
1541
|
-
rank: Infinity
|
|
1544
|
+
rank: Infinity,
|
|
1545
|
+
length: key.length
|
|
1542
1546
|
});
|
|
1543
1547
|
continue;
|
|
1544
1548
|
}
|
|
1549
|
+
if (key.lastIndexOf("*") !== star) continue;
|
|
1545
1550
|
const prefix = key.slice(0, star);
|
|
1546
1551
|
const suffix = key.slice(star + 1);
|
|
1547
|
-
if (subpath.startsWith(prefix) && subpath.endsWith(suffix) && subpath.length
|
|
1552
|
+
if (subpath.startsWith(prefix) && subpath.endsWith(suffix) && subpath.length > prefix.length + suffix.length) {
|
|
1548
1553
|
const middle = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
1549
1554
|
matches.push({
|
|
1550
1555
|
middle,
|
|
1551
1556
|
value,
|
|
1552
|
-
rank: prefix.length
|
|
1557
|
+
rank: prefix.length,
|
|
1558
|
+
length: key.length
|
|
1553
1559
|
});
|
|
1554
1560
|
}
|
|
1555
1561
|
}
|
|
1556
|
-
return matches.sort((a, b) => b.rank - a.rank);
|
|
1562
|
+
return matches.sort((a, b) => b.rank - a.rank || b.length - a.length);
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* The targets package `dir`'s `exports` map `subpath` (`./components/tooltip`) to, as written:
|
|
1566
|
+
* through the entry Node.js picks (its exact subpath, else the most specific pattern) and every
|
|
1567
|
+
* condition but `types`, with `*` filled in. Undefined when no entry maps the subpath; none when
|
|
1568
|
+
* the entry blocks it (`null`).
|
|
1569
|
+
*/
|
|
1570
|
+
function exportedTargets(dir, subpath) {
|
|
1571
|
+
const [match] = exportMatches(dir, subpath);
|
|
1572
|
+
return match && exportTargets(match.value).map((t) => t.replaceAll("*", match.middle));
|
|
1557
1573
|
}
|
|
1558
1574
|
/** Every target of an export condition map, in order, but its types, or those of `conditions` alone. */
|
|
1559
1575
|
function exportTargets(value, conditions) {
|
|
@@ -1603,7 +1619,7 @@ function declaredConfig(dir, pkg = readJson$1(path.join(dir, "package.json"))) {
|
|
|
1603
1619
|
if (typeof value !== "string" || !value.endsWith(".json")) return { problem: `${field} is ${JSON.stringify(value)}: it names a JSON config file in the package, such as "./onsystem.config.json".` };
|
|
1604
1620
|
const file = path.resolve(dir, value);
|
|
1605
1621
|
if (!isInside(dir, file) || file === path.resolve(dir)) return { problem: `${field} names ${JSON.stringify(value)}, which is outside the package.` };
|
|
1606
|
-
if (!isFile(file)) return { problem: `${field} names ${JSON.stringify(value)}, which does not exist.` };
|
|
1622
|
+
if (!isFile$1(file)) return { problem: `${field} names ${JSON.stringify(value)}, which does not exist.` };
|
|
1607
1623
|
return { file };
|
|
1608
1624
|
}
|
|
1609
1625
|
/**
|
|
@@ -1722,7 +1738,7 @@ function scopeOf$1(name) {
|
|
|
1722
1738
|
function declaresTypes(dir, pkg) {
|
|
1723
1739
|
if (typeof pkg.types === "string" || typeof pkg.typings === "string") return true;
|
|
1724
1740
|
const hasTypes = (value) => Array.isArray(value) ? value.some(hasTypes) : value !== null && typeof value === "object" && Object.entries(value).some(([key, nested]) => key === "types" || hasTypes(nested));
|
|
1725
|
-
return hasTypes(pkg.exports) || isFile(path.join(dir, "index.d.ts"));
|
|
1741
|
+
return hasTypes(pkg.exports) || isFile$1(path.join(dir, "index.d.ts"));
|
|
1726
1742
|
}
|
|
1727
1743
|
/** Files that hold no component to read: declarations, tests and stories, as `exclude` has them. */
|
|
1728
1744
|
const NOT_COMPONENT_SOURCES = [
|
|
@@ -2061,7 +2077,7 @@ function readJson$1(file) {
|
|
|
2061
2077
|
function asRecord(value) {
|
|
2062
2078
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2063
2079
|
}
|
|
2064
|
-
function isFile(file) {
|
|
2080
|
+
function isFile$1(file) {
|
|
2065
2081
|
try {
|
|
2066
2082
|
return fs.statSync(file).isFile();
|
|
2067
2083
|
} catch {
|
|
@@ -8130,21 +8146,29 @@ function toDesignMd(tokens, options) {
|
|
|
8130
8146
|
const list = tokens.filter((t) => t.category === section.category);
|
|
8131
8147
|
if (!list.length) continue;
|
|
8132
8148
|
if (section.key) {
|
|
8133
|
-
const values =
|
|
8149
|
+
const values = /* @__PURE__ */ new Map();
|
|
8150
|
+
let steps;
|
|
8134
8151
|
for (const token of list) {
|
|
8152
|
+
if (isSpacingUnit(token)) {
|
|
8153
|
+
steps = spacingSteps(token, lookup);
|
|
8154
|
+
continue;
|
|
8155
|
+
}
|
|
8135
8156
|
const key = keys.get(token);
|
|
8136
8157
|
if (key === void 0) continue;
|
|
8137
8158
|
const target = token.aliasOf ? byName.get(token.aliasOf) : void 0;
|
|
8138
|
-
const targetKey = target?.category === token.category && frontMatterValue(target, section.key, lookup) !== void 0 ? keys.get(target) : void 0;
|
|
8159
|
+
const targetKey = section.key !== "typography" && target?.category === token.category && !isSpacingUnit(target) && frontMatterValue(target, section.key, lookup) !== void 0 ? keys.get(target) : void 0;
|
|
8139
8160
|
const value = targetKey === void 0 ? frontMatterValue(token, section.key, lookup) : `{${section.key}.${targetKey}}`;
|
|
8140
8161
|
if (value === void 0) continue;
|
|
8141
|
-
if (key
|
|
8162
|
+
if (values.has(key)) {
|
|
8142
8163
|
warnings.push(`${token.name} is left out of the front matter: another token has its key`);
|
|
8143
8164
|
continue;
|
|
8144
8165
|
}
|
|
8145
|
-
values
|
|
8166
|
+
values.set(key, value);
|
|
8146
8167
|
}
|
|
8147
|
-
if (
|
|
8168
|
+
for (const [key, value] of steps ?? []) if (!values.has(key)) values.set(key, value);
|
|
8169
|
+
const step = (key) => Number.isFinite(Number(key)) ? Number(key) : Infinity;
|
|
8170
|
+
const ordered = steps ? new Map([...values].sort(([a], [b]) => step(a) - step(b) || 0)) : values;
|
|
8171
|
+
if (ordered.size) sections[section.key] = ordered;
|
|
8148
8172
|
}
|
|
8149
8173
|
body.push("", `## ${section.heading}`, "", section.intro, "", ...table(list, keys));
|
|
8150
8174
|
}
|
|
@@ -8164,6 +8188,59 @@ function designKeys(tokens) {
|
|
|
8164
8188
|
}
|
|
8165
8189
|
return out;
|
|
8166
8190
|
}
|
|
8191
|
+
/** Tailwind's spacing unit, `--spacing`, which `p-4` takes 4 times. */
|
|
8192
|
+
function isSpacingUnit(token) {
|
|
8193
|
+
return token.category === "spacing" && token.tailwind === "";
|
|
8194
|
+
}
|
|
8195
|
+
/** The steps of Tailwind's default spacing scale, `p-0.5` to `p-96`, in spacing units. */
|
|
8196
|
+
const SPACING_STEPS = [
|
|
8197
|
+
.5,
|
|
8198
|
+
1,
|
|
8199
|
+
1.5,
|
|
8200
|
+
2,
|
|
8201
|
+
2.5,
|
|
8202
|
+
3,
|
|
8203
|
+
3.5,
|
|
8204
|
+
4,
|
|
8205
|
+
5,
|
|
8206
|
+
6,
|
|
8207
|
+
7,
|
|
8208
|
+
8,
|
|
8209
|
+
9,
|
|
8210
|
+
10,
|
|
8211
|
+
11,
|
|
8212
|
+
12,
|
|
8213
|
+
14,
|
|
8214
|
+
16,
|
|
8215
|
+
20,
|
|
8216
|
+
24,
|
|
8217
|
+
28,
|
|
8218
|
+
32,
|
|
8219
|
+
36,
|
|
8220
|
+
40,
|
|
8221
|
+
44,
|
|
8222
|
+
48,
|
|
8223
|
+
52,
|
|
8224
|
+
56,
|
|
8225
|
+
60,
|
|
8226
|
+
64,
|
|
8227
|
+
72,
|
|
8228
|
+
80,
|
|
8229
|
+
96
|
|
8230
|
+
];
|
|
8231
|
+
/**
|
|
8232
|
+
* Tailwind's spacing unit as the steps it makes: `"4": 1rem` for `p-4`. A DESIGN.md has no
|
|
8233
|
+
* multiplier: a reader takes each spacing entry as a step, so the unit alone (`base: 0.25rem`)
|
|
8234
|
+
* would make 4px the only one.
|
|
8235
|
+
*/
|
|
8236
|
+
function spacingSteps(token, lookup) {
|
|
8237
|
+
const plain = PLAIN_LENGTH.exec(token.value.trim());
|
|
8238
|
+
const [amount, unit] = plain ? [Number(plain[1]), plain[2] ?? "px"] : [evaluateLength(token.value, lookup), "px"];
|
|
8239
|
+
const steps = /* @__PURE__ */ new Map();
|
|
8240
|
+
if (amount === void 0 || !Number.isFinite(amount) || amount <= 0) return steps;
|
|
8241
|
+
for (const n of SPACING_STEPS) steps.set(String(n), `${round(n * amount)}${unit}`);
|
|
8242
|
+
return steps;
|
|
8243
|
+
}
|
|
8167
8244
|
function frontMatterValue(token, key, lookup) {
|
|
8168
8245
|
const value = token.value.trim();
|
|
8169
8246
|
switch (key) {
|
|
@@ -8243,6 +8320,7 @@ async function loadTokens(root, sources) {
|
|
|
8243
8320
|
const warnings = [];
|
|
8244
8321
|
const all = [];
|
|
8245
8322
|
const sheets = [];
|
|
8323
|
+
const sheetFiles = [];
|
|
8246
8324
|
let sheetsAt;
|
|
8247
8325
|
for (const source of sources) {
|
|
8248
8326
|
const rel = relativePath(root, source.file);
|
|
@@ -8266,6 +8344,7 @@ async function loadTokens(root, sources) {
|
|
|
8266
8344
|
warnings.push(...result.warnings);
|
|
8267
8345
|
} else {
|
|
8268
8346
|
sheets.push(readCssSheet(text, rel));
|
|
8347
|
+
sheetFiles.push(rel);
|
|
8269
8348
|
sheetsAt ??= all.length;
|
|
8270
8349
|
}
|
|
8271
8350
|
} catch (error) {
|
|
@@ -8273,6 +8352,9 @@ async function loadTokens(root, sources) {
|
|
|
8273
8352
|
}
|
|
8274
8353
|
}
|
|
8275
8354
|
if (sheets.length) {
|
|
8355
|
+
const partial = sheets.findIndex((s) => s.theme.size > 0 || s.resets.size > 0);
|
|
8356
|
+
const sheet = sheets[partial];
|
|
8357
|
+
if (sheet && !sheets.some((s) => s.tailwind) && await runsTailwindV4(root)) sheet.tailwind = sheetFiles[partial];
|
|
8276
8358
|
const result = cssSheetTokens(sheets);
|
|
8277
8359
|
all.splice(sheetsAt ?? all.length, 0, ...result.tokens);
|
|
8278
8360
|
warnings.push(...result.warnings);
|
|
@@ -8282,24 +8364,65 @@ async function loadTokens(root, sources) {
|
|
|
8282
8364
|
warnings
|
|
8283
8365
|
};
|
|
8284
8366
|
}
|
|
8367
|
+
/** The packages that run Tailwind CSS v4 in a build: PostCSS's, Vite's and its CLI. */
|
|
8368
|
+
const TAILWIND_V4_PACKAGES = [
|
|
8369
|
+
"@tailwindcss/postcss",
|
|
8370
|
+
"@tailwindcss/vite",
|
|
8371
|
+
"@tailwindcss/cli"
|
|
8372
|
+
];
|
|
8373
|
+
/**
|
|
8374
|
+
* Whether the project at `root` runs Tailwind CSS v4, whose default theme has a spacing unit and
|
|
8375
|
+
* the radius scale up to `rounded-4xl`: its package.json depends on a package that runs v4, or on
|
|
8376
|
+
* `tailwindcss` in a range that is not v3's (`^3.4.1`, `~3.4`, `3.x`), which has neither. Its
|
|
8377
|
+
* plugins (`@tailwindcss/typography`) say nothing of the version.
|
|
8378
|
+
*/
|
|
8379
|
+
async function runsTailwindV4(root) {
|
|
8380
|
+
let pkg;
|
|
8381
|
+
try {
|
|
8382
|
+
pkg = JSON.parse(await fsp.readFile(path.join(root, "package.json"), "utf8"));
|
|
8383
|
+
} catch {
|
|
8384
|
+
return false;
|
|
8385
|
+
}
|
|
8386
|
+
if (typeof pkg !== "object" || pkg === null) return false;
|
|
8387
|
+
const lists = [];
|
|
8388
|
+
for (const field of [
|
|
8389
|
+
"dependencies",
|
|
8390
|
+
"devDependencies",
|
|
8391
|
+
"peerDependencies"
|
|
8392
|
+
]) {
|
|
8393
|
+
const dependencies = pkg[field];
|
|
8394
|
+
if (typeof dependencies === "object" && dependencies !== null) lists.push(dependencies);
|
|
8395
|
+
}
|
|
8396
|
+
if (lists.some((list) => TAILWIND_V4_PACKAGES.some((name) => Object.hasOwn(list, name)))) return true;
|
|
8397
|
+
const declared = lists.find((list) => Object.hasOwn(list, "tailwindcss"));
|
|
8398
|
+
return declared !== void 0 && !beforeV4(declared.tailwindcss);
|
|
8399
|
+
}
|
|
8400
|
+
/** A range of Tailwind CSS v3 or older in package.json: `^3.4.1`, `~3`, `3.x`, `^2 || ^3`. */
|
|
8401
|
+
function beforeV4(range) {
|
|
8402
|
+
return typeof range === "string" && range.split("||").every((alternative) => /^(?:npm:tailwindcss@)?[\^~=v]*\s*[0-3](?:\.|$)/.test(alternative.trim()));
|
|
8403
|
+
}
|
|
8285
8404
|
/**
|
|
8286
8405
|
* DTCG files and the CSS generated from them often describe the same tokens.
|
|
8287
8406
|
* Merge entries that share a custom property: keep the DTCG name and
|
|
8288
|
-
* description, and add the Tailwind mapping from CSS.
|
|
8407
|
+
* description, and add the Tailwind mapping from CSS. A token without one (a
|
|
8408
|
+
* `@theme inline` value, `rounded-sm`) merges with the token of its name and
|
|
8409
|
+
* Tailwind key, such as the one a DTCG file exported from the stylesheet has.
|
|
8289
8410
|
*/
|
|
8290
8411
|
function mergeTokens(tokens) {
|
|
8291
8412
|
const overridden = new Set(tokens.filter((t) => t.origin !== "tailwind-default").map((t) => themeKey(t)));
|
|
8292
|
-
const
|
|
8413
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
8293
8414
|
const out = [];
|
|
8294
8415
|
for (const token of tokens) {
|
|
8295
8416
|
if (token.origin === "tailwind-default" && overridden.has(themeKey(token))) continue;
|
|
8296
|
-
const
|
|
8417
|
+
const key = token.cssVar ?? (token.tailwind === void 0 ? void 0 : `${token.name}:${token.tailwind}`);
|
|
8418
|
+
const existing = key === void 0 ? void 0 : byKey.get(key);
|
|
8297
8419
|
if (!existing) {
|
|
8298
|
-
if (
|
|
8420
|
+
if (key !== void 0) byKey.set(key, token);
|
|
8299
8421
|
out.push(token);
|
|
8300
8422
|
continue;
|
|
8301
8423
|
}
|
|
8302
8424
|
if (existing.tailwind === void 0 && token.tailwind !== void 0) existing.tailwind = token.tailwind;
|
|
8425
|
+
if (existing.category === "other" && token.category !== "other") existing.category = token.category;
|
|
8303
8426
|
existing.usage = [.../* @__PURE__ */ new Set([...token.usage, ...existing.usage])];
|
|
8304
8427
|
existing.description ??= token.description;
|
|
8305
8428
|
if (token.modes) existing.modes = {
|
|
@@ -8976,6 +9099,8 @@ var LintTarget = class {
|
|
|
8976
9099
|
sources;
|
|
8977
9100
|
/** Published libraries the model read from type declarations: `@mui/material`. */
|
|
8978
9101
|
libraries;
|
|
9102
|
+
/** The name in each package.json read, by its path: undefined where there is none. */
|
|
9103
|
+
manifests = /* @__PURE__ */ new Map();
|
|
8979
9104
|
/**
|
|
8980
9105
|
* `resolver` finds the module an import points at and what it exports
|
|
8981
9106
|
* (`@calcom/ui/components/icon` → `components/icon/index.ts`), so a name from
|
|
@@ -9052,14 +9177,49 @@ var LintTarget = class {
|
|
|
9052
9177
|
* model left out rather than an invented one: its module exists outside the
|
|
9053
9178
|
* folders extraction read and exports `name`, or re-exports from such a
|
|
9054
9179
|
* module (an excluded `icons/` folder, a barrel's `export * from "./icons"`).
|
|
9055
|
-
* A module declared in a package's `exports` but not on disk counts too
|
|
9056
|
-
* except the design system's own import path
|
|
9180
|
+
* A module declared in a package's `exports` but not on disk counts too (built to `dist/`,
|
|
9181
|
+
* not built yet), except the design system's own import path, and one whose export, as the
|
|
9182
|
+
* package.json writes it, leads to a source file only: `@acme/ui/components/tooltip` is
|
|
9183
|
+
* `src/components/tooltip.tsx` through `"./components/*": "./src/components/*.tsx"`, and with
|
|
9184
|
+
* no such file it does not exist.
|
|
9057
9185
|
*/
|
|
9058
9186
|
outsideModel(specifier, name, fromFile = "snippet.tsx") {
|
|
9059
9187
|
const location = this.resolver?.locate(specifier, fromFile);
|
|
9060
9188
|
if (!location) return false;
|
|
9061
|
-
if (
|
|
9062
|
-
|
|
9189
|
+
if (location.file) return this.mayExport(location.file, name, 0);
|
|
9190
|
+
if (this.importPaths.has(specifier) || specifier === this.config.importPath) return false;
|
|
9191
|
+
const source = this.exportedSource(specifier);
|
|
9192
|
+
return source === void 0 || this.mayExport(source, name, 0);
|
|
9193
|
+
}
|
|
9194
|
+
/**
|
|
9195
|
+
* The module a design-system package's `exports` lead `specifier` to, relative to the root, as
|
|
9196
|
+
* its package.json writes them: the first of the entry's targets that is on disk, else, when
|
|
9197
|
+
* each of them is a source file, the first (which does not exist). Undefined when a target
|
|
9198
|
+
* leads to a build folder (`"./*": "./dist/components/*.js"`, maybe not built yet, whose
|
|
9199
|
+
* sources may be anywhere), the entry blocks the subpath (`null`), or no entry maps it.
|
|
9200
|
+
*/
|
|
9201
|
+
exportedSource(specifier) {
|
|
9202
|
+
const name = packageOf(specifier);
|
|
9203
|
+
const led = this.config.imports?.find((m) => packageOf(m.specifier) === name);
|
|
9204
|
+
const dir = led && this.packageDir(path.resolve(this.model.root, led.target), name);
|
|
9205
|
+
const targets = dir ? exportedTargets(dir, `.${specifier.slice(name.length)}`) : void 0;
|
|
9206
|
+
if (!dir || !targets?.length) return void 0;
|
|
9207
|
+
const files = targets.map((target) => path.resolve(dir, target));
|
|
9208
|
+
const file = files.flatMap((f) => f.endsWith(".jsx") ? [f, `${f.slice(0, -4)}.tsx`] : [f]).find((f) => isInside(dir, f) && isFile(f)) ?? (targets.every(isSourceFile) ? files[0] : void 0);
|
|
9209
|
+
return file && relativePath(this.model.root, file);
|
|
9210
|
+
}
|
|
9211
|
+
/**
|
|
9212
|
+
* The folder of package `name` that `file` is in: the nearest package.json above it with a
|
|
9213
|
+
* name, when that name is `name`. One without a name (`{"type": "module"}` in a subfolder) is
|
|
9214
|
+
* no package's. Each package.json is read once.
|
|
9215
|
+
*/
|
|
9216
|
+
packageDir(file, name) {
|
|
9217
|
+
for (let dir = path.dirname(file); dir !== path.dirname(dir); dir = path.dirname(dir)) {
|
|
9218
|
+
const manifest = path.join(dir, "package.json");
|
|
9219
|
+
if (!this.manifests.has(manifest)) this.manifests.set(manifest, manifestName(manifest));
|
|
9220
|
+
const found = this.manifests.get(manifest);
|
|
9221
|
+
if (found !== void 0) return found === name ? dir : void 0;
|
|
9222
|
+
}
|
|
9063
9223
|
}
|
|
9064
9224
|
/**
|
|
9065
9225
|
* The component a JSX tag means when `name` is imported from `specifier`, among the
|
|
@@ -9236,6 +9396,30 @@ function fit(component, element) {
|
|
|
9236
9396
|
function isPackageName(specifier) {
|
|
9237
9397
|
return specifier.startsWith("@") ? /^@[^/]+\/[^/]+$/.test(specifier) : /^[a-z0-9][^/]*$/i.test(specifier);
|
|
9238
9398
|
}
|
|
9399
|
+
/** The name a package.json gives its package; undefined when it has none, or there is none. */
|
|
9400
|
+
function manifestName(manifest) {
|
|
9401
|
+
try {
|
|
9402
|
+
const { name } = JSON.parse(fs.readFileSync(manifest, "utf8")) ?? {};
|
|
9403
|
+
return typeof name === "string" && name ? name : void 0;
|
|
9404
|
+
} catch {
|
|
9405
|
+
return;
|
|
9406
|
+
}
|
|
9407
|
+
}
|
|
9408
|
+
function isFile(file) {
|
|
9409
|
+
return fs.statSync(file, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
9410
|
+
}
|
|
9411
|
+
/** The package an import specifier names: `@acme/ui` for `@acme/ui/components/button`. */
|
|
9412
|
+
function packageOf(specifier) {
|
|
9413
|
+
return specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
|
|
9414
|
+
}
|
|
9415
|
+
/**
|
|
9416
|
+
* An export target that is a TypeScript or JSX source file (`./src/components/tooltip.tsx`), not
|
|
9417
|
+
* a declaration file or a file in a build folder (`./dist/tooltip.tsx`, not built yet).
|
|
9418
|
+
*/
|
|
9419
|
+
function isSourceFile(target) {
|
|
9420
|
+
if (/\.d\.[cm]?ts$/.test(target) || /^(?:\.\/)?(?:dist|build|lib|out|esm|cjs)\//.test(target)) return false;
|
|
9421
|
+
return /\.(?:[cm]?tsx?|jsx)$/.test(target);
|
|
9422
|
+
}
|
|
9239
9423
|
function stripExtension(file) {
|
|
9240
9424
|
return file.replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
9241
9425
|
}
|
|
@@ -12124,7 +12308,7 @@ function isObject(value) {
|
|
|
12124
12308
|
// package.json
|
|
12125
12309
|
var name = "onsystem";
|
|
12126
12310
|
// src/version.ts
|
|
12127
|
-
const VERSION = "0.
|
|
12311
|
+
const VERSION = "0.11.0";
|
|
12128
12312
|
const NAME = name;
|
|
12129
12313
|
// src/lint/sarif.ts
|
|
12130
12314
|
const SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";
|
package/dist/eslint-worker.d.ts
CHANGED
|
@@ -31,4 +31,6 @@ export interface Call {
|
|
|
31
31
|
signal: Int32Array;
|
|
32
32
|
port: MessagePort;
|
|
33
33
|
}
|
|
34
|
+
/** Resolves when the looks under way have ended. Nothing waits on them but tests. */
|
|
35
|
+
export declare function looking(): Promise<unknown>;
|
|
34
36
|
export declare function load(request: LoadRequest): Promise<LoadResponse>;
|
package/dist/eslint-worker.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { At as relativePath, i as componentFiles, ot as excludedBy, r as buildModel } from "./design-system-
|
|
2
|
-
import { r as loadTarget } from "./workspace-
|
|
1
|
+
import { At as relativePath, a as fingerprint, i as componentFiles, ot as excludedBy, r as buildModel } from "./design-system-Csqts7Eq.js";
|
|
2
|
+
import { r as loadTarget } from "./workspace-Dbxubo9n.js";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { parentPort } from "node:worker_threads";
|
|
@@ -8,13 +9,25 @@ import { parentPort } from "node:worker_threads";
|
|
|
8
9
|
* The ESLint plugin's loader, in a worker thread. ESLint rules run synchronously, and finding a
|
|
9
10
|
* project's design system does not (config files written in code, globs, the extraction
|
|
10
11
|
* cache), so the plugin asks this worker and waits for the answer (see `bridge.ts`).
|
|
12
|
+
*
|
|
13
|
+
* The worker keeps what it loaded and answers from it at once. Once that is two seconds old, the
|
|
14
|
+
* next lint starts a look at the project again (its config, then its design system's files) in
|
|
15
|
+
* the background, and the lints after the look get what it found. Waiting for the look instead
|
|
16
|
+
* held up every lint after a pause in an editor for as long as the look took, which grows with
|
|
17
|
+
* the design system.
|
|
11
18
|
*/
|
|
12
19
|
/** What the configs said (a design-system package's skipped, or its paths ignored), each said once. */
|
|
13
20
|
const warned = /* @__PURE__ */ new Set();
|
|
14
|
-
/** How long a
|
|
21
|
+
/** How long what a look found is used before a lint starts the next look. */
|
|
15
22
|
const FRESH_MS = 2e3;
|
|
23
|
+
/** By where ESLint runs and its settings. */
|
|
16
24
|
const targets = /* @__PURE__ */ new Map();
|
|
25
|
+
/**
|
|
26
|
+
* By target and project root: two targets can reach the same project with configs of their own
|
|
27
|
+
* (runs from two folders, two ESLint configs), and neither may be answered with the other's.
|
|
28
|
+
*/
|
|
17
29
|
const projects = /* @__PURE__ */ new Map();
|
|
30
|
+
const looks = /* @__PURE__ */ new Set();
|
|
18
31
|
function realPath(file) {
|
|
19
32
|
try {
|
|
20
33
|
return fs.realpathSync.native(file);
|
|
@@ -22,46 +35,122 @@ function realPath(file) {
|
|
|
22
35
|
return file;
|
|
23
36
|
}
|
|
24
37
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cwd,
|
|
28
|
-
root,
|
|
29
|
-
config
|
|
30
|
-
]);
|
|
31
|
-
const cached = targets.get(key);
|
|
32
|
-
if (cached && Date.now() - cached.at < FRESH_MS) return cached.target;
|
|
33
|
-
const target = loadTarget({
|
|
38
|
+
function loadTargetFor({ cwd, root, config }) {
|
|
39
|
+
return loadTarget({
|
|
34
40
|
cwd,
|
|
35
41
|
root: root === void 0 ? void 0 : path.resolve(cwd, root),
|
|
36
42
|
config: config === void 0 ? void 0 : path.resolve(cwd, config)
|
|
37
43
|
});
|
|
38
|
-
|
|
44
|
+
}
|
|
45
|
+
function keep(target) {
|
|
46
|
+
target.catch(() => void 0);
|
|
47
|
+
return {
|
|
39
48
|
at: Date.now(),
|
|
40
49
|
target
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The config a file is checked with: its own project's, from a monorepo root. */
|
|
53
|
+
async function configFor(target, file) {
|
|
54
|
+
return target.workspace ? (await target.workspace.projectFor(file)).config : target.config;
|
|
55
|
+
}
|
|
56
|
+
function versionOf(key, config) {
|
|
57
|
+
return createHash("sha256").update(key).update(JSON.stringify(config)).digest("hex");
|
|
58
|
+
}
|
|
59
|
+
async function build(config) {
|
|
60
|
+
const { model, key = String(Date.now()), dependencies = [] } = await buildModel(config, { cache: true });
|
|
61
|
+
const own = new Set((await componentFiles(config)).map(realPath));
|
|
62
|
+
return {
|
|
63
|
+
at: Date.now(),
|
|
64
|
+
key,
|
|
65
|
+
dependencies,
|
|
66
|
+
version: versionOf(key, config),
|
|
67
|
+
config,
|
|
68
|
+
model,
|
|
69
|
+
own
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* `project` for `config` as the files are now: the same model when nothing it is built from has
|
|
74
|
+
* changed (a config edit that only changes rules, or no change at all), else a new build.
|
|
75
|
+
*/
|
|
76
|
+
async function rebuild(project, config) {
|
|
77
|
+
if (await fingerprint(config, project.dependencies) !== project.key) return build(config);
|
|
78
|
+
const { key, dependencies, model, own } = project;
|
|
79
|
+
return {
|
|
80
|
+
at: Date.now(),
|
|
81
|
+
key,
|
|
82
|
+
dependencies,
|
|
83
|
+
version: versionOf(key, config),
|
|
84
|
+
config,
|
|
85
|
+
model,
|
|
86
|
+
own
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Runs a look in the background, held in `looks` until it ends. It starts on a later turn of the
|
|
91
|
+
* event loop, after the lint that started it has its answer: the start of a look (finding the
|
|
92
|
+
* project, reading its config, listing the design system's files) runs synchronously, and run at
|
|
93
|
+
* once it held up that answer for as long.
|
|
94
|
+
*/
|
|
95
|
+
function background(look) {
|
|
96
|
+
const running = new Promise((resolve) => setImmediate(resolve)).then(look).catch(() => void 0).finally(() => looks.delete(running));
|
|
97
|
+
looks.add(running);
|
|
98
|
+
return running;
|
|
99
|
+
}
|
|
100
|
+
function projectKey(key, config) {
|
|
101
|
+
return JSON.stringify([key, config.root]);
|
|
102
|
+
}
|
|
103
|
+
/** A build that fails drops the project, so that the next lint builds it again and says why. */
|
|
104
|
+
function lookAtProject(slot, project, config) {
|
|
105
|
+
project.looking = background(async () => {
|
|
106
|
+
try {
|
|
107
|
+
projects.set(slot, await rebuild(project, config));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (projects.get(slot) === project) projects.delete(slot);
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return project.looking;
|
|
114
|
+
}
|
|
115
|
+
function lookAtTarget(key, kept, request) {
|
|
116
|
+
kept.looking = background(async () => {
|
|
117
|
+
const loading = loadTargetFor(request);
|
|
118
|
+
await loading.catch(() => void 0);
|
|
119
|
+
targets.set(key, keep(loading));
|
|
120
|
+
const config = await configFor(await loading, request.file);
|
|
121
|
+
const slot = projectKey(key, config);
|
|
122
|
+
const project = projects.get(slot);
|
|
123
|
+
if (project && !project.looking) await lookAtProject(slot, project, config);
|
|
41
124
|
});
|
|
42
|
-
return
|
|
125
|
+
return kept.looking;
|
|
126
|
+
}
|
|
127
|
+
/** Resolves when the looks under way have ended. Nothing waits on them but tests. */
|
|
128
|
+
function looking() {
|
|
129
|
+
return Promise.all(looks);
|
|
43
130
|
}
|
|
44
131
|
async function load(request) {
|
|
45
|
-
const
|
|
46
|
-
|
|
132
|
+
const key = JSON.stringify([
|
|
133
|
+
request.cwd,
|
|
134
|
+
request.root,
|
|
135
|
+
request.config
|
|
136
|
+
]);
|
|
137
|
+
let kept = targets.get(key);
|
|
138
|
+
if (!kept) {
|
|
139
|
+
kept = keep(loadTargetFor(request));
|
|
140
|
+
targets.set(key, kept);
|
|
141
|
+
} else if (!kept.looking && Date.now() - kept.at >= FRESH_MS) lookAtTarget(key, kept, request);
|
|
142
|
+
const config = await configFor(await kept.target, request.file);
|
|
47
143
|
for (const text of config.warnings ?? []) {
|
|
48
144
|
if (warned.has(text)) continue;
|
|
49
145
|
warned.add(text);
|
|
50
146
|
process.stderr.write(`onsystem: ${text}\n`);
|
|
51
147
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
project
|
|
57
|
-
|
|
58
|
-
version: key ?? String(Date.now()),
|
|
59
|
-
config,
|
|
60
|
-
model,
|
|
61
|
-
own
|
|
62
|
-
};
|
|
63
|
-
projects.set(config.root, project);
|
|
64
|
-
}
|
|
148
|
+
const slot = projectKey(key, config);
|
|
149
|
+
let project = projects.get(slot);
|
|
150
|
+
if (!project) {
|
|
151
|
+
project = await build(config);
|
|
152
|
+
projects.set(slot, project);
|
|
153
|
+
} else if (!kept.looking && !project.looking && (project.config !== config || Date.now() - project.at >= FRESH_MS)) lookAtProject(slot, project, config);
|
|
65
154
|
const relative = relativePath(config.root, request.file);
|
|
66
155
|
const excluded = excludedBy(config, relative, { includeTests: true });
|
|
67
156
|
if (excluded) return { skip: `excluded by "${excluded}"` };
|
|
@@ -89,4 +178,4 @@ parentPort?.on("message", ({ request, signal, port }) => {
|
|
|
89
178
|
reply({ error: error.message });
|
|
90
179
|
});
|
|
91
180
|
});
|
|
92
|
-
export { load };
|
|
181
|
+
export { load, looking };
|
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-
|
|
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-Csqts7Eq.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { MessageChannel, Worker, receiveMessageOnPort } from "node:worker_threads";
|
|
4
4
|
// src/eslint/bridge.ts
|
|
@@ -51,7 +51,8 @@ function loadSync(request) {
|
|
|
51
51
|
* working directory), with the project's config: its `rules` and `overrides` turn rules off
|
|
52
52
|
* per file, `// onsystem-disable-*` comments suppress findings, and the files `check .` leaves
|
|
53
53
|
* out (the config's `exclude`, the design system's own components) are not checked. ESLint's
|
|
54
|
-
* config sets each rule's severity.
|
|
54
|
+
* config sets each rule's severity, and can set a rule's options (`allow`) over the project's.
|
|
55
|
+
* `onsystem/suppression` reports a misspelled rule in a suppression comment, as check does.
|
|
55
56
|
*/
|
|
56
57
|
const RULES_PAGE = "https://onsystem.vercel.app/rules";
|
|
57
58
|
/** Design systems by project root, at the version the loader last reported. */
|
|
@@ -101,7 +102,25 @@ function run(cwd, file, text, settings) {
|
|
|
101
102
|
if (result.skipped) return { skipped: true };
|
|
102
103
|
return {
|
|
103
104
|
result,
|
|
104
|
-
fromSystem: (specifier) => ds.lint.isDesignSystemImport(specifier, relative)
|
|
105
|
+
fromSystem: (specifier) => ds.lint.isDesignSystemImport(specifier, relative),
|
|
106
|
+
checkWith(id, options) {
|
|
107
|
+
const own = rulesFor(ds.config, relative)[id];
|
|
108
|
+
const off = {
|
|
109
|
+
severity: "off",
|
|
110
|
+
options: {}
|
|
111
|
+
};
|
|
112
|
+
const rules = Object.fromEntries(RULE_IDS.map((rule) => [rule, rule === id ? {
|
|
113
|
+
...own,
|
|
114
|
+
options: {
|
|
115
|
+
...own.options,
|
|
116
|
+
...options
|
|
117
|
+
}
|
|
118
|
+
} : off]));
|
|
119
|
+
return checkSource(text, ds.lint, {
|
|
120
|
+
filename: relative,
|
|
121
|
+
rules
|
|
122
|
+
});
|
|
123
|
+
}
|
|
105
124
|
};
|
|
106
125
|
}
|
|
107
126
|
/**
|
|
@@ -153,27 +172,45 @@ function typeOnly(def) {
|
|
|
153
172
|
const kind = (node) => node?.importKind;
|
|
154
173
|
return def.type === "ImportBinding" && (kind(def.node) === "type" || kind(def.parent) === "type");
|
|
155
174
|
}
|
|
175
|
+
/** A rule's options in ESLint's config, as in onsystem.config.json: `['error', { allow: ['#fff'] }]`. */
|
|
176
|
+
const OPTIONS_SCHEMA = [{
|
|
177
|
+
type: "object",
|
|
178
|
+
properties: { allow: {
|
|
179
|
+
type: "array",
|
|
180
|
+
items: { type: "string" }
|
|
181
|
+
} },
|
|
182
|
+
additionalProperties: false
|
|
183
|
+
}];
|
|
184
|
+
/**
|
|
185
|
+
* Check's misspelled rule names in `// onsystem-disable-*` comments, which suppress nothing. A rule
|
|
186
|
+
* of its own, so that it is a warning, as check reports it, and can be turned off like the others.
|
|
187
|
+
*/
|
|
188
|
+
const SUPPRESSION = "suppression";
|
|
156
189
|
function createRule(id, description) {
|
|
190
|
+
const suppression = id === SUPPRESSION;
|
|
157
191
|
return {
|
|
158
192
|
meta: {
|
|
159
193
|
type: "problem",
|
|
160
194
|
docs: {
|
|
161
195
|
description,
|
|
162
|
-
url: `${RULES_PAGE}#${id}`
|
|
196
|
+
url: `${RULES_PAGE}#${suppression ? "suppressing-findings" : id}`
|
|
197
|
+
},
|
|
198
|
+
...suppression ? {} : {
|
|
199
|
+
fixable: "code",
|
|
200
|
+
hasSuggestions: true
|
|
163
201
|
},
|
|
164
|
-
|
|
165
|
-
hasSuggestions: true,
|
|
166
|
-
schema: []
|
|
202
|
+
schema: suppression ? [] : OPTIONS_SCHEMA
|
|
167
203
|
},
|
|
168
204
|
create(context) {
|
|
169
205
|
const file = path.resolve(context.cwd, context.filename);
|
|
170
206
|
const settings = context.settings.onsystem ?? {};
|
|
207
|
+
const options = context.options?.[0];
|
|
171
208
|
return { "Program:exit"(node) {
|
|
172
209
|
const pass = passFor(context, file, settings);
|
|
173
210
|
const { outcome } = pass;
|
|
174
211
|
if ("skipped" in outcome) return;
|
|
175
212
|
if ("error" in outcome) {
|
|
176
|
-
if (pass.reported) return;
|
|
213
|
+
if (suppression || pass.reported) return;
|
|
177
214
|
pass.reported = true;
|
|
178
215
|
context.report({
|
|
179
216
|
node,
|
|
@@ -181,7 +218,8 @@ function createRule(id, description) {
|
|
|
181
218
|
});
|
|
182
219
|
return;
|
|
183
220
|
}
|
|
184
|
-
|
|
221
|
+
const { diagnostics } = !suppression && options && Object.keys(options).length ? outcome.checkWith(id, options) : outcome.result;
|
|
222
|
+
for (const d of diagnostics) {
|
|
185
223
|
if (d.ruleId !== id) continue;
|
|
186
224
|
const edits = d.fix ?? [];
|
|
187
225
|
const fix = (fixer) => edits.map((e) => fixer.replaceTextRange(e.range, e.text));
|
|
@@ -209,6 +247,7 @@ function createRule(id, description) {
|
|
|
209
247
|
};
|
|
210
248
|
}
|
|
211
249
|
const rules = Object.fromEntries(RULES.map((rule) => [rule.id, createRule(rule.id, rule.description)]));
|
|
250
|
+
rules[SUPPRESSION] = createRule(SUPPRESSION, "Suppression comments must name rules that exist.");
|
|
212
251
|
const plugin = {
|
|
213
252
|
meta: {
|
|
214
253
|
name: NAME,
|
|
@@ -218,14 +257,17 @@ const plugin = {
|
|
|
218
257
|
configs: {}
|
|
219
258
|
};
|
|
220
259
|
/**
|
|
221
|
-
* Every rule at its default severity, for `.tsx` and `.jsx` files
|
|
222
|
-
* which `check` also leaves out unless asked (`--include-tests`).
|
|
260
|
+
* Every rule at its default severity, and `suppression` as a warning, for `.tsx` and `.jsx` files
|
|
261
|
+
* other than tests and stories, which `check` also leaves out unless asked (`--include-tests`).
|
|
223
262
|
*/
|
|
224
263
|
plugin.configs.recommended = {
|
|
225
264
|
name: "onsystem/recommended",
|
|
226
265
|
files: ["**/*.{tsx,jsx}"],
|
|
227
266
|
ignores: [DEFAULT_TEST_EXCLUDE, DEFAULT_TEST_FOLDERS],
|
|
228
267
|
plugins: { onsystem: plugin },
|
|
229
|
-
rules:
|
|
268
|
+
rules: {
|
|
269
|
+
...Object.fromEntries(RULES.map((rule) => [`onsystem/${rule.id}`, DEFAULT_SEVERITY[rule.id]])),
|
|
270
|
+
[`onsystem/${SUPPRESSION}`]: "warn"
|
|
271
|
+
}
|
|
230
272
|
};
|
|
231
273
|
export { plugin as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -157,7 +157,9 @@ export declare function loadTokens(root: string, sources: TokenSource[]): Promis
|
|
|
157
157
|
/**
|
|
158
158
|
* DTCG files and the CSS generated from them often describe the same tokens.
|
|
159
159
|
* Merge entries that share a custom property: keep the DTCG name and
|
|
160
|
-
* description, and add the Tailwind mapping from CSS.
|
|
160
|
+
* description, and add the Tailwind mapping from CSS. A token without one (a
|
|
161
|
+
* `@theme inline` value, `rounded-sm`) merges with the token of its name and
|
|
162
|
+
* Tailwind key, such as the one a DTCG file exported from the stylesheet has.
|
|
161
163
|
*/
|
|
162
164
|
export declare function mergeTokens(tokens: Token[]): Token[];
|
|
163
165
|
interface ColorCandidate {
|
|
@@ -269,7 +271,7 @@ export declare class TokenIndex {
|
|
|
269
271
|
/** What the lint rules need to know about the design system. */
|
|
270
272
|
declare class LintTarget {
|
|
271
273
|
readonly model: DesignSystemModel;
|
|
272
|
-
readonly config: Pick<ResolvedConfig, 'elements' | 'importPath'> & Partial<Pick<ResolvedConfig, 'designSystems'>>;
|
|
274
|
+
readonly config: Pick<ResolvedConfig, 'elements' | 'importPath'> & Partial<Pick<ResolvedConfig, 'designSystems' | 'imports'>>;
|
|
273
275
|
private readonly resolver?;
|
|
274
276
|
readonly components: Map<string, ComponentInfo>;
|
|
275
277
|
/** Every component under each name and alias, when two design systems share one (`Button`). */
|
|
@@ -291,13 +293,15 @@ declare class LintTarget {
|
|
|
291
293
|
private readonly sources?;
|
|
292
294
|
/** Published libraries the model read from type declarations: `@mui/material`. */
|
|
293
295
|
readonly libraries: Set<string>;
|
|
296
|
+
/** The name in each package.json read, by its path: undefined where there is none. */
|
|
297
|
+
private readonly manifests;
|
|
294
298
|
/**
|
|
295
299
|
* `resolver` finds the module an import points at and what it exports
|
|
296
300
|
* (`@calcom/ui/components/icon` → `components/icon/index.ts`), so a name from
|
|
297
301
|
* a module the model left out is not taken for an invented one. Without it,
|
|
298
302
|
* every missing name is invented.
|
|
299
303
|
*/
|
|
300
|
-
constructor(model: DesignSystemModel, config: Pick<ResolvedConfig, 'elements' | 'importPath'> & Partial<Pick<ResolvedConfig, 'designSystems'>>, resolver?: Pick<ModuleResolver, "locate" | "exportsOf"> | undefined);
|
|
304
|
+
constructor(model: DesignSystemModel, config: Pick<ResolvedConfig, 'elements' | 'importPath'> & Partial<Pick<ResolvedConfig, 'designSystems' | 'imports'>>, resolver?: Pick<ModuleResolver, "locate" | "exportsOf"> | undefined);
|
|
301
305
|
/**
|
|
302
306
|
* Whether an import specifier points at the design system. Relative
|
|
303
307
|
* specifiers are resolved against `fromFile` (relative to the root) and
|
|
@@ -318,10 +322,27 @@ declare class LintTarget {
|
|
|
318
322
|
* model left out rather than an invented one: its module exists outside the
|
|
319
323
|
* folders extraction read and exports `name`, or re-exports from such a
|
|
320
324
|
* module (an excluded `icons/` folder, a barrel's `export * from "./icons"`).
|
|
321
|
-
* A module declared in a package's `exports` but not on disk counts too
|
|
322
|
-
* except the design system's own import path
|
|
325
|
+
* A module declared in a package's `exports` but not on disk counts too (built to `dist/`,
|
|
326
|
+
* not built yet), except the design system's own import path, and one whose export, as the
|
|
327
|
+
* package.json writes it, leads to a source file only: `@acme/ui/components/tooltip` is
|
|
328
|
+
* `src/components/tooltip.tsx` through `"./components/*": "./src/components/*.tsx"`, and with
|
|
329
|
+
* no such file it does not exist.
|
|
323
330
|
*/
|
|
324
331
|
outsideModel(specifier: string, name: string, fromFile?: string): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* The module a design-system package's `exports` lead `specifier` to, relative to the root, as
|
|
334
|
+
* its package.json writes them: the first of the entry's targets that is on disk, else, when
|
|
335
|
+
* each of them is a source file, the first (which does not exist). Undefined when a target
|
|
336
|
+
* leads to a build folder (`"./*": "./dist/components/*.js"`, maybe not built yet, whose
|
|
337
|
+
* sources may be anywhere), the entry blocks the subpath (`null`), or no entry maps it.
|
|
338
|
+
*/
|
|
339
|
+
private exportedSource;
|
|
340
|
+
/**
|
|
341
|
+
* The folder of package `name` that `file` is in: the nearest package.json above it with a
|
|
342
|
+
* name, when that name is `name`. One without a name (`{"type": "module"}` in a subfolder) is
|
|
343
|
+
* no package's. Each package.json is read once.
|
|
344
|
+
*/
|
|
345
|
+
private packageDir;
|
|
325
346
|
/**
|
|
326
347
|
* The component a JSX tag means when `name` is imported from `specifier`, among the
|
|
327
348
|
* model's components of that name: the one declared where the import leads, through
|
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-
|
|
2
|
-
import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-
|
|
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-Csqts7Eq.js";
|
|
2
|
+
import { n as INSTRUCTIONS, r as createServer, t as serveStdio } from "./stdio-0TpyqZaD.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-
|
|
2
|
-
import { i as projectDirOf, n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-
|
|
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-Csqts7Eq.js";
|
|
2
|
+
import { i as projectDirOf, n as hasProjectMarker, r as loadTarget, t as findProjectRoot } from "./workspace-Dbxubo9n.js";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -19,8 +19,11 @@ 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)
|
|
23
|
-
|
|
22
|
+
if (config.configured) {
|
|
23
|
+
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`);
|
|
24
|
+
const unpublished = unpublishedComponents(ds);
|
|
25
|
+
if (unpublished) out(` ${unpublished}`);
|
|
26
|
+
} else {
|
|
24
27
|
const steps = [];
|
|
25
28
|
detectProject(config.root, config.tsconfig, steps, config.designSystemPackage);
|
|
26
29
|
for (const step of steps) out(` ${(step.accepted ? "found" : "no").padEnd(6)} ${step.candidate}: ${step.reason}`);
|
|
@@ -85,6 +88,22 @@ function explainProject(ds, cwd, indent = "") {
|
|
|
85
88
|
}
|
|
86
89
|
return lines;
|
|
87
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Why a project that takes on the config of a design-system package installed in node_modules
|
|
93
|
+
* knows none of its components: the package publishes neither their sources nor their type
|
|
94
|
+
* declarations, or `"libraries": false` turns off the declarations it publishes. The one message
|
|
95
|
+
* for it, where a project without components would otherwise be told to check the "components"
|
|
96
|
+
* globs. Undefined otherwise.
|
|
97
|
+
*/
|
|
98
|
+
function unpublishedComponents(ds) {
|
|
99
|
+
const declared = ds.config.designSystemPackage;
|
|
100
|
+
if (!declared?.installed || !ds.config.inherits || ds.model.components.length) return void 0;
|
|
101
|
+
const tokens = ds.model.tokens.length ? " The token rules still check against the tokens it publishes." : "";
|
|
102
|
+
const name = pathOf(declared.name);
|
|
103
|
+
const see = "See https://onsystem.vercel.app/docs/design-system-packages#what-apps-get";
|
|
104
|
+
if (ds.config.librariesOff?.some((library) => library.package === declared.name)) return `${name} publishes no component sources, and "libraries": false in the config turns off the type declarations it publishes, so its components are unknown here and the component rules did not run: set "libraries" to [], which reads its declarations and no library, or remove it.${tokens} ${see}`;
|
|
105
|
+
return `${name} publishes neither its component sources nor their type declarations, so its components are unknown here and the component rules did not run: ask its team to add its sources to "files" in its package.json, or to publish type declarations.${tokens} ${see}`;
|
|
106
|
+
}
|
|
88
107
|
/** Why a library the project depends on is not read: `left out by "libraries" in onsystem.config.json`. */
|
|
89
108
|
function librariesLeftOut(config, cwd) {
|
|
90
109
|
return `left out by "libraries" in ${config.configFile ? display(cwd, config.configFile) : "the config"}`;
|
|
@@ -562,8 +581,12 @@ function listTail(listed) {
|
|
|
562
581
|
if (listed.omitted) lines.push("", `${listed.omitted.toLocaleString("en-US")} more not shown: pass a higher \`limit\`, or a \`query\`.`);
|
|
563
582
|
return lines;
|
|
564
583
|
}
|
|
565
|
-
/**
|
|
566
|
-
|
|
584
|
+
/**
|
|
585
|
+
* The shared explanation when a project has no design-system components to show. `reason`, when
|
|
586
|
+
* known, says why instead ({@link unpublishedComponents}).
|
|
587
|
+
*/
|
|
588
|
+
function noComponentsMessage(root, project, monorepo = false, reason) {
|
|
589
|
+
if (reason) return answer([reason]);
|
|
567
590
|
if (monorepo) return answer([`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.`]);
|
|
568
591
|
return answer([`No design-system components found${project ? ` in ${pathOf(project)}` : ""}. Check the "components" globs in the config (root: ${root}).`]);
|
|
569
592
|
}
|
|
@@ -571,7 +594,7 @@ function noComponentsMessage(root, project, monorepo = false) {
|
|
|
571
594
|
function renderComponentList(ds, project, filter = {}) {
|
|
572
595
|
const roots = ds.roots();
|
|
573
596
|
const where = project ? ` in ${pathOf(project)}` : "";
|
|
574
|
-
if (!roots.length) return noComponentsMessage(ds.root, project);
|
|
597
|
+
if (!roots.length) return noComponentsMessage(ds.root, project, false, unpublishedComponents(ds));
|
|
575
598
|
const listed = listComponents(roots, (c) => c, filter);
|
|
576
599
|
if (!listed.matched) return answer([`No components match ${filterText(filter)}${where} (${roots.length} in all). Call list_components without filters to see them.`]);
|
|
577
600
|
const marks = new Marks();
|
|
@@ -686,7 +709,7 @@ function renderAmbiguous(name, entries) {
|
|
|
686
709
|
}
|
|
687
710
|
/** get_component's answer for a name no component has, with the nearest and all of them. */
|
|
688
711
|
function renderNotFound(name, guess, names, where = "") {
|
|
689
|
-
return answer([`No component named ${json(name)}${where}.` + (guess ? ` Did you mean ${json(guess)}?` : "") + ` Available: ${names.join(", ")}.`]);
|
|
712
|
+
return answer([`No component named ${json(name)}${where}.` + (guess ? ` Did you mean ${json(guess)}?` : "") + (names.length ? ` Available: ${names.join(", ")}.` : "")]);
|
|
690
713
|
}
|
|
691
714
|
/**
|
|
692
715
|
* The build-with-design-system prompt: `task`, the steps, and what the design system has, its
|
|
@@ -1552,7 +1575,7 @@ function register(serve, { getDesignSystem, getProjects }) {
|
|
|
1552
1575
|
const { ds } = found;
|
|
1553
1576
|
const component = ds.getComponent(name);
|
|
1554
1577
|
if (!component) {
|
|
1555
|
-
if (!ds.roots().length) return refuse(noComponentsMessage(ds.root, found.project?.dir));
|
|
1578
|
+
if (!ds.roots().length) return refuse(noComponentsMessage(ds.root, found.project?.dir, false, unpublishedComponents(ds)));
|
|
1556
1579
|
const names = ds.roots().map((c) => c.name);
|
|
1557
1580
|
return refuse(renderNotFound(name, ds.suggestComponent(name), names));
|
|
1558
1581
|
}
|
|
@@ -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-
|
|
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-Csqts7Eq.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.11.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": [
|