@nexub/tokens 5.8.0 → 6.0.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.
- package/bin/README.md +1 -0
- package/bin/nexub-migrate.mjs +48 -4
- package/package.json +1 -1
package/bin/README.md
CHANGED
|
@@ -16,6 +16,7 @@ npx nexub-migrate --rules logical-classes --ignore 'src/legacy/**'
|
|
|
16
16
|
| `logical-classes` | `ml/mr` `pl/pr` `border-l/r` `rounded-l/r/tl/tr/bl/br` `text-left/right` → `ms/me` `ps/pe` `border-s/e` `rounded-s/e/ss/se/es/ee` `text-start/end`, keeping variants, `!` and `-`. `left-*`/`right-*` positions are reported only. |
|
|
17
17
|
| `tw-animate` | Reports tailwindcss-animate classes (`animate-in`, `fade-in-0`, `zoom-in-95`, `slide-in-from-*` …). Use `nx-motion` / `nx-pop` / `nx-dialog` from `@nexub/themes/base`. |
|
|
18
18
|
| `opacity-modifier` | Reports `bg-[var(--x)]/10` (Tailwind 3 emits nothing). `--fix` rewrites to `bg-[color-mix(in_srgb,var(--x)_10%,transparent)]`. |
|
|
19
|
+
| `keep-5-defaults` | **Opt-in** (`--rules keep-5-defaults`). Keeps 5.x behaviour on 6.0 by adding the defaults 6.0 changes as explicit props, in files that import from `@nexub/react`: `<Autocomplete>` without `mode` gets `mode="inline"`; `<DataTable>`/`<DataTableVirtual>` with `enableRowSelection` and no `selectionColumn` get `selectionColumn={false}`. Tags with a `{...spread}` are reported, not changed. |
|
|
19
20
|
| `deprecated-components` | `@nexub/react` components removed in 3.0, in files that import from `@nexub/react`: `Banner`/`Callout` → `Alert`; `Tag` → `<Badge variant="soft">`; `StatusPill label="x"` → `<Badge variant="soft">x</Badge>`; `*Props` types renamed; imports deduped; aliases (`Tag as T`) keep their local name. Reported only: `StatusPill dot`, `*Variants`, and uses outside JSX (`typeof Banner`, `styled(Tag)`). |
|
|
20
21
|
|
|
21
22
|
**Where classes are looked for.** `.html`/`.mdx`: `class=`/`className=` attributes. `.css`/`.scss`: `@apply`.
|
package/bin/nexub-migrate.mjs
CHANGED
|
@@ -6,7 +6,10 @@ 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'];
|
|
9
|
+
export const RULES = ['legacy-tokens', 'logical-classes', 'tw-animate', 'opacity-modifier', 'deprecated-components', 'tailwind-3-preset', 'keep-5-defaults'];
|
|
10
|
+
// Run only when asked for by --rules: they keep old behaviour instead of moving code forward.
|
|
11
|
+
const OPT_IN = new Set(['keep-5-defaults']);
|
|
12
|
+
export const DEFAULT_RULES = RULES.filter((r) => !OPT_IN.has(r));
|
|
10
13
|
const EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.css', '.scss', '.html', '.mdx']);
|
|
11
14
|
const SKIP_DIRS = new Set(['node_modules', 'dist', 'build', '.next', 'out', 'coverage']);
|
|
12
15
|
const MAX_BYTES = 1024 * 1024;
|
|
@@ -373,12 +376,45 @@ function migrateComponents(src) {
|
|
|
373
376
|
return { output, items };
|
|
374
377
|
}
|
|
375
378
|
|
|
379
|
+
// ─── keep-5-defaults (opt-in): pin the defaults 6.0 changes ──────────────────
|
|
380
|
+
// Adds the 5.x value as an explicit prop, so upgrading to 6.0 changes nothing.
|
|
381
|
+
const selection = (a) => (a.enableRowSelection && !a.selectionColumn ? ' selectionColumn={false}' : null);
|
|
382
|
+
const PINS = {
|
|
383
|
+
Autocomplete: (a) => (a.mode ? null : ' mode="inline"'),
|
|
384
|
+
DataTable: selection,
|
|
385
|
+
DataTableVirtual: selection,
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
function pinDefaults(src) {
|
|
389
|
+
const edits = [];
|
|
390
|
+
const items = [];
|
|
391
|
+
const locals = new Map(); // local JSX name -> exported name
|
|
392
|
+
for (const m of src.matchAll(/\bimport\s+\{([^}]*)\}\s*from\s*(['"])@nexub\/react(?:\/\w+)?\2/g)) {
|
|
393
|
+
for (const [, name, alias] of m[1].matchAll(/\b(\w+)(?:\s+as\s+(\w+))?/g)) if (PINS[name]) locals.set(alias ?? name, name);
|
|
394
|
+
}
|
|
395
|
+
for (const [local, name] of locals) {
|
|
396
|
+
for (const m of src.matchAll(new RegExp(`<${local}(?![\\w.$-])`, 'g'))) {
|
|
397
|
+
const at = m.index + m[0].length;
|
|
398
|
+
const tag = readTag(src, at);
|
|
399
|
+
const report = (message) => items.push({ line: src.slice(0, m.index).split('\n').length, rule: 'keep-5-defaults', message });
|
|
400
|
+
if (!tag) { report(`<${local}>: could not parse the tag; check its 6.0 defaults by hand`); continue; }
|
|
401
|
+
const pin = PINS[name](Object.fromEntries(tag.attrs.map((a) => [a.name, a])));
|
|
402
|
+
if (!pin) continue;
|
|
403
|
+
if (src.slice(at, tag.end).includes('{...')) { report(`<${local} {...spread}>: add${pin} unless the spread sets it`); continue; }
|
|
404
|
+
edits.push({ at, text: pin });
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
let output = src;
|
|
408
|
+
for (const e of edits.sort((a, b) => b.at - a.at)) output = output.slice(0, e.at) + e.text + output.slice(e.at);
|
|
409
|
+
return { output, items };
|
|
410
|
+
}
|
|
411
|
+
|
|
376
412
|
// ─── per-file migration ──────────────────────────────────────────────────────
|
|
377
413
|
/**
|
|
378
414
|
* Migrate one file's text. Returns { output, manual: [{ line, rule, message }] }.
|
|
379
415
|
* opts: { ext, rules: Set, fix: boolean, aliasMap: { aliases, mix } }
|
|
380
416
|
*/
|
|
381
|
-
export function migrateSource(src, { ext, rules = new Set(
|
|
417
|
+
export function migrateSource(src, { ext, rules = new Set(DEFAULT_RULES), fix = false, aliasMap = SNAPSHOT }) {
|
|
382
418
|
const items = [];
|
|
383
419
|
let text = src;
|
|
384
420
|
if (['logical-classes', 'tw-animate', 'opacity-modifier', 'legacy-tokens'].some((r) => rules.has(r))) {
|
|
@@ -404,6 +440,11 @@ export function migrateSource(src, { ext, rules = new Set(RULES), fix = false, a
|
|
|
404
440
|
text = r.output;
|
|
405
441
|
items.push(...r.items);
|
|
406
442
|
}
|
|
443
|
+
if (rules.has('keep-5-defaults') && COMPONENT_EXTS.has(ext) && /@nexub\/react['"/]/.test(text)) {
|
|
444
|
+
const r = pinDefaults(text);
|
|
445
|
+
text = r.output;
|
|
446
|
+
items.push(...r.items);
|
|
447
|
+
}
|
|
407
448
|
if (rules.has('tailwind-3-preset')) {
|
|
408
449
|
// Report only: moving a tailwind.config preset to CSS-first Tailwind 4 is a config change, not a rewrite.
|
|
409
450
|
for (const m of src.matchAll(/['"]@nexub\/tokens\/tailwind['"]/g))
|
|
@@ -452,7 +493,7 @@ Options:
|
|
|
452
493
|
--check exit 1 if anything fixable or reportable is found (CI)
|
|
453
494
|
--json print machine-readable results
|
|
454
495
|
--fix also rewrite opacity-modifier hits (preview, or apply with --write)
|
|
455
|
-
--rules <a,b> run only these rules (default: all)
|
|
496
|
+
--rules <a,b> run only these rules (default: all except keep-5-defaults)
|
|
456
497
|
--ignore <glob> skip paths matching glob (repeatable; supports * and **)
|
|
457
498
|
-h, --help show this help
|
|
458
499
|
|
|
@@ -471,6 +512,9 @@ Rules:
|
|
|
471
512
|
(dot and non-JSX uses reported); *Props types renamed
|
|
472
513
|
tailwind-3-preset report the Tailwind 3 preset (@nexub/tokens/tailwind), removed in 4.0;
|
|
473
514
|
use Tailwind 4 with @import "@nexub/tokens/tailwind.css"
|
|
515
|
+
keep-5-defaults opt-in: keep 5.x behaviour on 6.0 by pinning the defaults it changes:
|
|
516
|
+
<Autocomplete> gets mode="inline"; <DataTable enableRowSelection>
|
|
517
|
+
gets selectionColumn={false}
|
|
474
518
|
|
|
475
519
|
Ignored: node_modules, dist, build, .next, out, coverage, files over 1 MB.
|
|
476
520
|
Exit codes: 0 ok, 1 --check found something, 2 usage error.`;
|
|
@@ -492,7 +536,7 @@ export function run(argv, { cwd = process.cwd(), stdout = (s) => process.stdout.
|
|
|
492
536
|
}
|
|
493
537
|
const { values: o, positionals } = args;
|
|
494
538
|
if (o.help) { stdout(`${USAGE}\n`); return 0; }
|
|
495
|
-
const rules = new Set(o.rules ? o.rules.split(',').map((r) => r.trim()).filter(Boolean) :
|
|
539
|
+
const rules = new Set(o.rules ? o.rules.split(',').map((r) => r.trim()).filter(Boolean) : DEFAULT_RULES);
|
|
496
540
|
const unknown = [...rules].filter((r) => !RULES.includes(r));
|
|
497
541
|
if (unknown.length) { stderr(`Unknown rule(s): ${unknown.join(', ')}. Known: ${RULES.join(', ')}\n`); return 2; }
|
|
498
542
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexub/tokens",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.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",
|