pasika 0.10.143 → 0.10.144

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.
@@ -11512,128 +11512,110 @@ var themeResetRule = {
11512
11512
 
11513
11513
  // eslint/rules/tailwind/theme-token-order.ts
11514
11514
  import path77 from "path";
11515
- var THEME_GROUPS = [
11516
- "Color primitives",
11517
- "Semantic colors",
11518
- "Fixed and brand colors",
11519
- "Font families",
11520
- "Typography",
11521
- "Spacing and sizing",
11522
- "Breakpoints, containers, and aspect ratios",
11523
- "Border radii",
11524
- "Shadows and visual effects",
11525
- "Background images",
11526
- "Transitions and easing",
11527
- "Animations",
11528
- "Blur",
11529
- "Other tokens"
11530
- ];
11531
- var primitiveColors = /* @__PURE__ */ new Set([
11532
- "--accent",
11533
- "--base-canvas",
11534
- "--base-edge",
11535
- "--base-ink",
11536
- "--card",
11537
- "--destructive",
11538
- "--magenta",
11539
- "--muted",
11540
- "--muted-ink",
11541
- "--primary",
11542
- "--rainbow-ink",
11543
- "--retro-edge",
11544
- "--retro-shadow",
11545
- "--secondary",
11546
- "--violet"
11547
- ]);
11548
- function themeGroupName(name, value) {
11549
- if (primitiveColors.has(name)) return "Color primitives";
11550
- if (name.startsWith("--color-")) {
11551
- return value.includes("var(") ? "Semantic colors" : "Fixed and brand colors";
11552
- }
11553
- if (name.startsWith("--font-") && !name.startsWith("--font-weight-")) return "Font families";
11554
- if (/^--(?:font-weight|text-|tracking-|leading-)/u.test(name)) return "Typography";
11555
- if (name.startsWith("--spacing")) return "Spacing and sizing";
11556
- if (/^--(?:breakpoint|container|aspect)-/u.test(name)) return "Breakpoints, containers, and aspect ratios";
11557
- if (name.startsWith("--radius")) return "Border radii";
11558
- if (/^--(?:shadow|inset-shadow|drop-shadow|text-shadow)-/u.test(name)) return "Shadows and visual effects";
11559
- if (name.startsWith("--background-image-")) return "Background images";
11560
- if (/^--(?:default-transition|transition|ease)-/u.test(name)) return "Transitions and easing";
11561
- if (name.startsWith("--animate-")) return "Animations";
11562
- if (name.startsWith("--blur-")) return "Blur";
11563
- return "Other tokens";
11515
+ var GROUP_RE = /^\s*\/\*\s*(?:Group:\s*)?(?<paths>(?:global|src\/[\w./-]+\.(?:tsx?|jsx?))(?:\s*,\s*src\/[\w./-]+\.(?:tsx?|jsx?))*)\s*\*\/\s*$/u;
11516
+ var PATH_RE = /^src\/[\w./-]+\.(?:tsx?|jsx?)$/u;
11517
+ function normalizeGroup(label) {
11518
+ if (label === "global") return "global";
11519
+ return [...new Set(label.split(",").map((name) => name.trim()))].sort().join(", ");
11520
+ }
11521
+ function sectionOf(symbol) {
11522
+ if (symbol.kind === "theme-token") return "theme";
11523
+ if (symbol.kind === "utility") return "utility";
11524
+ if (symbol.kind === "keyframes") return "keyframes";
11525
+ return symbol.kind;
11526
+ }
11527
+ function ownerOf(symbol, graph, root) {
11528
+ const references = graph.references.filter((ref) => {
11529
+ if (ref.source !== "module" || !/\.(?:tsx|jsx)$/u.test(ref.file) || /\.(?:test|spec|stories)\.(?:tsx|jsx)$/u.test(ref.file)) {
11530
+ return false;
11531
+ }
11532
+ if (symbol.kind === "theme-token") {
11533
+ return ref.kind === "theme-class" && ref.token === symbol.name || ref.kind === "variable" && ref.name === symbol.name;
11534
+ }
11535
+ if (symbol.kind === "utility" || symbol.kind === "keyframes" || symbol.kind === "selector") {
11536
+ return ref.name === symbol.name;
11537
+ }
11538
+ return ref.kind === "variable" && ref.name === symbol.name;
11539
+ });
11540
+ const indirect = graph.references.some(
11541
+ (ref) => ref.source === "css" && ref.file !== symbol.file && (symbol.kind === "theme-token" && ref.kind === "variable" && ref.name === symbol.name || symbol.kind === "utility" && ref.kind === "utility" && ref.name === symbol.name || symbol.kind === "keyframes" && ref.kind === "keyframes" && ref.name === symbol.name)
11542
+ );
11543
+ if (indirect) return "global";
11544
+ const owners = [
11545
+ ...new Set(references.map((ref) => path77.relative(path77.dirname(root), ref.file).split(path77.sep).join("/")))
11546
+ ].filter((name) => PATH_RE.test(name)).sort();
11547
+ return owners.length > 0 ? owners.join(", ") : "global";
11564
11548
  }
11565
11549
  var themeTokenOrderRule = {
11566
11550
  meta: {
11567
11551
  schema: [],
11568
11552
  type: "problem",
11553
+ fixable: "code",
11569
11554
  docs: {
11570
- description: "Require global Tailwind theme tokens to follow purpose groups and alphabetical order."
11555
+ description: "Group CSS definitions by consuming component paths in alphabetical order."
11571
11556
  }
11572
11557
  },
11573
11558
  create(context) {
11574
11559
  const root = sourceRootOf(context);
11575
- const entry = path77.normalize(path77.join(root, "app", "styles", "globals.css"));
11576
- if (path77.normalize(path77.resolve(context.filename)) !== entry) return {};
11560
+ const current = path77.normalize(path77.resolve(context.filename));
11561
+ const textOf = cachedTextReader();
11562
+ const cssFiles = /* @__PURE__ */ new Set([...findFiles(root, CSS_EXTENSIONS).map((file) => path77.normalize(file)), current]);
11563
+ const graph = buildCssDependencyGraph({
11564
+ sourceRoot: root,
11565
+ css: [...cssFiles].map((file) => ({
11566
+ path: file,
11567
+ content: path77.normalize(file) === current ? context.sourceCode.text : textOf(file)
11568
+ })),
11569
+ modules: findFiles(root, MODULE_EXTENSIONS4).map((file) => ({ path: file, content: textOf(file) }))
11570
+ });
11571
+ const lines = context.sourceCode.text.split(/\r?\n/u);
11572
+ const groups = [];
11573
+ for (const [index, line] of lines.entries()) {
11574
+ const match = GROUP_RE.exec(line);
11575
+ if (match?.groups?.paths) groups.push({ label: normalizeGroup(match.groups.paths), line: index + 1 });
11576
+ }
11577
+ const items = graph.definitions.filter((symbol) => symbol.file === current && symbol.name !== "--*").filter(
11578
+ (symbol) => ["theme-token", "utility", "keyframes", "root-variable", "selector", "font-face"].includes(symbol.kind)
11579
+ ).map((symbol) => ({
11580
+ symbol,
11581
+ group: groups.filter((group) => group.line < symbol.line).at(-1),
11582
+ owner: ownerOf(symbol, graph, root),
11583
+ section: sectionOf(symbol)
11584
+ })).sort((a, b) => a.symbol.line - b.symbol.line);
11577
11585
  return {
11578
- "StyleSheet:exit"(sheet) {
11579
- const theme = [...sheet.children].find(
11580
- (child) => child.type === "Atrule" && child.name === "theme" && child.loc
11581
- );
11582
- if (!theme?.loc) return;
11583
- const raw = context.sourceCode.text.slice(theme.loc.start.offset, theme.loc.end.offset);
11584
- const opening = raw.indexOf("{");
11585
- const closing = raw.lastIndexOf("}");
11586
- if (opening === -1 || closing <= opening) return;
11587
- const lines = raw.slice(opening + 1, closing).split(/\r?\n/u);
11588
- const firstLine = theme.loc.start.line + (raw.slice(0, opening + 1).match(/\n/gu)?.length ?? 0);
11589
- const tokens = [];
11590
- let activeHeading;
11591
- let hasGroupHeadings = false;
11592
- for (const [index, line] of lines.entries()) {
11593
- const heading = /^\s*\/\*\s*(?<heading>.*?)\s*\*\/\s*$/u.exec(line)?.groups?.heading;
11594
- if (heading && THEME_GROUPS.includes(heading)) {
11595
- activeHeading = heading;
11596
- hasGroupHeadings = true;
11597
- }
11598
- const declaration = /^ {2}(?<name>--[a-z][a-z0-9-]*)\s*:\s*(?<value>.*)$/u.exec(line);
11599
- const { name, value } = declaration?.groups ?? {};
11600
- if (!name || value === void 0) continue;
11601
- tokens.push({
11602
- name,
11603
- group: themeGroupName(name, value),
11604
- activeHeading,
11605
- line: firstLine + index
11606
- });
11607
- }
11608
- if (tokens.length > 1 && !hasGroupHeadings) {
11609
- context.report({
11610
- node: sheet,
11611
- message: "Global theme tokens must use named purpose-group section comments."
11612
- });
11613
- }
11586
+ "StyleSheet:exit"(node) {
11614
11587
  let previous;
11615
- for (const token of tokens) {
11588
+ for (const item of items) {
11589
+ const currentGroup = item.group;
11590
+ const actual = currentGroup?.label;
11616
11591
  let message;
11617
- const groupIndex = THEME_GROUPS.indexOf(token.group);
11618
- const previousIndex = previous ? THEME_GROUPS.indexOf(previous.group) : -1;
11619
- if (previous && groupIndex < previousIndex) {
11620
- message = `Theme token "${token.name}" belongs to "${token.group}", which must appear before "${previous.group}".`;
11621
- } else if (previous && groupIndex === previousIndex && token.name.toLowerCase() < previous.name.toLowerCase()) {
11622
- message = `Theme tokens in "${token.group}" must be alphabetical: "${token.name}" goes before "${previous.name}".`;
11623
- } else if (hasGroupHeadings && token.activeHeading !== token.group) {
11624
- message = `Theme token "${token.name}" belongs under the "${token.group}" section comment.`;
11592
+ if (!currentGroup) {
11593
+ message = `CSS definition "${item.symbol.name}" requires a component-path group comment (or /* Group: global */).`;
11594
+ } else if (actual !== item.owner) {
11595
+ message = `CSS definition "${item.symbol.name}" belongs to group "${item.owner}", not "${currentGroup.label}".`;
11596
+ } else if (previous?.section === item.section && previous.group) {
11597
+ if (previous.group !== currentGroup && previous.group.label.localeCompare(currentGroup.label) > 0) {
11598
+ message = `CSS consumer groups in ${item.section} must be ordered alphabetically by path.`;
11599
+ } else if (previous.group === currentGroup && previous.symbol.name.localeCompare(item.symbol.name) > 0) {
11600
+ message = `CSS definitions in group "${previous.group.label}" must be alphabetical: "${item.symbol.name}" comes before "${previous.symbol.name}".`;
11601
+ }
11625
11602
  }
11626
11603
  if (message) {
11604
+ const line = item.symbol.line;
11627
11605
  context.report({
11628
- node: sheet,
11629
- loc: {
11630
- start: { line: token.line, column: 1 },
11631
- end: { line: token.line, column: 2 }
11632
- },
11633
- message
11606
+ node,
11607
+ loc: { start: { line, column: 1 }, end: { line, column: 2 } },
11608
+ message,
11609
+ ...currentGroup && actual !== item.owner && items.filter((candidate) => candidate.group === currentGroup).length === 1 ? {
11610
+ fix(fixer) {
11611
+ const start = context.sourceCode.getIndexFromLoc({ line: currentGroup.line, column: 1 });
11612
+ const end = start + (lines[currentGroup.line - 1] ?? "").length;
11613
+ return fixer.replaceTextRange([start, end], `/* Group: ${item.owner} */`);
11614
+ }
11615
+ } : {}
11634
11616
  });
11635
11617
  }
11636
- previous = token;
11618
+ previous = item;
11637
11619
  }
11638
11620
  }
11639
11621
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.10.143",
3
+ "version": "0.10.144",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",