bestax-migrate 2.1.6 → 2.2.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.
Files changed (61) hide show
  1. package/README.md +13 -8
  2. package/dist/cli.d.ts +53 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +159 -9
  5. package/dist/sources/_shared/imports.d.ts +46 -0
  6. package/dist/sources/_shared/imports.d.ts.map +1 -0
  7. package/dist/sources/_shared/imports.js +152 -0
  8. package/dist/sources/{react-bulma-components → _shared}/jsx-utils.d.ts +20 -12
  9. package/dist/sources/_shared/jsx-utils.d.ts.map +1 -0
  10. package/dist/sources/{react-bulma-components → _shared}/jsx-utils.js +15 -10
  11. package/dist/sources/_shared/make-styles-transform.d.ts +37 -0
  12. package/dist/sources/_shared/make-styles-transform.d.ts.map +1 -0
  13. package/dist/sources/_shared/make-styles-transform.js +440 -0
  14. package/dist/sources/_shared/props.d.ts +20 -0
  15. package/dist/sources/_shared/props.d.ts.map +1 -0
  16. package/dist/sources/{react-bulma-components → _shared}/props.js +11 -7
  17. package/dist/sources/_shared/specials-utils.d.ts +45 -0
  18. package/dist/sources/_shared/specials-utils.d.ts.map +1 -0
  19. package/dist/sources/_shared/specials-utils.js +124 -0
  20. package/dist/sources/rbx/deps.d.ts +18 -0
  21. package/dist/sources/rbx/deps.d.ts.map +1 -0
  22. package/dist/sources/rbx/deps.js +287 -0
  23. package/dist/sources/rbx/index.d.ts +3 -0
  24. package/dist/sources/rbx/index.d.ts.map +1 -0
  25. package/dist/sources/rbx/index.js +10 -0
  26. package/dist/sources/rbx/mapping.d.ts +49 -0
  27. package/dist/sources/rbx/mapping.d.ts.map +1 -0
  28. package/dist/sources/rbx/mapping.js +924 -0
  29. package/dist/sources/rbx/responsive.d.ts +30 -0
  30. package/dist/sources/rbx/responsive.d.ts.map +1 -0
  31. package/dist/sources/rbx/responsive.js +279 -0
  32. package/dist/sources/rbx/specials.d.ts +21 -0
  33. package/dist/sources/rbx/specials.d.ts.map +1 -0
  34. package/dist/sources/rbx/specials.js +706 -0
  35. package/dist/sources/rbx/styles.d.ts +21 -0
  36. package/dist/sources/rbx/styles.d.ts.map +1 -0
  37. package/dist/sources/rbx/styles.js +29 -0
  38. package/dist/sources/rbx/transform.d.ts +25 -0
  39. package/dist/sources/rbx/transform.d.ts.map +1 -0
  40. package/dist/sources/rbx/transform.js +911 -0
  41. package/dist/sources/react-bulma-components/deps.d.ts.map +1 -1
  42. package/dist/sources/react-bulma-components/deps.js +16 -0
  43. package/dist/sources/react-bulma-components/responsive.d.ts +1 -1
  44. package/dist/sources/react-bulma-components/responsive.d.ts.map +1 -1
  45. package/dist/sources/react-bulma-components/responsive.js +1 -1
  46. package/dist/sources/react-bulma-components/specials.d.ts +3 -9
  47. package/dist/sources/react-bulma-components/specials.d.ts.map +1 -1
  48. package/dist/sources/react-bulma-components/specials.js +4 -91
  49. package/dist/sources/react-bulma-components/styles.d.ts +9 -9
  50. package/dist/sources/react-bulma-components/styles.d.ts.map +1 -1
  51. package/dist/sources/react-bulma-components/styles.js +17 -389
  52. package/dist/sources/react-bulma-components/transform.d.ts.map +1 -1
  53. package/dist/sources/react-bulma-components/transform.js +378 -101
  54. package/dist/sources/registry.d.ts.map +1 -1
  55. package/dist/sources/registry.js +2 -0
  56. package/dist/types.d.ts +8 -0
  57. package/dist/types.d.ts.map +1 -1
  58. package/package.json +8 -7
  59. package/dist/sources/react-bulma-components/jsx-utils.d.ts.map +0 -1
  60. package/dist/sources/react-bulma-components/props.d.ts +0 -15
  61. package/dist/sources/react-bulma-components/props.d.ts.map +0 -1
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Flattens rbx's breakpoint objects into bestax-bulma's flat per-viewport
3
+ * props. rbx has three distinct shapes and this module handles all of them:
4
+ *
5
+ * 1. the universal `responsive` helper prop, nested two levels deep —
6
+ * breakpoint → helper → `{ value, only }`:
7
+ * <Generic responsive={{ tablet: { display: { value: "flex" } } }} />
8
+ * → displayTablet="flex"
9
+ * 2. Column's per-breakpoint sizing props:
10
+ * <Column tablet={{ size: 6, narrow: true }} />
11
+ * → sizeTablet={6} isNarrowTablet
12
+ * 3. Column.Group's per-breakpoint gap prop:
13
+ * <Column.Group tablet={{ gapSize: 4 }} />
14
+ * → gapTablet={4}
15
+ *
16
+ * `touch` has no bestax viewport and `only` has no `-only` prop, so both get a
17
+ * TODO rather than a guess. Non-object or dynamic values get a TODO too.
18
+ *
19
+ * rbx's value unions for display/textAlign/textSize are identical to bestax's,
20
+ * so unlike the react-bulma-components flattener there is no value mapping
21
+ * here — only the shape changes.
22
+ */
23
+ import type { ASTPath } from 'jscodeshift';
24
+ import { type TransformContext } from '../_shared/jsx-utils.js';
25
+ export type ResponsiveKind = 'generic' | 'column' | 'column-group';
26
+ /** Which specials opt their element into the extra breakpoint shapes. */
27
+ export declare const RESPONSIVE_KINDS: Record<string, ResponsiveKind>;
28
+ /** Run every breakpoint pass that applies to this element. */
29
+ export declare function flattenResponsiveProps(ctx: TransformContext, path: ASTPath<any>, element: any, kind: ResponsiveKind): void;
30
+ //# sourceMappingURL=responsive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responsive.d.ts","sourceRoot":"","sources":["../../../src/sources/rbx/responsive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEnE,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAG3D,CAAC;AAwVF,8DAA8D;AAC9D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,cAAc,GACnB,IAAI,CAKN"}
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Flattens rbx's breakpoint objects into bestax-bulma's flat per-viewport
3
+ * props. rbx has three distinct shapes and this module handles all of them:
4
+ *
5
+ * 1. the universal `responsive` helper prop, nested two levels deep —
6
+ * breakpoint → helper → `{ value, only }`:
7
+ * <Generic responsive={{ tablet: { display: { value: "flex" } } }} />
8
+ * → displayTablet="flex"
9
+ * 2. Column's per-breakpoint sizing props:
10
+ * <Column tablet={{ size: 6, narrow: true }} />
11
+ * → sizeTablet={6} isNarrowTablet
12
+ * 3. Column.Group's per-breakpoint gap prop:
13
+ * <Column.Group tablet={{ gapSize: 4 }} />
14
+ * → gapTablet={4}
15
+ *
16
+ * `touch` has no bestax viewport and `only` has no `-only` prop, so both get a
17
+ * TODO rather than a guess. Non-object or dynamic values get a TODO too.
18
+ *
19
+ * rbx's value unions for display/textAlign/textSize are identical to bestax's,
20
+ * so unlike the react-bulma-components flattener there is no value mapping
21
+ * here — only the shape changes.
22
+ */
23
+ import { RESPONSIVE_BREAKPOINTS } from './mapping.js';
24
+ import { addAttr, addTodo, attributesOf, makeAttr, removeAttr, } from '../_shared/jsx-utils.js';
25
+ /** Which specials opt their element into the extra breakpoint shapes. */
26
+ export const RESPONSIVE_KINDS = {
27
+ column: 'column',
28
+ 'column-group': 'column-group',
29
+ };
30
+ function literalOf(node) {
31
+ if (!node)
32
+ return undefined;
33
+ if (node.type === 'StringLiteral')
34
+ return node.value;
35
+ if (node.type === 'NumericLiteral')
36
+ return node.value;
37
+ if (node.type === 'BooleanLiteral')
38
+ return node.value;
39
+ return undefined;
40
+ }
41
+ /**
42
+ * Reuse a value node as a JSX attribute value: a string literal can sit bare
43
+ * (`size="one-third"`), anything else needs an expression container.
44
+ */
45
+ function attrValue(j, node) {
46
+ return node?.type === 'StringLiteral'
47
+ ? j.stringLiteral(node.value)
48
+ : j.jsxExpressionContainer(node);
49
+ }
50
+ function propKey(prop) {
51
+ const key = prop.key?.name ?? prop.key?.value;
52
+ return typeof key === 'string' ? key : undefined;
53
+ }
54
+ function objectExpressionOf(value) {
55
+ return value?.type === 'JSXExpressionContainer' &&
56
+ value.expression?.type === 'ObjectExpression'
57
+ ? value.expression
58
+ : null;
59
+ }
60
+ /**
61
+ * One `{ value, only }` cell of the universal `responsive` prop. Returns the
62
+ * inner `value` node, or undefined when the cell isn't the expected shape.
63
+ * `only: true` is reported as a TODO by the caller.
64
+ */
65
+ function readCell(cell) {
66
+ const obj = cell?.type === 'ObjectExpression'
67
+ ? cell
68
+ : cell?.type === 'JSXExpressionContainer' &&
69
+ cell.expression?.type === 'ObjectExpression'
70
+ ? cell.expression
71
+ : null;
72
+ if (!obj)
73
+ return undefined;
74
+ let value;
75
+ let only = false;
76
+ for (const prop of obj.properties) {
77
+ const key = propKey(prop);
78
+ if (key === 'value') {
79
+ value = prop.value;
80
+ }
81
+ else if (key === 'only') {
82
+ // A dynamic `only` is a third state, not `false`: collapsing it to
83
+ // false silently converted `{ value: 'flex', only: cond }` into an
84
+ // unconditional `displayTablet="flex"`, dropping the conditional
85
+ // `-only` behaviour with no TODO.
86
+ const literal = literalOf(prop.value);
87
+ only = typeof literal === 'boolean' ? literal : 'dynamic';
88
+ }
89
+ }
90
+ return value === undefined ? undefined : { value, only };
91
+ }
92
+ /**
93
+ * Pass 1 — the universal `responsive={{ <breakpoint>: { … } }}` prop.
94
+ *
95
+ * The whole prop always goes, even when some cells could not be converted.
96
+ * bestax has an unrelated `responsive` prop (`'mobile' | 'narrow'`), so a
97
+ * partially-emptied rbx object left behind is not a harmless leftover — it is
98
+ * a guaranteed type error on every migrated component. Each cell that could
99
+ * not be carried over gets its own TODO naming it, which is where that
100
+ * information belongs.
101
+ */
102
+ function flattenResponsiveHelper(ctx, path, element) {
103
+ const { j } = ctx;
104
+ const attr = attributesOf(element).find((a) => a.name.name === 'responsive');
105
+ if (!attr)
106
+ return;
107
+ const objectExpr = objectExpressionOf(attr.value);
108
+ if (!objectExpr) {
109
+ // Still remove it. bestax's `responsive` is an unrelated string union
110
+ // (`'mobile' | 'narrow'`), so leaving a dynamic rbx value behind is a
111
+ // guaranteed type error, not a leftover — the same contract the
112
+ // convertible path keeps.
113
+ addTodo(ctx, path, 'responsive', 'dropped the `responsive` prop: it must be an inline object literal to flatten to bestax per-viewport props, and bestax has its own unrelated `responsive` prop, so it could not be left in place — reapply it by hand');
114
+ removeAttr(element, attr);
115
+ ctx.dirty = true;
116
+ return;
117
+ }
118
+ const remainingBreakpoints = [];
119
+ for (const bpProp of objectExpr.properties) {
120
+ const breakpoint = propKey(bpProp);
121
+ if (breakpoint === undefined || !(breakpoint in RESPONSIVE_BREAKPOINTS)) {
122
+ remainingBreakpoints.push(String(breakpoint));
123
+ addTodo(ctx, path, 'responsive', `\`responsive.${String(breakpoint)}\` is not a breakpoint bestax knows; convert it by hand`);
124
+ continue;
125
+ }
126
+ const suffix = RESPONSIVE_BREAKPOINTS[breakpoint];
127
+ if (suffix === null) {
128
+ remainingBreakpoints.push(breakpoint);
129
+ addTodo(ctx, path, 'responsive', `no bestax-bulma helper variants for the \`${breakpoint}\` breakpoint; restyle with CSS or drop it`);
130
+ continue;
131
+ }
132
+ const cells = objectExpressionOf(bpProp.value) ?? bpProp.value;
133
+ if (cells?.type !== 'ObjectExpression') {
134
+ remainingBreakpoints.push(breakpoint);
135
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}\` must be an inline object literal to flatten; convert it by hand`);
136
+ continue;
137
+ }
138
+ const remainingCells = [];
139
+ for (const cellProp of cells.properties) {
140
+ const helper = propKey(cellProp);
141
+ const cell = readCell(cellProp.value);
142
+ if (!helper || !cell) {
143
+ remainingCells.push(cellProp);
144
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}.${String(helper)}\` is not the \`{ value }\` shape rbx documents; convert it by hand`);
145
+ continue;
146
+ }
147
+ if (cell.only) {
148
+ remainingCells.push(cellProp);
149
+ addTodo(ctx, path, 'responsive', cell.only === 'dynamic'
150
+ ? `\`responsive.${breakpoint}.${helper}.only\` has a dynamic value; Bulma's \`-only\` classes have no bestax prop, so apply it with className by hand`
151
+ : `\`responsive.${breakpoint}.${helper}.only\` (Bulma's \`-only\` classes) has no bestax prop; use className`);
152
+ continue;
153
+ }
154
+ const literal = literalOf(cell.value);
155
+ if (helper === 'hide') {
156
+ if (literal === true) {
157
+ addAttr(element, makeAttr(j, `visibility${suffix}`, 'hidden'));
158
+ }
159
+ else if (literal !== false) {
160
+ remainingCells.push(cellProp);
161
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}.hide\` has a dynamic value; set \`visibility${suffix}="hidden"\` conditionally by hand`);
162
+ continue;
163
+ }
164
+ // hide: { value: false } is a no-op — drop it.
165
+ }
166
+ else if (helper === 'display' || helper === 'textAlign') {
167
+ // rbx's displays and textAlignments are bestax's unions verbatim.
168
+ if (typeof literal === 'string') {
169
+ addAttr(element, makeAttr(j, `${helper}${suffix}`, literal));
170
+ }
171
+ else {
172
+ remainingCells.push(cellProp);
173
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}.${helper}\` has a dynamic value; set \`${helper}${suffix}\` by hand`);
174
+ continue;
175
+ }
176
+ }
177
+ else if (helper === 'textSize') {
178
+ if (literal !== undefined && typeof literal !== 'boolean') {
179
+ // bestax text sizes are strings; rbx's are numbers.
180
+ addAttr(element, makeAttr(j, `textSize${suffix}`, String(literal)));
181
+ }
182
+ else {
183
+ remainingCells.push(cellProp);
184
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}.textSize\` has a dynamic value; set \`textSize${suffix}\` by hand`);
185
+ continue;
186
+ }
187
+ }
188
+ else {
189
+ remainingCells.push(cellProp);
190
+ addTodo(ctx, path, 'responsive', `\`responsive.${breakpoint}.${helper}\` could not be flattened to a bestax per-viewport prop`);
191
+ continue;
192
+ }
193
+ }
194
+ if (remainingCells.length > 0) {
195
+ remainingBreakpoints.push(breakpoint);
196
+ }
197
+ }
198
+ if (remainingBreakpoints.length > 0) {
199
+ addTodo(ctx, path, 'responsive', `dropped the \`responsive\` prop; the ${remainingBreakpoints
200
+ .map(b => `\`${b}\``)
201
+ .join(', ')} settings above could not be converted and bestax's own \`responsive\` prop is unrelated (\`'mobile' | 'narrow'\`)`);
202
+ }
203
+ removeAttr(element, attr);
204
+ ctx.dirty = true;
205
+ }
206
+ /**
207
+ * Pass 2 — Column / Column.Group per-breakpoint props, which sit directly on
208
+ * the element (`<Column tablet={{ size: 6 }} />`) rather than under
209
+ * `responsive`.
210
+ */
211
+ function flattenColumnBreakpoints(ctx, path, element, kind) {
212
+ const { j } = ctx;
213
+ for (const attr of [...attributesOf(element)]) {
214
+ const name = attr.name.name;
215
+ if (!(name in RESPONSIVE_BREAKPOINTS))
216
+ continue;
217
+ // bestax's viewport-suffixed helper props have no `touch` variant — but
218
+ // Column is the one exception: `isNarrowTouch` does exist. So the column
219
+ // pass resolves `touch` itself rather than taking the shared table's
220
+ // `null`, and only the keys that genuinely have no counterpart
221
+ // (`sizeTouch`, `offsetTouch`, `gapTouch`) become TODOs.
222
+ const suffix = name === 'touch' ? 'Touch' : RESPONSIVE_BREAKPOINTS[name];
223
+ const touchOnlyNarrow = name === 'touch';
224
+ const objectExpr = objectExpressionOf(attr.value);
225
+ if (suffix === null || !objectExpr) {
226
+ // Nothing can be salvaged from this attribute, and leaving it behind is
227
+ // not harmless: `ColumnProps` spreads unrecognised props onto the
228
+ // `<div>`, so a leftover is both a TS excess-property error and a React
229
+ // unknown-attribute warning. Drop it and say so — the same contract
230
+ // `flattenResponsiveHelper` keeps.
231
+ addTodo(ctx, path, 'responsive', objectExpr
232
+ ? `dropped \`${name}\`: bestax has no column variants for the \`${name}\` breakpoint — restyle with CSS`
233
+ : `dropped \`${name}\`: it must be an inline object literal to flatten to bestax per-viewport props — convert it by hand`);
234
+ removeAttr(element, attr);
235
+ ctx.dirty = true;
236
+ continue;
237
+ }
238
+ const unconverted = [];
239
+ for (const prop of objectExpr.properties) {
240
+ const key = propKey(prop);
241
+ const literal = literalOf(prop.value);
242
+ if (kind === 'column' &&
243
+ (key === 'size' || key === 'offset') &&
244
+ !touchOnlyNarrow) {
245
+ // Column sizes take numbers and named strings alike; reuse the node.
246
+ addAttr(element, j.jsxAttribute(j.jsxIdentifier(`${key}${suffix}`), attrValue(j, prop.value)));
247
+ }
248
+ else if (kind === 'column' && key === 'narrow') {
249
+ if (literal === true) {
250
+ addAttr(element, makeAttr(j, `isNarrow${suffix}`));
251
+ }
252
+ else if (literal !== false) {
253
+ unconverted.push(`${key} (dynamic value)`);
254
+ }
255
+ }
256
+ else if (kind === 'column-group' &&
257
+ key === 'gapSize' &&
258
+ !touchOnlyNarrow) {
259
+ // bestax `gap*` supersedes the deprecated `gapSize*`, same 0-8 scale.
260
+ addAttr(element, j.jsxAttribute(j.jsxIdentifier(`gap${suffix}`), attrValue(j, prop.value)));
261
+ }
262
+ else {
263
+ unconverted.push(String(key));
264
+ }
265
+ }
266
+ if (unconverted.length > 0) {
267
+ addTodo(ctx, path, 'responsive', `dropped \`${name}.${unconverted.join('`, `' + name + '.')}\`: no bestax per-viewport equivalent — set it by hand`);
268
+ }
269
+ removeAttr(element, attr);
270
+ ctx.dirty = true;
271
+ }
272
+ }
273
+ /** Run every breakpoint pass that applies to this element. */
274
+ export function flattenResponsiveProps(ctx, path, element, kind) {
275
+ flattenResponsiveHelper(ctx, path, element);
276
+ if (kind === 'column' || kind === 'column-group') {
277
+ flattenColumnBreakpoints(ctx, path, element, kind);
278
+ }
279
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Structural handlers for rbx → bestax conversions a rename table cannot
3
+ * express: targets chosen by a prop's value (Level.Item align, Pagination.Step
4
+ * align), container collapsing (Select.Container, Image.Container,
5
+ * Modal.Container), and replacement with plain HTML where bestax has no
6
+ * component (Heading, Help, Label, Select.Option).
7
+ *
8
+ * The two genuinely new families relative to react-bulma-components are here
9
+ * too, though they are driven from transform.ts rather than the mapping table
10
+ * because they are helper *props* that can sit on any element at all:
11
+ * `badge*` and `tooltip*` become wrapping bestax components.
12
+ *
13
+ * A handler may return a `target` override for the rename step, or mark the
14
+ * element `replaced` when it substituted the node itself.
15
+ */
16
+ import type { ASTPath } from 'jscodeshift';
17
+ import { type TransformContext } from '../_shared/jsx-utils.js';
18
+ import { type SpecialResult } from '../_shared/specials-utils.js';
19
+ export type { SpecialResult };
20
+ export declare function runSpecial(name: string, ctx: TransformContext, path: ASTPath<any>, element: any): SpecialResult;
21
+ //# sourceMappingURL=specials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specials.d.ts","sourceRoot":"","sources":["../../../src/sources/rbx/specials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAO3C,OAAO,EAYL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EAAE,aAAa,EAAE,CAAC;AAy8B9B,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,GACX,aAAa,CAIf"}