cursedbelt 5.7.1 → 5.7.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt",
3
- "version": "5.7.1",
3
+ "version": "5.7.2",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The React design system of the cursedbelt split — components, styles, theme. cursedbelt-core below it; server tier in cursedbelt-server.",
@@ -75,7 +75,7 @@ describe('checkAreaStyles', () => {
75
75
  const js = [`const a="flex rounded-full";const b=\`recharts-tip \${x}\`;`];
76
76
  const css = [`.flex{display:flex}.rounded-full{border-radius:9999px}`];
77
77
  const result = checkAreaStyles({ js, css }, BELT);
78
- expect(result.missing).toEqual([{ className: 'recharts-tip', area: 'charts' }]);
78
+ expect(result.missing).toEqual([{ className: 'recharts-tip', area: 'charts', areas: ['charts'] }]);
79
79
  expect(result.referenced).toBe(3);
80
80
  });
81
81
 
@@ -177,7 +177,23 @@ describe('an area is `@source inline` candidates since 5.1.0 (task 2124)', () =>
177
177
  const belt = readBeltSheets();
178
178
  expect(inlineCandidatesIn(belt.areas.core ?? '').size).toBeGreaterThan(400);
179
179
  const { missing } = checkAreaStyles({ js: ['x("truncate")'], css: [''] }, belt);
180
- expect(missing).toEqual([{ className: 'truncate', area: 'core' }]);
180
+ expect(missing).toEqual([{ className: 'truncate', area: 'core', areas: ['core'] }]);
181
+ });
182
+ });
183
+
184
+ describe('🔴 a class two areas carry names BOTH (5.7.2)', () => {
185
+ test("station's `min-w-40`: `media` AND `workbench`, not just the alphabetically first", () => {
186
+ // Measured 2026-09-24: station adopted `ListToolbar` (a `workbench` module), its gate went red
187
+ // on `min-w-40`, and the fix this printed was `media.css` — an area station renders nothing from.
188
+ const { missing } = checkAreaStyles({ js: ['x("min-w-40")'], css: [''] }, readBeltSheets());
189
+ expect(missing).toHaveLength(1);
190
+ expect(missing[0]?.areas).toContain('media');
191
+ expect(missing[0]?.areas).toContain('workbench');
192
+ });
193
+
194
+ test('the areas are sorted and never repeat — whatever order the sheets were read in', () => {
195
+ const belt = { union: '.w-1{width:1px}', areas: { zeta: '@source inline("w-1");\n.w-1{width:1px}', alpha: '@source inline("w-1");' } };
196
+ expect(checkAreaStyles({ js: ['x("w-1")'], css: [''] }, belt).missing).toEqual([{ className: 'w-1', area: 'alpha', areas: ['alpha', 'zeta'] }]);
181
197
  });
182
198
  });
183
199
 
@@ -476,8 +476,13 @@ function filesUnder(dir: string, ext: string, out: string[] = []): string[] {
476
476
  }
477
477
 
478
478
  export interface AreaCheckResult {
479
- /** Belt classes the JS uses and the CSS does not style → the area that carries each. */
480
- missing: { className: string; area: string }[];
479
+ /**
480
+ * Belt classes the JS uses and the CSS does not style → the areas that carry each. `areas` is
481
+ * EVERY area whose sheet carries the class, sorted; `area` is the first of them. 🔴 Name them all:
482
+ * `min-w-40` is in both `media` and `workbench`, and until 5.7.2 this said only `media` —
483
+ * the wrong advice for station, whose `min-w-40` came from `ListToolbar` (a `workbench` module).
484
+ */
485
+ missing: { className: string; area: string; areas: string[] }[];
481
486
  jsFiles: number;
482
487
  cssFiles: number;
483
488
  /** How many belt classes the JS references — a zero here means the check saw nothing. */
@@ -494,9 +499,9 @@ export function checkAreaStyles(
494
499
  belt: { union: string; areas: Record<string, string> },
495
500
  ): Omit<AreaCheckResult, 'jsFiles' | 'cssFiles' | 'outOfOrder' | 'undefinedVariables'> {
496
501
  const union = classesInCss(belt.union);
497
- const areaOf = new Map<string, string>();
498
- for (const [area, css] of Object.entries(belt.areas)) {
499
- for (const name of [...classesInCss(css), ...inlineCandidatesIn(css)]) if (!areaOf.has(name)) areaOf.set(name, area);
502
+ const areaOf = new Map<string, string[]>();
503
+ for (const [area, css] of Object.entries(belt.areas).sort(([a], [b]) => a.localeCompare(b))) {
504
+ for (const name of new Set([...classesInCss(css), ...inlineCandidatesIn(css)])) areaOf.set(name, [...(areaOf.get(name) ?? []), area]);
500
505
  }
501
506
  const emitted = new Set<string>();
502
507
  for (const css of input.css) for (const name of classesInCss(css)) emitted.add(name);
@@ -507,7 +512,10 @@ export function checkAreaStyles(
507
512
  .filter((name) => !emitted.has(name))
508
513
  .filter((name) => !onlyInMergeTables(name, allJs) && !onlyAsPropertyName(name, allJs))
509
514
  .sort()
510
- .map((className) => ({ className, area: areaOf.get(className) as string }));
515
+ .map((className) => {
516
+ const areas = areaOf.get(className) as string[];
517
+ return { className, area: areas[0] as string, areas };
518
+ });
511
519
  return { missing, referenced: referenced.size };
512
520
  }
513
521
 
@@ -595,9 +603,14 @@ if (import.meta.main) {
595
603
  process.exit(0);
596
604
  }
597
605
  const byArea = new Map<string, string[]>();
598
- for (const { className, area } of result.missing) byArea.set(area, [...(byArea.get(area) ?? []), className]);
606
+ for (const { className, areas } of result.missing) {
607
+ const key = areas.map((a) => `${a}.css`).join(' | ');
608
+ byArea.set(key, [...(byArea.get(key) ?? []), className]);
609
+ }
599
610
  console.error(`✗ ${result.missing.length} cursedbelt class(es) the built JS uses have NO rule in the built CSS.`);
600
- console.error(' Import the area that carries them — `@import "cursedbelt/styles-areas/<area>.css";`:');
601
- for (const [area, names] of [...byArea].sort()) console.error(` ${area}.css ← ${names.slice(0, 8).join(' ')}${names.length > 8 ? ` … +${names.length - 8}` : ''}`);
611
+ console.error(' Import the area that carries them — `@import "cursedbelt/styles-areas/<area>.css";`.');
612
+ console.error(' Where a line names several (`a.css | b.css`), any one fixes it: import the area of the component you');
613
+ console.error(" mounted (scripts/styleAreas.ts says which that is) — not the first name, which is only alphabetical:");
614
+ for (const [areas, names] of [...byArea].sort()) console.error(` ${areas} ← ${names.slice(0, 8).join(' ')}${names.length > 8 ? ` … +${names.length - 8}` : ''}`);
602
615
  process.exit(1);
603
616
  }