better-design 0.35.2 → 0.35.5
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/index.js +109 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -178,8 +178,8 @@ function appSupport() {
|
|
|
178
178
|
return configHome();
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
function dirExists(...
|
|
182
|
-
return existsSync(path.join(...
|
|
181
|
+
function dirExists(...segments2) {
|
|
182
|
+
return existsSync(path.join(...segments2));
|
|
183
183
|
}
|
|
184
184
|
function onPath(bin) {
|
|
185
185
|
const dirs = (process.env.PATH ?? "").split(path.delimiter);
|
|
@@ -28889,9 +28889,9 @@ var init_schema3 = __esm({
|
|
|
28889
28889
|
});
|
|
28890
28890
|
|
|
28891
28891
|
// ../shared/src/mcp/feature-map/build.ts
|
|
28892
|
-
function toRoute(
|
|
28892
|
+
function toRoute(segments2) {
|
|
28893
28893
|
const out = [];
|
|
28894
|
-
for (const seg of
|
|
28894
|
+
for (const seg of segments2) {
|
|
28895
28895
|
if (/^\(.*\)$/.test(seg) || seg.startsWith("@")) continue;
|
|
28896
28896
|
if (seg.startsWith("_")) return null;
|
|
28897
28897
|
const param = /^\[{1,2}(?:\.\.\.)?([^\]]+)\]{1,2}$/.exec(seg);
|
|
@@ -29613,7 +29613,7 @@ var MCP_IMPLEMENTATION_VERSION;
|
|
|
29613
29613
|
var init_version2 = __esm({
|
|
29614
29614
|
"../shared/src/mcp/version.ts"() {
|
|
29615
29615
|
"use strict";
|
|
29616
|
-
MCP_IMPLEMENTATION_VERSION = "0.35.
|
|
29616
|
+
MCP_IMPLEMENTATION_VERSION = "0.35.5";
|
|
29617
29617
|
}
|
|
29618
29618
|
});
|
|
29619
29619
|
|
|
@@ -30550,7 +30550,10 @@ function maskTemplateImplementation(content, isMdx) {
|
|
|
30550
30550
|
const mask = (value) => value.replace(/[^\r\n]/g, " ");
|
|
30551
30551
|
let visible = content.replace(/^---\s*$[\s\S]*?^---\s*$/m, mask);
|
|
30552
30552
|
if (isMdx) visible = maskMdxEsm(visible, mask);
|
|
30553
|
-
visible = visible.replace(
|
|
30553
|
+
visible = visible.replace(
|
|
30554
|
+
/<!--[\s\S]*?-->|<(script|style|pre|code|blockquote)\b[^>]*>[\s\S]*?<\/\1\s*>/gi,
|
|
30555
|
+
mask
|
|
30556
|
+
);
|
|
30554
30557
|
visible = visible.replace(/\/\*[\s\S]*?\*\//g, mask);
|
|
30555
30558
|
visible = maskTags(visible, mask);
|
|
30556
30559
|
visible = visible.replace(/\{\{([\s\S]*?)\}\}/g, (value, expression) => mask(value.slice(0, 2)) + revealRenderedExpression(expression, mask) + mask(value.slice(-2)));
|
|
@@ -30634,6 +30637,70 @@ var init_template_rules = __esm({
|
|
|
30634
30637
|
}
|
|
30635
30638
|
});
|
|
30636
30639
|
|
|
30640
|
+
// ../shared/src/lint/path-glob.ts
|
|
30641
|
+
function segments(path6) {
|
|
30642
|
+
const parts = [];
|
|
30643
|
+
for (const part of path6.replace(/\\/g, "/").split("/")) {
|
|
30644
|
+
if (part === "..") parts.pop();
|
|
30645
|
+
else if (part && part !== ".") parts.push(part);
|
|
30646
|
+
}
|
|
30647
|
+
return parts;
|
|
30648
|
+
}
|
|
30649
|
+
function segmentMatches(segment, pattern) {
|
|
30650
|
+
let s = 0;
|
|
30651
|
+
let p = 0;
|
|
30652
|
+
let star = -1;
|
|
30653
|
+
let mark = 0;
|
|
30654
|
+
while (s < segment.length) {
|
|
30655
|
+
if (pattern[p] === "?" || pattern[p] === segment[s]) {
|
|
30656
|
+
s += 1;
|
|
30657
|
+
p += 1;
|
|
30658
|
+
} else if (pattern[p] === "*") {
|
|
30659
|
+
star = p;
|
|
30660
|
+
p += 1;
|
|
30661
|
+
mark = s;
|
|
30662
|
+
} else if (star !== -1) {
|
|
30663
|
+
p = star + 1;
|
|
30664
|
+
mark += 1;
|
|
30665
|
+
s = mark;
|
|
30666
|
+
} else {
|
|
30667
|
+
return false;
|
|
30668
|
+
}
|
|
30669
|
+
}
|
|
30670
|
+
while (pattern[p] === "*") p += 1;
|
|
30671
|
+
return p === pattern.length;
|
|
30672
|
+
}
|
|
30673
|
+
function matchesPathGlob(path6, glob) {
|
|
30674
|
+
if (glob.length > MAX_GLOB_LENGTH || path6.length > MAX_MATCH_PATH_LENGTH) return false;
|
|
30675
|
+
const parts = segments(path6);
|
|
30676
|
+
let reachable = Array(parts.length + 1).fill(false);
|
|
30677
|
+
reachable[0] = true;
|
|
30678
|
+
for (const segment of segments(glob)) {
|
|
30679
|
+
const next = reachable.map(() => false);
|
|
30680
|
+
if (segment === "**") {
|
|
30681
|
+
let seen = false;
|
|
30682
|
+
reachable.forEach((value, j) => {
|
|
30683
|
+
seen = seen || value;
|
|
30684
|
+
next[j] = seen;
|
|
30685
|
+
});
|
|
30686
|
+
} else {
|
|
30687
|
+
for (let j = 1; j <= parts.length; j += 1) {
|
|
30688
|
+
next[j] = reachable[j - 1] && segmentMatches(parts[j - 1], segment);
|
|
30689
|
+
}
|
|
30690
|
+
}
|
|
30691
|
+
reachable = next;
|
|
30692
|
+
}
|
|
30693
|
+
return reachable[parts.length];
|
|
30694
|
+
}
|
|
30695
|
+
var MAX_GLOB_LENGTH, MAX_MATCH_PATH_LENGTH;
|
|
30696
|
+
var init_path_glob = __esm({
|
|
30697
|
+
"../shared/src/lint/path-glob.ts"() {
|
|
30698
|
+
"use strict";
|
|
30699
|
+
MAX_GLOB_LENGTH = 200;
|
|
30700
|
+
MAX_MATCH_PATH_LENGTH = 512;
|
|
30701
|
+
}
|
|
30702
|
+
});
|
|
30703
|
+
|
|
30637
30704
|
// ../shared/src/lint/engine.ts
|
|
30638
30705
|
import ts3 from "typescript";
|
|
30639
30706
|
function severityFromFlag(flag, s) {
|
|
@@ -30741,7 +30808,13 @@ function elementHasOnlyIconChild(element) {
|
|
|
30741
30808
|
if (!tagName) return false;
|
|
30742
30809
|
return /icon$/i.test(tagName) || /^icon/i.test(tagName) || /^(Lucide|Phosphor|Tabler|Solar)/.test(tagName);
|
|
30743
30810
|
}
|
|
30744
|
-
function
|
|
30811
|
+
function withElementExemptions(path6, config) {
|
|
30812
|
+
const fromConfigFolder = config.pathsFrom ? `${config.pathsFrom}/${path6}` : path6;
|
|
30813
|
+
const exempt = config.rules.elementExemptions?.some((exemption) => matchesPathGlob(fromConfigFolder, exemption.path));
|
|
30814
|
+
return exempt ? { ...config, rules: { ...config.rules, elements: {} } } : config;
|
|
30815
|
+
}
|
|
30816
|
+
function lintFile(input, baseConfig) {
|
|
30817
|
+
const config = withElementExemptions(input.path, baseConfig);
|
|
30745
30818
|
if (/\.css$/i.test(input.path)) return lintStylesheet(input, config);
|
|
30746
30819
|
if (/\.(html|vue|svelte|mdx)$/i.test(input.path)) {
|
|
30747
30820
|
return [...lintTemplate(input, config), ...lintCodeRules(input)];
|
|
@@ -31420,9 +31493,9 @@ function collectFontExports(statement, loaderBindings, exports, reExports) {
|
|
|
31420
31493
|
}
|
|
31421
31494
|
function resolveImportedModule(importerPath, specifier, modules) {
|
|
31422
31495
|
const directory = importerPath.split("/").slice(0, -1).join("/");
|
|
31423
|
-
const
|
|
31424
|
-
const srcIndex =
|
|
31425
|
-
const aliasRoot = srcIndex >= 0 ?
|
|
31496
|
+
const segments2 = importerPath.split("/");
|
|
31497
|
+
const srcIndex = segments2.lastIndexOf("src");
|
|
31498
|
+
const aliasRoot = srcIndex >= 0 ? segments2.slice(0, srcIndex + 1).join("/") : /^(?:apps|packages)\//.test(importerPath) ? segments2.slice(0, 2).join("/") : "src";
|
|
31426
31499
|
const bases = /^(?:@|~|#)\//.test(specifier) ? [`${aliasRoot}/${specifier.slice(2)}`, `src/${specifier.slice(2)}`, specifier.slice(2)] : specifier.startsWith(".") ? [`${directory}/${specifier}`] : [];
|
|
31427
31500
|
for (const rawBase of bases) {
|
|
31428
31501
|
const base = normalizeSourcePath(rawBase);
|
|
@@ -31439,13 +31512,13 @@ function resolveImportedModule(importerPath, specifier, modules) {
|
|
|
31439
31512
|
return void 0;
|
|
31440
31513
|
}
|
|
31441
31514
|
function normalizeSourcePath(path6) {
|
|
31442
|
-
const
|
|
31515
|
+
const segments2 = [];
|
|
31443
31516
|
for (const segment of path6.replace(/\\/g, "/").split("/")) {
|
|
31444
31517
|
if (!segment || segment === ".") continue;
|
|
31445
|
-
if (segment === "..")
|
|
31446
|
-
else
|
|
31518
|
+
if (segment === "..") segments2.pop();
|
|
31519
|
+
else segments2.push(segment);
|
|
31447
31520
|
}
|
|
31448
|
-
return
|
|
31521
|
+
return segments2.join("/");
|
|
31449
31522
|
}
|
|
31450
31523
|
function isInsideDocumentShellClass(node) {
|
|
31451
31524
|
let current = node.parent;
|
|
@@ -31623,6 +31696,7 @@ var init_engine = __esm({
|
|
|
31623
31696
|
init_code_rules();
|
|
31624
31697
|
init_length_rules();
|
|
31625
31698
|
init_template_rules();
|
|
31699
|
+
init_path_glob();
|
|
31626
31700
|
NATIVE_HTML_TAGS = /* @__PURE__ */ new Set([
|
|
31627
31701
|
"a",
|
|
31628
31702
|
"abbr",
|
|
@@ -31784,6 +31858,10 @@ var init_engine = __esm({
|
|
|
31784
31858
|
|
|
31785
31859
|
// ../shared/src/lint/config.ts
|
|
31786
31860
|
import { z as z31 } from "zod";
|
|
31861
|
+
function parseReviewConfigOverride(value) {
|
|
31862
|
+
const parsed = reviewConfigOverrideSchema.safeParse(value);
|
|
31863
|
+
return parsed.success ? parsed.data : null;
|
|
31864
|
+
}
|
|
31787
31865
|
function mergeReviewConfig(override) {
|
|
31788
31866
|
if (!override) return DEFAULT_REVIEW_CONFIG;
|
|
31789
31867
|
return {
|
|
@@ -31810,6 +31888,7 @@ var DEFAULT_VISUAL_MODEL_SCREENSHOTS, DEFAULT_ELEMENTS, DEFAULT_REVIEW_CONFIG, r
|
|
|
31810
31888
|
var init_config = __esm({
|
|
31811
31889
|
"../shared/src/lint/config.ts"() {
|
|
31812
31890
|
"use strict";
|
|
31891
|
+
init_path_glob();
|
|
31813
31892
|
DEFAULT_VISUAL_MODEL_SCREENSHOTS = 24;
|
|
31814
31893
|
DEFAULT_ELEMENTS = {
|
|
31815
31894
|
"app-shell": { use: "Sidebar", from: "@/components/ui/sidebar" },
|
|
@@ -31874,6 +31953,10 @@ var init_config = __esm({
|
|
|
31874
31953
|
visual: visualReviewConfigSchema.optional(),
|
|
31875
31954
|
rules: z31.object({
|
|
31876
31955
|
elements: z31.record(z31.string(), z31.object({ use: z31.string(), from: z31.string() })).optional(),
|
|
31956
|
+
elementExemptions: z31.array(z31.object({
|
|
31957
|
+
path: z31.string().min(1).max(MAX_GLOB_LENGTH),
|
|
31958
|
+
reason: z31.string().trim().min(1).max(300)
|
|
31959
|
+
})).max(20).optional(),
|
|
31877
31960
|
tokens: z31.record(z31.string(), z31.string()).optional(),
|
|
31878
31961
|
wcag: z31.object({
|
|
31879
31962
|
enabled: z31.boolean().optional(),
|
|
@@ -31947,12 +32030,13 @@ var init_lint = __esm({
|
|
|
31947
32030
|
init_engine();
|
|
31948
32031
|
init_config();
|
|
31949
32032
|
init_report();
|
|
32033
|
+
init_path_glob();
|
|
31950
32034
|
}
|
|
31951
32035
|
});
|
|
31952
32036
|
|
|
31953
32037
|
// src/review/config-loader.ts
|
|
31954
32038
|
import { readFileSync as readFileSync3 } from "fs";
|
|
31955
|
-
import { dirname, join, parse as parse2 } from "path";
|
|
32039
|
+
import { dirname, join, parse as parse2, relative } from "path";
|
|
31956
32040
|
function isNotFound(cause) {
|
|
31957
32041
|
return cause?.code === "ENOENT" || cause?.code === "ENOTDIR";
|
|
31958
32042
|
}
|
|
@@ -31972,13 +32056,18 @@ function loadReviewConfig(cwd) {
|
|
|
31972
32056
|
}
|
|
31973
32057
|
}
|
|
31974
32058
|
if (raw !== null) {
|
|
32059
|
+
let parsed;
|
|
31975
32060
|
try {
|
|
31976
|
-
|
|
32061
|
+
parsed = JSON.parse(raw);
|
|
31977
32062
|
} catch (error) {
|
|
31978
32063
|
throw new Error(
|
|
31979
32064
|
`Could not parse ${path6}: ${error instanceof Error ? error.message : String(error)}`
|
|
31980
32065
|
);
|
|
31981
32066
|
}
|
|
32067
|
+
const override = parseReviewConfigOverride(parsed);
|
|
32068
|
+
if (!override) throw new Error(`${path6} does not match the review config schema.`);
|
|
32069
|
+
const pathsFrom = relative(dir, cwd).split("\\").join("/");
|
|
32070
|
+
return { ...mergeReviewConfig(override), ...pathsFrom && { pathsFrom } };
|
|
31982
32071
|
}
|
|
31983
32072
|
if (dir === root) return mergeReviewConfig();
|
|
31984
32073
|
const parent = dirname(dir);
|
|
@@ -31998,7 +32087,7 @@ var init_config_loader = __esm({
|
|
|
31998
32087
|
// src/review/file-sources.ts
|
|
31999
32088
|
import { execFileSync } from "child_process";
|
|
32000
32089
|
import { readdirSync, statSync } from "fs";
|
|
32001
|
-
import { isAbsolute, join as join2, relative } from "path";
|
|
32090
|
+
import { isAbsolute, join as join2, relative as relative2 } from "path";
|
|
32002
32091
|
function isReviewablePath(path6) {
|
|
32003
32092
|
return REVIEWABLE_RE.test(path6);
|
|
32004
32093
|
}
|
|
@@ -32020,7 +32109,7 @@ function expandPath(cwd, arg) {
|
|
|
32020
32109
|
return files;
|
|
32021
32110
|
}
|
|
32022
32111
|
function filesFromArgs(cwd, args) {
|
|
32023
|
-
return [...new Set(args.flatMap((arg) => expandPath(cwd, arg)))].map((abs) =>
|
|
32112
|
+
return [...new Set(args.flatMap((arg) => expandPath(cwd, arg)))].map((abs) => relative2(cwd, abs));
|
|
32024
32113
|
}
|
|
32025
32114
|
function git(cwd, args) {
|
|
32026
32115
|
const out = execFileSync("git", args, { cwd, encoding: "utf8" });
|
|
@@ -32052,7 +32141,7 @@ __export(hook_exports, {
|
|
|
32052
32141
|
runHook: () => runHook
|
|
32053
32142
|
});
|
|
32054
32143
|
import { readFileSync as readFileSync4 } from "fs";
|
|
32055
|
-
import { isAbsolute as isAbsolute2, resolve } from "path";
|
|
32144
|
+
import { isAbsolute as isAbsolute2, relative as relative3, resolve } from "path";
|
|
32056
32145
|
async function runHook(stdin = process.stdin) {
|
|
32057
32146
|
let payload;
|
|
32058
32147
|
try {
|
|
@@ -32075,7 +32164,7 @@ async function runHook(stdin = process.stdin) {
|
|
|
32075
32164
|
return 0;
|
|
32076
32165
|
}
|
|
32077
32166
|
try {
|
|
32078
|
-
const findings = lintFile({ path:
|
|
32167
|
+
const findings = lintFile({ path: relative3(cwd, absolutePath), content }, loadReviewConfig(cwd));
|
|
32079
32168
|
const actionable = findings.filter(
|
|
32080
32169
|
(f) => f.severity === "critical" || f.severity === "serious"
|
|
32081
32170
|
);
|