pasika 0.10.115 → 0.10.117
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.d.ts +2 -0
- package/dist/eslint/pasika/index.js +337 -71
- package/package.json +1 -1
|
@@ -133,6 +133,7 @@ declare const tailwindRules: {
|
|
|
133
133
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
134
134
|
"unused-utility": _eslint_css.CSSRuleDefinition;
|
|
135
135
|
"unique-css-definition": _eslint_css.CSSRuleDefinition;
|
|
136
|
+
"unique-css-token-value": _eslint_css.CSSRuleDefinition;
|
|
136
137
|
"no-utility-alias": _eslint_css.CSSRuleDefinition;
|
|
137
138
|
"global-selector-styling": _eslint_css.CSSRuleDefinition;
|
|
138
139
|
};
|
|
@@ -172,6 +173,7 @@ declare const pasikaPlugin: {
|
|
|
172
173
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
173
174
|
"unused-utility": _eslint_css.CSSRuleDefinition;
|
|
174
175
|
"unique-css-definition": _eslint_css.CSSRuleDefinition;
|
|
176
|
+
"unique-css-token-value": _eslint_css.CSSRuleDefinition;
|
|
175
177
|
"no-utility-alias": _eslint_css.CSSRuleDefinition;
|
|
176
178
|
"global-selector-styling": _eslint_css.CSSRuleDefinition;
|
|
177
179
|
"doc-kind-suffix": _eslint_markdown.MarkdownRuleDefinition;
|
|
@@ -10095,6 +10095,52 @@ function themeClasses(name) {
|
|
|
10095
10095
|
}
|
|
10096
10096
|
return ["bg", "text", "border", "fill", "stroke", "ring"].map((prefix) => `${prefix}-${stem}`);
|
|
10097
10097
|
}
|
|
10098
|
+
if (name.startsWith("--spacing-")) {
|
|
10099
|
+
const stem = name.slice("--spacing-".length);
|
|
10100
|
+
return [
|
|
10101
|
+
"p",
|
|
10102
|
+
"px",
|
|
10103
|
+
"py",
|
|
10104
|
+
"pt",
|
|
10105
|
+
"pr",
|
|
10106
|
+
"pb",
|
|
10107
|
+
"pl",
|
|
10108
|
+
"ps",
|
|
10109
|
+
"pe",
|
|
10110
|
+
"m",
|
|
10111
|
+
"mx",
|
|
10112
|
+
"my",
|
|
10113
|
+
"mt",
|
|
10114
|
+
"mr",
|
|
10115
|
+
"mb",
|
|
10116
|
+
"ml",
|
|
10117
|
+
"ms",
|
|
10118
|
+
"me",
|
|
10119
|
+
"w",
|
|
10120
|
+
"h",
|
|
10121
|
+
"size",
|
|
10122
|
+
"min-w",
|
|
10123
|
+
"min-h",
|
|
10124
|
+
"max-w",
|
|
10125
|
+
"max-h",
|
|
10126
|
+
"gap",
|
|
10127
|
+
"gap-x",
|
|
10128
|
+
"gap-y",
|
|
10129
|
+
"inset",
|
|
10130
|
+
"inset-x",
|
|
10131
|
+
"inset-y",
|
|
10132
|
+
"top",
|
|
10133
|
+
"right",
|
|
10134
|
+
"bottom",
|
|
10135
|
+
"left",
|
|
10136
|
+
"start",
|
|
10137
|
+
"end",
|
|
10138
|
+
"space-x",
|
|
10139
|
+
"space-y"
|
|
10140
|
+
].map((prefix) => `${prefix}-${stem}`);
|
|
10141
|
+
}
|
|
10142
|
+
if (name.startsWith("--aspect-")) return [`aspect-${name.slice("--aspect-".length)}`];
|
|
10143
|
+
if (name.startsWith("--leading-")) return [`leading-${name.slice("--leading-".length)}`];
|
|
10098
10144
|
if (name.startsWith("--animate-")) return [`animate-${name.slice("--animate-".length)}`];
|
|
10099
10145
|
if (name.startsWith("--radius-")) return [`rounded-${name.slice("--radius-".length)}`];
|
|
10100
10146
|
if (name.startsWith("--text-") || name.startsWith("--tracking-") || name.startsWith("--font-")) {
|
|
@@ -10156,7 +10202,7 @@ function buildCssDependencyGraph(options) {
|
|
|
10156
10202
|
} else if (node.name === "theme" && node.loc) {
|
|
10157
10203
|
const source = file.content.slice(node.loc.start.offset, node.loc.end.offset).replace(/\/\*[\s\S]*?\*\//gu, (comment) => comment.replace(/[^\r\n]/gu, " "));
|
|
10158
10204
|
for (const found of source.matchAll(
|
|
10159
|
-
/(?:^|[{;\r\n])\s*(?<name>--[a-z][\w-]*)\s*:\s*(?<value>[
|
|
10205
|
+
/(?:^|(?<=[{;\r\n]))\s*(?<name>--[a-z][\w-]*)\s*:\s*(?<value>[^;}\r\n]+)(?=;|[}])/gu
|
|
10160
10206
|
)) {
|
|
10161
10207
|
const name = found.groups?.name;
|
|
10162
10208
|
const value = found.groups?.value;
|
|
@@ -10912,48 +10958,129 @@ var uniqueCssDefinitionRule = {
|
|
|
10912
10958
|
schema: [],
|
|
10913
10959
|
type: "problem",
|
|
10914
10960
|
docs: {
|
|
10915
|
-
description: "Reject duplicate
|
|
10961
|
+
description: "Reject duplicate CSS definitions both within and across stylesheets while preserving scoped overrides."
|
|
10916
10962
|
}
|
|
10917
10963
|
},
|
|
10918
10964
|
create(context) {
|
|
10919
10965
|
const sourceRoot = sourceRootOf(context);
|
|
10966
|
+
const current = path74.normalize(path74.resolve(context.filename));
|
|
10920
10967
|
const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
|
|
10921
10968
|
if (cssFiles.length === 0) return {};
|
|
10922
10969
|
const textOf = cachedTextReader();
|
|
10923
10970
|
const graph = buildCssDependencyGraph({
|
|
10924
10971
|
sourceRoot,
|
|
10925
|
-
css: cssFiles.map((file) => ({
|
|
10972
|
+
css: cssFiles.map((file) => ({
|
|
10973
|
+
path: file,
|
|
10974
|
+
content: path74.normalize(file) === current ? context.sourceCode.text : textOf(file)
|
|
10975
|
+
})),
|
|
10926
10976
|
modules: [],
|
|
10927
10977
|
includeReferences: false
|
|
10928
10978
|
});
|
|
10929
|
-
const
|
|
10979
|
+
const groups = /* @__PURE__ */ new Map();
|
|
10930
10980
|
for (const symbol of graph.definitions) {
|
|
10931
10981
|
const key = ownershipKey(symbol);
|
|
10932
10982
|
if (!key) continue;
|
|
10933
|
-
const
|
|
10934
|
-
|
|
10935
|
-
|
|
10983
|
+
const definitions = groups.get(key) ?? [];
|
|
10984
|
+
definitions.push(symbol);
|
|
10985
|
+
groups.set(key, definitions);
|
|
10936
10986
|
}
|
|
10937
10987
|
return {
|
|
10938
10988
|
"StyleSheet:exit"(node) {
|
|
10939
|
-
const
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10989
|
+
for (const definitions of groups.values()) {
|
|
10990
|
+
if (definitions.length < 2) continue;
|
|
10991
|
+
definitions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
|
|
10992
|
+
const canonical = definitions[0];
|
|
10993
|
+
if (!canonical) continue;
|
|
10994
|
+
for (const symbol of definitions.slice(1)) {
|
|
10995
|
+
if (symbol.file !== current) continue;
|
|
10996
|
+
const message = symbol.file === canonical.file ? `${symbolLabel(symbol)} "${symbol.name}" is defined more than once in this CSS file; define it only once.` : `${symbolLabel(symbol)} "${symbol.name}" is also defined in ${path74.relative(sourceRoot, canonical.file)}; define it in only one CSS file.`;
|
|
10997
|
+
context.report({
|
|
10998
|
+
node,
|
|
10999
|
+
loc: {
|
|
11000
|
+
start: { line: symbol.line, column: 1 },
|
|
11001
|
+
end: { line: symbol.line, column: 2 }
|
|
11002
|
+
},
|
|
11003
|
+
message
|
|
11004
|
+
});
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
}
|
|
11008
|
+
};
|
|
11009
|
+
}
|
|
11010
|
+
};
|
|
11011
|
+
|
|
11012
|
+
// eslint/rules/tailwind/unique-css-token-value.ts
|
|
11013
|
+
import path75 from "path";
|
|
11014
|
+
function valueIdentity(value) {
|
|
11015
|
+
const text = value.trim();
|
|
11016
|
+
const hex = /^#(?<digits>[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/iu.exec(text)?.groups?.digits;
|
|
11017
|
+
if (!hex) return text;
|
|
11018
|
+
const lower = hex.toLowerCase();
|
|
11019
|
+
const full = lower.length <= 4 ? Array.from(lower, (digit) => digit + digit).join("") : lower;
|
|
11020
|
+
return `#${full.length === 8 && full.endsWith("ff") ? full.slice(0, -2) : full}`;
|
|
11021
|
+
}
|
|
11022
|
+
function isComparable(symbol) {
|
|
11023
|
+
if (symbol.value === void 0 || symbol.value.trim() === "") return false;
|
|
11024
|
+
if (/\b(?:var|env|attr|calc|min|max|clamp|color-mix|light-dark)\s*\(/iu.test(symbol.value)) return false;
|
|
11025
|
+
return symbol.kind === "theme-token" || symbol.kind === "root-variable" && symbol.scope === "default";
|
|
11026
|
+
}
|
|
11027
|
+
function compareLocations(left, right) {
|
|
11028
|
+
const file = left.file.localeCompare(right.file);
|
|
11029
|
+
return file || left.line - right.line;
|
|
11030
|
+
}
|
|
11031
|
+
var uniqueCssTokenValueRule = {
|
|
11032
|
+
meta: {
|
|
11033
|
+
schema: [],
|
|
11034
|
+
type: "problem",
|
|
11035
|
+
docs: {
|
|
11036
|
+
description: "Reject distinct CSS design tokens with duplicate static values across the project."
|
|
11037
|
+
}
|
|
11038
|
+
},
|
|
11039
|
+
create(context) {
|
|
11040
|
+
const sourceRoot = sourceRootOf(context);
|
|
11041
|
+
const current = path75.normalize(path75.resolve(context.filename));
|
|
11042
|
+
const textOf = cachedTextReader();
|
|
11043
|
+
const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
|
|
11044
|
+
const graph = buildCssDependencyGraph({
|
|
11045
|
+
sourceRoot,
|
|
11046
|
+
css: cssFiles.map((file) => ({
|
|
11047
|
+
path: file,
|
|
11048
|
+
content: path75.normalize(file) === current ? context.sourceCode.text : textOf(file)
|
|
11049
|
+
})),
|
|
11050
|
+
modules: [],
|
|
11051
|
+
includeReferences: false
|
|
11052
|
+
});
|
|
11053
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
11054
|
+
for (const definition of graph.definitions) {
|
|
11055
|
+
if (!isComparable(definition)) continue;
|
|
11056
|
+
const value = valueIdentity(definition.value ?? "");
|
|
11057
|
+
const group = byValue.get(value) ?? [];
|
|
11058
|
+
group.push(definition);
|
|
11059
|
+
byValue.set(value, group);
|
|
11060
|
+
}
|
|
11061
|
+
const redundant = /* @__PURE__ */ new Map();
|
|
11062
|
+
for (const group of byValue.values()) {
|
|
11063
|
+
group.sort(compareLocations);
|
|
11064
|
+
const first = group[0];
|
|
11065
|
+
if (!first) continue;
|
|
11066
|
+
for (const definition of group.slice(1)) {
|
|
11067
|
+
if (definition.name !== first.name) redundant.set(definition, first);
|
|
11068
|
+
}
|
|
11069
|
+
}
|
|
11070
|
+
return {
|
|
11071
|
+
"StyleSheet:exit"(node) {
|
|
11072
|
+
for (const [definition, original] of redundant) {
|
|
11073
|
+
if (definition.file !== current) continue;
|
|
10950
11074
|
context.report({
|
|
10951
11075
|
node,
|
|
10952
11076
|
loc: {
|
|
10953
|
-
start: { line:
|
|
10954
|
-
end: { line:
|
|
11077
|
+
start: { line: definition.line, column: 1 },
|
|
11078
|
+
end: { line: definition.line, column: 2 }
|
|
10955
11079
|
},
|
|
10956
|
-
message:
|
|
11080
|
+
message: `Token "${definition.name}" duplicates the value of "${original.name}" in ${path75.relative(
|
|
11081
|
+
sourceRoot,
|
|
11082
|
+
original.file
|
|
11083
|
+
)}:${String(original.line)}; reuse one design token.`
|
|
10957
11084
|
});
|
|
10958
11085
|
}
|
|
10959
11086
|
}
|
|
@@ -10963,7 +11090,7 @@ var uniqueCssDefinitionRule = {
|
|
|
10963
11090
|
|
|
10964
11091
|
// eslint/rules/tailwind/unused-utility.ts
|
|
10965
11092
|
import { statSync as statSync5 } from "fs";
|
|
10966
|
-
import
|
|
11093
|
+
import path76 from "path";
|
|
10967
11094
|
var unusedUtilityRule = {
|
|
10968
11095
|
meta: {
|
|
10969
11096
|
schema: [],
|
|
@@ -10979,7 +11106,7 @@ var unusedUtilityRule = {
|
|
|
10979
11106
|
} catch {
|
|
10980
11107
|
return {};
|
|
10981
11108
|
}
|
|
10982
|
-
const current =
|
|
11109
|
+
const current = path76.normalize(path76.resolve(context.filename));
|
|
10983
11110
|
const textOf = cachedTextReader();
|
|
10984
11111
|
const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
|
|
10985
11112
|
const moduleFiles = findFiles(sourceRoot, MODULE_EXTENSIONS4);
|
|
@@ -10987,7 +11114,7 @@ var unusedUtilityRule = {
|
|
|
10987
11114
|
sourceRoot,
|
|
10988
11115
|
css: cssFiles.map((file) => ({
|
|
10989
11116
|
path: file,
|
|
10990
|
-
content:
|
|
11117
|
+
content: path76.normalize(file) === current ? context.sourceCode.text : textOf(file)
|
|
10991
11118
|
})),
|
|
10992
11119
|
modules: moduleFiles.map((file) => ({ path: file, content: textOf(file) }))
|
|
10993
11120
|
});
|
|
@@ -11008,6 +11135,7 @@ var unusedUtilityRule = {
|
|
|
11008
11135
|
};
|
|
11009
11136
|
|
|
11010
11137
|
// eslint/rules/tailwind/utility-mapping.ts
|
|
11138
|
+
import path77 from "path";
|
|
11011
11139
|
function applyOperationCount(utility) {
|
|
11012
11140
|
let count = 0;
|
|
11013
11141
|
for (const apply of atrulesNamed(utility, "apply")) {
|
|
@@ -11023,30 +11151,79 @@ function applyOperationCount(utility) {
|
|
|
11023
11151
|
}
|
|
11024
11152
|
return count;
|
|
11025
11153
|
}
|
|
11154
|
+
var themeOperations = [
|
|
11155
|
+
{ property: "font-size", prefix: "text", namespace: "text" },
|
|
11156
|
+
{ property: "letter-spacing", prefix: "tracking", namespace: "tracking" },
|
|
11157
|
+
{ property: "line-height", prefix: "leading", namespace: "leading" },
|
|
11158
|
+
{ property: "font-family", prefix: "font", namespace: "font" },
|
|
11159
|
+
{ property: "font-weight", prefix: "font", namespace: "font-weight" },
|
|
11160
|
+
{ property: "tab-size", prefix: "tab", namespace: "tab-size" },
|
|
11161
|
+
{ property: "border-radius", prefix: "rounded", namespace: "radius" },
|
|
11162
|
+
{ property: "background-color", prefix: "bg", namespace: "color" },
|
|
11163
|
+
{ property: "color", prefix: "text", namespace: "color" },
|
|
11164
|
+
{ property: "border-color", prefix: "border", namespace: "color" },
|
|
11165
|
+
{ property: "outline-color", prefix: "outline", namespace: "color" },
|
|
11166
|
+
{ property: "fill", prefix: "fill", namespace: "color" },
|
|
11167
|
+
{ property: "stroke", prefix: "stroke", namespace: "color" },
|
|
11168
|
+
{ property: "caret-color", prefix: "caret", namespace: "color" },
|
|
11169
|
+
{ property: "text-decoration-color", prefix: "decoration", namespace: "color" },
|
|
11170
|
+
{ property: "padding", prefix: "p", namespace: "spacing" },
|
|
11171
|
+
{ property: "padding-top", prefix: "pt", namespace: "spacing" },
|
|
11172
|
+
{ property: "padding-right", prefix: "pr", namespace: "spacing" },
|
|
11173
|
+
{ property: "padding-bottom", prefix: "pb", namespace: "spacing" },
|
|
11174
|
+
{ property: "padding-left", prefix: "pl", namespace: "spacing" },
|
|
11175
|
+
{ property: "margin", prefix: "m", namespace: "spacing" },
|
|
11176
|
+
{ property: "margin-top", prefix: "mt", namespace: "spacing" },
|
|
11177
|
+
{ property: "margin-right", prefix: "mr", namespace: "spacing" },
|
|
11178
|
+
{ property: "margin-bottom", prefix: "mb", namespace: "spacing" },
|
|
11179
|
+
{ property: "margin-left", prefix: "ml", namespace: "spacing" },
|
|
11180
|
+
{ property: "gap", prefix: "gap", namespace: "spacing" },
|
|
11181
|
+
{ property: "width", prefix: "w", namespace: "spacing" },
|
|
11182
|
+
{ property: "height", prefix: "h", namespace: "spacing" },
|
|
11183
|
+
{ property: "aspect-ratio", prefix: "aspect", namespace: "aspect" },
|
|
11184
|
+
{ property: "transition-timing-function", prefix: "ease", namespace: "ease" },
|
|
11185
|
+
{ property: "zoom", prefix: "zoom", namespace: "zoom" },
|
|
11186
|
+
{ property: "perspective", prefix: "perspective", namespace: "perspective" },
|
|
11187
|
+
{ property: "animation", prefix: "animate", namespace: "animate" }
|
|
11188
|
+
];
|
|
11026
11189
|
function themeCandidate(name, utilityText) {
|
|
11027
11190
|
const source = utilityText.trim();
|
|
11028
|
-
const arbitrary = /^@utility\s+[\w-]+\s*\{\s*@apply\s+\[(?<property>
|
|
11191
|
+
const arbitrary = /^@utility\s+[\w-]+\s*\{\s*@apply\s+\[(?<property>[a-z-]+):(?<value>[^\]\r\n;{}]+)\];?\s*\}$/u.exec(
|
|
11029
11192
|
source
|
|
11030
11193
|
);
|
|
11031
|
-
const typed = /^@utility\s+[\w-]+\s*\{\s*@apply\s+(?<kind>
|
|
11194
|
+
const typed = /^@utility\s+[\w-]+\s*\{\s*@apply\s+(?<kind>[a-z]+)-\((?<hint>[a-z-]+:)?(?<variable>--[a-z][a-z0-9-]*)\);?\s*\}$/u.exec(
|
|
11032
11195
|
source
|
|
11033
11196
|
);
|
|
11034
|
-
const
|
|
11035
|
-
const
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11197
|
+
const property = arbitrary?.groups?.property;
|
|
11198
|
+
const matched = themeOperations.find((operation) => {
|
|
11199
|
+
if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
|
|
11200
|
+
if (property) return property === operation.property;
|
|
11201
|
+
if (typed?.groups?.kind !== operation.prefix) return false;
|
|
11202
|
+
const hint = typed.groups.hint;
|
|
11203
|
+
if (operation.prefix === "text") return hint === (operation.property === "font-size" ? "length:" : "color:");
|
|
11204
|
+
if (operation.prefix === "font") {
|
|
11205
|
+
return hint === (operation.property === "font-family" ? "family-name:" : "number:");
|
|
11206
|
+
}
|
|
11207
|
+
return hint === void 0;
|
|
11208
|
+
});
|
|
11209
|
+
if (!matched) return void 0;
|
|
11041
11210
|
const value = arbitrary?.groups?.value?.trim() ?? (typed?.groups?.variable ? `var(${typed.groups.variable})` : void 0);
|
|
11042
|
-
if (!
|
|
11043
|
-
const
|
|
11044
|
-
if (!name.startsWith(prefix) || name.length === prefix.length) return void 0;
|
|
11045
|
-
const length = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%)$/u.test(value);
|
|
11211
|
+
if (!value) return void 0;
|
|
11212
|
+
const simple = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%|vh|vw|ch|deg)?$/u.test(value);
|
|
11046
11213
|
const variable = /^var\(--[a-z][a-z0-9-]*\)$/u.test(value);
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11214
|
+
const color = /^#[\da-f]{3,8}$/iu.test(value);
|
|
11215
|
+
const keyword = /^[a-z][a-z-]*$/u.test(value);
|
|
11216
|
+
const ratio = /^\d+\/\d+$/u.test(value);
|
|
11217
|
+
if (!simple && !variable && !color && !keyword && !ratio) return void 0;
|
|
11218
|
+
if (matched.property === "font-size" && value.startsWith("-")) return void 0;
|
|
11219
|
+
const stem = name.slice(matched.prefix.length + 1);
|
|
11220
|
+
return {
|
|
11221
|
+
token: `--${matched.namespace}-${stem}`,
|
|
11222
|
+
property: matched.property,
|
|
11223
|
+
value,
|
|
11224
|
+
prefix: matched.prefix,
|
|
11225
|
+
namespace: matched.namespace
|
|
11226
|
+
};
|
|
11050
11227
|
}
|
|
11051
11228
|
var builtInTextSizes = /* @__PURE__ */ new Set([
|
|
11052
11229
|
"xs",
|
|
@@ -11092,6 +11269,19 @@ var utilityMappingRule = {
|
|
|
11092
11269
|
}
|
|
11093
11270
|
},
|
|
11094
11271
|
create(context) {
|
|
11272
|
+
const sourceRoot = sourceRootOf(context);
|
|
11273
|
+
const current = path77.normalize(path77.resolve(context.filename));
|
|
11274
|
+
const textOf = cachedTextReader();
|
|
11275
|
+
const graph = buildCssDependencyGraph({
|
|
11276
|
+
sourceRoot,
|
|
11277
|
+
css: findFiles(sourceRoot, CSS_EXTENSIONS).map((file) => ({
|
|
11278
|
+
path: file,
|
|
11279
|
+
content: path77.normalize(file) === current ? context.sourceCode.text : textOf(file)
|
|
11280
|
+
})),
|
|
11281
|
+
modules: [],
|
|
11282
|
+
includeReferences: false
|
|
11283
|
+
});
|
|
11284
|
+
const projectTokens = graph.definitions.filter((symbol) => symbol.kind === "theme-token");
|
|
11095
11285
|
return {
|
|
11096
11286
|
"StyleSheet:exit"(node) {
|
|
11097
11287
|
const utilities = atrulesNamed(node, "utility");
|
|
@@ -11180,7 +11370,38 @@ var utilityMappingRule = {
|
|
|
11180
11370
|
}
|
|
11181
11371
|
if (nameCounts.get(name) !== 1) continue;
|
|
11182
11372
|
const candidate = themeCandidate(name, context.sourceCode.getText(utility));
|
|
11183
|
-
if (!candidate
|
|
11373
|
+
if (!candidate) continue;
|
|
11374
|
+
const tokenAlreadyDefined = themeTokens.has(candidate.token) || projectTokens.some((token) => token.name === candidate.token);
|
|
11375
|
+
const namespacePrefix = `--${candidate.namespace}-`;
|
|
11376
|
+
const staticValue = !/\b(?:var|env|attr|calc|min|max|clamp|color-mix|light-dark)\s*\(/iu.test(
|
|
11377
|
+
candidate.value
|
|
11378
|
+
);
|
|
11379
|
+
const valueKey = (value) => {
|
|
11380
|
+
const input = value.trim();
|
|
11381
|
+
const digits = /^#(?<hex>[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/iu.exec(input)?.groups?.hex;
|
|
11382
|
+
if (digits) {
|
|
11383
|
+
const lower = digits.toLowerCase();
|
|
11384
|
+
return lower.length <= 4 ? Array.from(lower, (digit) => digit + digit).join("") : lower;
|
|
11385
|
+
}
|
|
11386
|
+
return input;
|
|
11387
|
+
};
|
|
11388
|
+
const sameOperation = (token, value) => token.startsWith(namespacePrefix) && !token.includes("--", 2) && valueKey(value) === valueKey(candidate.value) && (candidate.namespace !== "text" || !["--line-height", "--letter-spacing", "--font-weight"].some(
|
|
11389
|
+
(suffix) => themeDefinitions.has(`${token}${suffix}`) || projectTokens.some((definition) => definition.name === `${token}${suffix}`)
|
|
11390
|
+
));
|
|
11391
|
+
const equivalent = staticValue ? projectTokens.find((token) => token.value !== void 0 && sameOperation(token.name, token.value)) : void 0;
|
|
11392
|
+
const localEquivalent = staticValue ? [...themeDefinitions].find(
|
|
11393
|
+
([token, definitions]) => definitions.length === 1 && definitions[0]?.value !== void 0 && sameOperation(token, definitions[0].value)
|
|
11394
|
+
)?.[0] : void 0;
|
|
11395
|
+
const existingToken = equivalent?.name ?? localEquivalent;
|
|
11396
|
+
if (tokenAlreadyDefined && !existingToken) continue;
|
|
11397
|
+
if (existingToken) {
|
|
11398
|
+
const className = `${candidate.prefix}-${existingToken.slice(namespacePrefix.length)}`;
|
|
11399
|
+
context.report({
|
|
11400
|
+
node: utility,
|
|
11401
|
+
message: `Custom utility "${name}" duplicates theme-generated "${className}" (${candidate.property}: ${candidate.value}); reuse "${className}" instead.`
|
|
11402
|
+
});
|
|
11403
|
+
continue;
|
|
11404
|
+
}
|
|
11184
11405
|
if (candidate.property === "font-size" && themeTokens.has(`--color-${name.slice(5)}`)) continue;
|
|
11185
11406
|
context.report({
|
|
11186
11407
|
node: utility,
|
|
@@ -11207,12 +11428,13 @@ var tailwindRules = {
|
|
|
11207
11428
|
"global-stylesheet": globalStylesheetRule,
|
|
11208
11429
|
"unused-utility": unusedUtilityRule,
|
|
11209
11430
|
"unique-css-definition": uniqueCssDefinitionRule,
|
|
11431
|
+
"unique-css-token-value": uniqueCssTokenValueRule,
|
|
11210
11432
|
"no-utility-alias": noUtilityAliasRule,
|
|
11211
11433
|
"global-selector-styling": globalSelectorStylingRule
|
|
11212
11434
|
};
|
|
11213
11435
|
|
|
11214
11436
|
// eslint/rules/type-extraction.ts
|
|
11215
|
-
import
|
|
11437
|
+
import path78 from "path";
|
|
11216
11438
|
var typeExtractionRule = {
|
|
11217
11439
|
meta: {
|
|
11218
11440
|
schema: [],
|
|
@@ -11223,7 +11445,7 @@ var typeExtractionRule = {
|
|
|
11223
11445
|
},
|
|
11224
11446
|
create(context) {
|
|
11225
11447
|
const sourceRoot = sourceRootOf(context);
|
|
11226
|
-
const file =
|
|
11448
|
+
const file = path78.resolve(context.filename);
|
|
11227
11449
|
const segments = segmentsOf(file, sourceRoot);
|
|
11228
11450
|
if (segments.length === 0) return {};
|
|
11229
11451
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -11364,7 +11586,7 @@ var uiStateRule = {
|
|
|
11364
11586
|
// eslint/rules/unknown-utility.ts
|
|
11365
11587
|
import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync6 } from "fs";
|
|
11366
11588
|
import { createRequire } from "module";
|
|
11367
|
-
import
|
|
11589
|
+
import path79 from "path";
|
|
11368
11590
|
var PREFIX_NAMESPACES = {
|
|
11369
11591
|
bg: ["color"],
|
|
11370
11592
|
text: ["color", "text"],
|
|
@@ -11391,6 +11613,47 @@ var PREFIX_NAMESPACES = {
|
|
|
11391
11613
|
"backdrop-blur": ["blur"],
|
|
11392
11614
|
"ring-offset": ["color"]
|
|
11393
11615
|
};
|
|
11616
|
+
var SPACING_UTILITY_PREFIXES = /* @__PURE__ */ new Set([
|
|
11617
|
+
"p",
|
|
11618
|
+
"px",
|
|
11619
|
+
"py",
|
|
11620
|
+
"pt",
|
|
11621
|
+
"pr",
|
|
11622
|
+
"pb",
|
|
11623
|
+
"pl",
|
|
11624
|
+
"ps",
|
|
11625
|
+
"pe",
|
|
11626
|
+
"m",
|
|
11627
|
+
"mx",
|
|
11628
|
+
"my",
|
|
11629
|
+
"mt",
|
|
11630
|
+
"mr",
|
|
11631
|
+
"mb",
|
|
11632
|
+
"ml",
|
|
11633
|
+
"ms",
|
|
11634
|
+
"me",
|
|
11635
|
+
"w",
|
|
11636
|
+
"h",
|
|
11637
|
+
"size",
|
|
11638
|
+
"min-w",
|
|
11639
|
+
"min-h",
|
|
11640
|
+
"max-w",
|
|
11641
|
+
"max-h",
|
|
11642
|
+
"gap",
|
|
11643
|
+
"gap-x",
|
|
11644
|
+
"gap-y",
|
|
11645
|
+
"inset",
|
|
11646
|
+
"inset-x",
|
|
11647
|
+
"inset-y",
|
|
11648
|
+
"top",
|
|
11649
|
+
"right",
|
|
11650
|
+
"bottom",
|
|
11651
|
+
"left",
|
|
11652
|
+
"start",
|
|
11653
|
+
"end",
|
|
11654
|
+
"space-x",
|
|
11655
|
+
"space-y"
|
|
11656
|
+
]);
|
|
11394
11657
|
var PREFIX_BUILTINS = {
|
|
11395
11658
|
bg: [
|
|
11396
11659
|
"none",
|
|
@@ -11604,7 +11867,7 @@ function stylesheetFiles(dir) {
|
|
|
11604
11867
|
}
|
|
11605
11868
|
return entries.flatMap((entry) => {
|
|
11606
11869
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
11607
|
-
const entryPath =
|
|
11870
|
+
const entryPath = path79.join(dir, entry);
|
|
11608
11871
|
let stats;
|
|
11609
11872
|
try {
|
|
11610
11873
|
stats = statSync6(entryPath);
|
|
@@ -11612,7 +11875,7 @@ function stylesheetFiles(dir) {
|
|
|
11612
11875
|
return [];
|
|
11613
11876
|
}
|
|
11614
11877
|
if (stats.isDirectory()) return stylesheetFiles(entryPath);
|
|
11615
|
-
return
|
|
11878
|
+
return path79.extname(entry) === ".css" ? [entryPath] : [];
|
|
11616
11879
|
});
|
|
11617
11880
|
}
|
|
11618
11881
|
function packageNameOf(specifier) {
|
|
@@ -11623,10 +11886,10 @@ function packageNameOf(specifier) {
|
|
|
11623
11886
|
function resolvePackageStylesheet(fromFile, specifier) {
|
|
11624
11887
|
const packageName = packageNameOf(specifier);
|
|
11625
11888
|
if (!packageName || packageName === "tailwindcss") return void 0;
|
|
11626
|
-
let directory =
|
|
11627
|
-
while (directory !==
|
|
11628
|
-
const packageRoot =
|
|
11629
|
-
const manifestPath =
|
|
11889
|
+
let directory = path79.dirname(fromFile);
|
|
11890
|
+
while (directory !== path79.dirname(directory)) {
|
|
11891
|
+
const packageRoot = path79.join(directory, "node_modules", packageName);
|
|
11892
|
+
const manifestPath = path79.join(packageRoot, "package.json");
|
|
11630
11893
|
if (existsSync12(manifestPath)) {
|
|
11631
11894
|
try {
|
|
11632
11895
|
const manifest = readFileSync15(manifestPath, "utf8");
|
|
@@ -11634,13 +11897,13 @@ function resolvePackageStylesheet(fromFile, specifier) {
|
|
|
11634
11897
|
const main = /"main"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
|
|
11635
11898
|
const target = stylesheet ?? main;
|
|
11636
11899
|
if (!target) return void 0;
|
|
11637
|
-
const resolved =
|
|
11900
|
+
const resolved = path79.resolve(packageRoot, target);
|
|
11638
11901
|
return existsSync12(resolved) ? resolved : void 0;
|
|
11639
11902
|
} catch {
|
|
11640
11903
|
return void 0;
|
|
11641
11904
|
}
|
|
11642
11905
|
}
|
|
11643
|
-
directory =
|
|
11906
|
+
directory = path79.dirname(directory);
|
|
11644
11907
|
}
|
|
11645
11908
|
return void 0;
|
|
11646
11909
|
}
|
|
@@ -11768,7 +12031,7 @@ function isKnown(className, inventory) {
|
|
|
11768
12031
|
if (!utility.includes("-")) return true;
|
|
11769
12032
|
const dash = utility.indexOf("-");
|
|
11770
12033
|
const firstTwo = utility.split("-").slice(0, 2).join("-");
|
|
11771
|
-
const compound = PREFIX_NAMESPACES[firstTwo] ? firstTwo : void 0;
|
|
12034
|
+
const compound = PREFIX_NAMESPACES[firstTwo] || SPACING_UTILITY_PREFIXES.has(firstTwo) ? firstTwo : void 0;
|
|
11772
12035
|
const prefix = compound ?? utility.slice(0, dash);
|
|
11773
12036
|
const token = compound ? utility.slice(compound.length + 1) : utility.slice(dash + 1);
|
|
11774
12037
|
if (!token) return true;
|
|
@@ -11777,6 +12040,7 @@ function isKnown(className, inventory) {
|
|
|
11777
12040
|
const namespaces = PREFIX_NAMESPACES[prefix];
|
|
11778
12041
|
if (!namespaces) {
|
|
11779
12042
|
if (STATIC_VALUE_TOKENS[prefix]?.includes(token)) return true;
|
|
12043
|
+
if (SPACING_UTILITY_PREFIXES.has(prefix) && inventory.themeTokens.get("spacing")?.has(token)) return true;
|
|
11780
12044
|
const projectTokens = inventory.themeTokens.get(prefix);
|
|
11781
12045
|
if (projectTokens) {
|
|
11782
12046
|
if (projectTokens.has(token)) return true;
|
|
@@ -11895,7 +12159,7 @@ var unknownUtilityRule = {
|
|
|
11895
12159
|
};
|
|
11896
12160
|
|
|
11897
12161
|
// eslint/rules/util-file-name.ts
|
|
11898
|
-
import
|
|
12162
|
+
import path80 from "path";
|
|
11899
12163
|
function toKebabCase2(value) {
|
|
11900
12164
|
return value.replace(/(?<lower>[a-z0-9])(?<upper>[A-Z])/g, "$<lower>-$<upper>").replace(/(?<first>[A-Z])(?<rest>[A-Z][a-z])/g, "$<first>-$<rest>").toLowerCase();
|
|
11901
12165
|
}
|
|
@@ -11908,7 +12172,7 @@ var utilFileNameRule = {
|
|
|
11908
12172
|
}
|
|
11909
12173
|
},
|
|
11910
12174
|
create(context) {
|
|
11911
|
-
const filename =
|
|
12175
|
+
const filename = path80.resolve(context.filename);
|
|
11912
12176
|
const segments = filename.replace(/\\/g, "/").split("/");
|
|
11913
12177
|
if (!segments.includes("utils")) return {};
|
|
11914
12178
|
let module;
|
|
@@ -11922,13 +12186,13 @@ var utilFileNameRule = {
|
|
|
11922
12186
|
const functionName = functions[0]?.name;
|
|
11923
12187
|
if (!functionName) return {};
|
|
11924
12188
|
const expected = toKebabCase2(functionName);
|
|
11925
|
-
const actual =
|
|
12189
|
+
const actual = path80.basename(filename, path80.extname(filename));
|
|
11926
12190
|
if (!expected || actual === expected) return {};
|
|
11927
12191
|
return {
|
|
11928
12192
|
Program(node) {
|
|
11929
12193
|
context.report({
|
|
11930
12194
|
node,
|
|
11931
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${
|
|
12195
|
+
message: `A utility file exporting ${functionName} must be named ${expected}.${path80.extname(filename).slice(1)}.`
|
|
11932
12196
|
});
|
|
11933
12197
|
}
|
|
11934
12198
|
};
|
|
@@ -11936,7 +12200,7 @@ var utilFileNameRule = {
|
|
|
11936
12200
|
};
|
|
11937
12201
|
|
|
11938
12202
|
// eslint/rules/value-extraction.ts
|
|
11939
|
-
import
|
|
12203
|
+
import path81 from "path";
|
|
11940
12204
|
var valueExtractionRule = {
|
|
11941
12205
|
meta: {
|
|
11942
12206
|
schema: [],
|
|
@@ -11947,7 +12211,7 @@ var valueExtractionRule = {
|
|
|
11947
12211
|
},
|
|
11948
12212
|
create(context) {
|
|
11949
12213
|
const sourceRoot = sourceRootOf(context);
|
|
11950
|
-
const file =
|
|
12214
|
+
const file = path81.resolve(context.filename);
|
|
11951
12215
|
const segments = segmentsOf(file, sourceRoot);
|
|
11952
12216
|
if (segments.length === 0 || segments[0] !== "app") return {};
|
|
11953
12217
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -11969,7 +12233,7 @@ var valueExtractionRule = {
|
|
|
11969
12233
|
|
|
11970
12234
|
// eslint/rules/vulyk/tracked-docs.ts
|
|
11971
12235
|
import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
|
|
11972
|
-
import
|
|
12236
|
+
import path82 from "path";
|
|
11973
12237
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
11974
12238
|
var BASE_REQUIRED_TRACKED_DOCS = [
|
|
11975
12239
|
{ name: "documentation-guide", path: "docs/documentation-guide" },
|
|
@@ -12002,8 +12266,8 @@ var trackedDocsRule = {
|
|
|
12002
12266
|
if (!context.filename.endsWith("package.json")) return;
|
|
12003
12267
|
const root = node.body;
|
|
12004
12268
|
if (root.type !== "Object") return;
|
|
12005
|
-
const projectRoot =
|
|
12006
|
-
const configPath =
|
|
12269
|
+
const projectRoot = path82.dirname(path82.resolve(context.filename));
|
|
12270
|
+
const configPath = path82.join(projectRoot, "vulyk.config.ts");
|
|
12007
12271
|
if (!existsSync13(configPath)) {
|
|
12008
12272
|
context.report({
|
|
12009
12273
|
node,
|
|
@@ -12028,7 +12292,7 @@ var trackedDocsRule = {
|
|
|
12028
12292
|
});
|
|
12029
12293
|
}
|
|
12030
12294
|
}
|
|
12031
|
-
const agentsPath =
|
|
12295
|
+
const agentsPath = path82.join(projectRoot, "AGENTS.md");
|
|
12032
12296
|
if (!existsSync13(agentsPath)) {
|
|
12033
12297
|
context.report({
|
|
12034
12298
|
node,
|
|
@@ -12128,7 +12392,7 @@ var withResponseHelperRule = {
|
|
|
12128
12392
|
|
|
12129
12393
|
// eslint/rules/zirka-baseline.ts
|
|
12130
12394
|
import fs7 from "fs";
|
|
12131
|
-
import
|
|
12395
|
+
import path83 from "path";
|
|
12132
12396
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
12133
12397
|
var PRETTIER_CONFIGS = [
|
|
12134
12398
|
"prettier.config.mjs",
|
|
@@ -12147,10 +12411,10 @@ var zirkaBaselineRule = {
|
|
|
12147
12411
|
}
|
|
12148
12412
|
},
|
|
12149
12413
|
create(context) {
|
|
12150
|
-
const filename =
|
|
12151
|
-
const basename =
|
|
12414
|
+
const filename = path83.resolve(context.filename);
|
|
12415
|
+
const basename = path83.basename(filename);
|
|
12152
12416
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
12153
|
-
const projectRoot =
|
|
12417
|
+
const projectRoot = path83.dirname(filename);
|
|
12154
12418
|
const report3 = (message) => {
|
|
12155
12419
|
context.report({
|
|
12156
12420
|
node: context.sourceCode.ast,
|
|
@@ -12165,7 +12429,7 @@ var zirkaBaselineRule = {
|
|
|
12165
12429
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
12166
12430
|
);
|
|
12167
12431
|
}
|
|
12168
|
-
const tsconfigPath =
|
|
12432
|
+
const tsconfigPath = path83.join(projectRoot, "tsconfig.json");
|
|
12169
12433
|
if (!fs7.existsSync(tsconfigPath)) {
|
|
12170
12434
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
12171
12435
|
} else {
|
|
@@ -12183,13 +12447,13 @@ var zirkaBaselineRule = {
|
|
|
12183
12447
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
12184
12448
|
}
|
|
12185
12449
|
}
|
|
12186
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(
|
|
12450
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(path83.join(projectRoot, name)));
|
|
12187
12451
|
if (!prettierConfigFile) {
|
|
12188
12452
|
report3(
|
|
12189
12453
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
12190
12454
|
);
|
|
12191
12455
|
} else {
|
|
12192
|
-
const content = fs7.readFileSync(
|
|
12456
|
+
const content = fs7.readFileSync(path83.join(projectRoot, prettierConfigFile), "utf8");
|
|
12193
12457
|
if (!content.includes("zirka")) {
|
|
12194
12458
|
report3(
|
|
12195
12459
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -12525,7 +12789,7 @@ var tailwindStructureRules = {
|
|
|
12525
12789
|
languageOptions: { tolerant: true },
|
|
12526
12790
|
rules: Object.fromEntries(
|
|
12527
12791
|
tailwindRuleIds.filter(
|
|
12528
|
-
(id) => id !== "pasika/css-entry-point" && id !== "pasika/feature-css-placement" && id !== "pasika/unique-css-definition" && id !== "pasika/no-utility-alias" && id !== "pasika/root-variables" && id !== "pasika/color-role-usage"
|
|
12792
|
+
(id) => id !== "pasika/css-entry-point" && id !== "pasika/feature-css-placement" && id !== "pasika/unique-css-definition" && id !== "pasika/utility-mapping" && id !== "pasika/no-utility-alias" && id !== "pasika/root-variables" && id !== "pasika/color-role-usage"
|
|
12529
12793
|
).map((id) => [id, "error"])
|
|
12530
12794
|
)
|
|
12531
12795
|
};
|
|
@@ -12541,6 +12805,8 @@ var tailwindImportGraph = {
|
|
|
12541
12805
|
"pasika/css-entry-point": "error",
|
|
12542
12806
|
"pasika/feature-css-placement": "error",
|
|
12543
12807
|
"pasika/unique-css-definition": "error",
|
|
12808
|
+
"pasika/unique-css-token-value": "error",
|
|
12809
|
+
"pasika/utility-mapping": "error",
|
|
12544
12810
|
"pasika/no-utility-alias": "error",
|
|
12545
12811
|
"pasika/root-variables": "error",
|
|
12546
12812
|
"pasika/color-role-usage": "error"
|