@nexub/tokens 8.3.0 → 8.4.0

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.
@@ -6,7 +6,7 @@ import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { parseArgs } from 'node:util';
8
8
 
9
- export const RULES = ['legacy-tokens', 'logical-classes', 'tw-animate', 'opacity-modifier', 'deprecated-components', 'tailwind-3-preset', 'keep-5-defaults', 'removed-in-7', 'changes-in-8'];
9
+ export const RULES = ['legacy-tokens', 'logical-classes', 'tw-animate', 'opacity-modifier', 'deprecated-components', 'tailwind-3-preset', 'keep-5-defaults', 'removed-in-7', 'changes-in-8', 'button-aliases'];
10
10
  // Run only when asked for by --rules: they keep old behaviour instead of moving code forward.
11
11
  const OPT_IN = new Set(['keep-5-defaults']);
12
12
  export const DEFAULT_RULES = RULES.filter((r) => !OPT_IN.has(r));
@@ -450,6 +450,36 @@ function changesIn8(src, ext, report) {
450
450
  if (themes && !/data-style/.test(src)) report(themes.index, SIGNATURE_NOTE);
451
451
  }
452
452
 
453
+ // ─── button-aliases: Button's legacy variant names (deprecated 8.4, removed 9.0) ─
454
+ export const BUTTON_ALIASES = { primary: 'filled', secondary: 'tonal', outline: 'outlined', ghost: 'text' };
455
+ const ALIAS_RE = Object.keys(BUTTON_ALIASES).join('|');
456
+
457
+ function buttonAliases(src) {
458
+ const edits = [];
459
+ const items = [];
460
+ const report = (at, message) => items.push({ line: src.slice(0, at).split('\n').length, rule: 'button-aliases', message });
461
+ const locals = [];
462
+ for (const m of src.matchAll(/\bimport\s+\{([^}]*)\}\s*from\s*(['"])@nexub\/react(?:\/\w+)?\2/g))
463
+ for (const [, name, alias] of m[1].matchAll(/\b(\w+)(?:\s+as\s+(\w+))?/g)) if (name === 'Button') locals.push(alias ?? name);
464
+ for (const local of locals) {
465
+ for (const m of src.matchAll(new RegExp(`<${local}(?![\\w.$-])`, 'g'))) {
466
+ const variant = readTag(src, m.index + m[0].length)?.attrs.find((a) => a.name === 'variant');
467
+ if (!variant?.value) continue;
468
+ const lit = /^(?:\{\s*)?(["'])(\w+)\1(?:\s*\})?$/.exec(variant.value);
469
+ if (lit && BUTTON_ALIASES[lit[2]]) edits.push({ start: variant.end - variant.value.length, end: variant.end, text: `"${BUTTON_ALIASES[lit[2]]}"` });
470
+ else if (!lit && new RegExp(`['"](${ALIAS_RE})['"]`).test(variant.value)) report(m.index, `<${local} variant={…}> may pass a legacy alias (removed in 9.0): use ${Object.entries(BUTTON_ALIASES).map(([a, b]) => `${a} -> ${b}`).join(', ')}`);
471
+ }
472
+ }
473
+ // buttonVariants({ variant: 'primary' }) for links styled as buttons.
474
+ for (const m of src.matchAll(new RegExp(`\\bbuttonVariants\\(\\{[^}]*?\\bvariant:\\s*(['"])(${ALIAS_RE})\\1`, 'g'))) {
475
+ const at = m.index + m[0].length - m[2].length - 1;
476
+ edits.push({ start: at, end: at + m[2].length, text: BUTTON_ALIASES[m[2]] });
477
+ }
478
+ let output = src;
479
+ for (const e of edits.sort((a, b) => b.start - a.start)) output = output.slice(0, e.start) + e.text + output.slice(e.end);
480
+ return { output, items };
481
+ }
482
+
453
483
  // ─── per-file migration ──────────────────────────────────────────────────────
454
484
  /**
455
485
  * Migrate one file's text. Returns { output, manual: [{ line, rule, message }] }.
@@ -481,6 +511,11 @@ export function migrateSource(src, { ext, rules = new Set(DEFAULT_RULES), fix =
481
511
  text = r.output;
482
512
  items.push(...r.items);
483
513
  }
514
+ if (rules.has('button-aliases') && COMPONENT_EXTS.has(ext) && /@nexub\/react['"/]/.test(text)) {
515
+ const r = buttonAliases(text);
516
+ text = r.output;
517
+ items.push(...r.items);
518
+ }
484
519
  if (rules.has('keep-5-defaults') && COMPONENT_EXTS.has(ext) && /@nexub\/react['"/]/.test(text)) {
485
520
  const r = pinDefaults(text);
486
521
  text = r.output;
@@ -571,6 +606,9 @@ Rules:
571
606
  changes-in-8 report what 8.0 removes and flips: legacy --duration-*/--ease-* tokens,
572
607
  the Motion easing prop, the default scrollLock (becomes "class"),
573
608
  non-strict safeHref and custom-scheme links, and the Signature look
609
+ button-aliases Button's legacy variants (deprecated 8.4, removed 9.0): primary -> filled,
610
+ secondary -> tonal, outline -> outlined, ghost -> text (JSX literals and
611
+ buttonVariants({ variant })); variant={expressions} reported
574
612
 
575
613
  Ignored: node_modules, dist, build, .next, out, coverage, files over 1 MB.
576
614
  Exit codes: 0 ok, 1 --check found something, 2 usage error.`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexub/tokens",
3
- "version": "8.3.0",
3
+ "version": "8.4.0",
4
4
  "description": "Design tokens for Nexub Design System — colours, typography, spacing, radii, shadows, and motion as CSS variables, a Tailwind 4 theme, Figma variables and native (React Native, SwiftUI, Compose) tokens.",
5
5
  "type": "module",
6
6
  "license": "MIT",