pasika 0.10.111 → 0.10.113
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 +119 -23
- package/package.json +1 -1
|
@@ -10376,12 +10376,21 @@ function applyOperationCount(utility) {
|
|
|
10376
10376
|
return count;
|
|
10377
10377
|
}
|
|
10378
10378
|
function themeCandidate(name, utilityText) {
|
|
10379
|
-
const
|
|
10380
|
-
|
|
10379
|
+
const source = utilityText.trim();
|
|
10380
|
+
const arbitrary = /^@utility\s+[\w-]+\s*\{\s*@apply\s+\[(?<property>font-size|letter-spacing):(?<value>[^\]\r\n;{}]+)\];?\s*\}$/u.exec(
|
|
10381
|
+
source
|
|
10381
10382
|
);
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10383
|
+
const typed = /^@utility\s+[\w-]+\s*\{\s*@apply\s+(?<kind>text|tracking)-\((?<hint>length:)?(?<variable>--[a-z][a-z0-9-]*)\);?\s*\}$/u.exec(
|
|
10384
|
+
source
|
|
10385
|
+
);
|
|
10386
|
+
const kind = typed?.groups?.kind;
|
|
10387
|
+
const hint = typed?.groups?.hint;
|
|
10388
|
+
if (kind === "text" && hint !== "length:") return void 0;
|
|
10389
|
+
if (kind === "tracking" && hint !== void 0) return void 0;
|
|
10390
|
+
let property = arbitrary?.groups?.property;
|
|
10391
|
+
if (!property && kind === "text") property = "font-size";
|
|
10392
|
+
if (!property && kind === "tracking") property = "letter-spacing";
|
|
10393
|
+
const value = arbitrary?.groups?.value?.trim() ?? (typed?.groups?.variable ? `var(${typed.groups.variable})` : void 0);
|
|
10385
10394
|
if (!property || !value) return void 0;
|
|
10386
10395
|
const prefix = property === "font-size" ? "text-" : "tracking-";
|
|
10387
10396
|
if (!name.startsWith(prefix) || name.length === prefix.length) return void 0;
|
|
@@ -10391,37 +10400,124 @@ function themeCandidate(name, utilityText) {
|
|
|
10391
10400
|
if (property === "font-size" && value.startsWith("-")) return void 0;
|
|
10392
10401
|
return { token: `--${name}`, property, value };
|
|
10393
10402
|
}
|
|
10403
|
+
var builtInTextSizes = /* @__PURE__ */ new Set([
|
|
10404
|
+
"xs",
|
|
10405
|
+
"sm",
|
|
10406
|
+
"base",
|
|
10407
|
+
"lg",
|
|
10408
|
+
"xl",
|
|
10409
|
+
"2xl",
|
|
10410
|
+
"3xl",
|
|
10411
|
+
"4xl",
|
|
10412
|
+
"5xl",
|
|
10413
|
+
"6xl",
|
|
10414
|
+
"7xl",
|
|
10415
|
+
"8xl",
|
|
10416
|
+
"9xl"
|
|
10417
|
+
]);
|
|
10418
|
+
var builtInTracking = /* @__PURE__ */ new Set(["tighter", "tight", "normal", "wide", "wider", "widest"]);
|
|
10419
|
+
function lengthIdentity(value) {
|
|
10420
|
+
const match = /^(?<number>-?(?:\d+(?:\.\d*)?|\.\d+))(?<unit>px|rem|em|%)$/u.exec(value);
|
|
10421
|
+
const number = match?.groups?.number;
|
|
10422
|
+
const unit = match?.groups?.unit;
|
|
10423
|
+
if (!number || !unit) return void 0;
|
|
10424
|
+
return `${String(Number(number))}${unit}`;
|
|
10425
|
+
}
|
|
10426
|
+
function declarationValue(text) {
|
|
10427
|
+
const match = /^--[\w-]+\s*:\s*(?<value>[^;{}]+);?$/u.exec(text.trim());
|
|
10428
|
+
return match?.groups?.value?.trim();
|
|
10429
|
+
}
|
|
10430
|
+
function canonicalToken(name) {
|
|
10431
|
+
if (name.startsWith("--text-")) return builtInTextSizes.has(name.slice("--text-".length));
|
|
10432
|
+
if (name.startsWith("--tracking-")) return builtInTracking.has(name.slice("--tracking-".length));
|
|
10433
|
+
return false;
|
|
10434
|
+
}
|
|
10435
|
+
function isTypographySize(name) {
|
|
10436
|
+
return /^--text-(?!.*--)(?:[a-z0-9]+-)*[a-z0-9]+$/u.test(name);
|
|
10437
|
+
}
|
|
10394
10438
|
var utilityMappingRule = {
|
|
10395
10439
|
meta: {
|
|
10396
|
-
schema: [
|
|
10397
|
-
{
|
|
10398
|
-
type: "object",
|
|
10399
|
-
properties: { preferThemeTokens: { type: "boolean" } },
|
|
10400
|
-
additionalProperties: false
|
|
10401
|
-
}
|
|
10402
|
-
],
|
|
10440
|
+
schema: [],
|
|
10403
10441
|
type: "problem",
|
|
10404
10442
|
docs: {
|
|
10405
|
-
description: "Require one styling operation per custom utility
|
|
10443
|
+
description: "Require one styling operation per custom utility and enforce theme tokens instead of redundant mappings."
|
|
10406
10444
|
}
|
|
10407
10445
|
},
|
|
10408
10446
|
create(context) {
|
|
10409
|
-
const option = context.options[0];
|
|
10410
|
-
const preferThemeTokens = typeof option === "object" && option !== null && "preferThemeTokens" in option && option.preferThemeTokens === true;
|
|
10411
10447
|
return {
|
|
10412
10448
|
"StyleSheet:exit"(node) {
|
|
10413
10449
|
const utilities = atrulesNamed(node, "utility");
|
|
10414
10450
|
const themeTokens = /* @__PURE__ */ new Set();
|
|
10415
10451
|
const nameCounts = /* @__PURE__ */ new Map();
|
|
10416
|
-
|
|
10417
|
-
for (const
|
|
10418
|
-
|
|
10419
|
-
|
|
10452
|
+
for (const theme of atrulesNamed(node, "theme")) {
|
|
10453
|
+
for (const child of blockChildren2(theme)) {
|
|
10454
|
+
if (child.type === "Declaration") themeTokens.add(child.property);
|
|
10455
|
+
}
|
|
10456
|
+
}
|
|
10457
|
+
for (const utility of utilities) {
|
|
10458
|
+
const name = preludeIdentifiers(utility)[0] ?? "";
|
|
10459
|
+
nameCounts.set(name, (nameCounts.get(name) ?? 0) + 1);
|
|
10460
|
+
}
|
|
10461
|
+
const themeDefinitions = /* @__PURE__ */ new Map();
|
|
10462
|
+
for (const theme of atrulesNamed(node, "theme")) {
|
|
10463
|
+
for (const child of blockChildren2(theme)) {
|
|
10464
|
+
if (child.type !== "Declaration") continue;
|
|
10465
|
+
const value = declarationValue(context.sourceCode.getText(child));
|
|
10466
|
+
if (!value) continue;
|
|
10467
|
+
const definitions = themeDefinitions.get(child.property) ?? [];
|
|
10468
|
+
definitions.push({ node: child, value });
|
|
10469
|
+
themeDefinitions.set(child.property, definitions);
|
|
10470
|
+
}
|
|
10471
|
+
}
|
|
10472
|
+
const rootValues = /* @__PURE__ */ new Map();
|
|
10473
|
+
const overriddenVariables = /* @__PURE__ */ new Set();
|
|
10474
|
+
for (const cssRule of rules(node)) {
|
|
10475
|
+
if (!("prelude" in cssRule) || !cssRule.prelude) continue;
|
|
10476
|
+
const isRoot = context.sourceCode.getText(cssRule.prelude).trim() === ":root";
|
|
10477
|
+
for (const child of blockChildren2(cssRule)) {
|
|
10478
|
+
if (child.type !== "Declaration" || !child.property.startsWith("--")) continue;
|
|
10479
|
+
if (!isRoot) {
|
|
10480
|
+
overriddenVariables.add(child.property);
|
|
10481
|
+
continue;
|
|
10420
10482
|
}
|
|
10483
|
+
const value = declarationValue(context.sourceCode.getText(child));
|
|
10484
|
+
if (!value) continue;
|
|
10485
|
+
const definitions = rootValues.get(child.property) ?? [];
|
|
10486
|
+
definitions.push(value);
|
|
10487
|
+
rootValues.set(child.property, definitions);
|
|
10421
10488
|
}
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10489
|
+
}
|
|
10490
|
+
function identity(value) {
|
|
10491
|
+
const variable = /^var\((?<name>--[a-z][a-z0-9-]*)\)$/u.exec(value);
|
|
10492
|
+
if (!variable) return lengthIdentity(value);
|
|
10493
|
+
const name = variable.groups?.name;
|
|
10494
|
+
if (!name || overriddenVariables.has(name)) return void 0;
|
|
10495
|
+
const definitions = rootValues.get(name);
|
|
10496
|
+
const definition = definitions?.length === 1 ? definitions[0] : void 0;
|
|
10497
|
+
return definition ? lengthIdentity(definition) : void 0;
|
|
10498
|
+
}
|
|
10499
|
+
for (const [name, definitions] of themeDefinitions) {
|
|
10500
|
+
const definition = definitions.length === 1 ? definitions[0] : void 0;
|
|
10501
|
+
if (!definition || canonicalToken(name)) continue;
|
|
10502
|
+
if (!isTypographySize(name) && !name.startsWith("--tracking-")) continue;
|
|
10503
|
+
if (name.includes("--", 2)) continue;
|
|
10504
|
+
const value = identity(definition.value);
|
|
10505
|
+
if (!value) continue;
|
|
10506
|
+
const prefix = name.startsWith("--text-") ? "--text-" : "--tracking-";
|
|
10507
|
+
for (const [other, otherDefinitions] of themeDefinitions) {
|
|
10508
|
+
const otherDefinition = otherDefinitions.length === 1 ? otherDefinitions[0] : void 0;
|
|
10509
|
+
if (!canonicalToken(other) || !other.startsWith(prefix) || !otherDefinition) continue;
|
|
10510
|
+
if (identity(otherDefinition.value) !== value) continue;
|
|
10511
|
+
if (prefix === "--text-" && ["--line-height", "--letter-spacing", "--font-weight"].some(
|
|
10512
|
+
(suffix) => themeDefinitions.has(`${name}${suffix}`) || themeDefinitions.has(`${other}${suffix}`)
|
|
10513
|
+
)) {
|
|
10514
|
+
continue;
|
|
10515
|
+
}
|
|
10516
|
+
context.report({
|
|
10517
|
+
node: definition.node,
|
|
10518
|
+
message: `Theme token "${name}" duplicates the configured built-in "${other}" (${value}); reuse the "${other.slice(2)}" utility instead of defining an equivalent theme token.`
|
|
10519
|
+
});
|
|
10520
|
+
break;
|
|
10425
10521
|
}
|
|
10426
10522
|
}
|
|
10427
10523
|
for (const utility of utilities) {
|
|
@@ -10434,7 +10530,7 @@ var utilityMappingRule = {
|
|
|
10434
10530
|
});
|
|
10435
10531
|
continue;
|
|
10436
10532
|
}
|
|
10437
|
-
if (
|
|
10533
|
+
if (nameCounts.get(name) !== 1) continue;
|
|
10438
10534
|
const candidate = themeCandidate(name, context.sourceCode.getText(utility));
|
|
10439
10535
|
if (!candidate || themeTokens.has(candidate.token)) continue;
|
|
10440
10536
|
if (candidate.property === "font-size" && themeTokens.has(`--color-${name.slice(5)}`)) continue;
|