pasika 0.10.115 → 0.10.116

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.
@@ -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;
@@ -10156,7 +10156,7 @@ function buildCssDependencyGraph(options) {
10156
10156
  } else if (node.name === "theme" && node.loc) {
10157
10157
  const source = file.content.slice(node.loc.start.offset, node.loc.end.offset).replace(/\/\*[\s\S]*?\*\//gu, (comment) => comment.replace(/[^\r\n]/gu, " "));
10158
10158
  for (const found of source.matchAll(
10159
- /(?:^|[{;\r\n])\s*(?<name>--[a-z][\w-]*)\s*:\s*(?<value>[^;\r\n]+);/gu
10159
+ /(?:^|(?<=[{;\r\n]))\s*(?<name>--[a-z][\w-]*)\s*:\s*(?<value>[^;}\r\n]+)(?=;|[}])/gu
10160
10160
  )) {
10161
10161
  const name = found.groups?.name;
10162
10162
  const value = found.groups?.value;
@@ -10912,48 +10912,129 @@ var uniqueCssDefinitionRule = {
10912
10912
  schema: [],
10913
10913
  type: "problem",
10914
10914
  docs: {
10915
- description: "Reject duplicate project-level CSS definitions across stylesheets while preserving scoped overrides."
10915
+ description: "Reject duplicate CSS definitions both within and across stylesheets while preserving scoped overrides."
10916
10916
  }
10917
10917
  },
10918
10918
  create(context) {
10919
10919
  const sourceRoot = sourceRootOf(context);
10920
+ const current = path74.normalize(path74.resolve(context.filename));
10920
10921
  const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
10921
10922
  if (cssFiles.length === 0) return {};
10922
10923
  const textOf = cachedTextReader();
10923
10924
  const graph = buildCssDependencyGraph({
10924
10925
  sourceRoot,
10925
- css: cssFiles.map((file) => ({ path: file, content: textOf(file) })),
10926
+ css: cssFiles.map((file) => ({
10927
+ path: file,
10928
+ content: path74.normalize(file) === current ? context.sourceCode.text : textOf(file)
10929
+ })),
10926
10930
  modules: [],
10927
10931
  includeReferences: false
10928
10932
  });
10929
- const owners = /* @__PURE__ */ new Map();
10933
+ const groups = /* @__PURE__ */ new Map();
10930
10934
  for (const symbol of graph.definitions) {
10931
10935
  const key = ownershipKey(symbol);
10932
10936
  if (!key) continue;
10933
- const files = owners.get(key) ?? /* @__PURE__ */ new Set();
10934
- files.add(symbol.file);
10935
- owners.set(key, files);
10937
+ const definitions = groups.get(key) ?? [];
10938
+ definitions.push(symbol);
10939
+ groups.set(key, definitions);
10936
10940
  }
10937
10941
  return {
10938
10942
  "StyleSheet:exit"(node) {
10939
- const current = path74.normalize(path74.resolve(context.filename));
10940
- const checked = /* @__PURE__ */ new Set();
10941
- for (const symbol of graph.definitions) {
10942
- if (symbol.file !== current) continue;
10943
- const key = ownershipKey(symbol);
10944
- if (!key || checked.has(key)) continue;
10945
- checked.add(key);
10946
- const files = owners.get(key);
10947
- if (!files || files.size < 2) continue;
10948
- const canonical = [...files].sort()[0];
10949
- if (!canonical || canonical === current) continue;
10943
+ for (const definitions of groups.values()) {
10944
+ if (definitions.length < 2) continue;
10945
+ definitions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
10946
+ const canonical = definitions[0];
10947
+ if (!canonical) continue;
10948
+ for (const symbol of definitions.slice(1)) {
10949
+ if (symbol.file !== current) continue;
10950
+ 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.`;
10951
+ context.report({
10952
+ node,
10953
+ loc: {
10954
+ start: { line: symbol.line, column: 1 },
10955
+ end: { line: symbol.line, column: 2 }
10956
+ },
10957
+ message
10958
+ });
10959
+ }
10960
+ }
10961
+ }
10962
+ };
10963
+ }
10964
+ };
10965
+
10966
+ // eslint/rules/tailwind/unique-css-token-value.ts
10967
+ import path75 from "path";
10968
+ function valueIdentity(value) {
10969
+ const text = value.trim();
10970
+ const hex = /^#(?<digits>[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/iu.exec(text)?.groups?.digits;
10971
+ if (!hex) return text;
10972
+ const lower = hex.toLowerCase();
10973
+ const full = lower.length <= 4 ? Array.from(lower, (digit) => digit + digit).join("") : lower;
10974
+ return `#${full.length === 8 && full.endsWith("ff") ? full.slice(0, -2) : full}`;
10975
+ }
10976
+ function isComparable(symbol) {
10977
+ if (symbol.value === void 0 || symbol.value.trim() === "") return false;
10978
+ if (/\b(?:var|env|attr|calc|min|max|clamp|color-mix|light-dark)\s*\(/iu.test(symbol.value)) return false;
10979
+ return symbol.kind === "theme-token" || symbol.kind === "root-variable" && symbol.scope === "default";
10980
+ }
10981
+ function compareLocations(left, right) {
10982
+ const file = left.file.localeCompare(right.file);
10983
+ return file || left.line - right.line;
10984
+ }
10985
+ var uniqueCssTokenValueRule = {
10986
+ meta: {
10987
+ schema: [],
10988
+ type: "problem",
10989
+ docs: {
10990
+ description: "Reject distinct CSS design tokens with duplicate static values across the project."
10991
+ }
10992
+ },
10993
+ create(context) {
10994
+ const sourceRoot = sourceRootOf(context);
10995
+ const current = path75.normalize(path75.resolve(context.filename));
10996
+ const textOf = cachedTextReader();
10997
+ const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
10998
+ const graph = buildCssDependencyGraph({
10999
+ sourceRoot,
11000
+ css: cssFiles.map((file) => ({
11001
+ path: file,
11002
+ content: path75.normalize(file) === current ? context.sourceCode.text : textOf(file)
11003
+ })),
11004
+ modules: [],
11005
+ includeReferences: false
11006
+ });
11007
+ const byValue = /* @__PURE__ */ new Map();
11008
+ for (const definition of graph.definitions) {
11009
+ if (!isComparable(definition)) continue;
11010
+ const value = valueIdentity(definition.value ?? "");
11011
+ const group = byValue.get(value) ?? [];
11012
+ group.push(definition);
11013
+ byValue.set(value, group);
11014
+ }
11015
+ const redundant = /* @__PURE__ */ new Map();
11016
+ for (const group of byValue.values()) {
11017
+ group.sort(compareLocations);
11018
+ const first = group[0];
11019
+ if (!first) continue;
11020
+ for (const definition of group.slice(1)) {
11021
+ if (definition.name !== first.name) redundant.set(definition, first);
11022
+ }
11023
+ }
11024
+ return {
11025
+ "StyleSheet:exit"(node) {
11026
+ for (const [definition, original] of redundant) {
11027
+ if (definition.file !== current) continue;
10950
11028
  context.report({
10951
11029
  node,
10952
11030
  loc: {
10953
- start: { line: symbol.line, column: 1 },
10954
- end: { line: symbol.line, column: 2 }
11031
+ start: { line: definition.line, column: 1 },
11032
+ end: { line: definition.line, column: 2 }
10955
11033
  },
10956
- message: `${symbolLabel(symbol)} "${symbol.name}" is also defined in ${path74.relative(sourceRoot, canonical)}; define it in only one CSS file.`
11034
+ message: `Token "${definition.name}" duplicates the value of "${original.name}" in ${path75.relative(
11035
+ sourceRoot,
11036
+ original.file
11037
+ )}:${String(original.line)}; reuse one design token.`
10957
11038
  });
10958
11039
  }
10959
11040
  }
@@ -10963,7 +11044,7 @@ var uniqueCssDefinitionRule = {
10963
11044
 
10964
11045
  // eslint/rules/tailwind/unused-utility.ts
10965
11046
  import { statSync as statSync5 } from "fs";
10966
- import path75 from "path";
11047
+ import path76 from "path";
10967
11048
  var unusedUtilityRule = {
10968
11049
  meta: {
10969
11050
  schema: [],
@@ -10979,7 +11060,7 @@ var unusedUtilityRule = {
10979
11060
  } catch {
10980
11061
  return {};
10981
11062
  }
10982
- const current = path75.normalize(path75.resolve(context.filename));
11063
+ const current = path76.normalize(path76.resolve(context.filename));
10983
11064
  const textOf = cachedTextReader();
10984
11065
  const cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
10985
11066
  const moduleFiles = findFiles(sourceRoot, MODULE_EXTENSIONS4);
@@ -10987,7 +11068,7 @@ var unusedUtilityRule = {
10987
11068
  sourceRoot,
10988
11069
  css: cssFiles.map((file) => ({
10989
11070
  path: file,
10990
- content: path75.normalize(file) === current ? context.sourceCode.text : textOf(file)
11071
+ content: path76.normalize(file) === current ? context.sourceCode.text : textOf(file)
10991
11072
  })),
10992
11073
  modules: moduleFiles.map((file) => ({ path: file, content: textOf(file) }))
10993
11074
  });
@@ -11008,6 +11089,7 @@ var unusedUtilityRule = {
11008
11089
  };
11009
11090
 
11010
11091
  // eslint/rules/tailwind/utility-mapping.ts
11092
+ import path77 from "path";
11011
11093
  function applyOperationCount(utility) {
11012
11094
  let count = 0;
11013
11095
  for (const apply of atrulesNamed(utility, "apply")) {
@@ -11023,30 +11105,79 @@ function applyOperationCount(utility) {
11023
11105
  }
11024
11106
  return count;
11025
11107
  }
11108
+ var themeOperations = [
11109
+ { property: "font-size", prefix: "text", namespace: "text" },
11110
+ { property: "letter-spacing", prefix: "tracking", namespace: "tracking" },
11111
+ { property: "line-height", prefix: "leading", namespace: "leading" },
11112
+ { property: "font-family", prefix: "font", namespace: "font" },
11113
+ { property: "font-weight", prefix: "font", namespace: "font-weight" },
11114
+ { property: "tab-size", prefix: "tab", namespace: "tab-size" },
11115
+ { property: "border-radius", prefix: "rounded", namespace: "radius" },
11116
+ { property: "background-color", prefix: "bg", namespace: "color" },
11117
+ { property: "color", prefix: "text", namespace: "color" },
11118
+ { property: "border-color", prefix: "border", namespace: "color" },
11119
+ { property: "outline-color", prefix: "outline", namespace: "color" },
11120
+ { property: "fill", prefix: "fill", namespace: "color" },
11121
+ { property: "stroke", prefix: "stroke", namespace: "color" },
11122
+ { property: "caret-color", prefix: "caret", namespace: "color" },
11123
+ { property: "text-decoration-color", prefix: "decoration", namespace: "color" },
11124
+ { property: "padding", prefix: "p", namespace: "spacing" },
11125
+ { property: "padding-top", prefix: "pt", namespace: "spacing" },
11126
+ { property: "padding-right", prefix: "pr", namespace: "spacing" },
11127
+ { property: "padding-bottom", prefix: "pb", namespace: "spacing" },
11128
+ { property: "padding-left", prefix: "pl", namespace: "spacing" },
11129
+ { property: "margin", prefix: "m", namespace: "spacing" },
11130
+ { property: "margin-top", prefix: "mt", namespace: "spacing" },
11131
+ { property: "margin-right", prefix: "mr", namespace: "spacing" },
11132
+ { property: "margin-bottom", prefix: "mb", namespace: "spacing" },
11133
+ { property: "margin-left", prefix: "ml", namespace: "spacing" },
11134
+ { property: "gap", prefix: "gap", namespace: "spacing" },
11135
+ { property: "width", prefix: "w", namespace: "spacing" },
11136
+ { property: "height", prefix: "h", namespace: "spacing" },
11137
+ { property: "aspect-ratio", prefix: "aspect", namespace: "aspect" },
11138
+ { property: "transition-timing-function", prefix: "ease", namespace: "ease" },
11139
+ { property: "zoom", prefix: "zoom", namespace: "zoom" },
11140
+ { property: "perspective", prefix: "perspective", namespace: "perspective" },
11141
+ { property: "animation", prefix: "animate", namespace: "animate" }
11142
+ ];
11026
11143
  function themeCandidate(name, utilityText) {
11027
11144
  const source = utilityText.trim();
11028
- const arbitrary = /^@utility\s+[\w-]+\s*\{\s*@apply\s+\[(?<property>font-size|letter-spacing):(?<value>[^\]\r\n;{}]+)\];?\s*\}$/u.exec(
11145
+ const arbitrary = /^@utility\s+[\w-]+\s*\{\s*@apply\s+\[(?<property>[a-z-]+):(?<value>[^\]\r\n;{}]+)\];?\s*\}$/u.exec(
11029
11146
  source
11030
11147
  );
11031
- const typed = /^@utility\s+[\w-]+\s*\{\s*@apply\s+(?<kind>text|tracking)-\((?<hint>length:)?(?<variable>--[a-z][a-z0-9-]*)\);?\s*\}$/u.exec(
11148
+ 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
11149
  source
11033
11150
  );
11034
- const kind = typed?.groups?.kind;
11035
- const hint = typed?.groups?.hint;
11036
- if (kind === "text" && hint !== "length:") return void 0;
11037
- if (kind === "tracking" && hint !== void 0) return void 0;
11038
- let property = arbitrary?.groups?.property;
11039
- if (!property && kind === "text") property = "font-size";
11040
- if (!property && kind === "tracking") property = "letter-spacing";
11151
+ const property = arbitrary?.groups?.property;
11152
+ const matched = themeOperations.find((operation) => {
11153
+ if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
11154
+ if (property) return property === operation.property;
11155
+ if (typed?.groups?.kind !== operation.prefix) return false;
11156
+ const hint = typed.groups.hint;
11157
+ if (operation.prefix === "text") return hint === (operation.property === "font-size" ? "length:" : "color:");
11158
+ if (operation.prefix === "font") {
11159
+ return hint === (operation.property === "font-family" ? "family-name:" : "number:");
11160
+ }
11161
+ return hint === void 0;
11162
+ });
11163
+ if (!matched) return void 0;
11041
11164
  const value = arbitrary?.groups?.value?.trim() ?? (typed?.groups?.variable ? `var(${typed.groups.variable})` : void 0);
11042
- if (!property || !value) return void 0;
11043
- const prefix = property === "font-size" ? "text-" : "tracking-";
11044
- if (!name.startsWith(prefix) || name.length === prefix.length) return void 0;
11045
- const length = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%)$/u.test(value);
11165
+ if (!value) return void 0;
11166
+ const simple = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%|vh|vw|ch|deg)?$/u.test(value);
11046
11167
  const variable = /^var\(--[a-z][a-z0-9-]*\)$/u.test(value);
11047
- if (!length && !variable) return void 0;
11048
- if (property === "font-size" && value.startsWith("-")) return void 0;
11049
- return { token: `--${name}`, property, value };
11168
+ const color = /^#[\da-f]{3,8}$/iu.test(value);
11169
+ const keyword = /^[a-z][a-z-]*$/u.test(value);
11170
+ const ratio = /^\d+\/\d+$/u.test(value);
11171
+ if (!simple && !variable && !color && !keyword && !ratio) return void 0;
11172
+ if (matched.property === "font-size" && value.startsWith("-")) return void 0;
11173
+ const stem = name.slice(matched.prefix.length + 1);
11174
+ return {
11175
+ token: `--${matched.namespace}-${stem}`,
11176
+ property: matched.property,
11177
+ value,
11178
+ prefix: matched.prefix,
11179
+ namespace: matched.namespace
11180
+ };
11050
11181
  }
11051
11182
  var builtInTextSizes = /* @__PURE__ */ new Set([
11052
11183
  "xs",
@@ -11092,6 +11223,19 @@ var utilityMappingRule = {
11092
11223
  }
11093
11224
  },
11094
11225
  create(context) {
11226
+ const sourceRoot = sourceRootOf(context);
11227
+ const current = path77.normalize(path77.resolve(context.filename));
11228
+ const textOf = cachedTextReader();
11229
+ const graph = buildCssDependencyGraph({
11230
+ sourceRoot,
11231
+ css: findFiles(sourceRoot, CSS_EXTENSIONS).map((file) => ({
11232
+ path: file,
11233
+ content: path77.normalize(file) === current ? context.sourceCode.text : textOf(file)
11234
+ })),
11235
+ modules: [],
11236
+ includeReferences: false
11237
+ });
11238
+ const projectTokens = graph.definitions.filter((symbol) => symbol.kind === "theme-token");
11095
11239
  return {
11096
11240
  "StyleSheet:exit"(node) {
11097
11241
  const utilities = atrulesNamed(node, "utility");
@@ -11180,7 +11324,38 @@ var utilityMappingRule = {
11180
11324
  }
11181
11325
  if (nameCounts.get(name) !== 1) continue;
11182
11326
  const candidate = themeCandidate(name, context.sourceCode.getText(utility));
11183
- if (!candidate || themeTokens.has(candidate.token)) continue;
11327
+ if (!candidate) continue;
11328
+ const tokenAlreadyDefined = themeTokens.has(candidate.token) || projectTokens.some((token) => token.name === candidate.token);
11329
+ const namespacePrefix = `--${candidate.namespace}-`;
11330
+ const staticValue = !/\b(?:var|env|attr|calc|min|max|clamp|color-mix|light-dark)\s*\(/iu.test(
11331
+ candidate.value
11332
+ );
11333
+ const valueKey = (value) => {
11334
+ const input = value.trim();
11335
+ const digits = /^#(?<hex>[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/iu.exec(input)?.groups?.hex;
11336
+ if (digits) {
11337
+ const lower = digits.toLowerCase();
11338
+ return lower.length <= 4 ? Array.from(lower, (digit) => digit + digit).join("") : lower;
11339
+ }
11340
+ return input;
11341
+ };
11342
+ 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(
11343
+ (suffix) => themeDefinitions.has(`${token}${suffix}`) || projectTokens.some((definition) => definition.name === `${token}${suffix}`)
11344
+ ));
11345
+ const equivalent = staticValue ? projectTokens.find((token) => token.value !== void 0 && sameOperation(token.name, token.value)) : void 0;
11346
+ const localEquivalent = staticValue ? [...themeDefinitions].find(
11347
+ ([token, definitions]) => definitions.length === 1 && definitions[0]?.value !== void 0 && sameOperation(token, definitions[0].value)
11348
+ )?.[0] : void 0;
11349
+ const existingToken = equivalent?.name ?? localEquivalent;
11350
+ if (tokenAlreadyDefined && !existingToken) continue;
11351
+ if (existingToken) {
11352
+ const className = `${candidate.prefix}-${existingToken.slice(namespacePrefix.length)}`;
11353
+ context.report({
11354
+ node: utility,
11355
+ message: `Custom utility "${name}" duplicates theme-generated "${className}" (${candidate.property}: ${candidate.value}); reuse "${className}" instead.`
11356
+ });
11357
+ continue;
11358
+ }
11184
11359
  if (candidate.property === "font-size" && themeTokens.has(`--color-${name.slice(5)}`)) continue;
11185
11360
  context.report({
11186
11361
  node: utility,
@@ -11207,12 +11382,13 @@ var tailwindRules = {
11207
11382
  "global-stylesheet": globalStylesheetRule,
11208
11383
  "unused-utility": unusedUtilityRule,
11209
11384
  "unique-css-definition": uniqueCssDefinitionRule,
11385
+ "unique-css-token-value": uniqueCssTokenValueRule,
11210
11386
  "no-utility-alias": noUtilityAliasRule,
11211
11387
  "global-selector-styling": globalSelectorStylingRule
11212
11388
  };
11213
11389
 
11214
11390
  // eslint/rules/type-extraction.ts
11215
- import path76 from "path";
11391
+ import path78 from "path";
11216
11392
  var typeExtractionRule = {
11217
11393
  meta: {
11218
11394
  schema: [],
@@ -11223,7 +11399,7 @@ var typeExtractionRule = {
11223
11399
  },
11224
11400
  create(context) {
11225
11401
  const sourceRoot = sourceRootOf(context);
11226
- const file = path76.resolve(context.filename);
11402
+ const file = path78.resolve(context.filename);
11227
11403
  const segments = segmentsOf(file, sourceRoot);
11228
11404
  if (segments.length === 0) return {};
11229
11405
  const index = getProjectIndex(sourceRoot);
@@ -11364,7 +11540,7 @@ var uiStateRule = {
11364
11540
  // eslint/rules/unknown-utility.ts
11365
11541
  import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync6 } from "fs";
11366
11542
  import { createRequire } from "module";
11367
- import path77 from "path";
11543
+ import path79 from "path";
11368
11544
  var PREFIX_NAMESPACES = {
11369
11545
  bg: ["color"],
11370
11546
  text: ["color", "text"],
@@ -11604,7 +11780,7 @@ function stylesheetFiles(dir) {
11604
11780
  }
11605
11781
  return entries.flatMap((entry) => {
11606
11782
  if (entry.startsWith(".") || entry === "node_modules") return [];
11607
- const entryPath = path77.join(dir, entry);
11783
+ const entryPath = path79.join(dir, entry);
11608
11784
  let stats;
11609
11785
  try {
11610
11786
  stats = statSync6(entryPath);
@@ -11612,7 +11788,7 @@ function stylesheetFiles(dir) {
11612
11788
  return [];
11613
11789
  }
11614
11790
  if (stats.isDirectory()) return stylesheetFiles(entryPath);
11615
- return path77.extname(entry) === ".css" ? [entryPath] : [];
11791
+ return path79.extname(entry) === ".css" ? [entryPath] : [];
11616
11792
  });
11617
11793
  }
11618
11794
  function packageNameOf(specifier) {
@@ -11623,10 +11799,10 @@ function packageNameOf(specifier) {
11623
11799
  function resolvePackageStylesheet(fromFile, specifier) {
11624
11800
  const packageName = packageNameOf(specifier);
11625
11801
  if (!packageName || packageName === "tailwindcss") return void 0;
11626
- let directory = path77.dirname(fromFile);
11627
- while (directory !== path77.dirname(directory)) {
11628
- const packageRoot = path77.join(directory, "node_modules", packageName);
11629
- const manifestPath = path77.join(packageRoot, "package.json");
11802
+ let directory = path79.dirname(fromFile);
11803
+ while (directory !== path79.dirname(directory)) {
11804
+ const packageRoot = path79.join(directory, "node_modules", packageName);
11805
+ const manifestPath = path79.join(packageRoot, "package.json");
11630
11806
  if (existsSync12(manifestPath)) {
11631
11807
  try {
11632
11808
  const manifest = readFileSync15(manifestPath, "utf8");
@@ -11634,13 +11810,13 @@ function resolvePackageStylesheet(fromFile, specifier) {
11634
11810
  const main = /"main"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
11635
11811
  const target = stylesheet ?? main;
11636
11812
  if (!target) return void 0;
11637
- const resolved = path77.resolve(packageRoot, target);
11813
+ const resolved = path79.resolve(packageRoot, target);
11638
11814
  return existsSync12(resolved) ? resolved : void 0;
11639
11815
  } catch {
11640
11816
  return void 0;
11641
11817
  }
11642
11818
  }
11643
- directory = path77.dirname(directory);
11819
+ directory = path79.dirname(directory);
11644
11820
  }
11645
11821
  return void 0;
11646
11822
  }
@@ -11895,7 +12071,7 @@ var unknownUtilityRule = {
11895
12071
  };
11896
12072
 
11897
12073
  // eslint/rules/util-file-name.ts
11898
- import path78 from "path";
12074
+ import path80 from "path";
11899
12075
  function toKebabCase2(value) {
11900
12076
  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
12077
  }
@@ -11908,7 +12084,7 @@ var utilFileNameRule = {
11908
12084
  }
11909
12085
  },
11910
12086
  create(context) {
11911
- const filename = path78.resolve(context.filename);
12087
+ const filename = path80.resolve(context.filename);
11912
12088
  const segments = filename.replace(/\\/g, "/").split("/");
11913
12089
  if (!segments.includes("utils")) return {};
11914
12090
  let module;
@@ -11922,13 +12098,13 @@ var utilFileNameRule = {
11922
12098
  const functionName = functions[0]?.name;
11923
12099
  if (!functionName) return {};
11924
12100
  const expected = toKebabCase2(functionName);
11925
- const actual = path78.basename(filename, path78.extname(filename));
12101
+ const actual = path80.basename(filename, path80.extname(filename));
11926
12102
  if (!expected || actual === expected) return {};
11927
12103
  return {
11928
12104
  Program(node) {
11929
12105
  context.report({
11930
12106
  node,
11931
- message: `A utility file exporting ${functionName} must be named ${expected}.${path78.extname(filename).slice(1)}.`
12107
+ message: `A utility file exporting ${functionName} must be named ${expected}.${path80.extname(filename).slice(1)}.`
11932
12108
  });
11933
12109
  }
11934
12110
  };
@@ -11936,7 +12112,7 @@ var utilFileNameRule = {
11936
12112
  };
11937
12113
 
11938
12114
  // eslint/rules/value-extraction.ts
11939
- import path79 from "path";
12115
+ import path81 from "path";
11940
12116
  var valueExtractionRule = {
11941
12117
  meta: {
11942
12118
  schema: [],
@@ -11947,7 +12123,7 @@ var valueExtractionRule = {
11947
12123
  },
11948
12124
  create(context) {
11949
12125
  const sourceRoot = sourceRootOf(context);
11950
- const file = path79.resolve(context.filename);
12126
+ const file = path81.resolve(context.filename);
11951
12127
  const segments = segmentsOf(file, sourceRoot);
11952
12128
  if (segments.length === 0 || segments[0] !== "app") return {};
11953
12129
  const index = getProjectIndex(sourceRoot);
@@ -11969,7 +12145,7 @@ var valueExtractionRule = {
11969
12145
 
11970
12146
  // eslint/rules/vulyk/tracked-docs.ts
11971
12147
  import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
11972
- import path80 from "path";
12148
+ import path82 from "path";
11973
12149
  var PASIKA_REPO = "Bredansky/pasika";
11974
12150
  var BASE_REQUIRED_TRACKED_DOCS = [
11975
12151
  { name: "documentation-guide", path: "docs/documentation-guide" },
@@ -12002,8 +12178,8 @@ var trackedDocsRule = {
12002
12178
  if (!context.filename.endsWith("package.json")) return;
12003
12179
  const root = node.body;
12004
12180
  if (root.type !== "Object") return;
12005
- const projectRoot = path80.dirname(path80.resolve(context.filename));
12006
- const configPath = path80.join(projectRoot, "vulyk.config.ts");
12181
+ const projectRoot = path82.dirname(path82.resolve(context.filename));
12182
+ const configPath = path82.join(projectRoot, "vulyk.config.ts");
12007
12183
  if (!existsSync13(configPath)) {
12008
12184
  context.report({
12009
12185
  node,
@@ -12028,7 +12204,7 @@ var trackedDocsRule = {
12028
12204
  });
12029
12205
  }
12030
12206
  }
12031
- const agentsPath = path80.join(projectRoot, "AGENTS.md");
12207
+ const agentsPath = path82.join(projectRoot, "AGENTS.md");
12032
12208
  if (!existsSync13(agentsPath)) {
12033
12209
  context.report({
12034
12210
  node,
@@ -12128,7 +12304,7 @@ var withResponseHelperRule = {
12128
12304
 
12129
12305
  // eslint/rules/zirka-baseline.ts
12130
12306
  import fs7 from "fs";
12131
- import path81 from "path";
12307
+ import path83 from "path";
12132
12308
  var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
12133
12309
  var PRETTIER_CONFIGS = [
12134
12310
  "prettier.config.mjs",
@@ -12147,10 +12323,10 @@ var zirkaBaselineRule = {
12147
12323
  }
12148
12324
  },
12149
12325
  create(context) {
12150
- const filename = path81.resolve(context.filename);
12151
- const basename = path81.basename(filename);
12326
+ const filename = path83.resolve(context.filename);
12327
+ const basename = path83.basename(filename);
12152
12328
  if (!ESLINT_CONFIG.test(basename)) return {};
12153
- const projectRoot = path81.dirname(filename);
12329
+ const projectRoot = path83.dirname(filename);
12154
12330
  const report3 = (message) => {
12155
12331
  context.report({
12156
12332
  node: context.sourceCode.ast,
@@ -12165,7 +12341,7 @@ var zirkaBaselineRule = {
12165
12341
  'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
12166
12342
  );
12167
12343
  }
12168
- const tsconfigPath = path81.join(projectRoot, "tsconfig.json");
12344
+ const tsconfigPath = path83.join(projectRoot, "tsconfig.json");
12169
12345
  if (!fs7.existsSync(tsconfigPath)) {
12170
12346
  report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
12171
12347
  } else {
@@ -12183,13 +12359,13 @@ var zirkaBaselineRule = {
12183
12359
  report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
12184
12360
  }
12185
12361
  }
12186
- const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(path81.join(projectRoot, name)));
12362
+ const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(path83.join(projectRoot, name)));
12187
12363
  if (!prettierConfigFile) {
12188
12364
  report3(
12189
12365
  "No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
12190
12366
  );
12191
12367
  } else {
12192
- const content = fs7.readFileSync(path81.join(projectRoot, prettierConfigFile), "utf8");
12368
+ const content = fs7.readFileSync(path83.join(projectRoot, prettierConfigFile), "utf8");
12193
12369
  if (!content.includes("zirka")) {
12194
12370
  report3(
12195
12371
  "The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
@@ -12525,7 +12701,7 @@ var tailwindStructureRules = {
12525
12701
  languageOptions: { tolerant: true },
12526
12702
  rules: Object.fromEntries(
12527
12703
  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"
12704
+ (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
12705
  ).map((id) => [id, "error"])
12530
12706
  )
12531
12707
  };
@@ -12541,6 +12717,8 @@ var tailwindImportGraph = {
12541
12717
  "pasika/css-entry-point": "error",
12542
12718
  "pasika/feature-css-placement": "error",
12543
12719
  "pasika/unique-css-definition": "error",
12720
+ "pasika/unique-css-token-value": "error",
12721
+ "pasika/utility-mapping": "error",
12544
12722
  "pasika/no-utility-alias": "error",
12545
12723
  "pasika/root-variables": "error",
12546
12724
  "pasika/color-role-usage": "error"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.10.115",
3
+ "version": "0.10.116",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",