bestax-migrate 2.29.2 → 2.31.1
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/README.md +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/sources/bulma-classes/class-map.d.ts +76 -3
- package/dist/sources/bulma-classes/class-map.d.ts.map +1 -1
- package/dist/sources/bulma-classes/class-map.js +166 -45
- package/dist/sources/bulma-classes/plan.d.ts +7 -0
- package/dist/sources/bulma-classes/plan.d.ts.map +1 -1
- package/dist/sources/bulma-classes/plan.js +153 -20
- package/dist/sources/bulma-classes/rules.d.ts.map +1 -1
- package/dist/sources/bulma-classes/rules.js +1 -0
- package/dist/sources/bulma-classes/transform.d.ts.map +1 -1
- package/dist/sources/bulma-classes/transform.js +20 -5
- package/dist/sources/react-bulma-components/mapping.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ Run it from your app root. `--param paths="src lib"` (default `src`) and `--para
|
|
|
88
88
|
| Flag | Description |
|
|
89
89
|
| -------------------- | ---------------------------------------------------------------------------------------------- |
|
|
90
90
|
| `--dry`, `-d` | Report what would change without writing files |
|
|
91
|
-
| `--print`, `-p` | Print transformed sources to stdout
|
|
91
|
+
| `--print`, `-p` | Print transformed sources to stdout, still writing them unless `--dry` is set |
|
|
92
92
|
| `--extensions`, `-e` | File extensions to include in a folder (default `js,jsx,ts,tsx,scss,sass`; `html` for pages) |
|
|
93
93
|
| `--css <mode>` | Stylesheet target: `bestax`, `bulma`, or `keep` (default `bestax`; `keep` for `bulma-classes`) |
|
|
94
94
|
| `--no-deps` | Skip updating package.json dependencies |
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAIV,eAAe,EAEhB,MAAM,YAAY,CAAC;AA2BpB;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,EAAE,CAwBV;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5D;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgDlD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBvD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAEpE;AA2QD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,KAAK,EACT,KAAK,GAAE,QAAwB,EAC/B,MAAM,GAAE,QAAyB,EAGjC,aAAa,GAAE,OAAO,eAAiC,GACtD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,EAAE,EAAE,KAAK,EACT,aAAa,GAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAA0B,GAC7E,OAAO,CAAC,IAAI,CAAC,CAqBf;AAYD,wBAAgB,SAAS,CACvB,EAAE,GAAE,KAAkD,GACrD,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAIV,eAAe,EAEhB,MAAM,YAAY,CAAC;AA2BpB;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,EAAE,CAwBV;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5D;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgDlD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBvD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAEpE;AA2QD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,KAAK,EACT,KAAK,GAAE,QAAwB,EAC/B,MAAM,GAAE,QAAyB,EAGjC,aAAa,GAAE,OAAO,eAAiC,GACtD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,EAAE,EAAE,KAAK,EACT,aAAa,GAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAA0B,GAC7E,OAAO,CAAC,IAAI,CAAC,CAqBf;AAYD,wBAAgB,SAAS,CACvB,EAAE,GAAE,KAAkD,GACrD,OAAO,CAmJT"}
|
package/dist/cli.js
CHANGED
|
@@ -524,7 +524,7 @@ export function createCLI(io = { log: console.log, error: console.error }) {
|
|
|
524
524
|
.argument('<source>', `library to migrate from (${sourceNames().join(', ')})`)
|
|
525
525
|
.argument('<paths...>', 'files or directories to transform')
|
|
526
526
|
.option('-d, --dry', 'dry run — report what would change without writing', false)
|
|
527
|
-
.option('-p, --print', 'print transformed sources to stdout', false)
|
|
527
|
+
.option('-p, --print', 'print transformed sources to stdout (still writes them unless --dry)', false)
|
|
528
528
|
.option('-e, --extensions <list>', 'comma-separated file extensions to include in a folder (html for HTML pages)', 'js,jsx,ts,tsx,scss,sass')
|
|
529
529
|
.option('--css <mode>', `stylesheet target: ${CSS_MODES.join(', ')} (default bestax; keep for bulma-classes)`)
|
|
530
530
|
.option('--no-deps', 'skip updating package.json dependencies')
|
|
@@ -52,6 +52,33 @@ export interface Modifier {
|
|
|
52
52
|
readonly name: string;
|
|
53
53
|
readonly value: string;
|
|
54
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* Off the tags in `tagIn`, where the class stays a class, the prop that
|
|
57
|
+
* sizes the element the same without picking its tag (`textSize`, whose
|
|
58
|
+
* `is-size-4` Bulma sizes as it does `Title`'s `is-4`). The MCP lookup reads
|
|
59
|
+
* it, and the truth e2e holds it to Bulma's stylesheet; the codemod writes
|
|
60
|
+
* it nowhere, with no TODO either, since its class differs.
|
|
61
|
+
*/
|
|
62
|
+
readonly offTag?: PropWrite;
|
|
63
|
+
/**
|
|
64
|
+
* Another of the root's modifiers whose prop this one writes another value
|
|
65
|
+
* of, and that value renders that modifier's class too (`Field`'s
|
|
66
|
+
* `hasAddons="centered"` renders `has-addons` beside `has-addons-centered`).
|
|
67
|
+
* The class converts only beside that one, the two as the one value, and
|
|
68
|
+
* stays a class on its own. Beside it, `tagIn` and `needsAttr` hold as they
|
|
69
|
+
* do for any modifier.
|
|
70
|
+
*/
|
|
71
|
+
readonly beside?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The tag the target renders with this class's prop and no `as`, in place
|
|
74
|
+
* of the root's `tag` (`Image` puts a ratio on a <figure>), so the element
|
|
75
|
+
* converts with `as` only on another tag. The planner's tag check, which
|
|
76
|
+
* comes before every refusal, reads it, and the render truth test holds it
|
|
77
|
+
* to one of the tags it renders the root on. Only one such class converts
|
|
78
|
+
* on an element; a second stays a class, the way a second class for a prop
|
|
79
|
+
* already written does.
|
|
80
|
+
*/
|
|
81
|
+
readonly rendersTag?: string;
|
|
55
82
|
}
|
|
56
83
|
/**
|
|
57
84
|
* - `mapped`: converts to `target`.
|
|
@@ -126,6 +153,14 @@ export interface Absorbs {
|
|
|
126
153
|
readonly to: string;
|
|
127
154
|
readonly beside: string;
|
|
128
155
|
}>>;
|
|
156
|
+
/**
|
|
157
|
+
* The bestax component that takes a `<label>` beside the child as its own
|
|
158
|
+
* `label` (`Select`, which renders a `Field` and a `Control` around the
|
|
159
|
+
* target, and so takes one only outside a `Field` or `Control`), for the
|
|
160
|
+
* TODO on an element holding one: the target renders no label, so the
|
|
161
|
+
* element stays markup.
|
|
162
|
+
*/
|
|
163
|
+
readonly label?: string;
|
|
129
164
|
}
|
|
130
165
|
/** How a target that renders a glyph from props reads one (`Icon`). */
|
|
131
166
|
export interface ReadsGlyph {
|
|
@@ -351,6 +386,14 @@ export interface RootEntry {
|
|
|
351
386
|
* no prop for them.
|
|
352
387
|
*/
|
|
353
388
|
readonly omits?: Readonly<Record<string, string>>;
|
|
389
|
+
/**
|
|
390
|
+
* How to keep this class on an element another root converts, where
|
|
391
|
+
* wrapping or nesting its component is not always the answer: `.container`
|
|
392
|
+
* there is often only centering the element, which `mx="auto"` does. For
|
|
393
|
+
* that element's TODO and the MCP lookup, which otherwise say to wrap or
|
|
394
|
+
* nest it.
|
|
395
|
+
*/
|
|
396
|
+
readonly onAnother?: string;
|
|
354
397
|
/**
|
|
355
398
|
* Bulma styles this root's modifiers, and the classes it omits, only on
|
|
356
399
|
* the element that carries the root itself (`.image.is-64x64`), so on an
|
|
@@ -358,7 +401,25 @@ export interface RootEntry {
|
|
|
358
401
|
*/
|
|
359
402
|
readonly modifiersNeedRoot?: boolean;
|
|
360
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Whether a root's target renders this tag: the one it renders by itself (or
|
|
406
|
+
* `renders`, the one the element's classes pick: a heading's size, an
|
|
407
|
+
* `Image` ratio's <figure>), or one its `as` takes. A root that doesn't loses
|
|
408
|
+
* to one that does on the same element.
|
|
409
|
+
*/
|
|
410
|
+
export declare function reachesTag(entry: RootEntry, tag: string, renders?: string): boolean;
|
|
411
|
+
/**
|
|
412
|
+
* How well a root fits an element's tag, for picking one of two: 2 when its
|
|
413
|
+
* target renders the tag with no `as` (`Hero`'s <section>, or `renders`, the
|
|
414
|
+
* tag the element's classes pick: an `Image` ratio's <figure>), 1 when it
|
|
415
|
+
* reaches it only through `as` (`Container`'s <section>), 0 when it can't
|
|
416
|
+
* render it. The higher wins, so `<section className="hero container">` is a
|
|
417
|
+
* `Hero`, and `<div className="media-left image is-1by1">` no `Image`, which
|
|
418
|
+
* that ratio puts on a <figure>.
|
|
419
|
+
*/
|
|
420
|
+
export declare function tagFit(entry: RootEntry, tag: string, renders?: string): number;
|
|
361
421
|
export declare const COLORS: readonly ["primary", "link", "info", "success", "warning", "danger", "black", "black-bis", "black-ter", "grey-darker", "grey-dark", "grey", "grey-light", "grey-lighter", "white", "white-bis", "white-ter", "light", "dark"];
|
|
422
|
+
export declare const COLOR_SHADES: readonly ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55", "60", "65", "70", "75", "80", "85", "90", "95", "invert", "light", "dark", "soft", "bold", "on-scheme"];
|
|
362
423
|
export declare const SIZES: readonly ["0", "1", "2", "3", "4", "5", "6", "auto"];
|
|
363
424
|
export declare const TEXT_SIZES: readonly ["1", "2", "3", "4", "5", "6", "7"];
|
|
364
425
|
export declare const ALIGNMENTS: readonly ["centered", "justified", "left", "right"];
|
|
@@ -391,9 +452,16 @@ export declare const ROOTS: Readonly<Record<string, RootEntry>>;
|
|
|
391
452
|
*/
|
|
392
453
|
export declare const PLACED: Readonly<Record<string, RootEntry>>;
|
|
393
454
|
/**
|
|
394
|
-
* Which root wins when an element carries two (`column box`)
|
|
395
|
-
* surface, so the element keeps the role that decides
|
|
396
|
-
*
|
|
455
|
+
* Which root wins when an element carries two (`column box`) that fit its tag
|
|
456
|
+
* alike: layout before surface, so the element keeps the role that decides
|
|
457
|
+
* where it sits. A better fit beats a higher place here (`tagFit`): `Image`
|
|
458
|
+
* takes a `<figure className="image container">`, which `Container` can't
|
|
459
|
+
* render, and `Hero` a `<section className="hero container">`, whose tag is
|
|
460
|
+
* its own and only reached through `as` by `Container`. The fit is to the
|
|
461
|
+
* tag the element's classes make a root render, so `Image` with a ratio fits
|
|
462
|
+
* a <figure> as its own and a <div> only through `as`. The other root stays
|
|
463
|
+
* in `className`, which renders the same either way, and the element gets a
|
|
464
|
+
* TODO naming its component.
|
|
397
465
|
*/
|
|
398
466
|
export declare const PRECEDENCE: readonly string[];
|
|
399
467
|
/**
|
|
@@ -445,6 +513,11 @@ export type HelperGroup = 'text-color' | 'background' | 'spacing' | 'gap' | 'typ
|
|
|
445
513
|
export interface HelperToken {
|
|
446
514
|
readonly group: HelperGroup;
|
|
447
515
|
readonly write: PropWrite;
|
|
516
|
+
/**
|
|
517
|
+
* A second prop the class needs beside `write`, which it converts only
|
|
518
|
+
* with (a color shade's `colorShade` beside its color).
|
|
519
|
+
*/
|
|
520
|
+
readonly also?: PropWrite;
|
|
448
521
|
}
|
|
449
522
|
export declare const HELPER_TOKENS: ReadonlyMap<string, HelperToken>;
|
|
450
523
|
/** Every helper prop name, for the attribute-collision check. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,MAAM,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,31 @@
|
|
|
21
21
|
export function inTagSet(set, tag) {
|
|
22
22
|
return 'on' in set ? set.on.includes(tag) : !set.except.includes(tag);
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Whether a root's target renders this tag: the one it renders by itself (or
|
|
26
|
+
* `renders`, the one the element's classes pick: a heading's size, an
|
|
27
|
+
* `Image` ratio's <figure>), or one its `as` takes. A root that doesn't loses
|
|
28
|
+
* to one that does on the same element.
|
|
29
|
+
*/
|
|
30
|
+
export function reachesTag(entry, tag, renders = entry.tag) {
|
|
31
|
+
if (tag === renders || entry.as === 'any')
|
|
32
|
+
return true;
|
|
33
|
+
return entry.as?.includes(tag) ?? false;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* How well a root fits an element's tag, for picking one of two: 2 when its
|
|
37
|
+
* target renders the tag with no `as` (`Hero`'s <section>, or `renders`, the
|
|
38
|
+
* tag the element's classes pick: an `Image` ratio's <figure>), 1 when it
|
|
39
|
+
* reaches it only through `as` (`Container`'s <section>), 0 when it can't
|
|
40
|
+
* render it. The higher wins, so `<section className="hero container">` is a
|
|
41
|
+
* `Hero`, and `<div className="media-left image is-1by1">` no `Image`, which
|
|
42
|
+
* that ratio puts on a <figure>.
|
|
43
|
+
*/
|
|
44
|
+
export function tagFit(entry, tag, renders = entry.tag) {
|
|
45
|
+
if (tag === renders)
|
|
46
|
+
return 2;
|
|
47
|
+
return reachesTag(entry, tag, renders) ? 1 : 0;
|
|
48
|
+
}
|
|
24
49
|
// ---- Value vocabularies (held to @allxsmith/bestax-bulma/constants) --------
|
|
25
50
|
export const COLORS = [
|
|
26
51
|
'primary',
|
|
@@ -43,6 +68,34 @@ export const COLORS = [
|
|
|
43
68
|
'light',
|
|
44
69
|
'dark',
|
|
45
70
|
];
|
|
71
|
+
export const COLOR_SHADES = [
|
|
72
|
+
'00',
|
|
73
|
+
'05',
|
|
74
|
+
'10',
|
|
75
|
+
'15',
|
|
76
|
+
'20',
|
|
77
|
+
'25',
|
|
78
|
+
'30',
|
|
79
|
+
'35',
|
|
80
|
+
'40',
|
|
81
|
+
'45',
|
|
82
|
+
'50',
|
|
83
|
+
'55',
|
|
84
|
+
'60',
|
|
85
|
+
'65',
|
|
86
|
+
'70',
|
|
87
|
+
'75',
|
|
88
|
+
'80',
|
|
89
|
+
'85',
|
|
90
|
+
'90',
|
|
91
|
+
'95',
|
|
92
|
+
'invert',
|
|
93
|
+
'light',
|
|
94
|
+
'dark',
|
|
95
|
+
'soft',
|
|
96
|
+
'bold',
|
|
97
|
+
'on-scheme',
|
|
98
|
+
];
|
|
46
99
|
export const SIZES = ['0', '1', '2', '3', '4', '5', '6', 'auto'];
|
|
47
100
|
export const TEXT_SIZES = ['1', '2', '3', '4', '5', '6', '7'];
|
|
48
101
|
export const ALIGNMENTS = ['centered', 'justified', 'left', 'right'];
|
|
@@ -269,6 +322,28 @@ function perViewport(prefix, values, prop, viewports) {
|
|
|
269
322
|
function flags(map) {
|
|
270
323
|
return Object.fromEntries(Object.entries(map).map(([token, prop]) => [token, flag(prop)]));
|
|
271
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* `Title`'s and `SubTitle`'s `is-1` to `is-6`: `size`, exact only on the
|
|
327
|
+
* heading it names (or a <p>), since the size picks the heading. On any
|
|
328
|
+
* other tag the class stays, and `textSize` sizes it the same.
|
|
329
|
+
*/
|
|
330
|
+
function headingSizes() {
|
|
331
|
+
return Object.fromEntries(['1', '2', '3', '4', '5', '6'].map(n => [
|
|
332
|
+
`is-${n}`,
|
|
333
|
+
{
|
|
334
|
+
writes: [{ prop: 'size', value: n }],
|
|
335
|
+
tagIn: [`h${n}`, 'p'],
|
|
336
|
+
offTag: { prop: 'textSize', value: n },
|
|
337
|
+
},
|
|
338
|
+
]));
|
|
339
|
+
}
|
|
340
|
+
/** The same modifiers, each converting only beside `other`. */
|
|
341
|
+
function beside(other, modifiers) {
|
|
342
|
+
return Object.fromEntries(Object.entries(modifiers).map(([token, modifier]) => [
|
|
343
|
+
token,
|
|
344
|
+
{ ...modifier, beside: other },
|
|
345
|
+
]));
|
|
346
|
+
}
|
|
272
347
|
const BASE = {
|
|
273
348
|
status: 'mapped',
|
|
274
349
|
textColor: 'textColor',
|
|
@@ -700,6 +775,9 @@ export const ROOTS = {
|
|
|
700
775
|
'breakpoint',
|
|
701
776
|
'isMax',
|
|
702
777
|
],
|
|
778
|
+
// On another root's element it is often there only to center it (a sized
|
|
779
|
+
// `.image`), which `mx="auto"` does and nothing else `.container` sets.
|
|
780
|
+
onAnother: 'where it is only there to center this element, `mx="auto"` centers it, and otherwise wrap the element in a `Container`; either way drop the class, then check the layout',
|
|
703
781
|
},
|
|
704
782
|
content: {
|
|
705
783
|
...BASE,
|
|
@@ -743,8 +821,6 @@ export const ROOTS = {
|
|
|
743
821
|
...BASE,
|
|
744
822
|
target: 'Field',
|
|
745
823
|
tag: 'div',
|
|
746
|
-
// `has-addons-centered`, `is-grouped-right` and the like stay classes:
|
|
747
|
-
// the prop values that render them render `has-addons` too.
|
|
748
824
|
modifiers: {
|
|
749
825
|
...flags({
|
|
750
826
|
'is-horizontal': 'horizontal',
|
|
@@ -754,6 +830,11 @@ export const ROOTS = {
|
|
|
754
830
|
// `grouped` renders `is-grouped` for `true` and its three layouts, and
|
|
755
831
|
// for nothing else truthy.
|
|
756
832
|
'is-grouped': { writes: [{ prop: 'grouped' }], onlyTrue: true },
|
|
833
|
+
// The prop values that render `has-addons-centered`, `is-grouped-right`
|
|
834
|
+
// and the like render `has-addons` or `is-grouped` too, so each converts
|
|
835
|
+
// only beside that class, and stays a class on its own.
|
|
836
|
+
...beside('has-addons', tokens('has-addons-', ['centered', 'right'], 'hasAddons')),
|
|
837
|
+
...beside('is-grouped', tokens('is-grouped-', ['centered', 'right', 'multiline'], 'grouped')),
|
|
757
838
|
},
|
|
758
839
|
wrapsChildren: {
|
|
759
840
|
in: 'field-body',
|
|
@@ -941,6 +1022,7 @@ export const ROOTS = {
|
|
|
941
1022
|
}),
|
|
942
1023
|
pairs: { multiple: 'is-multiple' },
|
|
943
1024
|
renames: { size: { to: 'multipleSize', beside: 'multiple' } },
|
|
1025
|
+
label: 'Select',
|
|
944
1026
|
},
|
|
945
1027
|
numberAttrs: ['multipleSize'],
|
|
946
1028
|
adoptsIdFrom: ['Field'],
|
|
@@ -1198,10 +1280,7 @@ export const ROOTS = {
|
|
|
1198
1280
|
as: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'],
|
|
1199
1281
|
sizeDrivesTag: true,
|
|
1200
1282
|
modifiers: {
|
|
1201
|
-
...
|
|
1202
|
-
`is-${n}`,
|
|
1203
|
-
{ writes: [{ prop: 'size', value: n }], tagIn: [`h${n}`, 'p'] },
|
|
1204
|
-
])),
|
|
1283
|
+
...headingSizes(),
|
|
1205
1284
|
...flags({ 'has-skeleton': 'hasSkeleton' }),
|
|
1206
1285
|
},
|
|
1207
1286
|
ownProps: ['size', 'as', 'hasSkeleton', 'textColor', 'bgColor'],
|
|
@@ -1280,10 +1359,7 @@ export const ROOTS = {
|
|
|
1280
1359
|
as: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'],
|
|
1281
1360
|
sizeDrivesTag: true,
|
|
1282
1361
|
modifiers: {
|
|
1283
|
-
...
|
|
1284
|
-
`is-${n}`,
|
|
1285
|
-
{ writes: [{ prop: 'size', value: n }], tagIn: [`h${n}`, 'p'] },
|
|
1286
|
-
])),
|
|
1362
|
+
...headingSizes(),
|
|
1287
1363
|
...flags({ 'is-spaced': 'isSpaced', 'has-skeleton': 'hasSkeleton' }),
|
|
1288
1364
|
},
|
|
1289
1365
|
ownProps: ['size', 'isSpaced', 'as', 'hasSkeleton', 'textColor', 'bgColor'],
|
|
@@ -1442,42 +1518,45 @@ export const ROOTS = {
|
|
|
1442
1518
|
ownProps: ['textColor', 'bgColor', 'color', 'iconProps', 'items'],
|
|
1443
1519
|
},
|
|
1444
1520
|
// `Image` renders `.image` and the `<img>` inside it together, from `src`
|
|
1445
|
-
// and `alt`. A ratio
|
|
1521
|
+
// and `alt`. A ratio as `size` puts it on a <figure> unless `as` says
|
|
1522
|
+
// otherwise.
|
|
1446
1523
|
image: {
|
|
1447
1524
|
...BASE,
|
|
1448
1525
|
target: 'Image',
|
|
1449
1526
|
tag: 'div',
|
|
1450
1527
|
as: ['div', 'figure', 'p'],
|
|
1451
|
-
modifiers:
|
|
1452
|
-
'
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1528
|
+
modifiers: {
|
|
1529
|
+
...tokens('is-', [
|
|
1530
|
+
'16x16',
|
|
1531
|
+
'24x24',
|
|
1532
|
+
'32x32',
|
|
1533
|
+
'48x48',
|
|
1534
|
+
'64x64',
|
|
1535
|
+
'96x96',
|
|
1536
|
+
'128x128',
|
|
1537
|
+
'square',
|
|
1538
|
+
], 'size'),
|
|
1539
|
+
...Object.fromEntries([
|
|
1540
|
+
'1by1',
|
|
1541
|
+
'5by4',
|
|
1542
|
+
'4by3',
|
|
1543
|
+
'3by2',
|
|
1544
|
+
'5by3',
|
|
1545
|
+
'16by9',
|
|
1546
|
+
'2by1',
|
|
1547
|
+
'3by1',
|
|
1548
|
+
'4by5',
|
|
1549
|
+
'3by4',
|
|
1550
|
+
'2by3',
|
|
1551
|
+
'3by5',
|
|
1552
|
+
'9by16',
|
|
1553
|
+
'1by2',
|
|
1554
|
+
'1by3',
|
|
1555
|
+
].map(ratio => [
|
|
1556
|
+
`is-${ratio}`,
|
|
1557
|
+
{ ...set('size', ratio), rendersTag: 'figure' },
|
|
1558
|
+
])),
|
|
1559
|
+
},
|
|
1481
1560
|
modifiersNeedRoot: true,
|
|
1482
1561
|
absorbs: {
|
|
1483
1562
|
tag: 'img',
|
|
@@ -1910,9 +1989,16 @@ export const PLACED = {
|
|
|
1910
1989
|
},
|
|
1911
1990
|
};
|
|
1912
1991
|
/**
|
|
1913
|
-
* Which root wins when an element carries two (`column box`)
|
|
1914
|
-
* surface, so the element keeps the role that decides
|
|
1915
|
-
*
|
|
1992
|
+
* Which root wins when an element carries two (`column box`) that fit its tag
|
|
1993
|
+
* alike: layout before surface, so the element keeps the role that decides
|
|
1994
|
+
* where it sits. A better fit beats a higher place here (`tagFit`): `Image`
|
|
1995
|
+
* takes a `<figure className="image container">`, which `Container` can't
|
|
1996
|
+
* render, and `Hero` a `<section className="hero container">`, whose tag is
|
|
1997
|
+
* its own and only reached through `as` by `Container`. The fit is to the
|
|
1998
|
+
* tag the element's classes make a root render, so `Image` with a ratio fits
|
|
1999
|
+
* a <figure> as its own and a <div> only through `as`. The other root stays
|
|
2000
|
+
* in `className`, which renders the same either way, and the element gets a
|
|
2001
|
+
* TODO naming its component.
|
|
1916
2002
|
*/
|
|
1917
2003
|
export const PRECEDENCE = [
|
|
1918
2004
|
'columns',
|
|
@@ -2077,6 +2163,39 @@ function helperFlag(group, token, prop) {
|
|
|
2077
2163
|
}
|
|
2078
2164
|
/** The color helpers also take the two CSS keywords. */
|
|
2079
2165
|
const HELPER_COLORS = [...COLORS, 'inherit', 'current'];
|
|
2166
|
+
/**
|
|
2167
|
+
* The colors Bulma writes shade helpers for: its own palette, but `text`,
|
|
2168
|
+
* which bestax's color props don't take.
|
|
2169
|
+
*/
|
|
2170
|
+
const SHADED_COLORS = [
|
|
2171
|
+
'primary',
|
|
2172
|
+
'link',
|
|
2173
|
+
'info',
|
|
2174
|
+
'success',
|
|
2175
|
+
'warning',
|
|
2176
|
+
'danger',
|
|
2177
|
+
'black',
|
|
2178
|
+
'white',
|
|
2179
|
+
'light',
|
|
2180
|
+
'dark',
|
|
2181
|
+
];
|
|
2182
|
+
/**
|
|
2183
|
+
* `has-text-{color}-{shade}` → the color prop and `colorShade`, which render
|
|
2184
|
+
* it together; `has-background-…` the same with `backgroundColorShade`. The
|
|
2185
|
+
* color prop is a placeholder the planner swaps for the target's own, as for
|
|
2186
|
+
* the plain color helpers. A class with no single shade to write (`-100`,
|
|
2187
|
+
* `-30-invert`) is not one of these, and stays a class.
|
|
2188
|
+
*/
|
|
2189
|
+
function shadeTokens(group, prefix, prop, shadeProp) {
|
|
2190
|
+
return SHADED_COLORS.flatMap(color => COLOR_SHADES.map((shade) => [
|
|
2191
|
+
`${prefix}${color}-${shade}`,
|
|
2192
|
+
{
|
|
2193
|
+
group,
|
|
2194
|
+
write: { prop, value: color },
|
|
2195
|
+
also: { prop: shadeProp, value: shade },
|
|
2196
|
+
},
|
|
2197
|
+
]));
|
|
2198
|
+
}
|
|
2080
2199
|
const SPACING_PROPS = [
|
|
2081
2200
|
'm',
|
|
2082
2201
|
'mt',
|
|
@@ -2097,6 +2216,8 @@ export const HELPER_TOKENS = new Map([
|
|
|
2097
2216
|
// Colors: the prop is a placeholder the planner swaps for the target's own.
|
|
2098
2217
|
...helperTokens('text-color', 'has-text-', HELPER_COLORS, 'textColor'),
|
|
2099
2218
|
...helperTokens('background', 'has-background-', HELPER_COLORS, 'bgColor'),
|
|
2219
|
+
...shadeTokens('text-color', 'has-text-', 'textColor', 'colorShade'),
|
|
2220
|
+
...shadeTokens('background', 'has-background-', 'bgColor', 'backgroundColorShade'),
|
|
2100
2221
|
...SPACING_PROPS.flatMap(prop => helperTokens('spacing', `${prop}-`, SIZES, prop)),
|
|
2101
2222
|
// Bulma 0.9's, as the v1 helper that replaced each (`REPLACED_IN_V1`).
|
|
2102
2223
|
['is-marginless', { group: 'spacing', write: { prop: 'm', value: '0' } }],
|
|
@@ -2179,7 +2300,7 @@ export const HELPER_PROPS = new Set([
|
|
|
2179
2300
|
*/
|
|
2180
2301
|
export const PASSTHROUGH = [
|
|
2181
2302
|
{
|
|
2182
|
-
why: 'a color shade, a scheme color or a palette
|
|
2303
|
+
why: 'a color shade with no single shade for `colorShade` or `backgroundColorShade` to write (`-100`, or one with `-invert` on the end), a shade of the `text` color, a scheme color or a palette',
|
|
2183
2304
|
match: /^(?:has-(?:text|background)-[a-z]+(?:-[a-z]+)?-(?:\d{2,3}|invert|light|dark|soft|bold|on-scheme)(?:-invert)?|has-(?:text|background)-text|has-background|is-palette-[a-z]+|is-(?:bold|soft))$/,
|
|
2184
2305
|
},
|
|
2185
2306
|
{
|
|
@@ -63,6 +63,13 @@ export interface ElementFacts {
|
|
|
63
63
|
* component). What an entry that `countsChildren` reads.
|
|
64
64
|
*/
|
|
65
65
|
childElements?: readonly ChildFacts[];
|
|
66
|
+
/**
|
|
67
|
+
* The element's children as plain HTML elements, read as `childElements`
|
|
68
|
+
* is, when nothing else beside them renders but spaces (`{" "}` between
|
|
69
|
+
* them); left out when `childElements` is there. What the TODO on an
|
|
70
|
+
* element holding a <label> beside the child its target renders reads.
|
|
71
|
+
*/
|
|
72
|
+
spacedElements?: readonly ChildFacts[];
|
|
66
73
|
/** The bestax components already in the file inside this element. */
|
|
67
74
|
bestaxInside?: readonly string[];
|
|
68
75
|
/** The bestax components already in the file around this element. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* way. And a Bulma 0.9 helper v1 removed (`REPLACED_IN_V1`), which styles
|
|
15
15
|
* nothing under v1, converts as the v1 helper that does its job.
|
|
16
16
|
*/
|
|
17
|
-
import { FORWARDS_REF, HELPER_PROPS, HELPER_TOKENS, inTagSet, legacyHint, modifierFor, modifiesRoot, numberAttrsOf, placedFor, PRECEDENCE, replacedBy, rootFor, rootItNeeds, WRAPPER_OWN_PROPS, wrapperFor, } from './class-map.js';
|
|
17
|
+
import { FORWARDS_REF, HELPER_PROPS, HELPER_TOKENS, inTagSet, legacyHint, modifierFor, modifiesRoot, numberAttrsOf, placedFor, PRECEDENCE, reachesTag, replacedBy, rootFor, rootItNeeds, tagFit, WRAPPER_OWN_PROPS, wrapperFor, } from './class-map.js';
|
|
18
18
|
import { glyphProps, readDrawnGlyph, readGlyph, readHiddenGlyph, } from './glyph.js';
|
|
19
19
|
import { aTag } from '../_shared/articles.js';
|
|
20
20
|
import { ruleId } from './rules.js';
|
|
@@ -54,13 +54,6 @@ function precedence(token) {
|
|
|
54
54
|
function rootLabel(tokens) {
|
|
55
55
|
return tokens.find(token => rootFor(token)?.status === 'mapped') ?? 'button';
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Whether the target renders this tag: the one it renders by itself (or the
|
|
59
|
-
* heading its size picks), or one its `as` takes.
|
|
60
|
-
*/
|
|
61
|
-
function reachesTag(entry, tag, renders = entry.tag) {
|
|
62
|
-
return (tag === renders || entry.as === 'any' || (entry.as?.includes(tag) ?? false));
|
|
63
|
-
}
|
|
64
57
|
function tagsItReaches(entry) {
|
|
65
58
|
if (entry.as === 'any')
|
|
66
59
|
return 'any tag through `as`';
|
|
@@ -68,6 +61,50 @@ function tagsItReaches(entry) {
|
|
|
68
61
|
return entry.as.map(tag => `<${tag}>`).join(', ');
|
|
69
62
|
return `only <${entry.tag}>`;
|
|
70
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* A TODO for each other component class on an element that converts
|
|
66
|
+
* (`columns box`). The class stays in `className`, which renders the same,
|
|
67
|
+
* but on a bestax component it is raw Bulma markup the lint rule reports, so
|
|
68
|
+
* each says which root won and why, and how to keep what the class does.
|
|
69
|
+
* `rendered` holds the tag the element's classes make each root's target
|
|
70
|
+
* render with no `as`, for the roots the planner picked from.
|
|
71
|
+
*/
|
|
72
|
+
function secondComponents(carried, fixed, root, target, tag, rendered) {
|
|
73
|
+
return carried.flatMap(token => {
|
|
74
|
+
const other = rootFor(token);
|
|
75
|
+
if (token === root || other?.status !== 'mapped')
|
|
76
|
+
return [];
|
|
77
|
+
const name = other.target;
|
|
78
|
+
if (name === target)
|
|
79
|
+
return [];
|
|
80
|
+
const fitsBetter = root !== undefined &&
|
|
81
|
+
tagFit(rootFor(root), tag, rendered.get(root)) >
|
|
82
|
+
tagFit(other, tag, rendered.get(token));
|
|
83
|
+
// The tag is the target's own, or one the element's classes pick.
|
|
84
|
+
const fits = root !== undefined && rootFor(root).tag === tag
|
|
85
|
+
? `${aTag(tag)} is \`${target}\`'s own element`
|
|
86
|
+
: `\`${target}\` renders ${aTag(tag)} with these classes and no \`as\``;
|
|
87
|
+
const why = !fixed.includes(token)
|
|
88
|
+
? `since \`.${token}\` is there only when its condition holds, and the codemod picks from the classes the element always carries`
|
|
89
|
+
: root === undefined
|
|
90
|
+
? 'since an item of a list converts by where it sits'
|
|
91
|
+
: !reachesTag(other, tag, rendered.get(token))
|
|
92
|
+
? `since \`${name}\` renders ${tagsItReaches(other)}, not ${aTag(tag)}`
|
|
93
|
+
: fitsBetter
|
|
94
|
+
? `since ${fits}, and \`${name}\` renders one only through \`as\``
|
|
95
|
+
: precedence(root) < precedence(token)
|
|
96
|
+
? `since the codemod ranks \`.${root}\` first, putting layout and parts ahead of surfaces`
|
|
97
|
+
: `since \`.${root}\` comes first on the element`;
|
|
98
|
+
const advice = other.onAnother ??
|
|
99
|
+
`to use \`${name}\`, give it an element of its own around or inside this one and drop the class, then check the layout, since two elements space differently from one`;
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
rule: ruleId('second-component', name),
|
|
103
|
+
message: `\`.${token}\` is bestax \`${name}\`'s class too, and an element converts to one component: \`${target}\` here, ${why}, so \`.${token}\` stays in its \`className\`, which renders the same; ${advice}`,
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
});
|
|
107
|
+
}
|
|
71
108
|
/**
|
|
72
109
|
* Every class the element may carry: its fixed ones, and any a condition
|
|
73
110
|
* adds, which the element has to be right with as well as without.
|
|
@@ -151,11 +188,21 @@ function planElement(facts) {
|
|
|
151
188
|
: tokens.find(token => rootFor(token)?.status === 'fold');
|
|
152
189
|
if (wrapper)
|
|
153
190
|
return planFold(facts, wrapper, todos);
|
|
154
|
-
|
|
155
|
-
|
|
191
|
+
// Of two roots, the one that fits the element's tag best wins (the tag the
|
|
192
|
+
// element's classes make its target render with no `as`, then one `as`
|
|
193
|
+
// reaches), and the table's precedence decides a tie. So an `Image` ratio,
|
|
194
|
+
// which puts it on a <figure>, fits a <div> only through `as`.
|
|
195
|
+
const roots = placed
|
|
196
|
+
? []
|
|
156
197
|
: tokens
|
|
157
198
|
.filter(token => rootFor(token)?.status === 'mapped')
|
|
158
|
-
.sort((a, b) => precedence(a) - precedence(b))
|
|
199
|
+
.sort((a, b) => precedence(a) - precedence(b));
|
|
200
|
+
const rendered = new Map(roots.map(token => [
|
|
201
|
+
token,
|
|
202
|
+
rendersWith(rootFor(token), tokens, tag, token, facts.attributes),
|
|
203
|
+
]));
|
|
204
|
+
const fit = (token) => tagFit(rootFor(token), tag, rendered.get(token));
|
|
205
|
+
const root = roots.reduce((best, token) => best === undefined || fit(token) > fit(best) ? token : best, undefined);
|
|
159
206
|
let entry;
|
|
160
207
|
if (placed) {
|
|
161
208
|
entry = placed;
|
|
@@ -189,12 +236,10 @@ function planElement(facts) {
|
|
|
189
236
|
// On a tag the target can't render, the tag is the work that comes first:
|
|
190
237
|
// any other refusal would ask for work (an attribute added or dropped, a
|
|
191
238
|
// child moved) that a re-run then refuses on the tag anyway.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
renders = `h${size}`;
|
|
197
|
-
}
|
|
239
|
+
// What the classes write picks the tag the target renders with no `as`
|
|
240
|
+
// (`rendersWith`), as it did when the root was picked.
|
|
241
|
+
const renders = (root && rendered.get(root)) ??
|
|
242
|
+
rendersWith(entry, tokens, tag, root, facts.attributes);
|
|
198
243
|
let as;
|
|
199
244
|
if (renders !== tag) {
|
|
200
245
|
if (!reachesTag(entry, tag, renders)) {
|
|
@@ -517,6 +562,7 @@ function planElement(facts) {
|
|
|
517
562
|
if (entry.classNameReplaces && (rest.length > 0 || conditionalStays)) {
|
|
518
563
|
return refuse('attr', 'className', `bestax \`${target}\` writes a \`className\` it's given in place of \`.${root}\`, so this converts only with no other class; keep it as markup`);
|
|
519
564
|
}
|
|
565
|
+
todos.push(...secondComponents(carried, tokens, root, target, tag, rendered));
|
|
520
566
|
// A glyph the target renders from props takes the place of the only child.
|
|
521
567
|
const glyph = moved ?? (entry.readsGlyph ? readGlyph(facts.soleChild) : undefined);
|
|
522
568
|
return {
|
|
@@ -831,6 +877,7 @@ function buildIcons(children, target) {
|
|
|
831
877
|
*/
|
|
832
878
|
function propsFrom(entry, tokens, tag, root, attributes) {
|
|
833
879
|
const numbers = [];
|
|
880
|
+
let rendersTag;
|
|
834
881
|
// What the root itself needs comes first, so no class can take its prop.
|
|
835
882
|
const writes = new Map((entry.writes ?? []).map(write => [write.prop, write.value ?? true]));
|
|
836
883
|
/** The tokens each written prop came from, so a group rule can undo it. */
|
|
@@ -841,11 +888,24 @@ function propsFrom(entry, tokens, tag, root, attributes) {
|
|
|
841
888
|
...tokens.filter(token => !replacedBy(token)),
|
|
842
889
|
...tokens.filter(token => replacedBy(token)),
|
|
843
890
|
];
|
|
844
|
-
|
|
891
|
+
// A class that converts only beside another (`has-addons-centered`) goes
|
|
892
|
+
// first, so the value it writes takes the prop ahead of that one's flag and
|
|
893
|
+
// renders both classes. On its own it stays a class. Neither is ever a
|
|
894
|
+
// removed class, so the two orders compose.
|
|
895
|
+
const paired = (token) => {
|
|
896
|
+
const other = modifierFor(entry, token)?.beside;
|
|
897
|
+
return other !== undefined && tokens.includes(other);
|
|
898
|
+
};
|
|
899
|
+
for (const token of [
|
|
900
|
+
...claiming.filter(paired),
|
|
901
|
+
...claiming.filter(token => !paired(token)),
|
|
902
|
+
]) {
|
|
845
903
|
if (converted.has(token))
|
|
846
904
|
continue;
|
|
847
905
|
const modifier = modifierFor(entry, token);
|
|
848
906
|
if (modifier) {
|
|
907
|
+
if (modifier.beside && !paired(token))
|
|
908
|
+
continue;
|
|
849
909
|
if (modifier.tagIn && !modifier.tagIn.includes(tag))
|
|
850
910
|
continue;
|
|
851
911
|
if (modifier.needsAttr && !attributes.has(modifier.needsAttr.name)) {
|
|
@@ -853,13 +913,20 @@ function propsFrom(entry, tokens, tag, root, attributes) {
|
|
|
853
913
|
}
|
|
854
914
|
if (modifier.writes.some(write => writes.has(write.prop)))
|
|
855
915
|
continue;
|
|
916
|
+
// Only one class picks the tag, as only one sets a prop: a second one
|
|
917
|
+
// stays a class, the way a second size does.
|
|
918
|
+
if (modifier.rendersTag && rendersTag)
|
|
919
|
+
continue;
|
|
856
920
|
for (const write of modifier.writes) {
|
|
857
921
|
writes.set(write.prop, write.value ?? true);
|
|
858
922
|
sourceOf.set(write.prop, token);
|
|
859
923
|
if (write.numeric)
|
|
860
924
|
numbers.push(write.prop);
|
|
861
925
|
}
|
|
926
|
+
rendersTag ??= modifier.rendersTag;
|
|
862
927
|
converted.add(token);
|
|
928
|
+
if (modifier.beside)
|
|
929
|
+
converted.add(modifier.beside);
|
|
863
930
|
continue;
|
|
864
931
|
}
|
|
865
932
|
const helper = entry.noHelpers ? undefined : HELPER_TOKENS.get(token);
|
|
@@ -875,9 +942,17 @@ function propsFrom(entry, tokens, tag, root, attributes) {
|
|
|
875
942
|
if (entry.helpersLeftOut && Object.hasOwn(entry.helpersLeftOut, prop)) {
|
|
876
943
|
continue;
|
|
877
944
|
}
|
|
945
|
+
// A shade renders its class only together with its color, so it
|
|
946
|
+
// converts only when both props are free: a shade beside a color or
|
|
947
|
+
// shade already written stays a class.
|
|
948
|
+
const also = helper.also;
|
|
949
|
+
if (also && writes.has(also.prop))
|
|
950
|
+
continue;
|
|
878
951
|
writes.set(prop, helper.write.value ?? true);
|
|
879
952
|
sourceOf.set(prop, token);
|
|
880
953
|
groupOf.set(prop, helper.group);
|
|
954
|
+
if (also)
|
|
955
|
+
writes.set(also.prop, also.value ?? true);
|
|
881
956
|
converted.add(token);
|
|
882
957
|
}
|
|
883
958
|
const undo = (prop) => {
|
|
@@ -910,7 +985,65 @@ function propsFrom(entry, tokens, tag, root, attributes) {
|
|
|
910
985
|
(groupOf.has('overflowX') || groupOf.has('overflowY'))) {
|
|
911
986
|
undo('overflow');
|
|
912
987
|
}
|
|
913
|
-
return { writes, converted, numbers };
|
|
988
|
+
return { writes, converted, numbers, rendersTag };
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* The tag a root's target renders with the element's classes and no `as`,
|
|
992
|
+
* from what `propsFrom` takes them as: the one class with a `rendersTag`
|
|
993
|
+
* (`Image`'s ratio) its tag, else the heading Title's `size` names, which
|
|
994
|
+
* only `as="p"` overrides, else the root's own.
|
|
995
|
+
*/
|
|
996
|
+
function rendersWith(entry, tokens, tag, root, attributes) {
|
|
997
|
+
const picked = propsFrom(entry, tokens, tag, root, attributes);
|
|
998
|
+
if (picked.rendersTag)
|
|
999
|
+
return picked.rendersTag;
|
|
1000
|
+
const size = picked.writes.get('size');
|
|
1001
|
+
return entry.sizeDrivesTag && tag !== 'p' && size !== undefined
|
|
1002
|
+
? `h${size}`
|
|
1003
|
+
: entry.tag;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* For an element whose children are the child its target renders and one
|
|
1007
|
+
* <label> beside it: where the label goes instead, when the table names a
|
|
1008
|
+
* component that takes one (`Select`'s `label`). Empty otherwise.
|
|
1009
|
+
*
|
|
1010
|
+
* That component renders the label in a `Field` of its own, which it renders
|
|
1011
|
+
* only outside one: inside a `Field` it drops `label` and `labelProps`, and
|
|
1012
|
+
* inside a bare `Control` it nests a `.field` in the `.control`. So inside
|
|
1013
|
+
* either the label stays a label of the page's, moved out beside the
|
|
1014
|
+
* element, or the child takes an `aria-label` in its place.
|
|
1015
|
+
*/
|
|
1016
|
+
function labelBeside(facts, spec, where) {
|
|
1017
|
+
const children = facts.childElements ?? facts.spacedElements ?? [];
|
|
1018
|
+
const label = children.find(child => child.tag === 'label');
|
|
1019
|
+
if (!spec.label ||
|
|
1020
|
+
children.length !== 2 ||
|
|
1021
|
+
!label ||
|
|
1022
|
+
!children.some(child => child.tag === spec.tag)) {
|
|
1023
|
+
return '';
|
|
1024
|
+
}
|
|
1025
|
+
const around = (name) => facts.bestaxAround?.includes(name) ||
|
|
1026
|
+
facts.classesAround?.includes(name.toLowerCase());
|
|
1027
|
+
const inForm = around('Field')
|
|
1028
|
+
? `inside a \`Field\` bestax's \`${spec.label}\` renders no label of its own and drops \`label\` and \`labelProps\``
|
|
1029
|
+
: around('Control')
|
|
1030
|
+
? `inside a \`Control\` with no \`Field\` around it, bestax's \`${spec.label}\` renders its label in a \`.field\` of its own inside the \`.control\`, which Bulma's styles aren't written for`
|
|
1031
|
+
: undefined;
|
|
1032
|
+
if (inForm) {
|
|
1033
|
+
return `; the <label> beside it can't stay inside the ${where} that bestax renders, and ${inForm}, so move the <label> out beside ${where}, its \`htmlFor\` on the <${spec.tag}>'s \`id\`, or give the <${spec.tag}> an \`aria-label\` in its place, then re-run`;
|
|
1034
|
+
}
|
|
1035
|
+
// A computed `className` (`null`) is one the codemod can't read, and it
|
|
1036
|
+
// may be what hides the label, so it is named rather than left out. So is
|
|
1037
|
+
// a spread, which can carry a `className` of its own.
|
|
1038
|
+
const classes = label.tokens === null
|
|
1039
|
+
? ', its `className`, which is computed, as `labelProps={{ className: … }}` with the same expression'
|
|
1040
|
+
: label.tokens?.length
|
|
1041
|
+
? `, its classes as \`labelProps={{ className: '${label.tokens.join(' ')}' }}\``
|
|
1042
|
+
: '';
|
|
1043
|
+
const spread = label.hasSpread
|
|
1044
|
+
? ', what its spread carries in `labelProps` too, since it can set a `className` of its own'
|
|
1045
|
+
: '';
|
|
1046
|
+
return `; the <label> beside it goes on bestax's \`${spec.label}\` instead, which renders ${where} inside a \`Field\` and a \`Control\`: the label's text as \`label\`${classes}${spread}, and \`${spec.label}\` points the label at the <${spec.tag}>'s \`id\` itself, so convert the two by hand`;
|
|
914
1047
|
}
|
|
915
1048
|
/** `a`, `a or b`, `a, b or c`, each in backticks. */
|
|
916
1049
|
function orList(names, word = 'or') {
|
|
@@ -942,7 +1075,7 @@ function absorb(facts, where, entry, target, refuse) {
|
|
|
942
1075
|
(next && next.tag !== after?.tag)) {
|
|
943
1076
|
return refuse('children', target, after
|
|
944
1077
|
? `${itself}, and a \`${after.target}\` after it from among its children, so this element converts only around a single <${spec.tag}>, and at most one <${after.tag}> after it, with nothing else beside them`
|
|
945
|
-
: `${itself}, so this element converts only around a single <${spec.tag}>, with nothing else beside it`);
|
|
1078
|
+
: `${itself}, so this element converts only around a single <${spec.tag}>, with nothing else beside it${labelBeside(facts, spec, where)}`);
|
|
946
1079
|
}
|
|
947
1080
|
if (next &&
|
|
948
1081
|
(next.tokens !== undefined ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAepC,CAAC;AAqCH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AA+iCvD;;;;GAIG;AACH,eAAO,MAAM,UAAU,0DAKb,CAAC;AAGX,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CA89BpB"}
|
|
@@ -662,15 +662,25 @@ function childFacts(child) {
|
|
|
662
662
|
isEmpty: (child.children ?? []).every(dropped),
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
|
+
/** A space React renders between elements: blank text, or `{" "}`. */
|
|
666
|
+
function space(child) {
|
|
667
|
+
const blank = (text) => /^[ \t\n\r]*$/.test(text);
|
|
668
|
+
if (child.type === 'JSXText')
|
|
669
|
+
return blank(child.value);
|
|
670
|
+
return (child.type === 'JSXExpressionContainer' &&
|
|
671
|
+
child.expression?.type === 'StringLiteral' &&
|
|
672
|
+
blank(child.expression.value));
|
|
673
|
+
}
|
|
665
674
|
/**
|
|
666
675
|
* An element's children as plain HTML elements, when that is every one
|
|
667
|
-
* React renders
|
|
668
|
-
* is known of
|
|
676
|
+
* React renders but what `skip` passes over (whitespace React drops);
|
|
677
|
+
* undefined when one is anything else. `more` adds what else is known of
|
|
678
|
+
* each.
|
|
669
679
|
*/
|
|
670
|
-
function childElementsOf(element, more = () => ({})) {
|
|
680
|
+
function childElementsOf(element, more = () => ({}), skip = dropped) {
|
|
671
681
|
const children = [];
|
|
672
682
|
for (const child of element.children ?? []) {
|
|
673
|
-
if (
|
|
683
|
+
if (skip(child))
|
|
674
684
|
continue;
|
|
675
685
|
const found = child.type === 'JSXElement' ? childFacts(child) : undefined;
|
|
676
686
|
if (!found)
|
|
@@ -1258,6 +1268,10 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
1258
1268
|
const className = classAttr ? staticClassName(classAttr) : '';
|
|
1259
1269
|
const surrounding = around(elementPath);
|
|
1260
1270
|
const sole = soleChild(element);
|
|
1271
|
+
const childElements = childElementsOf(element, readChild);
|
|
1272
|
+
const spaced = childElements
|
|
1273
|
+
? undefined
|
|
1274
|
+
: childElementsOf(element, undefined, space);
|
|
1261
1275
|
// A joiner call the codemod can read converts exactly: its fixed classes
|
|
1262
1276
|
// as for a static className, and each condition on a flag as its prop.
|
|
1263
1277
|
const joined = className === null
|
|
@@ -1275,7 +1289,8 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
1275
1289
|
childTargets: childTargets(elementPath),
|
|
1276
1290
|
soleChildTarget: planned.get(sole)?.conversion?.target,
|
|
1277
1291
|
soleChild: sole && childFacts(sole),
|
|
1278
|
-
childElements
|
|
1292
|
+
childElements,
|
|
1293
|
+
...(spaced && { spacedElements: spaced }),
|
|
1279
1294
|
bestaxInside: bestaxInside.get(element) ?? [],
|
|
1280
1295
|
bestaxAround: surrounding.bestax,
|
|
1281
1296
|
componentsAround: surrounding.other,
|
|
@@ -33,7 +33,7 @@ export const UNIVERSAL_PROPS = {
|
|
|
33
33
|
backgroundColor: { rename: 'bgColor' },
|
|
34
34
|
textColor: {},
|
|
35
35
|
colorVariant: {
|
|
36
|
-
todo: "no direct equivalent; use isLight (Button/Notification) or a color shade like
|
|
36
|
+
todo: "no direct equivalent; use isLight (Button/Notification) or a color shade like bgColor='primary' backgroundColorShade='90'",
|
|
37
37
|
},
|
|
38
38
|
// TypographyProps
|
|
39
39
|
textSize: { numberToString: true },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bestax-migrate",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.1",
|
|
4
4
|
"description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"jscodeshift": "^17.3.0",
|
|
41
41
|
"parse5": "^7.3.0",
|
|
42
42
|
"property-information": "^7.2.0",
|
|
43
|
-
"@allxsmith/bestax-bulma": "^5.
|
|
43
|
+
"@allxsmith/bestax-bulma": "^5.41.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@jest/globals": "^30.0.0",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"clean": "rimraf dist",
|
|
79
79
|
"release": "npx semantic-release"
|
|
80
80
|
},
|
|
81
|
-
"readme": "# bestax-migrate\n\n[](https://www.npmjs.com/package/bestax-migrate)\n[](https://www.npmjs.com/package/bestax-migrate)\n[](https://opensource.org/licenses/MIT)\n[](https://socket.dev/npm/package/bestax-migrate/overview)\n[](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)\n[](https://www.bestpractices.dev/projects/14361)\n[](https://www.npmjs.com/package/bestax-migrate#provenance)\n[](https://github.com/allxsmith/bestax/blob/main/SECURITY.md)\n\nCodemods that migrate existing React apps to [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) — the actively maintained React component library for **Bulma v1**.\n\nCurrently supported sources:\n\n| Source | Status |\n| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| [`react-bulma-components`](https://github.com/couds/react-bulma-components) (v4) | ✅ All 32 components mapped (a few patterns are flagged as TODOs) |\n| [`rbx`](https://github.com/dfee/rbx) (v2) | ✅ Full export surface mapped (a few patterns are flagged as TODOs) |\n| [`bloomer`](https://github.com/AlgusDark/bloomer) (0.6) | ✅ All 108 exports mapped (Font Awesome 4 icons and Bulma 0.4's `Nav` are flagged) |\n| `bulma-classes`: Bulma's classes on plain JSX, no library | ✅ Converts an element only when bestax renders the same markup; the rest is flagged |\n| `bulma-classes` on HTML: static pages and templates styled with Bulma | ✅ Writes a React component beside each page; its head and scripts are flagged |\n\nPass the source as the first argument: `bestax-migrate <source> <paths…>`.\n\n## Requirements\n\n**Node.js 22 or newer.** Node 18 and 20 are both past end-of-life. On an older runtime the CLI\nexits immediately with an explicit upgrade message.\n\nThis applies only to the Node version the codemod itself runs on. It places no requirement on\nthe app being migrated — the source is read as text and is never executed.\n\n## Usage\n\n```bash\n# Preview what would change (no writes)\npnpm dlx bestax-migrate react-bulma-components src/ --dry\n# …or, for an rbx or bloomer app\npnpm dlx bestax-migrate rbx src/ --dry\npnpm dlx bestax-migrate bloomer src/ --dry\n# …or, for an app that writes Bulma's classes on plain JSX\npnpm dlx bestax-migrate bulma-classes src/ --dry\n# …or, for static HTML pages styled with Bulma: name a page, or walk a folder with -e html\n# (-e html,htm takes .htm pages too)\npnpm dlx bestax-migrate bulma-classes src/pages/login/index.html --dry\npnpm dlx bestax-migrate bulma-classes -e html src/pages/ --dry\n\n# Apply the migration\npnpm dlx bestax-migrate react-bulma-components src/\n```\n\nnpm and yarn work too: `npx bestax-migrate …` / `yarn dlx bestax-migrate …`.\n\nThe codemod uses [jscodeshift](https://github.com/facebook/jscodeshift) to:\n\n- rewrite the source library's imports to `@allxsmith/bestax-bulma` (including destructuring and namespace imports)\n- rename components and compound sub-components (`Form.Textarea` → `TextArea`, `Card.Footer.Item` → `Card.FooterItem`, `Hero.Footer` → `Hero.Foot`, …) — and, for bloomer, its flat names onto bestax's compounds (`CardHeaderTitle` → `Card.Header.Title`)\n- convert props (`renderAs` → `as`, `loading` → `isLoading`, numeric spacing/text sizes → string unions, `textAlign=\"center\"` → `textAlign=\"centered\"`, …)\n- flatten responsive breakpoint objects (`mobile={{ size: 4 }}` → `sizeMobile={4}`) and bloomer's `isDisplay`/`isHidden` strings, arrays and objects (`isHidden=\"touch\"` → `visibilityTouch=\"hidden\"`)\n- for `bulma-classes`, turn raw Bulma markup into components and props (`<a className=\"button is-primary\">` → `<Button as=\"a\" color=\"primary\">`, `<p className=\"has-text-centered mt-4\">` → `<Paragraph textAlign=\"centered\" mt=\"4\">`), converting an element only when bestax renders exactly the same markup\n- for `bulma-classes` on an HTML page, write a React module beside it (`index.html` → `index.tsx`, or `.jsx` when the package isn't TypeScript) whose default export is the page's body as a component (`LoginPage`), converted as the same markup written as JSX would be. The page is never changed and an existing module is never overwritten; the head, the `<html>` and `<body>` attributes, the stylesheets and scripts it loads, and inline handlers are left as `html-*` TODOs, except that under `--css bestax` or `--css bulma` the module imports the stylesheet in place of the page's Bulma `<link>`\n- restructure patterns bestax models differently (`Table.Container`, Navbar dropdowns, `Form.Help`, icon-font children → `<Icon name=…>`)\n- migrate stylesheets: CSS imports converge on `@allxsmith/bestax-bulma/bestax.css`, and SCSS files move from Bulma 0.9's `@import` + `$var !default` overrides to `@use 'bulma/sass' with (…)` plus `@use '@allxsmith/bestax-bulma/scss/extras'`\n- update `package.json`: remove the source library, add `@allxsmith/bestax-bulma`, raise a declared pre-1.0 `bulma` to `^1` (adding it only when your sources import `bulma/…` directly — otherwise it arrives transitively), and swap the dead `node-sass` for dart `sass` (no install is ever run). Migrating **rbx** is what frees an app from Bulma 0.7.5: rbx pinned it as a _direct_ dependency, so the app could not choose its own Bulma version at all. The four Bulma extensions rbx also pulled in (`bulma-badge`, `bulma-divider`, `bulma-pageloader`, `bulma-tooltip`) are **reported rather than removed** — bestax replaces all four, but a manifest entry is a deliberate declaration and your own Sass may import them. A **bloomer** app declared its own Bulma 0.6, which is what gets bumped. For **bulma-classes** there is no library to remove, and by default (`--css keep`) the app's Bulma version, Sass and stylesheet imports all stay: its own Bulma already styles every class a converted element renders. `--css bestax` or `--css bulma` moves it to Bulma v1 like the other sources\n\nAnything without a safe automatic conversion is left in place with a `// TODO(bestax-migrate): …` comment, and the run ends with a report of every TODO by file and line. TODOs are expected output, not errors — resolve them with the migration guide ([react-bulma-components](https://bestax.io/docs/guides/getting-started/migration/react-bulma-components), [rbx](https://bestax.io/docs/guides/getting-started/migration/rbx), [bloomer](https://bestax.io/docs/guides/getting-started/migration/bloomer), [Bulma classes](https://bestax.io/docs/guides/getting-started/migration/bulma-classes)), or let the [`bestax-migrate` Agent Skill](https://bestax.io/docs/skills/intro) walk them for you:\n\n```bash\nnpx skills add https://github.com/allxsmith/bestax --skill bestax-migrate\n```\n\n### Through the Codemod Registry\n\nbestax-migrate is also in the [Codemod Registry](https://app.codemod.com/registry) as `bestax-migrate`, for teams that run their migrations through Codemod. That package runs this CLI from npm at a pinned release, which can trail the newest one:\n\n```bash\n# Preview (no writes)\nnpx codemod bestax-migrate --workflow preview --param source=react-bulma-components\n# Apply\nnpx codemod bestax-migrate --param source=react-bulma-components\n```\n\nRun it from your app root. `--param paths=\"src lib\"` (default `src`) and `--param options=\"--css keep\"` pass through to the CLI. Codemod's own `--dry-run` skips the shell step this package runs, so use the `preview` workflow for a dry run.\n\n## Options\n\n| Flag | Description |\n| -------------------- | ---------------------------------------------------------------------------------------------- |\n| `--dry`, `-d` | Report what would change without writing files |\n| `--print`, `-p` | Print transformed sources to stdout |\n| `--extensions`, `-e` | File extensions to include in a folder (default `js,jsx,ts,tsx,scss,sass`; `html` for pages) |\n| `--css <mode>` | Stylesheet target: `bestax`, `bulma`, or `keep` (default `bestax`; `keep` for `bulma-classes`) |\n| `--no-deps` | Skip updating package.json dependencies |\n\n## After the codemod\n\n1. Run your package manager's install (the codemod rewrote `package.json` but never installs)\n2. Search for `TODO(bestax-migrate)` and resolve each comment\n3. Typecheck/build and review the rendered app\n\nFull walkthrough: [react-bulma-components migration guide](https://bestax.io/docs/guides/getting-started/migration/react-bulma-components) · [rbx migration guide](https://bestax.io/docs/guides/getting-started/migration/rbx) · [bloomer migration guide](https://bestax.io/docs/guides/getting-started/migration/bloomer) · [Bulma classes migration guide](https://bestax.io/docs/guides/getting-started/migration/bulma-classes).\n\n## Hardened by default\n\nA codemod rewrites your source in place, so how it is built and published matters:\n\n- **Signed provenance** — every release carries a sigstore attestation linking the tarball to the exact commit and CI run that built it. Check the **Provenance** section on the [npm page](https://www.npmjs.com/package/bestax-migrate#provenance), or run `npm audit signatures`.\n- **npm OIDC trusted publishing** — short-lived, per-run credentials; no long-lived `NPM_TOKEN` exists to be stolen. Release commits and tags are GPG-signed.\n- **Socket.dev scans every PR** for malware, install scripts, obfuscated code, and privilege escalation before it can reach `main`.\n- **The libraries this tool migrates away from are never installed here** — source fixtures are read as text only, so no unmaintained third-party package enters the dependency tree.\n- **Dependencies are a deliberate act** — install scripts are blocked unless individually allow-listed, freshly published versions are refused for 3 days, and CI installs only what the reviewed lockfile resolves.\n- **Every GitHub Action is pinned to a full commit SHA**, and CodeQL, Dependency Review, and Dependabot run continuously alongside a high-severity `pnpm audit` gate.\n- **Layered AI review before merge** — [CodeRabbit](https://coderabbit.ai) plus an independent adversarial Claude review (a different model from the one writing AI-authored changes), on top of required green CI, an approving review, and a human merge.\n\nFull detail: [`SECURITY.md`](https://github.com/allxsmith/bestax/blob/main/SECURITY.md) · [Security guide](https://bestax.io/docs/guides/security)\n\n## Telemetry\n\n`bestax-migrate` can send one **anonymous** usage event after a successful\nrun — only if you opt in when asked (once, on an interactive terminal). The\nevent is just the run's shape — source library, CSS mode, the dry/deps flags, a\ncapped changed-file count, and per-rule TODO counts — plus the CLI version,\nNode major version, and OS platform name. Never file paths, file contents,\ncode, names, IPs, or machine IDs, and no identifier exists that could link two\nevents together. Opt out any time with `--no-telemetry`,\n`BESTAX_TELEMETRY=0`, or `DO_NOT_TRACK=1`.\n\nFull disclosure of every field and control: [Telemetry guide](https://bestax.io/docs/guides/telemetry)\n\n## License\n\nSource code licensed MIT\n"
|
|
81
|
+
"readme": "# bestax-migrate\n\n[](https://www.npmjs.com/package/bestax-migrate)\n[](https://www.npmjs.com/package/bestax-migrate)\n[](https://opensource.org/licenses/MIT)\n[](https://socket.dev/npm/package/bestax-migrate/overview)\n[](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)\n[](https://www.bestpractices.dev/projects/14361)\n[](https://www.npmjs.com/package/bestax-migrate#provenance)\n[](https://github.com/allxsmith/bestax/blob/main/SECURITY.md)\n\nCodemods that migrate existing React apps to [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) — the actively maintained React component library for **Bulma v1**.\n\nCurrently supported sources:\n\n| Source | Status |\n| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| [`react-bulma-components`](https://github.com/couds/react-bulma-components) (v4) | ✅ All 32 components mapped (a few patterns are flagged as TODOs) |\n| [`rbx`](https://github.com/dfee/rbx) (v2) | ✅ Full export surface mapped (a few patterns are flagged as TODOs) |\n| [`bloomer`](https://github.com/AlgusDark/bloomer) (0.6) | ✅ All 108 exports mapped (Font Awesome 4 icons and Bulma 0.4's `Nav` are flagged) |\n| `bulma-classes`: Bulma's classes on plain JSX, no library | ✅ Converts an element only when bestax renders the same markup; the rest is flagged |\n| `bulma-classes` on HTML: static pages and templates styled with Bulma | ✅ Writes a React component beside each page; its head and scripts are flagged |\n\nPass the source as the first argument: `bestax-migrate <source> <paths…>`.\n\n## Requirements\n\n**Node.js 22 or newer.** Node 18 and 20 are both past end-of-life. On an older runtime the CLI\nexits immediately with an explicit upgrade message.\n\nThis applies only to the Node version the codemod itself runs on. It places no requirement on\nthe app being migrated — the source is read as text and is never executed.\n\n## Usage\n\n```bash\n# Preview what would change (no writes)\npnpm dlx bestax-migrate react-bulma-components src/ --dry\n# …or, for an rbx or bloomer app\npnpm dlx bestax-migrate rbx src/ --dry\npnpm dlx bestax-migrate bloomer src/ --dry\n# …or, for an app that writes Bulma's classes on plain JSX\npnpm dlx bestax-migrate bulma-classes src/ --dry\n# …or, for static HTML pages styled with Bulma: name a page, or walk a folder with -e html\n# (-e html,htm takes .htm pages too)\npnpm dlx bestax-migrate bulma-classes src/pages/login/index.html --dry\npnpm dlx bestax-migrate bulma-classes -e html src/pages/ --dry\n\n# Apply the migration\npnpm dlx bestax-migrate react-bulma-components src/\n```\n\nnpm and yarn work too: `npx bestax-migrate …` / `yarn dlx bestax-migrate …`.\n\nThe codemod uses [jscodeshift](https://github.com/facebook/jscodeshift) to:\n\n- rewrite the source library's imports to `@allxsmith/bestax-bulma` (including destructuring and namespace imports)\n- rename components and compound sub-components (`Form.Textarea` → `TextArea`, `Card.Footer.Item` → `Card.FooterItem`, `Hero.Footer` → `Hero.Foot`, …) — and, for bloomer, its flat names onto bestax's compounds (`CardHeaderTitle` → `Card.Header.Title`)\n- convert props (`renderAs` → `as`, `loading` → `isLoading`, numeric spacing/text sizes → string unions, `textAlign=\"center\"` → `textAlign=\"centered\"`, …)\n- flatten responsive breakpoint objects (`mobile={{ size: 4 }}` → `sizeMobile={4}`) and bloomer's `isDisplay`/`isHidden` strings, arrays and objects (`isHidden=\"touch\"` → `visibilityTouch=\"hidden\"`)\n- for `bulma-classes`, turn raw Bulma markup into components and props (`<a className=\"button is-primary\">` → `<Button as=\"a\" color=\"primary\">`, `<p className=\"has-text-centered mt-4\">` → `<Paragraph textAlign=\"centered\" mt=\"4\">`), converting an element only when bestax renders exactly the same markup\n- for `bulma-classes` on an HTML page, write a React module beside it (`index.html` → `index.tsx`, or `.jsx` when the package isn't TypeScript) whose default export is the page's body as a component (`LoginPage`), converted as the same markup written as JSX would be. The page is never changed and an existing module is never overwritten; the head, the `<html>` and `<body>` attributes, the stylesheets and scripts it loads, and inline handlers are left as `html-*` TODOs, except that under `--css bestax` or `--css bulma` the module imports the stylesheet in place of the page's Bulma `<link>`\n- restructure patterns bestax models differently (`Table.Container`, Navbar dropdowns, `Form.Help`, icon-font children → `<Icon name=…>`)\n- migrate stylesheets: CSS imports converge on `@allxsmith/bestax-bulma/bestax.css`, and SCSS files move from Bulma 0.9's `@import` + `$var !default` overrides to `@use 'bulma/sass' with (…)` plus `@use '@allxsmith/bestax-bulma/scss/extras'`\n- update `package.json`: remove the source library, add `@allxsmith/bestax-bulma`, raise a declared pre-1.0 `bulma` to `^1` (adding it only when your sources import `bulma/…` directly — otherwise it arrives transitively), and swap the dead `node-sass` for dart `sass` (no install is ever run). Migrating **rbx** is what frees an app from Bulma 0.7.5: rbx pinned it as a _direct_ dependency, so the app could not choose its own Bulma version at all. The four Bulma extensions rbx also pulled in (`bulma-badge`, `bulma-divider`, `bulma-pageloader`, `bulma-tooltip`) are **reported rather than removed** — bestax replaces all four, but a manifest entry is a deliberate declaration and your own Sass may import them. A **bloomer** app declared its own Bulma 0.6, which is what gets bumped. For **bulma-classes** there is no library to remove, and by default (`--css keep`) the app's Bulma version, Sass and stylesheet imports all stay: its own Bulma already styles every class a converted element renders. `--css bestax` or `--css bulma` moves it to Bulma v1 like the other sources\n\nAnything without a safe automatic conversion is left in place with a `// TODO(bestax-migrate): …` comment, and the run ends with a report of every TODO by file and line. TODOs are expected output, not errors — resolve them with the migration guide ([react-bulma-components](https://bestax.io/docs/guides/getting-started/migration/react-bulma-components), [rbx](https://bestax.io/docs/guides/getting-started/migration/rbx), [bloomer](https://bestax.io/docs/guides/getting-started/migration/bloomer), [Bulma classes](https://bestax.io/docs/guides/getting-started/migration/bulma-classes)), or let the [`bestax-migrate` Agent Skill](https://bestax.io/docs/skills/intro) walk them for you:\n\n```bash\nnpx skills add https://github.com/allxsmith/bestax --skill bestax-migrate\n```\n\n### Through the Codemod Registry\n\nbestax-migrate is also in the [Codemod Registry](https://app.codemod.com/registry) as `bestax-migrate`, for teams that run their migrations through Codemod. That package runs this CLI from npm at a pinned release, which can trail the newest one:\n\n```bash\n# Preview (no writes)\nnpx codemod bestax-migrate --workflow preview --param source=react-bulma-components\n# Apply\nnpx codemod bestax-migrate --param source=react-bulma-components\n```\n\nRun it from your app root. `--param paths=\"src lib\"` (default `src`) and `--param options=\"--css keep\"` pass through to the CLI. Codemod's own `--dry-run` skips the shell step this package runs, so use the `preview` workflow for a dry run.\n\n## Options\n\n| Flag | Description |\n| -------------------- | ---------------------------------------------------------------------------------------------- |\n| `--dry`, `-d` | Report what would change without writing files |\n| `--print`, `-p` | Print transformed sources to stdout, still writing them unless `--dry` is set |\n| `--extensions`, `-e` | File extensions to include in a folder (default `js,jsx,ts,tsx,scss,sass`; `html` for pages) |\n| `--css <mode>` | Stylesheet target: `bestax`, `bulma`, or `keep` (default `bestax`; `keep` for `bulma-classes`) |\n| `--no-deps` | Skip updating package.json dependencies |\n\n## After the codemod\n\n1. Run your package manager's install (the codemod rewrote `package.json` but never installs)\n2. Search for `TODO(bestax-migrate)` and resolve each comment\n3. Typecheck/build and review the rendered app\n\nFull walkthrough: [react-bulma-components migration guide](https://bestax.io/docs/guides/getting-started/migration/react-bulma-components) · [rbx migration guide](https://bestax.io/docs/guides/getting-started/migration/rbx) · [bloomer migration guide](https://bestax.io/docs/guides/getting-started/migration/bloomer) · [Bulma classes migration guide](https://bestax.io/docs/guides/getting-started/migration/bulma-classes).\n\n## Hardened by default\n\nA codemod rewrites your source in place, so how it is built and published matters:\n\n- **Signed provenance** — every release carries a sigstore attestation linking the tarball to the exact commit and CI run that built it. Check the **Provenance** section on the [npm page](https://www.npmjs.com/package/bestax-migrate#provenance), or run `npm audit signatures`.\n- **npm OIDC trusted publishing** — short-lived, per-run credentials; no long-lived `NPM_TOKEN` exists to be stolen. Release commits and tags are GPG-signed.\n- **Socket.dev scans every PR** for malware, install scripts, obfuscated code, and privilege escalation before it can reach `main`.\n- **The libraries this tool migrates away from are never installed here** — source fixtures are read as text only, so no unmaintained third-party package enters the dependency tree.\n- **Dependencies are a deliberate act** — install scripts are blocked unless individually allow-listed, freshly published versions are refused for 3 days, and CI installs only what the reviewed lockfile resolves.\n- **Every GitHub Action is pinned to a full commit SHA**, and CodeQL, Dependency Review, and Dependabot run continuously alongside a high-severity `pnpm audit` gate.\n- **Layered AI review before merge** — [CodeRabbit](https://coderabbit.ai) plus an independent adversarial Claude review (a different model from the one writing AI-authored changes), on top of required green CI, an approving review, and a human merge.\n\nFull detail: [`SECURITY.md`](https://github.com/allxsmith/bestax/blob/main/SECURITY.md) · [Security guide](https://bestax.io/docs/guides/security)\n\n## Telemetry\n\n`bestax-migrate` can send one **anonymous** usage event after a successful\nrun — only if you opt in when asked (once, on an interactive terminal). The\nevent is just the run's shape — source library, CSS mode, the dry/deps flags, a\ncapped changed-file count, and per-rule TODO counts — plus the CLI version,\nNode major version, and OS platform name. Never file paths, file contents,\ncode, names, IPs, or machine IDs, and no identifier exists that could link two\nevents together. Opt out any time with `--no-telemetry`,\n`BESTAX_TELEMETRY=0`, or `DO_NOT_TRACK=1`.\n\nFull disclosure of every field and control: [Telemetry guide](https://bestax.io/docs/guides/telemetry)\n\n## License\n\nSource code licensed MIT\n"
|
|
82
82
|
}
|