pasika 0.10.142 → 0.10.144
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/eslint/pasika/index.js +103 -106
- package/package.json +1 -1
|
@@ -10093,6 +10093,16 @@ var baseLayerPairRule = {
|
|
|
10093
10093
|
return {
|
|
10094
10094
|
"StyleSheet:exit"(node) {
|
|
10095
10095
|
const applied = collectBodyUtilities(node);
|
|
10096
|
+
const themeColors = /* @__PURE__ */ new Set();
|
|
10097
|
+
const collectThemeColors = (source) => {
|
|
10098
|
+
const uncommented = source.replace(/\/\*[\s\S]*?\*\//gu, " ");
|
|
10099
|
+
for (const theme of uncommented.matchAll(/@theme(?:\s+[\w-]+)*\s*\{(?<body>[^}]*)\}/gu)) {
|
|
10100
|
+
for (const token of (theme.groups?.body ?? "").matchAll(/(?:^|[;\r\n])\s*--color-(?<name>[\w-]+)\s*:/gu)) {
|
|
10101
|
+
if (token.groups?.name) themeColors.add(token.groups.name);
|
|
10102
|
+
}
|
|
10103
|
+
}
|
|
10104
|
+
};
|
|
10105
|
+
collectThemeColors(context.sourceCode.text);
|
|
10096
10106
|
const seen = /* @__PURE__ */ new Set([current]);
|
|
10097
10107
|
const queue = [{ file: current, source: context.sourceCode.text }];
|
|
10098
10108
|
const textOf = cachedTextReader();
|
|
@@ -10106,6 +10116,7 @@ var baseLayerPairRule = {
|
|
|
10106
10116
|
if (seen.has(filename) || !existsSync8(filename)) continue;
|
|
10107
10117
|
seen.add(filename);
|
|
10108
10118
|
const source = textOf(filename);
|
|
10119
|
+
collectThemeColors(source);
|
|
10109
10120
|
const parsed = toPlainObject(parse3(source, { parseAtrulePrelude: true }));
|
|
10110
10121
|
if (parsed.type !== "StyleSheet") continue;
|
|
10111
10122
|
const fragment = collectBodyUtilities(parsed);
|
|
@@ -10115,8 +10126,12 @@ var baseLayerPairRule = {
|
|
|
10115
10126
|
}
|
|
10116
10127
|
}
|
|
10117
10128
|
if (!applied.hasBaseLayer) return;
|
|
10118
|
-
const hasCanvas = applied.names.some(
|
|
10119
|
-
|
|
10129
|
+
const hasCanvas = applied.names.some(
|
|
10130
|
+
(name) => name.includes("canvas") || name.startsWith("bg-") && themeColors.has(name.slice(3))
|
|
10131
|
+
);
|
|
10132
|
+
const hasInk = applied.names.some(
|
|
10133
|
+
(name) => name.includes("ink") || name.startsWith("text-") && themeColors.has(name.slice(5))
|
|
10134
|
+
);
|
|
10120
10135
|
if (!hasCanvas || !hasInk) {
|
|
10121
10136
|
context.report({
|
|
10122
10137
|
node,
|
|
@@ -11497,128 +11512,110 @@ var themeResetRule = {
|
|
|
11497
11512
|
|
|
11498
11513
|
// eslint/rules/tailwind/theme-token-order.ts
|
|
11499
11514
|
import path77 from "path";
|
|
11500
|
-
var
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
"
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
"
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
"
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
function themeGroupName(name, value) {
|
|
11534
|
-
if (primitiveColors.has(name)) return "Color primitives";
|
|
11535
|
-
if (name.startsWith("--color-")) {
|
|
11536
|
-
return value.includes("var(") ? "Semantic colors" : "Fixed and brand colors";
|
|
11537
|
-
}
|
|
11538
|
-
if (name.startsWith("--font-") && !name.startsWith("--font-weight-")) return "Font families";
|
|
11539
|
-
if (/^--(?:font-weight|text-|tracking-|leading-)/u.test(name)) return "Typography";
|
|
11540
|
-
if (name.startsWith("--spacing")) return "Spacing and sizing";
|
|
11541
|
-
if (/^--(?:breakpoint|container|aspect)-/u.test(name)) return "Breakpoints, containers, and aspect ratios";
|
|
11542
|
-
if (name.startsWith("--radius")) return "Border radii";
|
|
11543
|
-
if (/^--(?:shadow|inset-shadow|drop-shadow|text-shadow)-/u.test(name)) return "Shadows and visual effects";
|
|
11544
|
-
if (name.startsWith("--background-image-")) return "Background images";
|
|
11545
|
-
if (/^--(?:default-transition|transition|ease)-/u.test(name)) return "Transitions and easing";
|
|
11546
|
-
if (name.startsWith("--animate-")) return "Animations";
|
|
11547
|
-
if (name.startsWith("--blur-")) return "Blur";
|
|
11548
|
-
return "Other tokens";
|
|
11515
|
+
var GROUP_RE = /^\s*\/\*\s*(?:Group:\s*)?(?<paths>(?:global|src\/[\w./-]+\.(?:tsx?|jsx?))(?:\s*,\s*src\/[\w./-]+\.(?:tsx?|jsx?))*)\s*\*\/\s*$/u;
|
|
11516
|
+
var PATH_RE = /^src\/[\w./-]+\.(?:tsx?|jsx?)$/u;
|
|
11517
|
+
function normalizeGroup(label) {
|
|
11518
|
+
if (label === "global") return "global";
|
|
11519
|
+
return [...new Set(label.split(",").map((name) => name.trim()))].sort().join(", ");
|
|
11520
|
+
}
|
|
11521
|
+
function sectionOf(symbol) {
|
|
11522
|
+
if (symbol.kind === "theme-token") return "theme";
|
|
11523
|
+
if (symbol.kind === "utility") return "utility";
|
|
11524
|
+
if (symbol.kind === "keyframes") return "keyframes";
|
|
11525
|
+
return symbol.kind;
|
|
11526
|
+
}
|
|
11527
|
+
function ownerOf(symbol, graph, root) {
|
|
11528
|
+
const references = graph.references.filter((ref) => {
|
|
11529
|
+
if (ref.source !== "module" || !/\.(?:tsx|jsx)$/u.test(ref.file) || /\.(?:test|spec|stories)\.(?:tsx|jsx)$/u.test(ref.file)) {
|
|
11530
|
+
return false;
|
|
11531
|
+
}
|
|
11532
|
+
if (symbol.kind === "theme-token") {
|
|
11533
|
+
return ref.kind === "theme-class" && ref.token === symbol.name || ref.kind === "variable" && ref.name === symbol.name;
|
|
11534
|
+
}
|
|
11535
|
+
if (symbol.kind === "utility" || symbol.kind === "keyframes" || symbol.kind === "selector") {
|
|
11536
|
+
return ref.name === symbol.name;
|
|
11537
|
+
}
|
|
11538
|
+
return ref.kind === "variable" && ref.name === symbol.name;
|
|
11539
|
+
});
|
|
11540
|
+
const indirect = graph.references.some(
|
|
11541
|
+
(ref) => ref.source === "css" && ref.file !== symbol.file && (symbol.kind === "theme-token" && ref.kind === "variable" && ref.name === symbol.name || symbol.kind === "utility" && ref.kind === "utility" && ref.name === symbol.name || symbol.kind === "keyframes" && ref.kind === "keyframes" && ref.name === symbol.name)
|
|
11542
|
+
);
|
|
11543
|
+
if (indirect) return "global";
|
|
11544
|
+
const owners = [
|
|
11545
|
+
...new Set(references.map((ref) => path77.relative(path77.dirname(root), ref.file).split(path77.sep).join("/")))
|
|
11546
|
+
].filter((name) => PATH_RE.test(name)).sort();
|
|
11547
|
+
return owners.length > 0 ? owners.join(", ") : "global";
|
|
11549
11548
|
}
|
|
11550
11549
|
var themeTokenOrderRule = {
|
|
11551
11550
|
meta: {
|
|
11552
11551
|
schema: [],
|
|
11553
11552
|
type: "problem",
|
|
11553
|
+
fixable: "code",
|
|
11554
11554
|
docs: {
|
|
11555
|
-
description: "
|
|
11555
|
+
description: "Group CSS definitions by consuming component paths in alphabetical order."
|
|
11556
11556
|
}
|
|
11557
11557
|
},
|
|
11558
11558
|
create(context) {
|
|
11559
11559
|
const root = sourceRootOf(context);
|
|
11560
|
-
const
|
|
11561
|
-
|
|
11560
|
+
const current = path77.normalize(path77.resolve(context.filename));
|
|
11561
|
+
const textOf = cachedTextReader();
|
|
11562
|
+
const cssFiles = /* @__PURE__ */ new Set([...findFiles(root, CSS_EXTENSIONS).map((file) => path77.normalize(file)), current]);
|
|
11563
|
+
const graph = buildCssDependencyGraph({
|
|
11564
|
+
sourceRoot: root,
|
|
11565
|
+
css: [...cssFiles].map((file) => ({
|
|
11566
|
+
path: file,
|
|
11567
|
+
content: path77.normalize(file) === current ? context.sourceCode.text : textOf(file)
|
|
11568
|
+
})),
|
|
11569
|
+
modules: findFiles(root, MODULE_EXTENSIONS4).map((file) => ({ path: file, content: textOf(file) }))
|
|
11570
|
+
});
|
|
11571
|
+
const lines = context.sourceCode.text.split(/\r?\n/u);
|
|
11572
|
+
const groups = [];
|
|
11573
|
+
for (const [index, line] of lines.entries()) {
|
|
11574
|
+
const match = GROUP_RE.exec(line);
|
|
11575
|
+
if (match?.groups?.paths) groups.push({ label: normalizeGroup(match.groups.paths), line: index + 1 });
|
|
11576
|
+
}
|
|
11577
|
+
const items = graph.definitions.filter((symbol) => symbol.file === current && symbol.name !== "--*").filter(
|
|
11578
|
+
(symbol) => ["theme-token", "utility", "keyframes", "root-variable", "selector", "font-face"].includes(symbol.kind)
|
|
11579
|
+
).map((symbol) => ({
|
|
11580
|
+
symbol,
|
|
11581
|
+
group: groups.filter((group) => group.line < symbol.line).at(-1),
|
|
11582
|
+
owner: ownerOf(symbol, graph, root),
|
|
11583
|
+
section: sectionOf(symbol)
|
|
11584
|
+
})).sort((a, b) => a.symbol.line - b.symbol.line);
|
|
11562
11585
|
return {
|
|
11563
|
-
"StyleSheet:exit"(
|
|
11564
|
-
const theme = [...sheet.children].find(
|
|
11565
|
-
(child) => child.type === "Atrule" && child.name === "theme" && child.loc
|
|
11566
|
-
);
|
|
11567
|
-
if (!theme?.loc) return;
|
|
11568
|
-
const raw = context.sourceCode.text.slice(theme.loc.start.offset, theme.loc.end.offset);
|
|
11569
|
-
const opening = raw.indexOf("{");
|
|
11570
|
-
const closing = raw.lastIndexOf("}");
|
|
11571
|
-
if (opening === -1 || closing <= opening) return;
|
|
11572
|
-
const lines = raw.slice(opening + 1, closing).split(/\r?\n/u);
|
|
11573
|
-
const firstLine = theme.loc.start.line + (raw.slice(0, opening + 1).match(/\n/gu)?.length ?? 0);
|
|
11574
|
-
const tokens = [];
|
|
11575
|
-
let activeHeading;
|
|
11576
|
-
let hasGroupHeadings = false;
|
|
11577
|
-
for (const [index, line] of lines.entries()) {
|
|
11578
|
-
const heading = /^\s*\/\*\s*(?<heading>.*?)\s*\*\/\s*$/u.exec(line)?.groups?.heading;
|
|
11579
|
-
if (heading && THEME_GROUPS.includes(heading)) {
|
|
11580
|
-
activeHeading = heading;
|
|
11581
|
-
hasGroupHeadings = true;
|
|
11582
|
-
}
|
|
11583
|
-
const declaration = /^ {2}(?<name>--[a-z][a-z0-9-]*)\s*:\s*(?<value>.*)$/u.exec(line);
|
|
11584
|
-
const { name, value } = declaration?.groups ?? {};
|
|
11585
|
-
if (!name || value === void 0) continue;
|
|
11586
|
-
tokens.push({
|
|
11587
|
-
name,
|
|
11588
|
-
group: themeGroupName(name, value),
|
|
11589
|
-
activeHeading,
|
|
11590
|
-
line: firstLine + index
|
|
11591
|
-
});
|
|
11592
|
-
}
|
|
11593
|
-
if (tokens.length > 1 && !hasGroupHeadings) {
|
|
11594
|
-
context.report({
|
|
11595
|
-
node: sheet,
|
|
11596
|
-
message: "Global theme tokens must use named purpose-group section comments."
|
|
11597
|
-
});
|
|
11598
|
-
}
|
|
11586
|
+
"StyleSheet:exit"(node) {
|
|
11599
11587
|
let previous;
|
|
11600
|
-
for (const
|
|
11588
|
+
for (const item of items) {
|
|
11589
|
+
const currentGroup = item.group;
|
|
11590
|
+
const actual = currentGroup?.label;
|
|
11601
11591
|
let message;
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
if (
|
|
11605
|
-
message = `
|
|
11606
|
-
} else if (previous
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11592
|
+
if (!currentGroup) {
|
|
11593
|
+
message = `CSS definition "${item.symbol.name}" requires a component-path group comment (or /* Group: global */).`;
|
|
11594
|
+
} else if (actual !== item.owner) {
|
|
11595
|
+
message = `CSS definition "${item.symbol.name}" belongs to group "${item.owner}", not "${currentGroup.label}".`;
|
|
11596
|
+
} else if (previous?.section === item.section && previous.group) {
|
|
11597
|
+
if (previous.group !== currentGroup && previous.group.label.localeCompare(currentGroup.label) > 0) {
|
|
11598
|
+
message = `CSS consumer groups in ${item.section} must be ordered alphabetically by path.`;
|
|
11599
|
+
} else if (previous.group === currentGroup && previous.symbol.name.localeCompare(item.symbol.name) > 0) {
|
|
11600
|
+
message = `CSS definitions in group "${previous.group.label}" must be alphabetical: "${item.symbol.name}" comes before "${previous.symbol.name}".`;
|
|
11601
|
+
}
|
|
11610
11602
|
}
|
|
11611
11603
|
if (message) {
|
|
11604
|
+
const line = item.symbol.line;
|
|
11612
11605
|
context.report({
|
|
11613
|
-
node
|
|
11614
|
-
loc: {
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11606
|
+
node,
|
|
11607
|
+
loc: { start: { line, column: 1 }, end: { line, column: 2 } },
|
|
11608
|
+
message,
|
|
11609
|
+
...currentGroup && actual !== item.owner && items.filter((candidate) => candidate.group === currentGroup).length === 1 ? {
|
|
11610
|
+
fix(fixer) {
|
|
11611
|
+
const start = context.sourceCode.getIndexFromLoc({ line: currentGroup.line, column: 1 });
|
|
11612
|
+
const end = start + (lines[currentGroup.line - 1] ?? "").length;
|
|
11613
|
+
return fixer.replaceTextRange([start, end], `/* Group: ${item.owner} */`);
|
|
11614
|
+
}
|
|
11615
|
+
} : {}
|
|
11619
11616
|
});
|
|
11620
11617
|
}
|
|
11621
|
-
previous =
|
|
11618
|
+
previous = item;
|
|
11622
11619
|
}
|
|
11623
11620
|
}
|
|
11624
11621
|
};
|