uilint-eslint 0.1.16 → 0.1.18
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.d.ts +18 -6
- package/dist/index.js +726 -101
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -267,36 +267,129 @@ var COLOR_PREFIXES = [
|
|
|
267
267
|
"to-"
|
|
268
268
|
];
|
|
269
269
|
var EXEMPT_SUFFIXES = ["transparent", "inherit", "current", "auto", "none"];
|
|
270
|
-
var
|
|
271
|
-
//
|
|
272
|
-
"
|
|
273
|
-
"
|
|
274
|
-
"
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
//
|
|
278
|
-
"
|
|
279
|
-
"
|
|
280
|
-
"
|
|
281
|
-
"
|
|
282
|
-
"
|
|
283
|
-
"
|
|
284
|
-
"
|
|
285
|
-
"
|
|
286
|
-
"
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
"
|
|
292
|
-
"
|
|
293
|
-
"
|
|
294
|
-
"
|
|
295
|
-
|
|
296
|
-
"
|
|
297
|
-
"
|
|
270
|
+
var NON_COLOR_UTILITIES = /* @__PURE__ */ new Set([
|
|
271
|
+
// Exempt values (colorless or inherited) - don't need dark variants
|
|
272
|
+
"transparent",
|
|
273
|
+
"inherit",
|
|
274
|
+
"current",
|
|
275
|
+
"auto",
|
|
276
|
+
"none",
|
|
277
|
+
// text- utilities that aren't colors
|
|
278
|
+
"xs",
|
|
279
|
+
"sm",
|
|
280
|
+
"base",
|
|
281
|
+
"lg",
|
|
282
|
+
"xl",
|
|
283
|
+
"2xl",
|
|
284
|
+
"3xl",
|
|
285
|
+
"4xl",
|
|
286
|
+
"5xl",
|
|
287
|
+
"6xl",
|
|
288
|
+
"7xl",
|
|
289
|
+
"8xl",
|
|
290
|
+
"9xl",
|
|
291
|
+
"left",
|
|
292
|
+
"center",
|
|
293
|
+
"right",
|
|
294
|
+
"justify",
|
|
295
|
+
"start",
|
|
296
|
+
"end",
|
|
297
|
+
"wrap",
|
|
298
|
+
"nowrap",
|
|
299
|
+
"balance",
|
|
300
|
+
"pretty",
|
|
301
|
+
"ellipsis",
|
|
302
|
+
"clip",
|
|
303
|
+
// border- utilities that aren't colors
|
|
304
|
+
"0",
|
|
305
|
+
"2",
|
|
306
|
+
"4",
|
|
307
|
+
"8",
|
|
308
|
+
"solid",
|
|
309
|
+
"dashed",
|
|
310
|
+
"dotted",
|
|
311
|
+
"double",
|
|
312
|
+
"hidden",
|
|
313
|
+
"collapse",
|
|
314
|
+
"separate",
|
|
315
|
+
// shadow- utilities that aren't colors
|
|
316
|
+
// Note: "sm", "lg", "xl", "2xl" already included above
|
|
317
|
+
"md",
|
|
318
|
+
"inner",
|
|
319
|
+
// ring- utilities that aren't colors
|
|
320
|
+
// Note: "0", "2", "4", "8" already included above
|
|
321
|
+
"1",
|
|
322
|
+
"inset",
|
|
323
|
+
// outline- utilities that aren't colors
|
|
324
|
+
// Note: numeric values already included
|
|
325
|
+
"offset-0",
|
|
326
|
+
"offset-1",
|
|
327
|
+
"offset-2",
|
|
328
|
+
"offset-4",
|
|
329
|
+
"offset-8",
|
|
330
|
+
// decoration- utilities that aren't colors
|
|
331
|
+
// Note: "solid", "double", "dotted", "dashed" already included
|
|
332
|
+
"wavy",
|
|
333
|
+
"from-font",
|
|
334
|
+
"clone",
|
|
335
|
+
"slice",
|
|
336
|
+
// divide- utilities that aren't colors
|
|
337
|
+
"x",
|
|
338
|
+
"y",
|
|
339
|
+
"x-0",
|
|
340
|
+
"x-2",
|
|
341
|
+
"x-4",
|
|
342
|
+
"x-8",
|
|
343
|
+
"y-0",
|
|
344
|
+
"y-2",
|
|
345
|
+
"y-4",
|
|
346
|
+
"y-8",
|
|
347
|
+
"x-reverse",
|
|
348
|
+
"y-reverse",
|
|
349
|
+
// gradient direction utilities (from-, via-, to- prefixes)
|
|
350
|
+
"t",
|
|
351
|
+
"tr",
|
|
352
|
+
"r",
|
|
353
|
+
"br",
|
|
354
|
+
"b",
|
|
355
|
+
"bl",
|
|
356
|
+
"l",
|
|
357
|
+
"tl"
|
|
298
358
|
]);
|
|
299
|
-
var
|
|
359
|
+
var SEMANTIC_COLOR_NAMES = /* @__PURE__ */ new Set([
|
|
360
|
+
// Core shadcn colors
|
|
361
|
+
"background",
|
|
362
|
+
"foreground",
|
|
363
|
+
// Component colors
|
|
364
|
+
"card",
|
|
365
|
+
"card-foreground",
|
|
366
|
+
"popover",
|
|
367
|
+
"popover-foreground",
|
|
368
|
+
"primary",
|
|
369
|
+
"primary-foreground",
|
|
370
|
+
"secondary",
|
|
371
|
+
"secondary-foreground",
|
|
372
|
+
"muted",
|
|
373
|
+
"muted-foreground",
|
|
374
|
+
"accent",
|
|
375
|
+
"accent-foreground",
|
|
376
|
+
"destructive",
|
|
377
|
+
"destructive-foreground",
|
|
378
|
+
// Form/UI colors
|
|
379
|
+
"border",
|
|
380
|
+
"input",
|
|
381
|
+
"ring",
|
|
382
|
+
// Sidebar colors (shadcn sidebar component)
|
|
383
|
+
"sidebar",
|
|
384
|
+
"sidebar-foreground",
|
|
385
|
+
"sidebar-border",
|
|
386
|
+
"sidebar-primary",
|
|
387
|
+
"sidebar-primary-foreground",
|
|
388
|
+
"sidebar-accent",
|
|
389
|
+
"sidebar-accent-foreground",
|
|
390
|
+
"sidebar-ring"
|
|
391
|
+
]);
|
|
392
|
+
var CHART_COLOR_PATTERN = /^chart-\d+$/;
|
|
300
393
|
function hasDarkVariant(className) {
|
|
301
394
|
const parts = className.split(":");
|
|
302
395
|
const variants = parts.slice(0, -1);
|
|
@@ -312,20 +405,28 @@ function getColorPrefix(baseClass) {
|
|
|
312
405
|
);
|
|
313
406
|
return sortedPrefixes.find((p) => baseClass.startsWith(p)) || null;
|
|
314
407
|
}
|
|
315
|
-
function
|
|
316
|
-
|
|
317
|
-
if (COLOR_VALUE_PATTERN.test(value)) {
|
|
408
|
+
function isSemanticColor(value) {
|
|
409
|
+
if (SEMANTIC_COLOR_NAMES.has(value)) {
|
|
318
410
|
return true;
|
|
319
411
|
}
|
|
320
|
-
|
|
321
|
-
if (COLOR_NAMES.has(firstPart)) {
|
|
322
|
-
return true;
|
|
323
|
-
}
|
|
324
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
412
|
+
if (CHART_COLOR_PATTERN.test(value)) {
|
|
325
413
|
return true;
|
|
326
414
|
}
|
|
327
415
|
return false;
|
|
328
416
|
}
|
|
417
|
+
function isColorValue(baseClass, prefix) {
|
|
418
|
+
const value = baseClass.slice(prefix.length);
|
|
419
|
+
if (!value) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (isSemanticColor(value)) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
if (NON_COLOR_UTILITIES.has(value)) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
329
430
|
function isExempt(baseClass) {
|
|
330
431
|
return EXEMPT_SUFFIXES.some((suffix) => baseClass.endsWith(suffix));
|
|
331
432
|
}
|
|
@@ -715,78 +816,602 @@ var prefer_zustand_state_management_default = createRule({
|
|
|
715
816
|
}
|
|
716
817
|
});
|
|
717
818
|
|
|
718
|
-
// src/
|
|
819
|
+
// src/utils/export-resolver.ts
|
|
820
|
+
import { ResolverFactory } from "oxc-resolver";
|
|
821
|
+
import { parse } from "@typescript-eslint/typescript-estree";
|
|
822
|
+
import { readFileSync, existsSync } from "fs";
|
|
823
|
+
import { dirname, join } from "path";
|
|
824
|
+
var resolverFactory = null;
|
|
825
|
+
var exportCache = /* @__PURE__ */ new Map();
|
|
826
|
+
var astCache = /* @__PURE__ */ new Map();
|
|
827
|
+
var resolvedPathCache = /* @__PURE__ */ new Map();
|
|
828
|
+
function getResolverFactory() {
|
|
829
|
+
if (!resolverFactory) {
|
|
830
|
+
resolverFactory = new ResolverFactory({
|
|
831
|
+
extensions: [".tsx", ".ts", ".jsx", ".js"],
|
|
832
|
+
mainFields: ["module", "main"],
|
|
833
|
+
conditionNames: ["import", "require", "node", "default"],
|
|
834
|
+
// Enable TypeScript path resolution
|
|
835
|
+
tsconfig: {
|
|
836
|
+
configFile: "tsconfig.json",
|
|
837
|
+
references: "auto"
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
return resolverFactory;
|
|
842
|
+
}
|
|
843
|
+
function resolveImportPath(importSource, fromFile) {
|
|
844
|
+
const cacheKey = `${fromFile}::${importSource}`;
|
|
845
|
+
if (resolvedPathCache.has(cacheKey)) {
|
|
846
|
+
return resolvedPathCache.get(cacheKey) ?? null;
|
|
847
|
+
}
|
|
848
|
+
if (importSource.startsWith("react") || importSource.startsWith("next") || !importSource.startsWith(".") && !importSource.startsWith("@/") && !importSource.startsWith("~/")) {
|
|
849
|
+
if (importSource.includes("@mui/") || importSource.includes("@chakra-ui/") || importSource.includes("antd") || importSource.includes("@radix-ui/")) {
|
|
850
|
+
resolvedPathCache.set(cacheKey, null);
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
resolvedPathCache.set(cacheKey, null);
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
try {
|
|
857
|
+
const factory = getResolverFactory();
|
|
858
|
+
const fromDir = dirname(fromFile);
|
|
859
|
+
const result = factory.sync(fromDir, importSource);
|
|
860
|
+
if (result.path) {
|
|
861
|
+
resolvedPathCache.set(cacheKey, result.path);
|
|
862
|
+
return result.path;
|
|
863
|
+
}
|
|
864
|
+
} catch {
|
|
865
|
+
const resolved = manualResolve(importSource, fromFile);
|
|
866
|
+
resolvedPathCache.set(cacheKey, resolved);
|
|
867
|
+
return resolved;
|
|
868
|
+
}
|
|
869
|
+
resolvedPathCache.set(cacheKey, null);
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
function manualResolve(importSource, fromFile) {
|
|
873
|
+
const fromDir = dirname(fromFile);
|
|
874
|
+
const extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
875
|
+
if (importSource.startsWith("@/")) {
|
|
876
|
+
const projectRoot = findProjectRoot(fromFile);
|
|
877
|
+
if (projectRoot) {
|
|
878
|
+
const relativePath = importSource.slice(2);
|
|
879
|
+
for (const ext of extensions) {
|
|
880
|
+
const candidate = join(projectRoot, relativePath + ext);
|
|
881
|
+
if (existsSync(candidate)) {
|
|
882
|
+
return candidate;
|
|
883
|
+
}
|
|
884
|
+
const indexCandidate = join(projectRoot, relativePath, `index${ext}`);
|
|
885
|
+
if (existsSync(indexCandidate)) {
|
|
886
|
+
return indexCandidate;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (importSource.startsWith(".")) {
|
|
892
|
+
for (const ext of extensions) {
|
|
893
|
+
const candidate = join(fromDir, importSource + ext);
|
|
894
|
+
if (existsSync(candidate)) {
|
|
895
|
+
return candidate;
|
|
896
|
+
}
|
|
897
|
+
const indexCandidate = join(fromDir, importSource, `index${ext}`);
|
|
898
|
+
if (existsSync(indexCandidate)) {
|
|
899
|
+
return indexCandidate;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
function findProjectRoot(fromFile) {
|
|
906
|
+
let dir = dirname(fromFile);
|
|
907
|
+
const root = "/";
|
|
908
|
+
while (dir !== root) {
|
|
909
|
+
if (existsSync(join(dir, "tsconfig.json"))) {
|
|
910
|
+
return dir;
|
|
911
|
+
}
|
|
912
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
913
|
+
return dir;
|
|
914
|
+
}
|
|
915
|
+
dir = dirname(dir);
|
|
916
|
+
}
|
|
917
|
+
return null;
|
|
918
|
+
}
|
|
919
|
+
function parseFile(filePath) {
|
|
920
|
+
if (astCache.has(filePath)) {
|
|
921
|
+
return astCache.get(filePath);
|
|
922
|
+
}
|
|
923
|
+
try {
|
|
924
|
+
const content = readFileSync(filePath, "utf-8");
|
|
925
|
+
const ast = parse(content, {
|
|
926
|
+
jsx: true,
|
|
927
|
+
loc: true,
|
|
928
|
+
range: true
|
|
929
|
+
});
|
|
930
|
+
astCache.set(filePath, ast);
|
|
931
|
+
return ast;
|
|
932
|
+
} catch {
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
function extractExports(filePath) {
|
|
937
|
+
if (exportCache.has(filePath)) {
|
|
938
|
+
return exportCache.get(filePath);
|
|
939
|
+
}
|
|
940
|
+
const exports = /* @__PURE__ */ new Map();
|
|
941
|
+
const ast = parseFile(filePath);
|
|
942
|
+
if (!ast) {
|
|
943
|
+
exportCache.set(filePath, exports);
|
|
944
|
+
return exports;
|
|
945
|
+
}
|
|
946
|
+
for (const node of ast.body) {
|
|
947
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "FunctionDeclaration" && node.declaration.id) {
|
|
948
|
+
exports.set(node.declaration.id.name, {
|
|
949
|
+
localName: node.declaration.id.name
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
|
|
953
|
+
for (const decl of node.declaration.declarations) {
|
|
954
|
+
if (decl.id.type === "Identifier") {
|
|
955
|
+
exports.set(decl.id.name, { localName: decl.id.name });
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
if (node.type === "ExportNamedDeclaration" && node.specifiers.length > 0) {
|
|
960
|
+
const source = node.source?.value;
|
|
961
|
+
for (const spec of node.specifiers) {
|
|
962
|
+
if (spec.type === "ExportSpecifier") {
|
|
963
|
+
const exportedName = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
|
|
964
|
+
const localName = spec.local.type === "Identifier" ? spec.local.name : spec.local.value;
|
|
965
|
+
exports.set(exportedName, {
|
|
966
|
+
localName,
|
|
967
|
+
reexportSource: source
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
|
|
973
|
+
exports.set("default", { localName: node.declaration.id.name });
|
|
974
|
+
}
|
|
975
|
+
if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "Identifier") {
|
|
976
|
+
exports.set("default", { localName: node.declaration.name });
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
exportCache.set(filePath, exports);
|
|
980
|
+
return exports;
|
|
981
|
+
}
|
|
982
|
+
function resolveExport(exportName, filePath, visited = /* @__PURE__ */ new Set()) {
|
|
983
|
+
const key = `${filePath}::${exportName}`;
|
|
984
|
+
if (visited.has(key)) {
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
987
|
+
visited.add(key);
|
|
988
|
+
const exports = extractExports(filePath);
|
|
989
|
+
const exportInfo = exports.get(exportName);
|
|
990
|
+
if (!exportInfo) {
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
if (exportInfo.reexportSource) {
|
|
994
|
+
const resolvedPath = resolveImportPath(exportInfo.reexportSource, filePath);
|
|
995
|
+
if (resolvedPath) {
|
|
996
|
+
return resolveExport(exportInfo.localName, resolvedPath, visited);
|
|
997
|
+
}
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
return {
|
|
1001
|
+
name: exportName,
|
|
1002
|
+
filePath,
|
|
1003
|
+
localName: exportInfo.localName,
|
|
1004
|
+
isReexport: false
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// src/utils/component-parser.ts
|
|
719
1009
|
var LIBRARY_PATTERNS = {
|
|
720
1010
|
shadcn: ["@/components/ui", "@radix-ui/", "components/ui/"],
|
|
721
|
-
mui: ["@mui/material", "@mui/icons-material", "@emotion/"]
|
|
1011
|
+
mui: ["@mui/material", "@mui/icons-material", "@emotion/"],
|
|
1012
|
+
chakra: ["@chakra-ui/"],
|
|
1013
|
+
antd: ["antd", "@ant-design/"]
|
|
722
1014
|
};
|
|
1015
|
+
function extractImports(ast) {
|
|
1016
|
+
const imports = /* @__PURE__ */ new Map();
|
|
1017
|
+
for (const node of ast.body) {
|
|
1018
|
+
if (node.type === "ImportDeclaration") {
|
|
1019
|
+
const source = node.source.value;
|
|
1020
|
+
for (const spec of node.specifiers) {
|
|
1021
|
+
if (spec.type === "ImportSpecifier") {
|
|
1022
|
+
imports.set(spec.local.name, source);
|
|
1023
|
+
} else if (spec.type === "ImportDefaultSpecifier") {
|
|
1024
|
+
imports.set(spec.local.name, source);
|
|
1025
|
+
} else if (spec.type === "ImportNamespaceSpecifier") {
|
|
1026
|
+
imports.set(spec.local.name, source);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return imports;
|
|
1032
|
+
}
|
|
1033
|
+
function detectLibraryFromSource(importSource) {
|
|
1034
|
+
for (const [library, patterns] of Object.entries(LIBRARY_PATTERNS)) {
|
|
1035
|
+
if (patterns.some((p) => importSource.includes(p))) {
|
|
1036
|
+
return library;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1041
|
+
function findComponentDefinition(ast, componentName) {
|
|
1042
|
+
for (const node of ast.body) {
|
|
1043
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "FunctionDeclaration" && node.declaration.id?.name === componentName) {
|
|
1044
|
+
return node.declaration;
|
|
1045
|
+
}
|
|
1046
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
|
|
1047
|
+
for (const decl of node.declaration.declarations) {
|
|
1048
|
+
if (decl.id.type === "Identifier" && decl.id.name === componentName && decl.init?.type === "ArrowFunctionExpression") {
|
|
1049
|
+
return decl.init;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (node.type === "FunctionDeclaration" && node.id?.name === componentName) {
|
|
1054
|
+
return node;
|
|
1055
|
+
}
|
|
1056
|
+
if (node.type === "VariableDeclaration") {
|
|
1057
|
+
for (const decl of node.declarations) {
|
|
1058
|
+
if (decl.id.type === "Identifier" && decl.id.name === componentName && decl.init?.type === "ArrowFunctionExpression") {
|
|
1059
|
+
return decl.init;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "FunctionDeclaration" && node.declaration.id?.name === componentName) {
|
|
1064
|
+
return node.declaration;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
function extractTailwindClasses(classString) {
|
|
1070
|
+
return classString.split(/\s+/).filter(Boolean);
|
|
1071
|
+
}
|
|
1072
|
+
function traverseForStyling(node, imports, result) {
|
|
1073
|
+
if (!node || typeof node !== "object") return;
|
|
1074
|
+
if (node.type === "JSXElement" && node.openingElement) {
|
|
1075
|
+
const opening = node.openingElement;
|
|
1076
|
+
if (opening.name.type === "JSXIdentifier" && /^[A-Z]/.test(opening.name.name)) {
|
|
1077
|
+
const componentName = opening.name.name;
|
|
1078
|
+
const importSource = imports.get(componentName);
|
|
1079
|
+
if (importSource) {
|
|
1080
|
+
result.usedComponents.push({
|
|
1081
|
+
name: componentName,
|
|
1082
|
+
importSource,
|
|
1083
|
+
line: opening.loc.start.line,
|
|
1084
|
+
column: opening.loc.start.column
|
|
1085
|
+
});
|
|
1086
|
+
const library = detectLibraryFromSource(importSource);
|
|
1087
|
+
if (library && !result.directLibrary) {
|
|
1088
|
+
result.directLibrary = library;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (opening.name.type === "JSXMemberExpression") {
|
|
1093
|
+
let objectName = null;
|
|
1094
|
+
let current = opening.name.object;
|
|
1095
|
+
while (current.type === "JSXMemberExpression") {
|
|
1096
|
+
current = current.object;
|
|
1097
|
+
}
|
|
1098
|
+
if (current.type === "JSXIdentifier") {
|
|
1099
|
+
objectName = current.name;
|
|
1100
|
+
}
|
|
1101
|
+
if (objectName) {
|
|
1102
|
+
const importSource = imports.get(objectName);
|
|
1103
|
+
if (importSource) {
|
|
1104
|
+
const library = detectLibraryFromSource(importSource);
|
|
1105
|
+
if (library && !result.directLibrary) {
|
|
1106
|
+
result.directLibrary = library;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
for (const attr of opening.attributes) {
|
|
1112
|
+
if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && (attr.name.name === "className" || attr.name.name === "class")) {
|
|
1113
|
+
if (attr.value?.type === "Literal" && typeof attr.value.value === "string") {
|
|
1114
|
+
result.tailwindClasses.push(
|
|
1115
|
+
...extractTailwindClasses(attr.value.value)
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
if (attr.value?.type === "JSXExpressionContainer") {
|
|
1119
|
+
const expr = attr.value.expression;
|
|
1120
|
+
if (expr.type === "Literal" && typeof expr.value === "string") {
|
|
1121
|
+
result.tailwindClasses.push(...extractTailwindClasses(expr.value));
|
|
1122
|
+
}
|
|
1123
|
+
if (expr.type === "TemplateLiteral") {
|
|
1124
|
+
for (const quasi of expr.quasis) {
|
|
1125
|
+
result.tailwindClasses.push(
|
|
1126
|
+
...extractTailwindClasses(quasi.value.raw)
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "style") {
|
|
1133
|
+
if (attr.value?.type === "JSXExpressionContainer") {
|
|
1134
|
+
result.inlineStyles.push("[inline style]");
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
if (node.type === "CallExpression" && node.callee.type === "Identifier" && ["cn", "clsx", "classnames", "twMerge"].includes(node.callee.name)) {
|
|
1140
|
+
for (const arg of node.arguments) {
|
|
1141
|
+
if (arg.type === "Literal" && typeof arg.value === "string") {
|
|
1142
|
+
result.tailwindClasses.push(...extractTailwindClasses(arg.value));
|
|
1143
|
+
}
|
|
1144
|
+
if (arg.type === "TemplateLiteral") {
|
|
1145
|
+
for (const quasi of arg.quasis) {
|
|
1146
|
+
result.tailwindClasses.push(
|
|
1147
|
+
...extractTailwindClasses(quasi.value.raw)
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
for (const key of Object.keys(node)) {
|
|
1154
|
+
if (key === "parent" || key === "loc" || key === "range") continue;
|
|
1155
|
+
const child = node[key];
|
|
1156
|
+
if (Array.isArray(child)) {
|
|
1157
|
+
for (const item of child) {
|
|
1158
|
+
if (item && typeof item === "object") {
|
|
1159
|
+
traverseForStyling(item, imports, result);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
} else if (child && typeof child === "object") {
|
|
1163
|
+
traverseForStyling(child, imports, result);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
function parseComponentBody(filePath, componentName) {
|
|
1168
|
+
const ast = parseFile(filePath);
|
|
1169
|
+
if (!ast) return null;
|
|
1170
|
+
const imports = extractImports(ast);
|
|
1171
|
+
const componentDef = findComponentDefinition(ast, componentName);
|
|
1172
|
+
if (!componentDef) {
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
const result = {
|
|
1176
|
+
tailwindClasses: [],
|
|
1177
|
+
inlineStyles: [],
|
|
1178
|
+
usedComponents: [],
|
|
1179
|
+
directLibrary: null
|
|
1180
|
+
};
|
|
1181
|
+
if (componentDef.body) {
|
|
1182
|
+
traverseForStyling(componentDef.body, imports, result);
|
|
1183
|
+
}
|
|
1184
|
+
result.tailwindClasses = [...new Set(result.tailwindClasses)];
|
|
1185
|
+
return result;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// src/utils/import-graph.ts
|
|
1189
|
+
var componentLibraryCache = /* @__PURE__ */ new Map();
|
|
1190
|
+
function getComponentLibrary(contextFilePath, componentName, importSource) {
|
|
1191
|
+
const directLibrary = detectLibraryFromSource(importSource);
|
|
1192
|
+
if (directLibrary) {
|
|
1193
|
+
return {
|
|
1194
|
+
library: directLibrary,
|
|
1195
|
+
internalLibraries: /* @__PURE__ */ new Set(),
|
|
1196
|
+
libraryEvidence: [],
|
|
1197
|
+
isLocalComponent: false
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
const resolvedPath = resolveImportPath(importSource, contextFilePath);
|
|
1201
|
+
if (!resolvedPath) {
|
|
1202
|
+
return {
|
|
1203
|
+
library: null,
|
|
1204
|
+
internalLibraries: /* @__PURE__ */ new Set(),
|
|
1205
|
+
libraryEvidence: [],
|
|
1206
|
+
isLocalComponent: false
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
const cacheKey = `${resolvedPath}::${componentName}`;
|
|
1210
|
+
if (componentLibraryCache.has(cacheKey)) {
|
|
1211
|
+
return componentLibraryCache.get(cacheKey);
|
|
1212
|
+
}
|
|
1213
|
+
const resolvedExport = resolveExport(componentName, resolvedPath);
|
|
1214
|
+
const actualFilePath = resolvedExport?.filePath ?? resolvedPath;
|
|
1215
|
+
const actualComponentName = resolvedExport?.localName ?? componentName;
|
|
1216
|
+
const result = analyzeComponentLibraries(
|
|
1217
|
+
actualFilePath,
|
|
1218
|
+
actualComponentName,
|
|
1219
|
+
/* @__PURE__ */ new Set([cacheKey])
|
|
1220
|
+
// Track visited to prevent cycles
|
|
1221
|
+
);
|
|
1222
|
+
componentLibraryCache.set(cacheKey, result);
|
|
1223
|
+
return result;
|
|
1224
|
+
}
|
|
1225
|
+
function analyzeComponentLibraries(filePath, componentName, visited) {
|
|
1226
|
+
const styleInfo = parseComponentBody(filePath, componentName);
|
|
1227
|
+
if (!styleInfo) {
|
|
1228
|
+
return {
|
|
1229
|
+
library: null,
|
|
1230
|
+
internalLibraries: /* @__PURE__ */ new Set(),
|
|
1231
|
+
libraryEvidence: [],
|
|
1232
|
+
isLocalComponent: true
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
const internalLibraries = /* @__PURE__ */ new Set();
|
|
1236
|
+
const libraryEvidence = [];
|
|
1237
|
+
if (styleInfo.directLibrary) {
|
|
1238
|
+
internalLibraries.add(styleInfo.directLibrary);
|
|
1239
|
+
}
|
|
1240
|
+
for (const usedComponent of styleInfo.usedComponents) {
|
|
1241
|
+
const usedLibrary = detectLibraryFromSource(usedComponent.importSource);
|
|
1242
|
+
if (usedLibrary) {
|
|
1243
|
+
internalLibraries.add(usedLibrary);
|
|
1244
|
+
libraryEvidence.push({
|
|
1245
|
+
componentName: usedComponent.name,
|
|
1246
|
+
library: usedLibrary
|
|
1247
|
+
});
|
|
1248
|
+
} else {
|
|
1249
|
+
const resolvedPath = resolveImportPath(usedComponent.importSource, filePath);
|
|
1250
|
+
if (resolvedPath) {
|
|
1251
|
+
const cacheKey = `${resolvedPath}::${usedComponent.name}`;
|
|
1252
|
+
if (!visited.has(cacheKey)) {
|
|
1253
|
+
visited.add(cacheKey);
|
|
1254
|
+
let nestedInfo;
|
|
1255
|
+
if (componentLibraryCache.has(cacheKey)) {
|
|
1256
|
+
nestedInfo = componentLibraryCache.get(cacheKey);
|
|
1257
|
+
} else {
|
|
1258
|
+
const resolvedExport = resolveExport(usedComponent.name, resolvedPath);
|
|
1259
|
+
const actualFilePath = resolvedExport?.filePath ?? resolvedPath;
|
|
1260
|
+
const actualComponentName = resolvedExport?.localName ?? usedComponent.name;
|
|
1261
|
+
nestedInfo = analyzeComponentLibraries(
|
|
1262
|
+
actualFilePath,
|
|
1263
|
+
actualComponentName,
|
|
1264
|
+
visited
|
|
1265
|
+
);
|
|
1266
|
+
componentLibraryCache.set(cacheKey, nestedInfo);
|
|
1267
|
+
}
|
|
1268
|
+
if (nestedInfo.library) {
|
|
1269
|
+
internalLibraries.add(nestedInfo.library);
|
|
1270
|
+
libraryEvidence.push({
|
|
1271
|
+
componentName: usedComponent.name,
|
|
1272
|
+
library: nestedInfo.library
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
for (const lib of nestedInfo.internalLibraries) {
|
|
1276
|
+
internalLibraries.add(lib);
|
|
1277
|
+
}
|
|
1278
|
+
for (const evidence of nestedInfo.libraryEvidence) {
|
|
1279
|
+
libraryEvidence.push({
|
|
1280
|
+
componentName: `${usedComponent.name} \u2192 ${evidence.componentName}`,
|
|
1281
|
+
library: evidence.library
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return {
|
|
1289
|
+
library: styleInfo.directLibrary,
|
|
1290
|
+
internalLibraries,
|
|
1291
|
+
libraryEvidence,
|
|
1292
|
+
isLocalComponent: true
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// src/rules/no-mixed-component-libraries.ts
|
|
723
1297
|
var no_mixed_component_libraries_default = createRule({
|
|
724
1298
|
name: "no-mixed-component-libraries",
|
|
725
1299
|
meta: {
|
|
726
1300
|
type: "problem",
|
|
727
1301
|
docs: {
|
|
728
|
-
description: "Forbid
|
|
1302
|
+
description: "Forbid using non-preferred UI component libraries. Reports at JSX usage sites, including transitive usage."
|
|
729
1303
|
},
|
|
730
1304
|
messages: {
|
|
731
|
-
|
|
732
|
-
|
|
1305
|
+
nonPreferredLibrary: "Component <{{component}}> is from {{library}}, but {{preferred}} is the preferred library.",
|
|
1306
|
+
transitiveNonPreferred: "Component <{{component}}> internally uses {{libraries}} components ({{internalComponents}}). The preferred library is {{preferred}}."
|
|
733
1307
|
},
|
|
734
1308
|
schema: [
|
|
735
1309
|
{
|
|
736
1310
|
type: "object",
|
|
737
1311
|
properties: {
|
|
738
|
-
libraries: {
|
|
739
|
-
type: "array",
|
|
740
|
-
items: { type: "string", enum: ["shadcn", "mui"] }
|
|
741
|
-
},
|
|
742
1312
|
preferred: {
|
|
743
1313
|
type: "string",
|
|
744
|
-
enum: ["shadcn", "mui"]
|
|
1314
|
+
enum: ["shadcn", "mui", "chakra", "antd"],
|
|
1315
|
+
description: "The preferred UI library"
|
|
1316
|
+
},
|
|
1317
|
+
libraries: {
|
|
1318
|
+
type: "array",
|
|
1319
|
+
items: {
|
|
1320
|
+
type: "string",
|
|
1321
|
+
enum: ["shadcn", "mui", "chakra", "antd"]
|
|
1322
|
+
},
|
|
1323
|
+
description: "Libraries to detect (defaults to all)"
|
|
745
1324
|
}
|
|
746
1325
|
},
|
|
1326
|
+
required: ["preferred"],
|
|
747
1327
|
additionalProperties: false
|
|
748
1328
|
}
|
|
749
1329
|
]
|
|
750
1330
|
},
|
|
751
|
-
defaultOptions: [
|
|
1331
|
+
defaultOptions: [
|
|
1332
|
+
{ preferred: "shadcn", libraries: ["shadcn", "mui", "chakra", "antd"] }
|
|
1333
|
+
],
|
|
752
1334
|
create(context) {
|
|
753
|
-
const options = context.options[0]
|
|
754
|
-
const libraries = options.libraries || ["shadcn", "mui"];
|
|
1335
|
+
const options = context.options[0];
|
|
755
1336
|
const preferred = options.preferred;
|
|
756
|
-
const
|
|
1337
|
+
const importMap = /* @__PURE__ */ new Map();
|
|
1338
|
+
const componentUsages = [];
|
|
757
1339
|
return {
|
|
758
1340
|
ImportDeclaration(node) {
|
|
759
1341
|
const source = node.source.value;
|
|
760
|
-
for (const
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1342
|
+
for (const spec of node.specifiers) {
|
|
1343
|
+
if (spec.type === "ImportSpecifier") {
|
|
1344
|
+
importMap.set(spec.local.name, source);
|
|
1345
|
+
} else if (spec.type === "ImportDefaultSpecifier") {
|
|
1346
|
+
importMap.set(spec.local.name, source);
|
|
1347
|
+
} else if (spec.type === "ImportNamespaceSpecifier") {
|
|
1348
|
+
importMap.set(spec.local.name, source);
|
|
766
1349
|
}
|
|
767
1350
|
}
|
|
768
1351
|
},
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1352
|
+
JSXOpeningElement(node) {
|
|
1353
|
+
let componentName = null;
|
|
1354
|
+
if (node.name.type === "JSXIdentifier") {
|
|
1355
|
+
componentName = node.name.name;
|
|
1356
|
+
} else if (node.name.type === "JSXMemberExpression") {
|
|
1357
|
+
let current = node.name.object;
|
|
1358
|
+
while (current.type === "JSXMemberExpression") {
|
|
1359
|
+
current = current.object;
|
|
1360
|
+
}
|
|
1361
|
+
if (current.type === "JSXIdentifier") {
|
|
1362
|
+
componentName = current.name;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (!componentName || !/^[A-Z]/.test(componentName)) {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
const importSource = importMap.get(componentName);
|
|
1369
|
+
if (!importSource) {
|
|
779
1370
|
return;
|
|
780
1371
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1372
|
+
componentUsages.push({
|
|
1373
|
+
node,
|
|
1374
|
+
componentName,
|
|
1375
|
+
importSource
|
|
1376
|
+
});
|
|
1377
|
+
},
|
|
1378
|
+
"Program:exit"() {
|
|
1379
|
+
const filename = context.filename || context.getFilename();
|
|
1380
|
+
for (const usage of componentUsages) {
|
|
1381
|
+
const libraryInfo = getComponentLibrary(
|
|
1382
|
+
filename,
|
|
1383
|
+
usage.componentName,
|
|
1384
|
+
usage.importSource
|
|
1385
|
+
);
|
|
1386
|
+
if (libraryInfo.library && libraryInfo.library !== preferred) {
|
|
785
1387
|
context.report({
|
|
786
|
-
node,
|
|
1388
|
+
node: usage.node,
|
|
787
1389
|
messageId: "nonPreferredLibrary",
|
|
788
|
-
data: {
|
|
1390
|
+
data: {
|
|
1391
|
+
component: usage.componentName,
|
|
1392
|
+
library: libraryInfo.library,
|
|
1393
|
+
preferred
|
|
1394
|
+
}
|
|
789
1395
|
});
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
if (libraryInfo.isLocalComponent && libraryInfo.internalLibraries.size > 0) {
|
|
1399
|
+
const nonPreferredLibs = [...libraryInfo.internalLibraries].filter(
|
|
1400
|
+
(lib) => lib !== preferred
|
|
1401
|
+
);
|
|
1402
|
+
if (nonPreferredLibs.length > 0) {
|
|
1403
|
+
const internalComponents = libraryInfo.libraryEvidence.filter((e) => e.library !== preferred).map((e) => e.componentName).slice(0, 3).join(", ");
|
|
1404
|
+
context.report({
|
|
1405
|
+
node: usage.node,
|
|
1406
|
+
messageId: "transitiveNonPreferred",
|
|
1407
|
+
data: {
|
|
1408
|
+
component: usage.componentName,
|
|
1409
|
+
libraries: nonPreferredLibs.join(", "),
|
|
1410
|
+
internalComponents: internalComponents || "unknown",
|
|
1411
|
+
preferred
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
790
1415
|
}
|
|
791
1416
|
}
|
|
792
1417
|
}
|
|
@@ -795,13 +1420,13 @@ var no_mixed_component_libraries_default = createRule({
|
|
|
795
1420
|
});
|
|
796
1421
|
|
|
797
1422
|
// src/rules/semantic.ts
|
|
798
|
-
import { existsSync as
|
|
1423
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
799
1424
|
import { spawnSync } from "child_process";
|
|
800
|
-
import { dirname as
|
|
1425
|
+
import { dirname as dirname4, join as join4, relative } from "path";
|
|
801
1426
|
|
|
802
1427
|
// src/utils/cache.ts
|
|
803
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
804
|
-
import { dirname, join } from "path";
|
|
1428
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
1429
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
805
1430
|
var xxhashInstance = null;
|
|
806
1431
|
async function getXxhash() {
|
|
807
1432
|
if (!xxhashInstance) {
|
|
@@ -831,15 +1456,15 @@ function hashContentSync(content) {
|
|
|
831
1456
|
var CACHE_VERSION = 1;
|
|
832
1457
|
var CACHE_FILE = ".uilint/.cache/eslint-semantic.json";
|
|
833
1458
|
function getCachePath(projectRoot) {
|
|
834
|
-
return
|
|
1459
|
+
return join2(projectRoot, CACHE_FILE);
|
|
835
1460
|
}
|
|
836
1461
|
function loadCache(projectRoot) {
|
|
837
1462
|
const cachePath = getCachePath(projectRoot);
|
|
838
|
-
if (!
|
|
1463
|
+
if (!existsSync2(cachePath)) {
|
|
839
1464
|
return { version: CACHE_VERSION, entries: {} };
|
|
840
1465
|
}
|
|
841
1466
|
try {
|
|
842
|
-
const content =
|
|
1467
|
+
const content = readFileSync2(cachePath, "utf-8");
|
|
843
1468
|
const cache = JSON.parse(content);
|
|
844
1469
|
if (cache.version !== CACHE_VERSION) {
|
|
845
1470
|
return { version: CACHE_VERSION, entries: {} };
|
|
@@ -852,8 +1477,8 @@ function loadCache(projectRoot) {
|
|
|
852
1477
|
function saveCache(projectRoot, cache) {
|
|
853
1478
|
const cachePath = getCachePath(projectRoot);
|
|
854
1479
|
try {
|
|
855
|
-
const cacheDir =
|
|
856
|
-
if (!
|
|
1480
|
+
const cacheDir = dirname2(cachePath);
|
|
1481
|
+
if (!existsSync2(cacheDir)) {
|
|
857
1482
|
mkdirSync(cacheDir, { recursive: true });
|
|
858
1483
|
}
|
|
859
1484
|
writeFileSync(cachePath, JSON.stringify(cache, null, 2), "utf-8");
|
|
@@ -884,8 +1509,8 @@ function clearCache(projectRoot) {
|
|
|
884
1509
|
}
|
|
885
1510
|
|
|
886
1511
|
// src/utils/styleguide-loader.ts
|
|
887
|
-
import { existsSync as
|
|
888
|
-
import { dirname as
|
|
1512
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
1513
|
+
import { dirname as dirname3, isAbsolute, join as join3, resolve } from "path";
|
|
889
1514
|
var DEFAULT_STYLEGUIDE_PATHS = [
|
|
890
1515
|
".uilint/styleguide.md",
|
|
891
1516
|
".uilint/styleguide.yaml",
|
|
@@ -894,10 +1519,10 @@ var DEFAULT_STYLEGUIDE_PATHS = [
|
|
|
894
1519
|
function findWorkspaceRoot(startDir) {
|
|
895
1520
|
let dir = startDir;
|
|
896
1521
|
for (let i = 0; i < 20; i++) {
|
|
897
|
-
if (
|
|
1522
|
+
if (existsSync3(join3(dir, "pnpm-workspace.yaml")) || existsSync3(join3(dir, ".git"))) {
|
|
898
1523
|
return dir;
|
|
899
1524
|
}
|
|
900
|
-
const parent =
|
|
1525
|
+
const parent = dirname3(dir);
|
|
901
1526
|
if (parent === dir) break;
|
|
902
1527
|
dir = parent;
|
|
903
1528
|
}
|
|
@@ -906,9 +1531,9 @@ function findWorkspaceRoot(startDir) {
|
|
|
906
1531
|
function findNearestPackageRoot(startDir, workspaceRoot) {
|
|
907
1532
|
let dir = startDir;
|
|
908
1533
|
for (let i = 0; i < 30; i++) {
|
|
909
|
-
if (
|
|
1534
|
+
if (existsSync3(join3(dir, "package.json"))) return dir;
|
|
910
1535
|
if (dir === workspaceRoot) break;
|
|
911
|
-
const parent =
|
|
1536
|
+
const parent = dirname3(dir);
|
|
912
1537
|
if (parent === dir) break;
|
|
913
1538
|
dir = parent;
|
|
914
1539
|
}
|
|
@@ -917,7 +1542,7 @@ function findNearestPackageRoot(startDir, workspaceRoot) {
|
|
|
917
1542
|
function findStyleguidePath(startDir, explicitPath) {
|
|
918
1543
|
if (explicitPath) {
|
|
919
1544
|
if (isAbsolute(explicitPath)) {
|
|
920
|
-
return
|
|
1545
|
+
return existsSync3(explicitPath) ? explicitPath : null;
|
|
921
1546
|
}
|
|
922
1547
|
const workspaceRoot2 = findWorkspaceRoot(startDir);
|
|
923
1548
|
const packageRoot = findNearestPackageRoot(startDir, workspaceRoot2);
|
|
@@ -927,7 +1552,7 @@ function findStyleguidePath(startDir, explicitPath) {
|
|
|
927
1552
|
resolve(workspaceRoot2, explicitPath)
|
|
928
1553
|
];
|
|
929
1554
|
for (const p of candidates) {
|
|
930
|
-
if (
|
|
1555
|
+
if (existsSync3(p)) return p;
|
|
931
1556
|
}
|
|
932
1557
|
return null;
|
|
933
1558
|
}
|
|
@@ -935,13 +1560,13 @@ function findStyleguidePath(startDir, explicitPath) {
|
|
|
935
1560
|
let dir = startDir;
|
|
936
1561
|
while (true) {
|
|
937
1562
|
for (const relativePath of DEFAULT_STYLEGUIDE_PATHS) {
|
|
938
|
-
const fullPath =
|
|
939
|
-
if (
|
|
1563
|
+
const fullPath = join3(dir, relativePath);
|
|
1564
|
+
if (existsSync3(fullPath)) {
|
|
940
1565
|
return fullPath;
|
|
941
1566
|
}
|
|
942
1567
|
}
|
|
943
1568
|
if (dir === workspaceRoot) break;
|
|
944
|
-
const parent =
|
|
1569
|
+
const parent = dirname3(dir);
|
|
945
1570
|
if (parent === dir) break;
|
|
946
1571
|
dir = parent;
|
|
947
1572
|
}
|
|
@@ -951,7 +1576,7 @@ function loadStyleguide(startDir, explicitPath) {
|
|
|
951
1576
|
const path = findStyleguidePath(startDir, explicitPath);
|
|
952
1577
|
if (!path) return null;
|
|
953
1578
|
try {
|
|
954
|
-
return
|
|
1579
|
+
return readFileSync3(path, "utf-8");
|
|
955
1580
|
} catch {
|
|
956
1581
|
return null;
|
|
957
1582
|
}
|
|
@@ -960,7 +1585,7 @@ function getStyleguide(startDir, explicitPath) {
|
|
|
960
1585
|
const path = findStyleguidePath(startDir, explicitPath);
|
|
961
1586
|
if (!path) return { path: null, content: null };
|
|
962
1587
|
try {
|
|
963
|
-
const content =
|
|
1588
|
+
const content = readFileSync3(path, "utf-8");
|
|
964
1589
|
return { path, content };
|
|
965
1590
|
} catch {
|
|
966
1591
|
return { path, content: null };
|
|
@@ -1003,7 +1628,7 @@ var semantic_default = createRule({
|
|
|
1003
1628
|
create(context) {
|
|
1004
1629
|
const options = context.options[0] || {};
|
|
1005
1630
|
const filePath = context.filename;
|
|
1006
|
-
const fileDir =
|
|
1631
|
+
const fileDir = dirname4(filePath);
|
|
1007
1632
|
const { path: styleguidePath, content: styleguide } = getStyleguide(
|
|
1008
1633
|
fileDir,
|
|
1009
1634
|
options.styleguidePath
|
|
@@ -1025,7 +1650,7 @@ var semantic_default = createRule({
|
|
|
1025
1650
|
}
|
|
1026
1651
|
let fileContent;
|
|
1027
1652
|
try {
|
|
1028
|
-
fileContent =
|
|
1653
|
+
fileContent = readFileSync4(filePath, "utf-8");
|
|
1029
1654
|
} catch {
|
|
1030
1655
|
console.error(`[uilint] Failed to read file ${filePath}`);
|
|
1031
1656
|
return {
|
|
@@ -1040,7 +1665,7 @@ var semantic_default = createRule({
|
|
|
1040
1665
|
}
|
|
1041
1666
|
const fileHash = hashContentSync(fileContent);
|
|
1042
1667
|
const styleguideHash = hashContentSync(styleguide);
|
|
1043
|
-
const projectRoot =
|
|
1668
|
+
const projectRoot = findProjectRoot2(fileDir);
|
|
1044
1669
|
const relativeFilePath = relative(projectRoot, filePath);
|
|
1045
1670
|
const cached = getCacheEntry(
|
|
1046
1671
|
projectRoot,
|
|
@@ -1093,13 +1718,13 @@ var semantic_default = createRule({
|
|
|
1093
1718
|
};
|
|
1094
1719
|
}
|
|
1095
1720
|
});
|
|
1096
|
-
function
|
|
1721
|
+
function findProjectRoot2(startDir) {
|
|
1097
1722
|
let dir = startDir;
|
|
1098
1723
|
for (let i = 0; i < 20; i++) {
|
|
1099
|
-
if (
|
|
1724
|
+
if (existsSync4(join4(dir, "package.json"))) {
|
|
1100
1725
|
return dir;
|
|
1101
1726
|
}
|
|
1102
|
-
const parent =
|
|
1727
|
+
const parent = dirname4(dir);
|
|
1103
1728
|
if (parent === dir) break;
|
|
1104
1729
|
dir = parent;
|
|
1105
1730
|
}
|