pasika 0.10.117 → 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,7 @@ 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)}`];
10098
10099
  if (name.startsWith("--spacing-")) {
10099
10100
  const stem = name.slice("--spacing-".length);
10100
10101
  return [
@@ -11160,6 +11161,7 @@ var themeOperations = [
11160
11161
  { property: "tab-size", prefix: "tab", namespace: "tab-size" },
11161
11162
  { property: "border-radius", prefix: "rounded", namespace: "radius" },
11162
11163
  { property: "background-color", prefix: "bg", namespace: "color" },
11164
+ { property: "background-image", prefix: "bg", namespace: "background-image" },
11163
11165
  { property: "color", prefix: "text", namespace: "color" },
11164
11166
  { property: "border-color", prefix: "border", namespace: "color" },
11165
11167
  { property: "outline-color", prefix: "outline", namespace: "color" },
@@ -11194,10 +11196,11 @@ function themeCandidate(name, utilityText) {
11194
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(
11195
11197
  source
11196
11198
  );
11197
- 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;
11198
11201
  const matched = themeOperations.find((operation) => {
11199
- if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
11200
11202
  if (property) return property === operation.property;
11203
+ if (!name.startsWith(`${operation.prefix}-`) || name.length <= operation.prefix.length + 1) return false;
11201
11204
  if (typed?.groups?.kind !== operation.prefix) return false;
11202
11205
  const hint = typed.groups.hint;
11203
11206
  if (operation.prefix === "text") return hint === (operation.property === "font-size" ? "length:" : "color:");
@@ -11207,7 +11210,7 @@ function themeCandidate(name, utilityText) {
11207
11210
  return hint === void 0;
11208
11211
  });
11209
11212
  if (!matched) return void 0;
11210
- 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);
11211
11214
  if (!value) return void 0;
11212
11215
  const simple = /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|%|vh|vw|ch|deg)?$/u.test(value);
11213
11216
  const variable = /^var\(--[a-z][a-z0-9-]*\)$/u.test(value);
@@ -11216,9 +11219,9 @@ function themeCandidate(name, utilityText) {
11216
11219
  const ratio = /^\d+\/\d+$/u.test(value);
11217
11220
  if (!simple && !variable && !color && !keyword && !ratio) return void 0;
11218
11221
  if (matched.property === "font-size" && value.startsWith("-")) return void 0;
11219
- const stem = name.slice(matched.prefix.length + 1);
11222
+ const stem = name.startsWith(`${matched.prefix}-`) ? name.slice(matched.prefix.length + 1) : void 0;
11220
11223
  return {
11221
- token: `--${matched.namespace}-${stem}`,
11224
+ token: stem ? `--${matched.namespace}-${stem}` : "",
11222
11225
  property: matched.property,
11223
11226
  value,
11224
11227
  prefix: matched.prefix,
@@ -11282,6 +11285,37 @@ var utilityMappingRule = {
11282
11285
  includeReferences: false
11283
11286
  });
11284
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
+ }
11285
11319
  return {
11286
11320
  "StyleSheet:exit"(node) {
11287
11321
  const utilities = atrulesNamed(node, "utility");
@@ -11307,6 +11341,16 @@ var utilityMappingRule = {
11307
11341
  themeDefinitions.set(child.property, definitions);
11308
11342
  }
11309
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
+ }
11310
11354
  const rootValues = /* @__PURE__ */ new Map();
11311
11355
  const overriddenVariables = /* @__PURE__ */ new Set();
11312
11356
  for (const cssRule of rules(node)) {
@@ -11358,56 +11402,104 @@ var utilityMappingRule = {
11358
11402
  break;
11359
11403
  }
11360
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
+ }
11361
11427
  for (const utility of utilities) {
11362
11428
  const name = preludeIdentifiers(utility)[0] ?? "unknown";
11363
- const operationCount = applyOperationCount(utility);
11364
- 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) {
11365
11432
  context.report({
11366
11433
  node: utility,
11367
- 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.`
11368
11435
  });
11369
11436
  continue;
11370
11437
  }
11371
- if (nameCounts.get(name) !== 1) continue;
11372
- const candidate = themeCandidate(name, context.sourceCode.getText(utility));
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)}`;
11438
+ const operationCount = applyOperationCount(utility);
11439
+ if (operationCount !== 1) {
11399
11440
  context.report({
11400
11441
  node: utility,
11401
- 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.`
11402
11443
  });
11403
11444
  continue;
11404
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;
11405
11449
  if (candidate.property === "font-size" && themeTokens.has(`--color-${name.slice(5)}`)) continue;
11406
11450
  context.report({
11407
11451
  node: utility,
11408
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.`
11409
11453
  });
11410
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);
11411
11503
  }
11412
11504
  };
11413
11505
  }
@@ -11588,7 +11680,7 @@ import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync a
11588
11680
  import { createRequire } from "module";
11589
11681
  import path79 from "path";
11590
11682
  var PREFIX_NAMESPACES = {
11591
- bg: ["color"],
11683
+ bg: ["color", "background-image"],
11592
11684
  text: ["color", "text"],
11593
11685
  border: ["color"],
11594
11686
  ring: ["color"],
@@ -11994,8 +12086,12 @@ function readInventory(files) {
11994
12086
  for (const block of themeBlocks(css2)) {
11995
12087
  if (/--\*\s*:\s*initial\b/.test(block)) defaultsReset = true;
11996
12088
  for (const decl of block.matchAll(/--(?<namespace>[a-z][a-z0-9]*)-(?<token>[a-z0-9][a-z0-9_-]*)\s*:/g)) {
11997
- const namespace = decl.groups?.namespace;
11998
- 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
+ }
11999
12095
  if (!namespace || !token) continue;
12000
12096
  let set = themeTokensByNamespace.get(namespace);
12001
12097
  if (!set) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.10.117",
3
+ "version": "0.10.118",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",