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.
@@ -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>[^;\r\n]+);/gu
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 project-level CSS definitions across stylesheets while preserving scoped overrides."
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) => ({ path: file, content: textOf(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 owners = /* @__PURE__ */ new Map();
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 files = owners.get(key) ?? /* @__PURE__ */ new Set();
10934
- files.add(symbol.file);
10935
- owners.set(key, files);
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 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;
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: symbol.line, column: 1 },
10954
- end: { line: symbol.line, column: 2 }
11077
+ start: { line: definition.line, column: 1 },
11078
+ end: { line: definition.line, column: 2 }
10955
11079
  },
10956
- message: `${symbolLabel(symbol)} "${symbol.name}" is also defined in ${path74.relative(sourceRoot, canonical)}; define it in only one CSS file.`
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 path75 from "path";
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 = path75.normalize(path75.resolve(context.filename));
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: path75.normalize(file) === current ? context.sourceCode.text : textOf(file)
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>font-size|letter-spacing):(?<value>[^\]\r\n;{}]+)\];?\s*\}$/u.exec(
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>text|tracking)-\((?<hint>length:)?(?<variable>--[a-z][a-z0-9-]*)\);?\s*\}$/u.exec(
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 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";
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 (!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);
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
- if (!length && !variable) return void 0;
11048
- if (property === "font-size" && value.startsWith("-")) return void 0;
11049
- return { token: `--${name}`, property, value };
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 || themeTokens.has(candidate.token)) continue;
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 path76 from "path";
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 = path76.resolve(context.filename);
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 path77 from "path";
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 = path77.join(dir, entry);
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 path77.extname(entry) === ".css" ? [entryPath] : [];
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 = 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");
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 = path77.resolve(packageRoot, target);
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 = path77.dirname(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 path78 from "path";
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 = path78.resolve(context.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 = path78.basename(filename, path78.extname(filename));
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}.${path78.extname(filename).slice(1)}.`
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 path79 from "path";
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 = path79.resolve(context.filename);
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 path80 from "path";
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 = path80.dirname(path80.resolve(context.filename));
12006
- const configPath = path80.join(projectRoot, "vulyk.config.ts");
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 = path80.join(projectRoot, "AGENTS.md");
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 path81 from "path";
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 = path81.resolve(context.filename);
12151
- const basename = path81.basename(filename);
12414
+ const filename = path83.resolve(context.filename);
12415
+ const basename = path83.basename(filename);
12152
12416
  if (!ESLINT_CONFIG.test(basename)) return {};
12153
- const projectRoot = path81.dirname(filename);
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 = path81.join(projectRoot, "tsconfig.json");
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(path81.join(projectRoot, name)));
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(path81.join(projectRoot, prettierConfigFile), "utf8");
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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.10.115",
3
+ "version": "0.10.117",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",