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.
- package/README.md +2 -0
- package/dist/cli.js +153 -56
- package/dist/{config-B98w8bcg.d.ts → config-BbTW1jKU.d.ts} +12 -2
- package/dist/{design-system-Bykei5W0.js → design-system-D53Jxybo.js} +440 -144
- package/dist/eslint-worker.d.ts +1 -1
- package/dist/eslint-worker.js +2 -2
- package/dist/eslint.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/{stdio-B7u6dqLd.js → stdio-ha4IF0CU.js} +38 -11
- package/dist/{workspace-Dp1q8qZ8.js → workspace-DAa_08uB.js} +8 -7
- package/package.json +1 -1
- package/schema.json +5 -1
|
@@ -5,10 +5,10 @@ import * as z from "zod";
|
|
|
5
5
|
import { escapePath, glob, globSync } from "tinyglobby";
|
|
6
6
|
import ts from "typescript";
|
|
7
7
|
import os from "node:os";
|
|
8
|
+
import postcss from "postcss";
|
|
8
9
|
import { clampChroma, colorsNamed, converter, differenceEuclidean, formatHex, parse, wcagContrast } from "culori";
|
|
9
10
|
import { createHash } from "node:crypto";
|
|
10
11
|
import fsp from "node:fs/promises";
|
|
11
|
-
import postcss from "postcss";
|
|
12
12
|
import { LineCounter, isMap, isScalar, parseDocument, stringify } from "yaml";
|
|
13
13
|
import { stemmer } from "stemmer";
|
|
14
14
|
//#region src/extract/program.ts
|
|
@@ -142,7 +142,7 @@ function slashGlob(pattern) {
|
|
|
142
142
|
* `.mjs` and `.cjs` forms, in any case. CSS, Markdown or JSON parsed as TSX gives hundreds of
|
|
143
143
|
* syntax errors (209 for a shadcn/ui `app/globals.css`).
|
|
144
144
|
*/
|
|
145
|
-
const SCRIPT_FILE$
|
|
145
|
+
const SCRIPT_FILE$2 = /\.(?:[jt]sx?|[cm][jt]s)$/i;
|
|
146
146
|
/** Path relative to `root`, always with forward slashes. */
|
|
147
147
|
function relativePath(root, file) {
|
|
148
148
|
return toPosix(path.relative(root, file));
|
|
@@ -514,6 +514,59 @@ function isFile$1(file) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
//#endregion
|
|
517
|
+
//#region src/tokens/imports.ts
|
|
518
|
+
/** Enough stylesheets for a theme split over files, without reading a whole design system. */
|
|
519
|
+
const MAX_IMPORTED = 50;
|
|
520
|
+
/**
|
|
521
|
+
* The specifiers a stylesheet `@import`s: `@import "./theme.css" layer(base)`,
|
|
522
|
+
* `@import url(theme.css)`, `@import "@acme/theme"`. Empty for CSS that does not parse.
|
|
523
|
+
*/
|
|
524
|
+
function cssImports(css) {
|
|
525
|
+
let root;
|
|
526
|
+
try {
|
|
527
|
+
root = postcss.parse(css);
|
|
528
|
+
} catch {
|
|
529
|
+
return [];
|
|
530
|
+
}
|
|
531
|
+
const out = [];
|
|
532
|
+
for (const node of root.nodes) {
|
|
533
|
+
if (node.type !== "atrule" || node.name !== "import") continue;
|
|
534
|
+
const match = /^\s*(?:url\(\s*)?(?:"([^"]+)"|'([^']+)'|([^\s"')]+)\s*\))/.exec(node.params);
|
|
535
|
+
const specifier = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
536
|
+
if (specifier) out.push(specifier);
|
|
537
|
+
}
|
|
538
|
+
return out;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* The stylesheets `files` import, and the ones those import in turn, each once, in the order
|
|
542
|
+
* the cascade ranks them, for a reader that keeps the first declaration of a variable. CSS
|
|
543
|
+
* puts an imported stylesheet where its `@import` is, so a later import overrides an earlier
|
|
544
|
+
* one, and the importing stylesheet's own rules override both: `@import "./base.css";
|
|
545
|
+
* @import "./brand.css";` lists brand.css, then what brand.css imports, then base.css. The
|
|
546
|
+
* files themselves are not repeated, and come before all of these.
|
|
547
|
+
*/
|
|
548
|
+
function importedStylesheets(files, resolve) {
|
|
549
|
+
const seen = new Set(files);
|
|
550
|
+
const out = [];
|
|
551
|
+
const visit = (file) => {
|
|
552
|
+
let text;
|
|
553
|
+
try {
|
|
554
|
+
text = fs.readFileSync(file, "utf8");
|
|
555
|
+
} catch {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
for (const specifier of cssImports(text).reverse()) {
|
|
559
|
+
const target = resolve(specifier, file);
|
|
560
|
+
if (!target || seen.has(target) || out.length >= MAX_IMPORTED) continue;
|
|
561
|
+
seen.add(target);
|
|
562
|
+
out.push(target);
|
|
563
|
+
visit(target);
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
for (const file of files) visit(file);
|
|
567
|
+
return out;
|
|
568
|
+
}
|
|
569
|
+
//#endregion
|
|
517
570
|
//#region src/util/strings.ts
|
|
518
571
|
/** `alert-dialog` / `alert_dialog` / `alertDialog` → `AlertDialog`. */
|
|
519
572
|
function pascalCase(input) {
|
|
@@ -579,7 +632,7 @@ function unique(items) {
|
|
|
579
632
|
const ignore = () => void 0;
|
|
580
633
|
const COMPONENT_FILE = /\.[jt]sx$/;
|
|
581
634
|
/** A module a barrel can lead to: TypeScript or JavaScript, not a declaration file. */
|
|
582
|
-
const SCRIPT_FILE = /(?<!\.d)\.[cm]?[jt]sx?$/;
|
|
635
|
+
const SCRIPT_FILE$1 = /(?<!\.d)\.[cm]?[jt]sx?$/;
|
|
583
636
|
const STYLESHEETS = [
|
|
584
637
|
"src/styles/globals.css",
|
|
585
638
|
"src/globals.css",
|
|
@@ -588,6 +641,18 @@ const STYLESHEETS = [
|
|
|
588
641
|
"src/index.css"
|
|
589
642
|
];
|
|
590
643
|
/**
|
|
644
|
+
* An app's own stylesheets, where zero config looks for them without components.json (the
|
|
645
|
+
* stylesheets of `DEFAULT_TOKENS` in config.ts).
|
|
646
|
+
*/
|
|
647
|
+
const APP_STYLESHEETS = [
|
|
648
|
+
"app/globals.css",
|
|
649
|
+
"src/app/globals.css",
|
|
650
|
+
"styles/globals.css",
|
|
651
|
+
"src/styles/globals.css",
|
|
652
|
+
"src/index.css",
|
|
653
|
+
"app/app.css"
|
|
654
|
+
];
|
|
655
|
+
/**
|
|
591
656
|
* Finds the design system without a config:
|
|
592
657
|
*
|
|
593
658
|
* 1. `components.json` (shadcn/ui): the `ui` alias, resolved through tsconfig
|
|
@@ -892,15 +957,28 @@ function fromComponentsJson(root, dir, json, project, packages, note = ignore) {
|
|
|
892
957
|
}
|
|
893
958
|
const tailwind = asRecord(json.tailwind);
|
|
894
959
|
const css = typeof tailwind.css === "string" && tailwind.css ? path.resolve(dir, tailwind.css) : void 0;
|
|
960
|
+
const named = css && fs.existsSync(css) ? [css] : [];
|
|
895
961
|
return {
|
|
896
962
|
components: [`${escapePath(relativePath(root, uiDir) || ".")}/**/*.{tsx,jsx}`],
|
|
897
|
-
tokens:
|
|
963
|
+
tokens: (dir === root ? withAppStylesheets(root, named) : named).map((f) => escapePath(relativePath(root, f))),
|
|
898
964
|
imports,
|
|
899
965
|
dirs: [uiDir],
|
|
900
966
|
source: `${ui} → ${relativePath(root, uiDir) || "."}`,
|
|
901
967
|
...ownerPackage(root, uiDir, ui)
|
|
902
968
|
};
|
|
903
969
|
}
|
|
970
|
+
/**
|
|
971
|
+
* The stylesheets an app's tokens come from when its components.json names a stylesheet in
|
|
972
|
+
* another package, as cal.com's names coss/ui's: the app's own stylesheets first, which hold
|
|
973
|
+
* its own tokens, then the named one, unless they import it, so that the cascade places it.
|
|
974
|
+
*/
|
|
975
|
+
function withAppStylesheets(root, named) {
|
|
976
|
+
if (named.every((file) => isInside(root, file))) return named;
|
|
977
|
+
const own = APP_STYLESHEETS.map((f) => path.join(root, f)).filter(isFile);
|
|
978
|
+
if (!own.length) return named;
|
|
979
|
+
const imported = new Set(importedStylesheets(own, stylesheetResolver(root)));
|
|
980
|
+
return [...own, ...named.filter((file) => !imported.has(file))];
|
|
981
|
+
}
|
|
904
982
|
/** How a shadcn registry is named in components.json: `@` and a name, so none leads out of the folder. */
|
|
905
983
|
const REGISTRY_NAMESPACE = /^@[a-z0-9][\w-]*$/i;
|
|
906
984
|
/**
|
|
@@ -1056,7 +1134,7 @@ function fromPackage(root, dir, pkg, note = ignore, installed = false) {
|
|
|
1056
1134
|
for (const mapping of mappings) {
|
|
1057
1135
|
const file = path.resolve(root, mapping.target);
|
|
1058
1136
|
if (installed && isCompiledExport(dir, file)) continue;
|
|
1059
|
-
if (mapping.target.includes("*") || !SCRIPT_FILE.test(file) || !isFile(file)) {
|
|
1137
|
+
if (mapping.target.includes("*") || !SCRIPT_FILE$1.test(file) || !isFile(file)) {
|
|
1060
1138
|
add(mapping, COMPONENT_FILE.test(mapping.target));
|
|
1061
1139
|
continue;
|
|
1062
1140
|
}
|
|
@@ -1346,7 +1424,7 @@ function presetResolver(root) {
|
|
|
1346
1424
|
if (file || specifier.startsWith(".")) return file;
|
|
1347
1425
|
const name = packageName(specifier);
|
|
1348
1426
|
const dir = name ? packages.find(name) : void 0;
|
|
1349
|
-
return name && dir ? exportedFile(dir, `.${specifier.slice(name.length)}`, (f) => SCRIPT_FILE.test(f)) : void 0;
|
|
1427
|
+
return name && dir ? exportedFile(dir, `.${specifier.slice(name.length)}`, (f) => SCRIPT_FILE$1.test(f)) : void 0;
|
|
1350
1428
|
};
|
|
1351
1429
|
}
|
|
1352
1430
|
/**
|
|
@@ -2009,7 +2087,7 @@ const KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
2009
2087
|
* `/ alpha` allowed): how Tailwind v3 projects, and shadcn/ui before v4, store
|
|
2010
2088
|
* colors, to be used as `hsl(var(--border))`.
|
|
2011
2089
|
*/
|
|
2012
|
-
const BARE_HSL = /^(
|
|
2090
|
+
const BARE_HSL = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(deg)?(?:\s*,\s*|\s+)(\d+(?:\.\d+)?|\.\d+)%(?:\s*,\s*|\s+)(\d+(?:\.\d+)?|\.\d+)%(?:\s*\/\s*((?:\d+(?:\.\d+)?|\.\d+)%?))?$/;
|
|
2013
2091
|
function isBareHsl(value) {
|
|
2014
2092
|
return BARE_HSL.test(value.trim());
|
|
2015
2093
|
}
|
|
@@ -2019,7 +2097,7 @@ function isBareHsl(value) {
|
|
|
2019
2097
|
* Three numbers alone are no sure color, so they count as one only in a token already
|
|
2020
2098
|
* known to be a color: one the Tailwind config reads with `rgb()`.
|
|
2021
2099
|
*/
|
|
2022
|
-
const BARE_RGB = /^(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})(?:\s*\/\s*(
|
|
2100
|
+
const BARE_RGB = /^(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})(?:\s*\/\s*((?:\d+(?:\.\d+)?|\.\d+)%?))?$/;
|
|
2023
2101
|
function isBareRgb(value) {
|
|
2024
2102
|
const match = BARE_RGB.exec(value.trim());
|
|
2025
2103
|
return match !== null && match.slice(1, 4).every((channel) => Number(channel) <= 255);
|
|
@@ -2757,7 +2835,7 @@ function classText(node) {
|
|
|
2757
2835
|
visit(node);
|
|
2758
2836
|
return parts.join(" ").replace(/\s+/g, " ").trim();
|
|
2759
2837
|
}
|
|
2760
|
-
const LENGTH = /^(-?(?:\d
|
|
2838
|
+
const LENGTH = /^(-?(?:\d+(?:\.\d*)?|\.\d+))(px|rem|em)?$/i;
|
|
2761
2839
|
/** `"0.5rem"` → 8, `"12px"` → 12, `"4"` → 4. Returns undefined for anything else. */
|
|
2762
2840
|
function lengthToPx(value) {
|
|
2763
2841
|
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
@@ -2785,13 +2863,27 @@ function evaluateLength(value, resolve, depth = 0) {
|
|
|
2785
2863
|
function expandVars(value, resolve, depth) {
|
|
2786
2864
|
let out = "";
|
|
2787
2865
|
let last = 0;
|
|
2788
|
-
for (
|
|
2789
|
-
|
|
2866
|
+
for (let at = value.indexOf("var(", last); at !== -1; at = value.indexOf("var(", last)) {
|
|
2867
|
+
let level = 0;
|
|
2868
|
+
let comma = -1;
|
|
2869
|
+
let end = -1;
|
|
2870
|
+
for (let i = at + 3; i < value.length; i++) {
|
|
2871
|
+
const c = value[i];
|
|
2872
|
+
if (c === "(") level++;
|
|
2873
|
+
else if (c === ")" && --level === 0) {
|
|
2874
|
+
end = i;
|
|
2875
|
+
break;
|
|
2876
|
+
} else if (c === "," && level === 1 && comma === -1) comma = i;
|
|
2877
|
+
}
|
|
2878
|
+
if (end === -1) return void 0;
|
|
2879
|
+
const name = value.slice(at + 4, comma === -1 ? end : comma).trim();
|
|
2880
|
+
if (!/^--[\w-]+$/.test(name)) return void 0;
|
|
2881
|
+
const fallback = comma === -1 ? void 0 : value.slice(comma + 1, end);
|
|
2790
2882
|
const resolved = resolve(name) ?? fallback;
|
|
2791
2883
|
const px = resolved === void 0 ? void 0 : evaluateLength(resolved, resolve, depth + 1);
|
|
2792
2884
|
if (px === void 0) return void 0;
|
|
2793
|
-
out += `${value.slice(last,
|
|
2794
|
-
last =
|
|
2885
|
+
out += `${value.slice(last, at)}${px}px`;
|
|
2886
|
+
last = end + 1;
|
|
2795
2887
|
}
|
|
2796
2888
|
return out + value.slice(last);
|
|
2797
2889
|
}
|
|
@@ -2917,6 +3009,10 @@ function utilities(namespace, key) {
|
|
|
2917
3009
|
//#region src/tokens/tailwind-config.ts
|
|
2918
3010
|
/** A preset chain is a few files deep; anything beyond is not a Tailwind config. */
|
|
2919
3011
|
const MAX_FILES = 12;
|
|
3012
|
+
/** A config or preset module, which is read for its theme. */
|
|
3013
|
+
const SCRIPT_FILE = /\.[cm]?[jt]s$/;
|
|
3014
|
+
/** Tailwind's own modules, such as `tailwindcss/defaultTheme`, which hold its defaults. */
|
|
3015
|
+
const TAILWIND_MODULE = /^tailwindcss(?:\/|$)/;
|
|
2920
3016
|
/**
|
|
2921
3017
|
* Reads which custom property backs which color class from a Tailwind v3
|
|
2922
3018
|
* config, without running it: every `colors` object in the file
|
|
@@ -2946,7 +3042,7 @@ function readTailwindColors(file, resolve) {
|
|
|
2946
3042
|
}
|
|
2947
3043
|
const specifier = importedSpecifier(node);
|
|
2948
3044
|
const target = specifier === void 0 ? void 0 : resolve(specifier, current);
|
|
2949
|
-
if (target &&
|
|
3045
|
+
if (target && SCRIPT_FILE.test(target)) queue.push(target);
|
|
2950
3046
|
ts.forEachChild(node, visit);
|
|
2951
3047
|
};
|
|
2952
3048
|
visit(source);
|
|
@@ -2978,13 +3074,47 @@ function collect(object, keys, colors, rgb) {
|
|
|
2978
3074
|
}
|
|
2979
3075
|
}
|
|
2980
3076
|
/**
|
|
3077
|
+
* Tailwind v3's default `borderRadius` scale, which `theme.extend.borderRadius` adds to and
|
|
3078
|
+
* `theme.borderRadius` replaces. `none` (0) is left out, as the rule skips zero, and `full`
|
|
3079
|
+
* is the token index's own `rounded-full`.
|
|
3080
|
+
*/
|
|
3081
|
+
const TAILWIND_V3_RADIUS = {
|
|
3082
|
+
sm: "0.125rem",
|
|
3083
|
+
DEFAULT: "0.25rem",
|
|
3084
|
+
md: "0.375rem",
|
|
3085
|
+
lg: "0.5rem",
|
|
3086
|
+
xl: "0.75rem",
|
|
3087
|
+
"2xl": "1rem",
|
|
3088
|
+
"3xl": "1.5rem"
|
|
3089
|
+
};
|
|
3090
|
+
/** borderRadius entries by key, and which of them are Tailwind's default scale rather than the config's. */
|
|
3091
|
+
var RadiusEntries = class extends Map {
|
|
3092
|
+
defaults = /* @__PURE__ */ new Set();
|
|
3093
|
+
};
|
|
3094
|
+
/**
|
|
2981
3095
|
* Reads `borderRadius` entries from a Tailwind v3 config without running it:
|
|
2982
3096
|
* every `borderRadius` object in the file, then in the project modules it
|
|
2983
|
-
* imports, such as a shared preset. The config's own entries win.
|
|
3097
|
+
* imports, such as a shared preset. The config's own entries win. Tailwind's
|
|
3098
|
+
* default scale follows, for the keys none of them sets, unless the first
|
|
3099
|
+
* `theme.borderRadius` outside `extend` replaces it without spreading it back
|
|
3100
|
+
* in (`...defaultTheme.borderRadius`), a `theme` is a whole module or spreads
|
|
3101
|
+
* one (`theme: require("./theme")`, `theme: { ...require("./theme") }`), other
|
|
3102
|
+
* than Tailwind's own, `presets: []` drops Tailwind's default config
|
|
3103
|
+
* and no `theme.borderRadius` spreads the scale back in, or the scale comes from
|
|
3104
|
+
* somewhere this cannot read. That is a module that is no project file (one
|
|
3105
|
+
* installed from npm, other than Tailwind's own) that the config takes as a
|
|
3106
|
+
* preset, a theme, or the config itself (`module.exports = require("x")`,
|
|
3107
|
+
* `{ ...require("x"), content }`), or spreads into a theme, its `extend` or a
|
|
3108
|
+
* `borderRadius`; a `presets` that is no array; or a `theme.borderRadius` or
|
|
3109
|
+
* `theme.extend.borderRadius` that is no object (`borderRadius: radius`,
|
|
3110
|
+
* `borderRadius: ({ theme }) => …`) or spreads anything but Tailwind's scale.
|
|
2984
3111
|
*/
|
|
2985
3112
|
function readTailwindRadii(file, resolve) {
|
|
2986
|
-
const radii =
|
|
3113
|
+
const radii = new RadiusEntries();
|
|
2987
3114
|
const files = [];
|
|
3115
|
+
let keepsDefaults;
|
|
3116
|
+
let unread = false;
|
|
3117
|
+
let noDefaultConfig = false;
|
|
2988
3118
|
const queue = [file];
|
|
2989
3119
|
while (queue.length && files.length < MAX_FILES) {
|
|
2990
3120
|
const current = queue.shift() ?? "";
|
|
@@ -2997,18 +3127,58 @@ function readTailwindRadii(file, resolve) {
|
|
|
2997
3127
|
}
|
|
2998
3128
|
files.push(current);
|
|
2999
3129
|
const source = ts.createSourceFile(current, text, ts.ScriptTarget.Latest, true, scriptKind(current));
|
|
3130
|
+
const bindings = importBindings(source);
|
|
3131
|
+
const external = (specifier) => {
|
|
3132
|
+
if (specifier === void 0 || TAILWIND_MODULE.test(specifier)) return false;
|
|
3133
|
+
const target = resolve(specifier, current);
|
|
3134
|
+
return !(target && SCRIPT_FILE.test(target));
|
|
3135
|
+
};
|
|
3136
|
+
const fromPackage = (value) => external(moduleOf(value, bindings));
|
|
3137
|
+
const fromTailwind = (value) => TAILWIND_MODULE.test(moduleOf(value, bindings) ?? "");
|
|
3000
3138
|
const visit = (node) => {
|
|
3001
|
-
if (ts.isPropertyAssignment(node) && propertyName(node.name) === "borderRadius"
|
|
3002
|
-
|
|
3003
|
-
|
|
3139
|
+
if ((ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) && propertyName(node.name) === "borderRadius") {
|
|
3140
|
+
const value = ts.isPropertyAssignment(node) ? node.initializer : void 0;
|
|
3141
|
+
const holder = themeSection(node.parent);
|
|
3142
|
+
if (value && ts.isObjectLiteralExpression(value)) {
|
|
3143
|
+
collectRadius(value, radii);
|
|
3144
|
+
let spreads = false;
|
|
3145
|
+
for (const property of value.properties) {
|
|
3146
|
+
if (!ts.isSpreadAssignment(property)) continue;
|
|
3147
|
+
if (fromTailwind(property.expression)) spreads = true;
|
|
3148
|
+
else unread = true;
|
|
3149
|
+
}
|
|
3150
|
+
if (holder === "theme") keepsDefaults ??= spreads;
|
|
3151
|
+
return;
|
|
3152
|
+
}
|
|
3153
|
+
if (holder === "theme") keepsDefaults ??= false;
|
|
3154
|
+
else if (holder === "extend") unread = true;
|
|
3155
|
+
}
|
|
3156
|
+
if ((ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) && propertyName(node.name) === "presets") {
|
|
3157
|
+
const value = ts.isPropertyAssignment(node) ? node.initializer : void 0;
|
|
3158
|
+
if (value && ts.isArrayLiteralExpression(value)) {
|
|
3159
|
+
if (!value.elements.length) noDefaultConfig = true;
|
|
3160
|
+
for (const element of value.elements) if (fromPackage(ts.isSpreadElement(element) ? element.expression : element)) unread = true;
|
|
3161
|
+
} else unread = true;
|
|
3162
|
+
}
|
|
3163
|
+
if ((ts.isShorthandPropertyAssignment(node) || ts.isPropertyAssignment(node) && !ts.isObjectLiteralExpression(node.initializer)) && propertyName(node.name) === "theme" && !ts.isPropertyAssignment(node.parent.parent)) {
|
|
3164
|
+
keepsDefaults ??= false;
|
|
3165
|
+
if (fromPackage(ts.isPropertyAssignment(node) ? node.initializer : node.name)) unread = true;
|
|
3004
3166
|
}
|
|
3167
|
+
if (ts.isSpreadAssignment(node) && fromPackage(node.expression) && (themeSection(node.parent) !== void 0 || !ts.isPropertyAssignment(node.parent.parent) && !themeValueOnly(node.parent, source))) unread = true;
|
|
3168
|
+
if (ts.isSpreadAssignment(node) && themeSection(node.parent) === "theme" && !fromTailwind(node.expression)) keepsDefaults ??= false;
|
|
3169
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && isModuleExports(node.left) && fromPackage(node.right) || ts.isExportAssignment(node) && fromPackage(node.expression) || ts.isExportDeclaration(node) && !node.isTypeOnly && node.exportClause !== void 0 && ts.isNamedExports(node.exportClause) && node.exportClause.elements.some((element) => element.name.text === "default") && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier) && external(node.moduleSpecifier.text)) unread = true;
|
|
3005
3170
|
const specifier = importedSpecifier(node);
|
|
3006
3171
|
const target = specifier === void 0 ? void 0 : resolve(specifier, current);
|
|
3007
|
-
if (target &&
|
|
3172
|
+
if (target && SCRIPT_FILE.test(target)) queue.push(target);
|
|
3008
3173
|
ts.forEachChild(node, visit);
|
|
3009
3174
|
};
|
|
3010
3175
|
visit(source);
|
|
3011
3176
|
}
|
|
3177
|
+
if ((noDefaultConfig ? keepsDefaults === true : keepsDefaults !== false) && !unread) for (const [key, value] of Object.entries(TAILWIND_V3_RADIUS)) {
|
|
3178
|
+
if (radii.has(key)) continue;
|
|
3179
|
+
radii.set(key, value);
|
|
3180
|
+
radii.defaults.add(key);
|
|
3181
|
+
}
|
|
3012
3182
|
return {
|
|
3013
3183
|
radii,
|
|
3014
3184
|
files
|
|
@@ -3028,6 +3198,10 @@ function collectRadius(object, radii) {
|
|
|
3028
3198
|
radii.set(key, raw);
|
|
3029
3199
|
}
|
|
3030
3200
|
}
|
|
3201
|
+
/** `module.exports`, as in `module.exports = require("@acme/tailwind-config")`. */
|
|
3202
|
+
function isModuleExports(node) {
|
|
3203
|
+
return ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
|
|
3204
|
+
}
|
|
3031
3205
|
/**
|
|
3032
3206
|
* Gives radius tokens their Tailwind v3 class names: each config entry is
|
|
3033
3207
|
* evaluated (its `var()` against radius token values, so
|
|
@@ -3036,15 +3210,29 @@ function collectRadius(object, radii) {
|
|
|
3036
3210
|
* token add a synthetic one, so the scale step exists as a candidate
|
|
3037
3211
|
* (mirrors the spacing-steps synthesis); without it the literal would keep
|
|
3038
3212
|
* matching the nearest unrelated token. Config entries win over presets.
|
|
3213
|
+
*
|
|
3214
|
+
* The steps of Tailwind's default scale ({@link RadiusEntries.defaults}) only add
|
|
3215
|
+
* a token for a size that has none, named after nothing the project names:
|
|
3216
|
+
* `rounded-xl` is 12px in a shadcn/ui v3 project, whose config extends the scale
|
|
3217
|
+
* with `lg`, `md` and `sm`. They add none when a config step has no size (its
|
|
3218
|
+
* `var(--radius)` is in no stylesheet read), as they would make a scale with
|
|
3219
|
+
* holes, nor when the tokens are a Tailwind v4 theme, whose own scale is read from
|
|
3220
|
+
* its stylesheet: Tailwind v4's defaults, or a token of an `@theme` variable outside
|
|
3221
|
+
* the colors (only v4 reads `@theme`; a v3 config names colors too).
|
|
3039
3222
|
*/
|
|
3040
3223
|
function applyTailwindRadii(tokens, radii, configFile = "tailwind.config") {
|
|
3041
3224
|
const byVar = /* @__PURE__ */ new Map();
|
|
3042
3225
|
for (const token of tokens) if (token.category === "radius" && token.cssVar) byVar.set(token.cssVar, token.value);
|
|
3043
3226
|
const resolve = (name) => byVar.get(name);
|
|
3227
|
+
const defaults = radii instanceof RadiusEntries ? radii.defaults : /* @__PURE__ */ new Set();
|
|
3228
|
+
const v4 = tokens.some((t) => t.origin === "tailwind-default" || t.category !== "color" && t.tailwind !== void 0);
|
|
3044
3229
|
const byPx = /* @__PURE__ */ new Map();
|
|
3230
|
+
let unsized = false;
|
|
3045
3231
|
for (const [key, raw] of radii) {
|
|
3232
|
+
if (defaults.has(key)) continue;
|
|
3046
3233
|
const px = evaluateLength(raw, resolve);
|
|
3047
|
-
if (px
|
|
3234
|
+
if (px === void 0) unsized = true;
|
|
3235
|
+
else if (!byPx.has(px)) byPx.set(px, key);
|
|
3048
3236
|
}
|
|
3049
3237
|
const havePx = /* @__PURE__ */ new Set();
|
|
3050
3238
|
for (const token of tokens) {
|
|
@@ -3076,6 +3264,123 @@ function applyTailwindRadii(tokens, radii, configFile = "tailwind.config") {
|
|
|
3076
3264
|
tokens.push(token);
|
|
3077
3265
|
havePx.add(px);
|
|
3078
3266
|
}
|
|
3267
|
+
if (unsized || v4) return;
|
|
3268
|
+
const names = new Set(tokens.map((t) => t.name));
|
|
3269
|
+
for (const key of defaults) {
|
|
3270
|
+
const value = radii.get(key) ?? "";
|
|
3271
|
+
const px = evaluateLength(value, resolve);
|
|
3272
|
+
const name = `radius-${key}`;
|
|
3273
|
+
if (px === void 0 || havePx.has(px) || names.has(name)) continue;
|
|
3274
|
+
const token = {
|
|
3275
|
+
name,
|
|
3276
|
+
category: "radius",
|
|
3277
|
+
value,
|
|
3278
|
+
tailwind: key,
|
|
3279
|
+
usage: usageFor({
|
|
3280
|
+
category: "radius",
|
|
3281
|
+
tailwind: key
|
|
3282
|
+
}, "--radius"),
|
|
3283
|
+
description: "Tailwind's default radius scale.",
|
|
3284
|
+
origin: "tailwind-default",
|
|
3285
|
+
source: {
|
|
3286
|
+
file: configFile,
|
|
3287
|
+
line: 1
|
|
3288
|
+
}
|
|
3289
|
+
};
|
|
3290
|
+
tokens.push(token);
|
|
3291
|
+
havePx.add(px);
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Whether an object is the value of a variable that its file uses only as a theme value of a
|
|
3296
|
+
* key other than `extend` and `borderRadius`, such as `const brand = { ...blue, ...blueDark }`
|
|
3297
|
+
* with `theme: { extend: { colors: brand } }`. What it spreads is then no config, theme or
|
|
3298
|
+
* radius scale. A variable that is exported, or used in any other way, may be one.
|
|
3299
|
+
*/
|
|
3300
|
+
function themeValueOnly(object, source) {
|
|
3301
|
+
let value = object;
|
|
3302
|
+
while (ts.isParenthesizedExpression(value.parent) || ts.isAsExpression(value.parent) || ts.isSatisfiesExpression(value.parent)) value = value.parent;
|
|
3303
|
+
const declaration = value.parent;
|
|
3304
|
+
if (!ts.isVariableDeclaration(declaration) || declaration.initializer !== value || !ts.isIdentifier(declaration.name) || !ts.isVariableStatement(declaration.parent.parent) || declaration.parent.parent.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) return false;
|
|
3305
|
+
const name = declaration.name;
|
|
3306
|
+
let only = true;
|
|
3307
|
+
const visit = (node) => {
|
|
3308
|
+
if (!only) return;
|
|
3309
|
+
const parent = node.parent;
|
|
3310
|
+
const key = parent !== void 0 && (ts.isPropertyAssignment(parent) || ts.isPropertyAccessExpression(parent)) && parent.name === node;
|
|
3311
|
+
if (ts.isIdentifier(node) && node !== name && node.text === name.text && !key) only = isThemeValue(node);
|
|
3312
|
+
ts.forEachChild(node, visit);
|
|
3313
|
+
};
|
|
3314
|
+
visit(source);
|
|
3315
|
+
return only;
|
|
3316
|
+
}
|
|
3317
|
+
/**
|
|
3318
|
+
* Whether a name is a theme value, under a key other than `extend` and `borderRadius`:
|
|
3319
|
+
* `colors: brand`, or `colors: { brand }`.
|
|
3320
|
+
*/
|
|
3321
|
+
function isThemeValue(reference) {
|
|
3322
|
+
const parent = reference.parent;
|
|
3323
|
+
let property;
|
|
3324
|
+
if (ts.isPropertyAssignment(parent) && parent.initializer === reference) property = parent;
|
|
3325
|
+
else if (ts.isShorthandPropertyAssignment(parent)) property = parent;
|
|
3326
|
+
else return false;
|
|
3327
|
+
for (;;) {
|
|
3328
|
+
const key = propertyName(property.name);
|
|
3329
|
+
const object = property.parent;
|
|
3330
|
+
if (themeSection(object) !== void 0) return key !== void 0 && key !== "extend" && key !== "borderRadius";
|
|
3331
|
+
const holder = object.parent;
|
|
3332
|
+
if (!ts.isPropertyAssignment(holder) || holder.initializer !== object) return false;
|
|
3333
|
+
property = holder;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
/** `theme` or `extend` for a property of `theme: {…}` or of `theme.extend: {…}`; else undefined. */
|
|
3337
|
+
function themeSection(object) {
|
|
3338
|
+
const holder = object.parent;
|
|
3339
|
+
if (!ts.isObjectLiteralExpression(object) || !ts.isPropertyAssignment(holder)) return void 0;
|
|
3340
|
+
const key = propertyName(holder.name);
|
|
3341
|
+
if (key === "theme") return "theme";
|
|
3342
|
+
return key === "extend" && themeSection(holder.parent) === "theme" ? "extend" : void 0;
|
|
3343
|
+
}
|
|
3344
|
+
/**
|
|
3345
|
+
* The names a module binds to what it imports or requires, by specifier: `acme` for
|
|
3346
|
+
* `import acme from "x"`, `import { acme } from "x"`, `const acme = require("x")` or
|
|
3347
|
+
* `const { default: acme } = require("x")`.
|
|
3348
|
+
*/
|
|
3349
|
+
function importBindings(source) {
|
|
3350
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
3351
|
+
const bind = (name, specifier) => {
|
|
3352
|
+
if (ts.isIdentifier(name)) {
|
|
3353
|
+
bindings.set(name.text, specifier);
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
for (const element of name.elements) if (!ts.isOmittedExpression(element)) bind(element.name, specifier);
|
|
3357
|
+
};
|
|
3358
|
+
for (const statement of source.statements) if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
3359
|
+
const specifier = statement.moduleSpecifier.text;
|
|
3360
|
+
const clause = statement.importClause;
|
|
3361
|
+
if (clause?.name) bind(clause.name, specifier);
|
|
3362
|
+
const named = clause?.namedBindings;
|
|
3363
|
+
if (named && ts.isNamespaceImport(named)) bind(named.name, specifier);
|
|
3364
|
+
else if (named) for (const element of named.elements) bind(element.name, specifier);
|
|
3365
|
+
} else if (ts.isVariableStatement(statement)) for (const declaration of statement.declarationList.declarations) {
|
|
3366
|
+
const specifier = declaration.initializer && moduleOf(declaration.initializer, bindings);
|
|
3367
|
+
if (specifier !== void 0) bind(declaration.name, specifier);
|
|
3368
|
+
}
|
|
3369
|
+
return bindings;
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
* The module an expression takes its value from: `"x"` for `require("x")`, `import("x")`, a
|
|
3373
|
+
* name bound to either ({@link importBindings}), a call of any of these
|
|
3374
|
+
* (`createPreset({…})`, `require("x")()`) or a property of one (`require("x").default`).
|
|
3375
|
+
*/
|
|
3376
|
+
function moduleOf(node, bindings) {
|
|
3377
|
+
let current = node;
|
|
3378
|
+
for (;;) if (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isSatisfiesExpression(current) || ts.isNonNullExpression(current) || ts.isAwaitExpression(current) || ts.isPropertyAccessExpression(current)) current = current.expression;
|
|
3379
|
+
else if (ts.isCallExpression(current)) {
|
|
3380
|
+
const specifier = importedSpecifier(current);
|
|
3381
|
+
if (specifier !== void 0) return specifier;
|
|
3382
|
+
current = current.expression;
|
|
3383
|
+
} else return ts.isIdentifier(current) ? bindings.get(current.text) : void 0;
|
|
3079
3384
|
}
|
|
3080
3385
|
/** The specifier of `require("x")`, `import x from "x"`, `export { default } from "x"` or `import("x")`. */
|
|
3081
3386
|
function importedSpecifier(node) {
|
|
@@ -3263,12 +3568,13 @@ const librariesSchema = z.union([z.literal(false), z.array(z.enum(LIBRARY_IDS))]
|
|
|
3263
3568
|
} });
|
|
3264
3569
|
const configShape = {
|
|
3265
3570
|
$schema: z.string().optional(),
|
|
3571
|
+
extends: z.boolean({ error: (issue) => `"extends" is true or false, not ${JSON.stringify(issue.input)}: the design-system package is found from the dependencies, the one whose package.json declares its config ("onsystem"). Leave "extends" out to build on it, or set it to false to read this config alone.` }).optional().describe("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."),
|
|
3266
3572
|
components: globsSchema.optional().describe("Globs for component source files, relative to the root."),
|
|
3267
3573
|
exclude: z.array(z.string()).optional().describe("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`."),
|
|
3268
3574
|
tokens: z.union([tokenSourceSchema, z.array(tokenSourceSchema)]).optional().describe("Token files: W3C DTCG JSON (*.json), CSS custom properties (*.css) or a DESIGN.md's front matter (*.md)."),
|
|
3269
3575
|
docs: globsSchema.optional().describe("Globs for per-component Markdown/MDX docs."),
|
|
3270
3576
|
tsconfig: z.string().optional().describe("tsconfig used to resolve types and path aliases."),
|
|
3271
|
-
importPath: z.string().optional().describe("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."),
|
|
3577
|
+
importPath: z.string().optional().describe("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."),
|
|
3272
3578
|
elements: z.record(z.string(), z.string()).optional().describe("Extra native element → component mappings, e.g. { \"a\": \"Link\" }."),
|
|
3273
3579
|
libraries: librariesSchema.optional().describe(`Published component libraries to read from their type declarations when the project depends on them. Omitted: every one onsystem reads (${LIBRARY_IDS.join(", ")}). false: none. A list: only those, e.g. ["mui"].`),
|
|
3274
3580
|
includeDesignSystem: z.boolean().optional().describe("check: lint the design system's own component files too. Off by default: they implement the scale and primitives the rules enforce."),
|
|
@@ -3348,9 +3654,11 @@ async function loadConfigWith(options, context = {}) {
|
|
|
3348
3654
|
let packages = context.packages?.root === searchDir ? context.packages : void 0;
|
|
3349
3655
|
const finder = (dir) => packages?.root === dir ? packages : packages = new PackageFinder(dir);
|
|
3350
3656
|
let lookup = context.lookup;
|
|
3657
|
+
/**
|
|
3658
|
+
* The project's own config: a config file in the folder searched, `--config`, or a workspace
|
|
3659
|
+
* root's that a project in it takes on.
|
|
3660
|
+
*/
|
|
3351
3661
|
let configFile;
|
|
3352
|
-
/** The design-system package whose config this project takes on, having none of its own. */
|
|
3353
|
-
let declared;
|
|
3354
3662
|
if (options.config) configFile = path.resolve(cwd, options.config);
|
|
3355
3663
|
else {
|
|
3356
3664
|
const find = (names) => names.map((name) => path.join(searchDir, name)).find((file) => fs.existsSync(file));
|
|
@@ -3358,120 +3666,131 @@ async function loadConfigWith(options, context = {}) {
|
|
|
3358
3666
|
const legacy = find(LEGACY_CONFIG_FILES);
|
|
3359
3667
|
if (legacy) deprecations.push(legacyConfigNotice(legacy, configFile));
|
|
3360
3668
|
configFile ??= legacy ?? ownDeclaredConfig(searchDir);
|
|
3361
|
-
if (!configFile) {
|
|
3362
|
-
lookup ??= findDesignSystemPackage(searchDir, finder(searchDir));
|
|
3363
|
-
if (lookup?.problems.length) throw declarationError(lookup, searchDir);
|
|
3364
|
-
declared = lookup?.found;
|
|
3365
|
-
configFile = declared?.config;
|
|
3366
|
-
}
|
|
3367
3669
|
}
|
|
3368
|
-
|
|
3369
|
-
let raw = {};
|
|
3370
|
-
if (configFile) {
|
|
3371
|
-
if (!fs.existsSync(configFile)) throw new ConfigError(`Config file not found: ${configFile}`);
|
|
3372
|
-
if (options.jsonConfigOnly && !configFile.endsWith(".json")) throw new ConfigError(`${configFile} was not run: the server runs a JavaScript or TypeScript config only in a project it was started in (its working directory, --root or the client's roots), not in one found from the path a tool call names. Start the server in the project, or use onsystem.config.json.`);
|
|
3373
|
-
raw = await readConfigFile(configFile);
|
|
3374
|
-
}
|
|
3375
|
-
const parsed = configSchema.safeParse(raw);
|
|
3376
|
-
if (!parsed.success) throw new ConfigError(`Invalid config in ${configFile ?? "(defaults)"}:\n${z.prettifyError(parsed.error)}`);
|
|
3377
|
-
const config = parsed.data;
|
|
3670
|
+
const config = configFile ? await readConfig(configFile, options) : {};
|
|
3378
3671
|
const root = options.root ? path.resolve(cwd, options.root) : options.config && configFile ? path.dirname(configFile) : searchDir;
|
|
3379
3672
|
if (!isDirectory(root)) throw new ConfigError(`Project root not found: ${root}`);
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3673
|
+
let declared;
|
|
3674
|
+
if (config.extends !== false) {
|
|
3675
|
+
lookup ??= findDesignSystemPackage(root, finder(root));
|
|
3676
|
+
if (!lookup?.problems.length) declared = lookup?.found;
|
|
3677
|
+
else if (!configFile) throw declarationError(lookup, root);
|
|
3678
|
+
else warnings.push(`${lookup.problems.map((p) => `${p.name}: ${p.problem}`).join("\n")}\nSo ${configFile} is read alone, without the config a design-system package declares. Fix the "${PACKAGE_FIELD}" field in that package, or set "extends": false in ${path.basename(configFile)}.`);
|
|
3679
|
+
}
|
|
3680
|
+
for (const { name, problem } of lookup?.skipped ?? []) warnings.push(`${name}'s onsystem config was skipped: ${problem} ${name} is installed in node_modules, so this project is read as if it declared none.`);
|
|
3681
|
+
const pkg = declared ? await readConfig(declared.config, options) : void 0;
|
|
3682
|
+
const base = options.base ? path.resolve(cwd, options.base) : root;
|
|
3683
|
+
const rebase = (from) => (p) => from === root ? p : toPosix(path.relative(root, path.resolve(from, slashGlob(p)))) || ".";
|
|
3684
|
+
const fromBase = rebase(base);
|
|
3685
|
+
const fromPackage = rebase(declared?.dir ?? root);
|
|
3383
3686
|
const toProject = toPosix(path.relative(base, root));
|
|
3384
3687
|
const excludeFromBase = (e) => {
|
|
3385
|
-
if (
|
|
3386
|
-
if (declared) return fromBase(e);
|
|
3688
|
+
if (base === root || e.startsWith("**/")) return e;
|
|
3387
3689
|
if (e === toProject) return "**";
|
|
3388
3690
|
return e.startsWith(`${toProject}/`) ? e.slice(toProject.length + 1) : void 0;
|
|
3389
3691
|
};
|
|
3692
|
+
const excludeFromPackage = (e) => e.startsWith("**/") ? e : fromPackage(e);
|
|
3390
3693
|
const outside = [];
|
|
3391
3694
|
const within = (field) => (p) => {
|
|
3392
3695
|
if (!declared || staysIn(declared.dir, declared.boundary, slashGlob(p))) return true;
|
|
3393
3696
|
outside.push(`${field} ${p}`);
|
|
3394
3697
|
return false;
|
|
3395
3698
|
};
|
|
3396
|
-
const
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3699
|
+
const pathOf = (t) => typeof t === "string" ? t : t.path;
|
|
3700
|
+
const tokensFrom = (move) => (t) => typeof t === "string" ? { path: move(t) } : {
|
|
3701
|
+
...t,
|
|
3702
|
+
path: move(t.path)
|
|
3703
|
+
};
|
|
3704
|
+
const packageComponents = pkg?.components === void 0 ? void 0 : toArray(pkg.components).filter(within("components")).map(fromPackage);
|
|
3705
|
+
const packageTokens = pkg?.tokens === void 0 ? void 0 : toArray(pkg.tokens).filter((t) => within("tokens")(pathOf(t))).map(tokensFrom(fromPackage));
|
|
3706
|
+
const packageDocs = pkg?.docs === void 0 ? void 0 : toArray(pkg.docs).filter(within("docs")).map(fromPackage);
|
|
3399
3707
|
if (declared && outside.length) warnings.push(`${declared.name}'s onsystem config names paths outside ${declared.installed ? "the package" : "the workspace"}, which were ignored: ${outside.join(", ")}.`);
|
|
3708
|
+
const inherits = pkg !== void 0 && config.components === void 0;
|
|
3709
|
+
const configComponents = config.components === void 0 ? packageComponents : toArray(config.components).map(fromBase);
|
|
3710
|
+
const configTokens = config.tokens === void 0 ? inherits ? packageTokens : void 0 : toArray(config.tokens).map(tokensFrom(fromBase));
|
|
3711
|
+
const configDocs = config.docs === void 0 ? inherits ? packageDocs : void 0 : toArray(config.docs).map(fromBase);
|
|
3712
|
+
const importPath = config.importPath ?? (inherits ? pkg.importPath : void 0);
|
|
3713
|
+
const librariesSetting = config.libraries ?? (inherits ? pkg.libraries : void 0);
|
|
3400
3714
|
const rules = {};
|
|
3401
3715
|
for (const id of RULE_IDS) {
|
|
3402
|
-
const setting = config.rules?.[id];
|
|
3716
|
+
const setting = config.rules?.[id] ?? pkg?.rules?.[id];
|
|
3403
3717
|
rules[id] = setting === void 0 ? {
|
|
3404
3718
|
severity: DEFAULT_SEVERITY[id],
|
|
3405
3719
|
options: {}
|
|
3406
3720
|
} : resolveRule(setting);
|
|
3407
3721
|
}
|
|
3408
|
-
const overrides = (
|
|
3722
|
+
const overrides = (config.overrides ?? []).map((override) => ({
|
|
3409
3723
|
files: toArray(override.files).map(slashGlob),
|
|
3410
3724
|
rules: Object.fromEntries(Object.entries(override.rules).map(([id, setting]) => [id, resolveRule(setting)]))
|
|
3411
3725
|
}));
|
|
3412
|
-
const tsconfig = config.tsconfig === void 0
|
|
3726
|
+
const tsconfig = config.tsconfig === void 0 ? void 0 : fromBase(config.tsconfig.replaceAll("\\", "/"));
|
|
3413
3727
|
if (tsconfig !== void 0 && !fs.existsSync(path.resolve(root, tsconfig))) throw new ConfigError(`tsconfig not found: ${path.resolve(root, tsconfig)} (from "tsconfig" in ${configFile ?? "the config"})`);
|
|
3414
|
-
const componentsSet = Boolean(options.components?.length) ||
|
|
3728
|
+
const componentsSet = Boolean(options.components?.length) || configComponents !== void 0;
|
|
3415
3729
|
const detection = componentsSet ? void 0 : detectProject(root, tsconfig, void 0, declared, finder(root));
|
|
3416
3730
|
const explicitTokens = options.tokens?.length ? {
|
|
3417
3731
|
paths: options.tokens,
|
|
3418
3732
|
from: "--tokens"
|
|
3419
|
-
} : config.tokens !== void 0
|
|
3420
|
-
paths: toArray(config.tokens).map((t) => fromBase(
|
|
3733
|
+
} : config.tokens !== void 0 ? {
|
|
3734
|
+
paths: toArray(config.tokens).map((t) => fromBase(pathOf(t))),
|
|
3421
3735
|
from: `"tokens" in ${configFile ?? "the config"}`
|
|
3422
3736
|
} : void 0;
|
|
3423
3737
|
for (const file of explicitTokens?.paths ?? []) {
|
|
3424
3738
|
const absolute = path.resolve(root, slashGlob(file));
|
|
3425
3739
|
if (!/[*?[\]{}()!]/.test(file) && !fs.existsSync(absolute)) throw new ConfigError(`Token file not found: ${absolute} (from ${explicitTokens?.from})`);
|
|
3426
3740
|
}
|
|
3427
|
-
const components = (options.components?.length ? options.components : configComponents
|
|
3428
|
-
const libraries = detectLibraries(root,
|
|
3429
|
-
importPath
|
|
3741
|
+
const components = (options.components?.length ? options.components : configComponents ?? (detection ? [...detection.withDefaults ? DEFAULT_COMPONENTS : [], ...detection.components] : DEFAULT_COMPONENTS)).map(slashGlob);
|
|
3742
|
+
const libraries = detectLibraries(root, librariesSetting, {
|
|
3743
|
+
importPath,
|
|
3430
3744
|
components
|
|
3431
3745
|
});
|
|
3432
|
-
const tokenSources = options.tokens?.length ? options.tokens.map((p) => ({ path: p })) : configTokens
|
|
3433
|
-
...t,
|
|
3434
|
-
path: fromBase(t.path)
|
|
3435
|
-
}) : [...(detection?.tokens.length ? [...detection.tokens, ...DEFAULT_TOKENS.filter((t) => t.endsWith(".json"))] : DEFAULT_TOKENS).map((p) => ({ path: p })), ...FALLBACK_TOKENS.map((p) => ({
|
|
3746
|
+
const tokenSources = options.tokens?.length ? options.tokens.map((p) => ({ path: p })) : configTokens ?? [...(detection?.tokens.length ? [...detection.tokens, ...DEFAULT_TOKENS.filter((t) => t.endsWith(".json"))] : DEFAULT_TOKENS).map((p) => ({ path: p })), ...FALLBACK_TOKENS.map((p) => ({
|
|
3436
3747
|
path: p,
|
|
3437
3748
|
fallback: true
|
|
3438
3749
|
}))];
|
|
3439
3750
|
const tidy = (e) => slashGlob(e).replace(/^(?:\.\/)+/, "").replace(/(.)\/+$/, "$1");
|
|
3440
|
-
const
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3751
|
+
const excludeOf = (listed, move) => {
|
|
3752
|
+
const dropped = new Set(listed.filter((e) => e.startsWith("!")).map((e) => tidy(e.slice(1))));
|
|
3753
|
+
for (const pattern of dropped) {
|
|
3754
|
+
if (DEFAULT_EXCLUDE.includes(pattern)) continue;
|
|
3755
|
+
warnings.push(`"!${pattern}" in "exclude" takes out none of the defaults, which are ${DEFAULT_EXCLUDE.map((d) => `"${d}"`).join(", ")}: a pattern that starts with "!" names one of them.`);
|
|
3756
|
+
}
|
|
3757
|
+
return [.../* @__PURE__ */ new Set([...DEFAULT_EXCLUDE.filter((d) => !dropped.has(d)), ...listed.filter((e) => !e.startsWith("!")).map(tidy)])].map(move).filter((e) => e !== void 0);
|
|
3758
|
+
};
|
|
3759
|
+
const exclude = excludeOf(config.exclude ?? [], excludeFromBase);
|
|
3760
|
+
const packageExclude = pkg?.exclude ? excludeOf(pkg.exclude, excludeFromPackage) : void 0;
|
|
3447
3761
|
return {
|
|
3448
3762
|
root,
|
|
3449
|
-
configFile,
|
|
3763
|
+
configFile: configFile ?? declared?.config,
|
|
3450
3764
|
components,
|
|
3451
|
-
exclude:
|
|
3452
|
-
...
|
|
3765
|
+
exclude: packageExclude ? [.../* @__PURE__ */ new Set([...exclude, ...packageExclude.filter((e) => !DEFAULT_EXCLUDE.includes(e))])] : exclude,
|
|
3766
|
+
...packageExclude && inherits ? { designSystemExclude: packageExclude } : {},
|
|
3453
3767
|
tokens: tokenSources.map((t) => ({
|
|
3454
3768
|
...t,
|
|
3455
3769
|
path: slashGlob(t.path)
|
|
3456
3770
|
})),
|
|
3457
3771
|
...!options.tokens?.length && configTokens === void 0 ? { tokensDetected: true } : {},
|
|
3458
|
-
docs: (options.docs?.length ? options.docs : configDocs
|
|
3772
|
+
docs: (options.docs?.length ? options.docs : configDocs ?? [.../* @__PURE__ */ new Set([...DEFAULT_DOCS, ...detection?.docs ?? []])]).map(slashGlob),
|
|
3459
3773
|
tsconfig,
|
|
3460
|
-
importPath
|
|
3461
|
-
imports: detection?.imports ?? (declared && componentsSet ? packageImports(root, declared.dir) : []),
|
|
3774
|
+
importPath,
|
|
3775
|
+
imports: detection?.imports ?? (declared && inherits && componentsSet ? packageImports(root, declared.dir) : []),
|
|
3462
3776
|
detected: detection?.source,
|
|
3463
3777
|
...detection?.designSystems ? { designSystems: detection.designSystems } : {},
|
|
3464
3778
|
tailwindConfig: findTailwindConfig(root),
|
|
3465
3779
|
libraries: libraries.read,
|
|
3466
|
-
libraryIds:
|
|
3780
|
+
libraryIds: librariesSetting,
|
|
3467
3781
|
librariesOff: libraries.off,
|
|
3468
3782
|
librariesUnread: libraries.unread,
|
|
3469
|
-
elements:
|
|
3470
|
-
|
|
3783
|
+
elements: {
|
|
3784
|
+
...inherits ? pkg.elements : {},
|
|
3785
|
+
...config.elements
|
|
3786
|
+
},
|
|
3787
|
+
includeDesignSystem: options.includeDesignSystem ?? config.includeDesignSystem ?? false,
|
|
3471
3788
|
rules,
|
|
3472
3789
|
overrides,
|
|
3473
|
-
...
|
|
3790
|
+
...base !== root ? { base } : {},
|
|
3474
3791
|
...declared ? { designSystemPackage: declared } : {},
|
|
3792
|
+
...inherits ? { inherits: true } : {},
|
|
3793
|
+
...config.extends === false ? { extendsOff: true } : {},
|
|
3475
3794
|
configured: componentsSet,
|
|
3476
3795
|
...deprecations.length ? { deprecations } : {},
|
|
3477
3796
|
...warnings.length ? { warnings } : {}
|
|
@@ -3480,7 +3799,7 @@ async function loadConfigWith(options, context = {}) {
|
|
|
3480
3799
|
/**
|
|
3481
3800
|
* Whether `dir` has a config of its own: a config file under its current or old name, or one its
|
|
3482
3801
|
* package.json names in its `onsystem` field. Without one, a project takes on its design-system
|
|
3483
|
-
* package's config,
|
|
3802
|
+
* package's config, and, from a workspace root, the root's over it.
|
|
3484
3803
|
*/
|
|
3485
3804
|
function hasOwnConfig(dir) {
|
|
3486
3805
|
if ([...CONFIG_FILES, ...LEGACY_CONFIG_FILES].some((name) => fs.existsSync(path.join(dir, name)))) return true;
|
|
@@ -3558,6 +3877,14 @@ function nodeRunsTypeScript(version = process.versions.node) {
|
|
|
3558
3877
|
const [major = 0, minor = 0] = version.replace(/^v/, "").split(".").map(Number);
|
|
3559
3878
|
return major > 23 || major === 23 && minor >= 6 || major === 22 && minor >= 18;
|
|
3560
3879
|
}
|
|
3880
|
+
/** A config file, read and validated: a JSON one only with `jsonConfigOnly`. */
|
|
3881
|
+
async function readConfig(file, options) {
|
|
3882
|
+
if (!fs.existsSync(file)) throw new ConfigError(`Config file not found: ${file}`);
|
|
3883
|
+
if (options.jsonConfigOnly && !file.endsWith(".json")) throw new ConfigError(`${file} was not run: the server runs a JavaScript or TypeScript config only in a project it was started in (its working directory, --root or the client's roots), not in one found from the path a tool call names. Start the server in the project, or use onsystem.config.json.`);
|
|
3884
|
+
const parsed = configSchema.safeParse(await readConfigFile(file));
|
|
3885
|
+
if (!parsed.success) throw new ConfigError(`Invalid config in ${file}:\n${z.prettifyError(parsed.error)}`);
|
|
3886
|
+
return parsed.data;
|
|
3887
|
+
}
|
|
3561
3888
|
async function readConfigFile(file) {
|
|
3562
3889
|
if (/\.[cm]?ts$/.test(file) && !nodeRunsTypeScript()) throw new ConfigError(`${file} is TypeScript, which Node.js runs from 22.18; this is ${process.version}. Use onsystem.config.json or .mjs, or Node.js 22.18 or later.`);
|
|
3563
3890
|
if (file.endsWith(".json")) try {
|
|
@@ -6193,7 +6520,7 @@ function cssSheetTokens(sheets) {
|
|
|
6193
6520
|
const category = isSpacingBase ? "spacing" : namespace?.[1] ?? "other";
|
|
6194
6521
|
const tailwindKey = isSpacingBase ? "" : variable.name.slice(namespace?.[0].length ?? 0);
|
|
6195
6522
|
const tailwindNamespace = isSpacingBase ? "--spacing" : namespace?.[0].slice(0, -1) ?? "";
|
|
6196
|
-
const alias =
|
|
6523
|
+
const alias = themeAlias(variable.value, base, lookup);
|
|
6197
6524
|
const target = alias ? base.get(alias) : void 0;
|
|
6198
6525
|
if (alias && target) {
|
|
6199
6526
|
consumed.add(alias);
|
|
@@ -6214,7 +6541,7 @@ function cssSheetTokens(sheets) {
|
|
|
6214
6541
|
add(finalize({
|
|
6215
6542
|
name: variable.name.slice(2),
|
|
6216
6543
|
category,
|
|
6217
|
-
value: variable.value,
|
|
6544
|
+
value: resolveValue(variable.value, lookup),
|
|
6218
6545
|
modes: modeValues(variable.name, modes, lookup),
|
|
6219
6546
|
cssVar: variable.inline ? void 0 : variable.name,
|
|
6220
6547
|
tailwind: tailwindKey,
|
|
@@ -6345,6 +6672,22 @@ function categorize$1(name, value) {
|
|
|
6345
6672
|
function varAlias(value) {
|
|
6346
6673
|
return /^var\(\s*(--[\w-]+)\s*\)$/.exec(value.trim())?.[1];
|
|
6347
6674
|
}
|
|
6675
|
+
/**
|
|
6676
|
+
* The base variable an `@theme` variable stands for: `--x` for `var(--x)`, and for
|
|
6677
|
+
* `hsl(var(--x))` or `rgb(var(--x))` when `--x` holds bare HSL or RGB channels, as
|
|
6678
|
+
* shadcn/ui's Tailwind v4 codemod leaves a v3 theme (`--color-primary: hsl(var(--primary))`).
|
|
6679
|
+
* The token is then `--x`, whose usage already wraps the channels (`hsl(var(--primary))`).
|
|
6680
|
+
*/
|
|
6681
|
+
function themeAlias(value, base, lookup) {
|
|
6682
|
+
const plain = varAlias(value);
|
|
6683
|
+
if (plain) return plain;
|
|
6684
|
+
const match = /^(hsl|rgb)a?\(\s*var\(\s*(--[\w-]+)\s*\)\s*(?:\/\s*<alpha-value>\s*)?\)$/.exec(value.trim());
|
|
6685
|
+
const name = match?.[2];
|
|
6686
|
+
const target = name ? base.get(name) : void 0;
|
|
6687
|
+
if (!match || !name || !target) return void 0;
|
|
6688
|
+
const channels = resolveValue(target.value, lookup);
|
|
6689
|
+
return (match[1] === "hsl" ? isBareHsl(channels) : isBareRgb(channels)) ? name : void 0;
|
|
6690
|
+
}
|
|
6348
6691
|
/** Follows plain `var(--x)` aliases so the token shows its concrete value. */
|
|
6349
6692
|
function resolveValue(value, lookup, depth = 0) {
|
|
6350
6693
|
const alias = /^var\(\s*(--[\w-]+)\s*\)$/.exec(value)?.[1];
|
|
@@ -7210,7 +7553,7 @@ function toDtcg(tokens) {
|
|
|
7210
7553
|
const paths = assignPaths(tokens, warnings);
|
|
7211
7554
|
const lookup = varLookup(tokens);
|
|
7212
7555
|
const byName = new Map(tokens.map((t) => [t.name, t]));
|
|
7213
|
-
const tree =
|
|
7556
|
+
const tree = Object.create(null);
|
|
7214
7557
|
let count = 0;
|
|
7215
7558
|
for (const category of TOKEN_CATEGORIES) for (const token of tokens) {
|
|
7216
7559
|
const path = token.category === category ? paths.get(token) : void 0;
|
|
@@ -7292,7 +7635,7 @@ function insert(tree, path, node) {
|
|
|
7292
7635
|
const next = group[key];
|
|
7293
7636
|
if (isObject$1(next)) group = next;
|
|
7294
7637
|
else {
|
|
7295
|
-
const created =
|
|
7638
|
+
const created = Object.create(null);
|
|
7296
7639
|
group[key] = created;
|
|
7297
7640
|
group = created;
|
|
7298
7641
|
}
|
|
@@ -7524,7 +7867,7 @@ function colorObject(css) {
|
|
|
7524
7867
|
else if (spec.space === "srgb" && components.every((c) => typeof c === "number" && Math.abs(c * 255 - Math.round(c * 255)) < .001)) out.hex = formatHex(color);
|
|
7525
7868
|
return out;
|
|
7526
7869
|
}
|
|
7527
|
-
const PLAIN_LENGTH = /^(-?(?:\d
|
|
7870
|
+
const PLAIN_LENGTH = /^(-?(?:\d+(?:\.\d*)?|\.\d+))(px|rem)$/;
|
|
7528
7871
|
/** `0.5rem` → `{ value: 0.5, unit: "rem" }`; a `calc()` of tokens → its px value. */
|
|
7529
7872
|
function dimensionValue(value, lookup) {
|
|
7530
7873
|
const plain = plainDimension(value);
|
|
@@ -7554,8 +7897,8 @@ function plainDimension(value) {
|
|
|
7554
7897
|
unit: match[2] ?? "px"
|
|
7555
7898
|
} : void 0;
|
|
7556
7899
|
}
|
|
7557
|
-
const COMPOSITE = /^[\w-]+\s
|
|
7558
|
-
const NUMBER = /^-?(?:\d
|
|
7900
|
+
const COMPOSITE = /^[\w-]+\s*:[^;]+(?:;\s*[\w-]+\s*:[^;]+)*;?$/;
|
|
7901
|
+
const NUMBER = /^-?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
7559
7902
|
/** What a typography token sets, from its name and Tailwind class (`font-sans`, `text-sm`). */
|
|
7560
7903
|
function typographyKind(token) {
|
|
7561
7904
|
const value = token.value.trim();
|
|
@@ -7815,7 +8158,7 @@ function frontMatterValue(token, key, lookup) {
|
|
|
7815
8158
|
}
|
|
7816
8159
|
}
|
|
7817
8160
|
/** A DESIGN.md dimension: px, em or rem. */
|
|
7818
|
-
const DESIGN_DIMENSION = /^-?(?:\d
|
|
8161
|
+
const DESIGN_DIMENSION = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:px|rem|em)$/;
|
|
7819
8162
|
/**
|
|
7820
8163
|
* A typography token as a DESIGN.md typography level: `{ fontFamily: "Inter" }` for
|
|
7821
8164
|
* `--font-sans`, every property of a composite. A `var()` is no font name (`next/font` sets
|
|
@@ -7858,7 +8201,8 @@ function table(tokens, keys) {
|
|
|
7858
8201
|
use(token),
|
|
7859
8202
|
...described ? [token.description ?? ""] : []
|
|
7860
8203
|
]);
|
|
7861
|
-
const
|
|
8204
|
+
const oneLine = (text) => text.split(/\r\n?|\n/).map((part) => part.trim()).filter(Boolean).join(" ");
|
|
8205
|
+
const line = (cells) => `| ${cells.map((c) => oneLine(c).replace(/\|/g, "\\|")).join(" | ")} |`;
|
|
7862
8206
|
return [
|
|
7863
8207
|
line(header),
|
|
7864
8208
|
line(header.map(() => "---")),
|
|
@@ -11677,7 +12021,7 @@ function isObject(value) {
|
|
|
11677
12021
|
var name = "onsystem";
|
|
11678
12022
|
//#endregion
|
|
11679
12023
|
//#region src/version.ts
|
|
11680
|
-
const VERSION = "0.
|
|
12024
|
+
const VERSION = "0.10.0";
|
|
11681
12025
|
const NAME = name;
|
|
11682
12026
|
//#endregion
|
|
11683
12027
|
//#region src/lint/sarif.ts
|
|
@@ -12505,55 +12849,6 @@ function searchComponents(index, query, limit = 5) {
|
|
|
12505
12849
|
}));
|
|
12506
12850
|
}
|
|
12507
12851
|
//#endregion
|
|
12508
|
-
//#region src/tokens/imports.ts
|
|
12509
|
-
/** Enough stylesheets for a theme split over files, without reading a whole design system. */
|
|
12510
|
-
const MAX_IMPORTED = 50;
|
|
12511
|
-
/**
|
|
12512
|
-
* The specifiers a stylesheet `@import`s: `@import "./theme.css" layer(base)`,
|
|
12513
|
-
* `@import url(theme.css)`, `@import "@acme/theme"`. Empty for CSS that does not parse.
|
|
12514
|
-
*/
|
|
12515
|
-
function cssImports(css) {
|
|
12516
|
-
let root;
|
|
12517
|
-
try {
|
|
12518
|
-
root = postcss.parse(css);
|
|
12519
|
-
} catch {
|
|
12520
|
-
return [];
|
|
12521
|
-
}
|
|
12522
|
-
const out = [];
|
|
12523
|
-
for (const node of root.nodes) {
|
|
12524
|
-
if (node.type !== "atrule" || node.name !== "import") continue;
|
|
12525
|
-
const match = /^\s*(?:url\(\s*)?(?:"([^"]+)"|'([^']+)'|([^\s"')]+)\s*\))/.exec(node.params);
|
|
12526
|
-
const specifier = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
12527
|
-
if (specifier) out.push(specifier);
|
|
12528
|
-
}
|
|
12529
|
-
return out;
|
|
12530
|
-
}
|
|
12531
|
-
/**
|
|
12532
|
-
* The stylesheets `files` import, and the ones those import in turn, each once and in the
|
|
12533
|
-
* order they are imported. The files themselves are not repeated.
|
|
12534
|
-
*/
|
|
12535
|
-
function importedStylesheets(files, resolve) {
|
|
12536
|
-
const seen = new Set(files);
|
|
12537
|
-
const out = [];
|
|
12538
|
-
const visit = (file) => {
|
|
12539
|
-
let text;
|
|
12540
|
-
try {
|
|
12541
|
-
text = fs.readFileSync(file, "utf8");
|
|
12542
|
-
} catch {
|
|
12543
|
-
return;
|
|
12544
|
-
}
|
|
12545
|
-
for (const specifier of cssImports(text)) {
|
|
12546
|
-
const target = resolve(specifier, file);
|
|
12547
|
-
if (!target || seen.has(target) || out.length >= MAX_IMPORTED) continue;
|
|
12548
|
-
seen.add(target);
|
|
12549
|
-
out.push(target);
|
|
12550
|
-
visit(target);
|
|
12551
|
-
}
|
|
12552
|
-
};
|
|
12553
|
-
for (const file of files) visit(file);
|
|
12554
|
-
return out;
|
|
12555
|
-
}
|
|
12556
|
-
//#endregion
|
|
12557
12852
|
//#region src/util/log.ts
|
|
12558
12853
|
const stderrLogger = {
|
|
12559
12854
|
info: (message) => process.stderr.write(`[onsystem] ${message}\n`),
|
|
@@ -13134,15 +13429,16 @@ var DesignSystemHost = class {
|
|
|
13134
13429
|
this.watchConfigFiles();
|
|
13135
13430
|
}
|
|
13136
13431
|
/**
|
|
13137
|
-
* Watches the config file, the
|
|
13138
|
-
*
|
|
13139
|
-
*
|
|
13140
|
-
* `extends` target is picked up.
|
|
13432
|
+
* Watches the config file, the config a design-system package declares, which a project with
|
|
13433
|
+
* a config of its own reads under that one, the tsconfig and the tsconfigs it extends through
|
|
13434
|
+
* their directories: editors save by renaming a new file over the old one, which ends a watch
|
|
13435
|
+
* on the file. Called again after each build, so a new `extends` target is picked up.
|
|
13141
13436
|
*/
|
|
13142
13437
|
watchConfigFiles() {
|
|
13143
13438
|
const { root, configFile, tsconfig, designSystemPackage } = this.config;
|
|
13144
13439
|
const files = [
|
|
13145
13440
|
configFile,
|
|
13441
|
+
designSystemPackage?.config,
|
|
13146
13442
|
designSystemPackage && path.join(designSystemPackage.dir, "package.json"),
|
|
13147
13443
|
...DETECTION_FILES.map((f) => path.join(root, f)),
|
|
13148
13444
|
...tsconfig ? [path.resolve(root, tsconfig)] : PROJECT_CONFIG_FILES.map((f) => path.join(root, f)),
|
|
@@ -13200,7 +13496,7 @@ var DesignSystemHost = class {
|
|
|
13200
13496
|
const { root, configFile, designSystemPackage, warnings } = this.config;
|
|
13201
13497
|
const load = this.options.loadConfig ?? (() => loadConfig({
|
|
13202
13498
|
root,
|
|
13203
|
-
config: designSystemPackage ? void 0 : configFile
|
|
13499
|
+
config: configFile === designSystemPackage?.config ? void 0 : configFile
|
|
13204
13500
|
}));
|
|
13205
13501
|
try {
|
|
13206
13502
|
this.config = await load();
|
|
@@ -13239,4 +13535,4 @@ var DesignSystemHost = class {
|
|
|
13239
13535
|
}
|
|
13240
13536
|
};
|
|
13241
13537
|
//#endregion
|
|
13242
|
-
export {
|
|
13538
|
+
export { DEFAULT_TOKENS as $, unrecordedRules as A, isInside as At, statusKinds as B, countBaseline as C, workspacePackageDirs as Ct, pruneBaseline as D, truncate as Dt, onLines as E, plural$1 as Et, loadTokens as F, readProjectConfig as Ft, parseDoc as G, parseDesignMd as H, mergeTokens as I, ConfigError as J, extractComponents as K, toDesignMd as L, writeBaseline as M, relativePath as Mt, RULES as N, toPosix as Nt, readBaseline as O, unique as Ot, TokenIndex as P, defaultProjectConfig as Pt, DEFAULT_TEST_FOLDERS as Q, toDtcg as R, applyBaseline as S, isWorkspaceRoot as St, goneFiles as T, closest as Tt, parseCssTokens as U, parseDtcgTokens as V, attachDocs as W, DEFAULT_SEVERITY as X, DEFAULT_DOCS as Y, DEFAULT_TEST_EXCLUDE as Z, formatDiagnostics as _, PackageFinder as _t, fingerprint as a, excludedBy as at, BASELINE_FILE as b, findDesignSystemPackage as bt, silentLogger as c, loadConfigWith as ct, descriptionOf as d, findVariantDefinitions as dt, FALLBACK_TOKENS as et, searchComponents as f, LIBRARIES as ft, escapeData as g, PACKAGE_FIELD as gt, uncheckedNotice as h, notReadYet as ht, componentFiles as i, defineConfig as it, updateBaseline as j, matchesGlob as jt, rulesRun as k, SCRIPT_FILE$2 as kt, stderrLogger as l, rulesFor as lt, checkSource as m, libraryTitle as mt, DesignSystemHost as n, RULE_IDS as nt, loadDesignSystem as o, hasOwnConfig as ot, applyFixes as p, LIBRARY_IDS as pt, CONFIG_FILES as q, buildModel as r, configJsonSchema as rt, tokenFiles as s, loadConfig as st, DesignSystem as t, LEGACY_CONFIG_FILES as tt, buildSearchIndex as u, formatPx as ut, NAME as v, declaredConfig as vt, findMoves as w, workspacePatterns as wt, LEGACY_BASELINE_FILE as x, isDesignSystemName as xt, VERSION as y, detectProject as yt, TOKEN_CATEGORIES as z };
|