pasika 0.10.116 → 0.10.118

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.
@@ -10095,6 +10095,53 @@ function themeClasses(name) {
10095
10095
  }
10096
10096
  return ["bg", "text", "border", "fill", "stroke", "ring"].map((prefix) => `${prefix}-${stem}`);
10097
10097
  }
10098
+ if (name.startsWith("--background-image-")) return [`bg-${name.slice("--background-image-".length)}`];
10099
+ if (name.startsWith("--spacing-")) {
10100
+ const stem = name.slice("--spacing-".length);
10101
+ return [
10102
+ "p",
10103
+ "px",
10104
+ "py",
10105
+ "pt",
10106
+ "pr",
10107
+ "pb",
10108
+ "pl",
10109
+ "ps",
10110
+ "pe",
10111
+ "m",
10112
+ "mx",
10113
+ "my",
10114
+ "mt",
10115
+ "mr",
10116
+ "mb",
10117
+ "ml",
10118
+ "ms",
10119
+ "me",
10120
+ "w",
10121
+ "h",
10122
+ "size",
10123
+ "min-w",
10124
+ "min-h",
10125
+ "max-w",
10126
+ "max-h",
10127
+ "gap",
10128
+ "gap-x",
10129
+ "gap-y",
10130
+ "inset",
10131
+ "inset-x",
10132
+ "inset-y",
10133
+ "top",
10134
+ "right",
10135
+ "bottom",
10136
+ "left",
10137
+ "start",
10138
+ "end",
10139
+ "space-x",
10140
+ "space-y"
10141
+ ].map((prefix) => `${prefix}-${stem}`);
10142
+ }
10143
+ if (name.startsWith("--aspect-")) return [`aspect-${name.slice("--aspect-".length)}`];
10144
+ if (name.startsWith("--leading-")) return [`leading-${name.slice("--leading-".length)}`];
10098
10145
  if (name.startsWith("--animate-")) return [`animate-${name.slice("--animate-".length)}`];
10099
10146
  if (name.startsWith("--radius-")) return [`rounded-${name.slice("--radius-".length)}`];
10100
10147
  if (name.startsWith("--text-") || name.startsWith("--tracking-") || name.startsWith("--font-")) {
@@ -11114,6 +11161,7 @@ var themeOperations = [
11114
11161
  { property: "tab-size", prefix: "tab", namespace: "tab-size" },
11115
11162
  { property: "border-radius", prefix: "rounded", namespace: "radius" },
11116
11163
  { property: "background-color", prefix: "bg", namespace: "color" },
11164
+ { property: "background-image", prefix: "bg", namespace: "background-image" },
11117
11165
  { property: "color", prefix: "text", namespace: "color" },
11118
11166
  { property: "border-color", prefix: "border", namespace: "color" },
11119
11167
  { property: "outline-color", prefix: "outline", namespace: "color" },
@@ -11148,10 +11196,11 @@ function themeCandidate(name, utilityText) {
11148
11196
  const typed = /^@utility\s+[\w-]+\s*\{\s*@apply\s+(?<kind>[a-z]+)-\((?<hint>[a-z-]+:)?(?<variable>--[a-z][a-z0-9-]*)\);?\s*\}$/u.exec(
11149
11197
  source
11150
11198
  );
11151
- const property = arbitrary?.groups?.property;
11199
+ const direct = /^@utility\s+[\w-]+\s*\{\s*(?<property>[a-z-]+)\s*:\s*(?<value>[^;{}\r\n]+);?\s*\}$/u.exec(source);
11200
+ const property = arbitrary?.groups?.property ?? direct?.groups?.property;
11152
11201
  const matched = themeOperations.find((operation) => {
11153
- if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
11154
11202
  if (property) return property === operation.property;
11203
+ if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
11155
11204
  if (typed?.groups?.kind !== operation.prefix) return false;
11156
11205
  const hint = typed.groups.hint;
11157
11206
  if (operation.prefix === "text") return hint === (operation.property === "font-size" ? "length:" : "color:");
@@ -11161,7 +11210,7 @@ function themeCandidate(name, utilityText) {
11161
11210
  return hint === void 0;
11162
11211
  });
11163
11212
  if (!matched) return void 0;
11164
- const value = arbitrary?.groups?.value?.trim() ?? (typed?.groups?.variable ? `var(${typed.groups.variable})` : void 0);
11213
+ const value = arbitrary?.groups?.value?.trim() ?? direct?.groups?.value?.trim() ?? (typed?.groups?.variable ? `var(${typed.groups.variable})` : void 0);
11165
11214
  if (!value) return void 0;
11166
11215
  const simple = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%|vh|vw|ch|deg)?$/u.test(value);
11167
11216
  const variable = /^var\(--[a-z][a-z0-9-]*\)$/u.test(value);
@@ -11170,9 +11219,9 @@ function themeCandidate(name, utilityText) {
11170
11219
  const ratio = /^\d+\/\d+$/u.test(value);
11171
11220
  if (!simple && !variable && !color && !keyword && !ratio) return void 0;
11172
11221
  if (matched.property === "font-size" && value.startsWith("-")) return void 0;
11173
- const stem = name.slice(matched.prefix.length + 1);
11222
+ const stem = name.startsWith(`${matched.prefix}-`) ? name.slice(matched.prefix.length + 1) : void 0;
11174
11223
  return {
11175
- token: `--${matched.namespace}-${stem}`,
11224
+ token: stem ? `--${matched.namespace}-${stem}` : "",
11176
11225
  property: matched.property,
11177
11226
  value,
11178
11227
  prefix: matched.prefix,
@@ -11236,6 +11285,37 @@ var utilityMappingRule = {
11236
11285
  includeReferences: false
11237
11286
  });
11238
11287
  const projectTokens = graph.definitions.filter((symbol) => symbol.kind === "theme-token");
11288
+ const rootDefinitions = /* @__PURE__ */ new Map();
11289
+ for (const symbol of graph.definitions) {
11290
+ if (symbol.kind !== "root-variable" || !symbol.value) continue;
11291
+ const values = rootDefinitions.get(symbol.name) ?? [];
11292
+ values.push({ value: symbol.value, scope: symbol.scope ?? "default" });
11293
+ rootDefinitions.set(symbol.name, values);
11294
+ }
11295
+ function comparableValue(value, visited = /* @__PURE__ */ new Set()) {
11296
+ const text = value.trim();
11297
+ const match = /^var\((?<name>--[a-z][a-z0-9-]*)\)$/u.exec(text);
11298
+ const name = match?.groups?.name;
11299
+ if (!name) {
11300
+ const hex = /^#(?<digits>[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/iu.exec(text)?.groups?.digits;
11301
+ if (!hex) return text;
11302
+ const lower = hex.toLowerCase();
11303
+ return lower.length <= 4 ? Array.from(lower, (digit) => digit + digit).join("") : lower;
11304
+ }
11305
+ if (visited.has(name)) return void 0;
11306
+ const values = rootDefinitions.get(name);
11307
+ if (!values) return text;
11308
+ if (values.length !== 1 || values[0]?.scope !== "default") return void 0;
11309
+ const next = values[0].value;
11310
+ if (!next) return void 0;
11311
+ visited.add(name);
11312
+ return comparableValue(next, visited);
11313
+ }
11314
+ function equivalentValue(a, b) {
11315
+ const left = comparableValue(a);
11316
+ const right = comparableValue(b);
11317
+ return left !== void 0 && right !== void 0 && left === right;
11318
+ }
11239
11319
  return {
11240
11320
  "StyleSheet:exit"(node) {
11241
11321
  const utilities = atrulesNamed(node, "utility");
@@ -11261,6 +11341,16 @@ var utilityMappingRule = {
11261
11341
  themeDefinitions.set(child.property, definitions);
11262
11342
  }
11263
11343
  }
11344
+ for (const cssRule of node.children) {
11345
+ if (cssRule.type !== "Rule") continue;
11346
+ if (context.sourceCode.getText(cssRule.prelude).trim() !== ":root") continue;
11347
+ for (const child of blockChildren2(cssRule)) {
11348
+ if (child.type !== "Declaration" || !child.property.startsWith("--")) continue;
11349
+ if (rootDefinitions.has(child.property)) continue;
11350
+ const value = declarationValue(context.sourceCode.getText(child));
11351
+ if (value) rootDefinitions.set(child.property, [{ value, scope: "default" }]);
11352
+ }
11353
+ }
11264
11354
  const rootValues = /* @__PURE__ */ new Map();
11265
11355
  const overriddenVariables = /* @__PURE__ */ new Set();
11266
11356
  for (const cssRule of rules(node)) {
@@ -11312,56 +11402,104 @@ var utilityMappingRule = {
11312
11402
  break;
11313
11403
  }
11314
11404
  }
11405
+ function matchingThemeToken(candidate) {
11406
+ const namespacePrefix = `--${candidate.namespace}-`;
11407
+ const available = [
11408
+ ...projectTokens,
11409
+ ...[...themeDefinitions].flatMap(
11410
+ ([name, definitions]) => definitions.length === 1 && definitions[0] ? [{ name, value: definitions[0].value }] : []
11411
+ )
11412
+ ];
11413
+ for (const token of available) {
11414
+ if (!token.value || !token.name.startsWith(namespacePrefix) || token.name.includes("--", 2)) continue;
11415
+ if (!equivalentValue(candidate.value, token.value)) continue;
11416
+ if (candidate.namespace === "text" && ["--line-height", "--letter-spacing", "--font-weight"].some(
11417
+ (suffix) => themeDefinitions.has(`${token.name}${suffix}`) || projectTokens.some((entry) => entry.name === `${token.name}${suffix}`)
11418
+ )) {
11419
+ continue;
11420
+ }
11421
+ const generatedClass = `${candidate.prefix}-${token.name.slice(namespacePrefix.length)}`;
11422
+ if (candidate.namespace === "color" && !themeClasses(token.name).includes(generatedClass)) continue;
11423
+ return generatedClass;
11424
+ }
11425
+ return void 0;
11426
+ }
11315
11427
  for (const utility of utilities) {
11316
11428
  const name = preludeIdentifiers(utility)[0] ?? "unknown";
11317
- const operationCount = applyOperationCount(utility);
11318
- if (operationCount !== 1) {
11429
+ const candidate = themeCandidate(name, context.sourceCode.getText(utility));
11430
+ const equivalent = candidate ? matchingThemeToken(candidate) : void 0;
11431
+ if (candidate && equivalent && nameCounts.get(name) === 1) {
11319
11432
  context.report({
11320
11433
  node: utility,
11321
- message: `Custom utility "${name}" maps ${String(operationCount)} Tailwind operations; custom utilities must map exactly one operation. Reusable presentation belongs in a component.`
11434
+ message: `Custom utility "${name}" duplicates theme-generated "${equivalent}" (${candidate.property}: ${candidate.value}); reuse "${equivalent}" instead.`
11322
11435
  });
11323
11436
  continue;
11324
11437
  }
11325
- if (nameCounts.get(name) !== 1) continue;
11326
- const candidate = themeCandidate(name, context.sourceCode.getText(utility));
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)}`;
11438
+ const operationCount = applyOperationCount(utility);
11439
+ if (operationCount !== 1) {
11353
11440
  context.report({
11354
11441
  node: utility,
11355
- message: `Custom utility "${name}" duplicates theme-generated "${className}" (${candidate.property}: ${candidate.value}); reuse "${className}" instead.`
11442
+ message: `Custom utility "${name}" maps ${String(operationCount)} Tailwind operations; custom utilities must map exactly one operation. Reusable presentation belongs in a component.`
11356
11443
  });
11357
11444
  continue;
11358
11445
  }
11446
+ if (nameCounts.get(name) !== 1 || !candidate?.token) continue;
11447
+ const tokenAlreadyDefined = themeTokens.has(candidate.token) || projectTokens.some((token) => token.name === candidate.token);
11448
+ if (tokenAlreadyDefined) continue;
11359
11449
  if (candidate.property === "font-size" && themeTokens.has(`--color-${name.slice(5)}`)) continue;
11360
11450
  context.report({
11361
11451
  node: utility,
11362
11452
  message: `Custom utility "${name}" only maps ${candidate.property} (${candidate.value}); prefer @theme inline token "${candidate.token}" backed by a :root variable. Preserve the class name and compare compiled CSS before removing the utility.`
11363
11453
  });
11364
11454
  }
11455
+ function checkClass(cssNode) {
11456
+ if (cssNode.type === "Atrule") {
11457
+ if (cssNode.name !== "layer" || !("prelude" in cssNode) || !cssNode.prelude) return;
11458
+ if (context.sourceCode.getText(cssNode.prelude).trim() === "base") return;
11459
+ for (const child of blockChildren2(cssNode)) checkClass(child);
11460
+ return;
11461
+ }
11462
+ if (cssNode.type !== "Rule") return;
11463
+ const selector = context.sourceCode.getText(cssNode.prelude).trim();
11464
+ if (!/^\.[a-zA-Z_][\w-]*$/u.test(selector)) return;
11465
+ const children = blockChildren2(cssNode);
11466
+ if (children.length !== 1) return;
11467
+ const only = children[0];
11468
+ if (!only) return;
11469
+ const declarationText = context.sourceCode.getText(only).trim();
11470
+ if (only.type === "Atrule" && only.name === "apply") {
11471
+ const alias = /^@apply\s+(?<name>[a-z][a-z0-9-]*)\s*;?$/u.exec(declarationText)?.groups?.name;
11472
+ if (alias && [...projectTokens.map((token) => token.name), ...themeDefinitions.keys()].some(
11473
+ (name) => themeClasses(name).includes(alias)
11474
+ )) {
11475
+ context.report({
11476
+ node: cssNode,
11477
+ message: `CSS class "${selector}" only aliases theme-generated "${alias}"; use "${alias}" instead.`
11478
+ });
11479
+ return;
11480
+ }
11481
+ }
11482
+ const found = only.type === "Declaration" ? /^(?<property>[a-z-]+)\s*:\s*(?<value>[^;{}]+);?$/u.exec(declarationText) : /^@apply\s+\[(?<property>[a-z-]+):(?<value>[^\]\r\n;{}]+)\]\s*;?$/u.exec(declarationText);
11483
+ const property = found?.groups?.property;
11484
+ const value = found?.groups?.value?.trim();
11485
+ if (!property || !value || value.endsWith("!important")) return;
11486
+ const operation = themeOperations.find((item) => item.property === property);
11487
+ if (!operation) return;
11488
+ const candidate = {
11489
+ token: "",
11490
+ property,
11491
+ value,
11492
+ prefix: operation.prefix,
11493
+ namespace: operation.namespace
11494
+ };
11495
+ const equivalent = matchingThemeToken(candidate);
11496
+ if (!equivalent) return;
11497
+ context.report({
11498
+ node: cssNode,
11499
+ message: `CSS class "${selector}" duplicates theme-generated "${equivalent}" (${property}: ${value}); use "${equivalent}" instead.`
11500
+ });
11501
+ }
11502
+ for (const cssRule of node.children) checkClass(cssRule);
11365
11503
  }
11366
11504
  };
11367
11505
  }
@@ -11542,7 +11680,7 @@ import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync a
11542
11680
  import { createRequire } from "module";
11543
11681
  import path79 from "path";
11544
11682
  var PREFIX_NAMESPACES = {
11545
- bg: ["color"],
11683
+ bg: ["color", "background-image"],
11546
11684
  text: ["color", "text"],
11547
11685
  border: ["color"],
11548
11686
  ring: ["color"],
@@ -11567,6 +11705,47 @@ var PREFIX_NAMESPACES = {
11567
11705
  "backdrop-blur": ["blur"],
11568
11706
  "ring-offset": ["color"]
11569
11707
  };
11708
+ var SPACING_UTILITY_PREFIXES = /* @__PURE__ */ new Set([
11709
+ "p",
11710
+ "px",
11711
+ "py",
11712
+ "pt",
11713
+ "pr",
11714
+ "pb",
11715
+ "pl",
11716
+ "ps",
11717
+ "pe",
11718
+ "m",
11719
+ "mx",
11720
+ "my",
11721
+ "mt",
11722
+ "mr",
11723
+ "mb",
11724
+ "ml",
11725
+ "ms",
11726
+ "me",
11727
+ "w",
11728
+ "h",
11729
+ "size",
11730
+ "min-w",
11731
+ "min-h",
11732
+ "max-w",
11733
+ "max-h",
11734
+ "gap",
11735
+ "gap-x",
11736
+ "gap-y",
11737
+ "inset",
11738
+ "inset-x",
11739
+ "inset-y",
11740
+ "top",
11741
+ "right",
11742
+ "bottom",
11743
+ "left",
11744
+ "start",
11745
+ "end",
11746
+ "space-x",
11747
+ "space-y"
11748
+ ]);
11570
11749
  var PREFIX_BUILTINS = {
11571
11750
  bg: [
11572
11751
  "none",
@@ -11907,8 +12086,12 @@ function readInventory(files) {
11907
12086
  for (const block of themeBlocks(css2)) {
11908
12087
  if (/--\*\s*:\s*initial\b/.test(block)) defaultsReset = true;
11909
12088
  for (const decl of block.matchAll(/--(?<namespace>[a-z][a-z0-9]*)-(?<token>[a-z0-9][a-z0-9_-]*)\s*:/g)) {
11910
- const namespace = decl.groups?.namespace;
11911
- const token = decl.groups?.token;
12089
+ let namespace = decl.groups?.namespace;
12090
+ let token = decl.groups?.token;
12091
+ if (namespace === "background" && token?.startsWith("image-")) {
12092
+ namespace = "background-image";
12093
+ token = token.slice("image-".length);
12094
+ }
11912
12095
  if (!namespace || !token) continue;
11913
12096
  let set = themeTokensByNamespace.get(namespace);
11914
12097
  if (!set) {
@@ -11944,7 +12127,7 @@ function isKnown(className, inventory) {
11944
12127
  if (!utility.includes("-")) return true;
11945
12128
  const dash = utility.indexOf("-");
11946
12129
  const firstTwo = utility.split("-").slice(0, 2).join("-");
11947
- const compound = PREFIX_NAMESPACES[firstTwo] ? firstTwo : void 0;
12130
+ const compound = PREFIX_NAMESPACES[firstTwo] || SPACING_UTILITY_PREFIXES.has(firstTwo) ? firstTwo : void 0;
11948
12131
  const prefix = compound ?? utility.slice(0, dash);
11949
12132
  const token = compound ? utility.slice(compound.length + 1) : utility.slice(dash + 1);
11950
12133
  if (!token) return true;
@@ -11953,6 +12136,7 @@ function isKnown(className, inventory) {
11953
12136
  const namespaces = PREFIX_NAMESPACES[prefix];
11954
12137
  if (!namespaces) {
11955
12138
  if (STATIC_VALUE_TOKENS[prefix]?.includes(token)) return true;
12139
+ if (SPACING_UTILITY_PREFIXES.has(prefix) && inventory.themeTokens.get("spacing")?.has(token)) return true;
11956
12140
  const projectTokens = inventory.themeTokens.get(prefix);
11957
12141
  if (projectTokens) {
11958
12142
  if (projectTokens.has(token)) return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.10.116",
3
+ "version": "0.10.118",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",