bestax-migrate 2.7.0 → 2.9.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.
@@ -16,6 +16,8 @@ export interface PropWrite {
16
16
  readonly prop: string;
17
17
  /** Omitted for a bare boolean prop. */
18
18
  readonly value?: string;
19
+ /** The prop is typed as a number, so the value is written as one. */
20
+ readonly numeric?: boolean;
19
21
  }
20
22
  export type TagSet = {
21
23
  readonly on: readonly string[];
@@ -33,8 +35,11 @@ export interface Modifier {
33
35
  * - `todo`: bestax has a component, but the markup does not map element by
34
36
  * element yet; the family's outermost class gets a TODO.
35
37
  * - `plain`: valid Bulma with nothing to convert to; left alone, no TODO.
38
+ * - `fold`: a wrapper the `target` renders itself from a prop, so the element
39
+ * folds into the one `target` inside it (`.table-container` into
40
+ * `Table isResponsive`).
36
41
  */
37
- export type RootStatus = 'mapped' | 'todo' | 'plain';
42
+ export type RootStatus = 'mapped' | 'todo' | 'plain' | 'fold';
38
43
  export interface RootEntry {
39
44
  readonly status: RootStatus;
40
45
  /**
@@ -87,6 +92,11 @@ export interface RootEntry {
87
92
  * takes a generated `id` when the element has none of its own.
88
93
  */
89
94
  readonly adoptsIdFrom?: readonly string[];
95
+ /**
96
+ * For a `fold` root: the props that render it on the target inside. Its
97
+ * modifiers add their props beside these.
98
+ */
99
+ readonly folds?: readonly PropWrite[];
90
100
  /** The target takes no helper props, so every helper class stays a class. */
91
101
  readonly noHelpers?: boolean;
92
102
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"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"}
@@ -146,6 +146,8 @@ const COMPONENT_COLORS = [
146
146
  'light',
147
147
  'dark',
148
148
  ];
149
+ /** Bulma's whole-step spacing scale, as `Grid`'s gap props take it. */
150
+ const GAPS = ['0', '1', '2', '3', '4', '5', '6', '7', '8'];
149
151
  const COLUMN_SIZES = [
150
152
  '1',
151
153
  '2',
@@ -183,6 +185,16 @@ const flag = (prop) => ({ writes: [{ prop }] });
183
185
  const set = (prop, value) => ({
184
186
  writes: [{ prop, value }],
185
187
  });
188
+ /**
189
+ * `prefix + n + suffix` → `prop={n}` for `n` from 1 to `max`, for a prop
190
+ * typed as a number.
191
+ */
192
+ function numbers(prefix, max, prop, suffix = '') {
193
+ return Object.fromEntries(Array.from({ length: max }, (_, i) => String(i + 1)).map(value => [
194
+ `${prefix}${value}${suffix}`,
195
+ { writes: [{ prop, value, numeric: true }] },
196
+ ]));
197
+ }
186
198
  /** `prefix + value + suffix` → `prop = value`, for each value. */
187
199
  function tokens(prefix, values, prop, suffix = '') {
188
200
  return Object.fromEntries(values.map(value => [`${prefix}${value}${suffix}`, set(prop, value)]));
@@ -481,6 +493,59 @@ export const ROOTS = {
481
493
  'isNarrowFullhd',
482
494
  ],
483
495
  },
496
+ // Grid's gaps take a numeric string, but its column minimum and every Cell
497
+ // placement are typed as numbers. The half steps (`is-gap-0.5`) have no prop.
498
+ grid: {
499
+ ...BASE,
500
+ target: 'Grid',
501
+ tag: 'div',
502
+ modifiers: {
503
+ ...tokens('is-gap-', GAPS, 'gap'),
504
+ ...tokens('is-column-gap-', GAPS, 'columnGap'),
505
+ ...tokens('is-row-gap-', GAPS, 'rowGap'),
506
+ ...numbers('is-col-min-', 32, 'minCol'),
507
+ },
508
+ ownProps: [
509
+ 'isFixed',
510
+ 'gap',
511
+ 'columnGap',
512
+ 'rowGap',
513
+ 'minCol',
514
+ 'fixedCols',
515
+ 'fixedColsMobile',
516
+ 'fixedColsTablet',
517
+ 'fixedColsDesktop',
518
+ 'fixedColsWidescreen',
519
+ 'fixedColsFullhd',
520
+ 'textColor',
521
+ 'color',
522
+ 'bgColor',
523
+ ],
524
+ },
525
+ cell: {
526
+ ...BASE,
527
+ target: 'Cell',
528
+ tag: 'div',
529
+ modifiers: {
530
+ ...numbers('is-col-start-', 12, 'colStart'),
531
+ ...numbers('is-col-from-end-', 12, 'colFromEnd'),
532
+ ...numbers('is-col-span-', 12, 'colSpan'),
533
+ ...numbers('is-row-start-', 12, 'rowStart'),
534
+ ...numbers('is-row-from-end-', 12, 'rowFromEnd'),
535
+ ...numbers('is-row-span-', 12, 'rowSpan'),
536
+ },
537
+ ownProps: [
538
+ 'colStart',
539
+ 'colFromEnd',
540
+ 'colSpan',
541
+ 'rowStart',
542
+ 'rowFromEnd',
543
+ 'rowSpan',
544
+ 'textColor',
545
+ 'color',
546
+ 'bgColor',
547
+ ],
548
+ },
484
549
  container: {
485
550
  ...BASE,
486
551
  target: 'Container',
@@ -1025,9 +1090,6 @@ export const ROOTS = {
1025
1090
  },
1026
1091
  // ---- Families bestax has but that do not map element by element yet ------
1027
1092
  breadcrumb: todo('Breadcrumb', 'bestax `Breadcrumb` renders the `<ul>` itself and adds an `aria-label`'),
1028
- cell: todo('Cell', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
1029
- grid: todo('Grid', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
1030
- 'fixed-grid': todo('Grid', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
1031
1093
  checkbox: todo('Checkbox', "bestax `Checkbox` renders its own styled markup, not Bulma's"),
1032
1094
  checkboxes: todo('Checkboxes', 'bestax `Checkboxes` renders its own `.field` and `.control` wrappers'),
1033
1095
  radio: todo('Radio', "bestax `Radio` renders its own styled markup, not Bulma's"),
@@ -1078,9 +1140,28 @@ export const ROOTS = {
1078
1140
  'panel-icon': part(),
1079
1141
  'panel-list': part(),
1080
1142
  tabs: todo('Tabs', "bestax `Tabs` renders each tab's `<li>` and `<a>` together, with tab roles"),
1081
- 'table-container': todo('Table', 'bestax renders `.table-container` from `Table isResponsive`'),
1082
1143
  'skeleton-block': todo('Skeleton', 'bestax `Skeleton` renders its own markup'),
1083
1144
  'skeleton-lines': todo('Skeleton', 'bestax `Skeleton` renders its own markup'),
1145
+ // ---- Wrappers a component renders from a prop ---------------------------------
1146
+ // Each renders the wrapper with its own class and nothing else, so the
1147
+ // element folds only when it carries no attribute and no other class.
1148
+ 'table-container': {
1149
+ status: 'fold',
1150
+ target: 'Table',
1151
+ tag: 'div',
1152
+ folds: [{ prop: 'isResponsive' }],
1153
+ },
1154
+ 'fixed-grid': {
1155
+ status: 'fold',
1156
+ target: 'Grid',
1157
+ tag: 'div',
1158
+ folds: [{ prop: 'isFixed' }],
1159
+ modifiers: {
1160
+ ...numbers('has-', 12, 'fixedCols', '-cols'),
1161
+ ...Object.assign({}, ...SIZE_VIEWPORTS.map(viewport => numbers('has-', 12, `fixedCols${viewportSuffix(viewport)}`, `-cols-${viewport}`))),
1162
+ 'has-auto-count': set('fixedCols', 'auto'),
1163
+ },
1164
+ },
1084
1165
  // ---- Valid Bulma, nothing to convert to --------------------------------------
1085
1166
  // The other sources emit these on purpose where bestax has no component.
1086
1167
  help: plain('bestax renders `.help` only inside its form controls'),
@@ -1113,6 +1194,8 @@ function plain(why) {
1113
1194
  export const PRECEDENCE = [
1114
1195
  'columns',
1115
1196
  'column',
1197
+ 'grid',
1198
+ 'cell',
1116
1199
  'container',
1117
1200
  'section',
1118
1201
  'hero',
@@ -1321,8 +1404,12 @@ export const PASSTHROUGH = [
1321
1404
  match: /-(?:touch|tablet-only|desktop-only|widescreen-only)$/,
1322
1405
  },
1323
1406
  {
1324
- why: 'Grid and Cell layout, which this source leaves as markup',
1325
- match: /^(?:is-(?:col|row)-.+|has-\d+-cols(?:-.+)?|is-(?:column|row)-gap-\d+|is-gap-\d+|is-auto-fill)$/,
1407
+ why: 'a Grid or Cell class, which converts only on its own `.grid` or `.cell`, and only where bestax has a prop for it',
1408
+ match: /^(?:is-(?:col|row)-.+|is-(?:column|row)-gap-\d+|is-gap-\d+|is-auto-fill)$/,
1409
+ },
1410
+ {
1411
+ why: 'a `.fixed-grid` column count, which converts only on its own `.fixed-grid`',
1412
+ match: /^(?:has-\d+-cols(?:-.+)?|has-auto-count)$/,
1326
1413
  },
1327
1414
  {
1328
1415
  why: 'an `.image` modifier; `.image` stays as markup',
@@ -1334,7 +1421,7 @@ export const PASSTHROUGH = [
1334
1421
  },
1335
1422
  {
1336
1423
  why: 'a modifier of markup this source leaves alone, or one bestax has no prop for',
1337
- match: /^(?:has-addons-.+|has-[a-z]+-separator|has-dropdown(?:-up)?|has-fixed-size|has-icons-(?:left|right)|has-name|has-(?:spaced-)?navbar-fixed-(?:top|bottom)(?:-desktop)?|has-shadow|has-auto-count|is-arrowless|is-boxed|is-center|is-current|is-delete|is-disabled|is-empty|is-expanded|is-fixed-(?:top|bottom)(?:-desktop)?|is-flexible|is-grouped(?:-.+)?|is-halfheight|is-horizontal|is-left|is-(?:lower|upper)-(?:alpha|roman)|is-multiple|is-responsive|is-selected|is-tab|is-toggle(?:-rounded)?|is-transparent|is-underlined|is-up|is-wrapped)$/,
1424
+ match: /^(?:has-addons-.+|has-[a-z]+-separator|has-dropdown(?:-up)?|has-fixed-size|has-icons-(?:left|right)|has-name|has-(?:spaced-)?navbar-fixed-(?:top|bottom)(?:-desktop)?|has-shadow|is-arrowless|is-boxed|is-center|is-current|is-delete|is-disabled|is-empty|is-expanded|is-fixed-(?:top|bottom)(?:-desktop)?|is-flexible|is-grouped(?:-.+)?|is-halfheight|is-horizontal|is-left|is-(?:lower|upper)-(?:alpha|roman)|is-multiple|is-responsive|is-selected|is-tab|is-toggle(?:-rounded)?|is-transparent|is-underlined|is-up|is-wrapped)$/,
1338
1425
  },
1339
1426
  ];
1340
1427
  /**
@@ -28,6 +28,11 @@ export interface ElementFacts {
28
28
  * counts: one in an expression may not render.
29
29
  */
30
30
  childTargets?: readonly string[];
31
+ /**
32
+ * What the element's only child converts to, when the element holds one
33
+ * element and nothing else (not even whitespace React would render).
34
+ */
35
+ soleChildTarget?: string;
31
36
  /** The bestax components already in the file inside this element. */
32
37
  bestaxInside?: readonly string[];
33
38
  /** The bestax components already in the file around this element. */
@@ -57,11 +62,23 @@ export interface Conversion {
57
62
  className: string | null;
58
63
  /** Attributes to remove: defaults the target renders by itself. */
59
64
  drop: string[];
60
- /** Attributes whose numeric string value becomes a number. */
65
+ /**
66
+ * Attributes, and props written above, whose numeric string value becomes
67
+ * a number (`minCol={4}`), because the target types them as numbers.
68
+ */
61
69
  numbers: string[];
62
70
  }
63
71
  export interface Plan {
64
72
  conversion: Conversion | null;
73
+ /**
74
+ * The element is a wrapper its only child's component renders from these
75
+ * props: they join that child's conversion, and the element goes.
76
+ */
77
+ fold?: {
78
+ target: string;
79
+ props: Array<[name: string, value: string | true]>;
80
+ numbers: string[];
81
+ };
65
82
  todos: Todo[];
66
83
  }
67
84
  export declare function plan(facts: ElementFacts): Plan;
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AA+BD,wBAAgB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CA8R9C"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AA+BD,wBAAgB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAkS9C"}
@@ -61,6 +61,9 @@ export function plan(facts) {
61
61
  });
62
62
  return { conversion: null, todos };
63
63
  }
64
+ const wrapper = tokens.find(token => rootFor(token)?.status === 'fold');
65
+ if (wrapper)
66
+ return planFold(facts, wrapper, todos);
64
67
  const root = tokens
65
68
  .filter(token => rootFor(token)?.status === 'mapped')
66
69
  .sort((a, b) => precedence(a) - precedence(b))[0];
@@ -183,6 +186,8 @@ export function plan(facts) {
183
186
  for (const write of modifier.writes) {
184
187
  writes.set(write.prop, write.value ?? true);
185
188
  sourceOf.set(write.prop, token);
189
+ if (write.numeric)
190
+ numbers.push(write.prop);
186
191
  }
187
192
  converted.add(token);
188
193
  continue;
@@ -255,3 +260,57 @@ export function plan(facts) {
255
260
  todos,
256
261
  };
257
262
  }
263
+ /**
264
+ * A wrapper the component inside it renders from a prop (`.table-container`
265
+ * from `Table isResponsive`). It folds into that component only when it is
266
+ * exactly what the component renders for it: its own tag and class, its own
267
+ * modifiers, no attribute, and one child that becomes the component.
268
+ */
269
+ function planFold(facts, wrapper, todos) {
270
+ const entry = rootFor(wrapper);
271
+ const target = entry.target;
272
+ if (!target)
273
+ return { conversion: null, todos };
274
+ const folds = entry.folds ?? [];
275
+ const renders = `\`${target} ${folds.map(write => write.prop).join(' ')}\``;
276
+ const refuse = (kind, token, message) => ({
277
+ conversion: null,
278
+ todos: [...todos, { rule: ruleId(kind, token), message }],
279
+ });
280
+ if (facts.tag !== entry.tag) {
281
+ return refuse('tag', target, `bestax ${renders} renders \`.${wrapper}\` on a <${entry.tag}>, not a <${facts.tag}>; keep the markup, or change the tag and re-run`);
282
+ }
283
+ if (facts.hasSpread) {
284
+ return refuse('spread', target, `this element spreads props, and bestax ${renders} renders \`.${wrapper}\` with none of its own; keep it as markup`);
285
+ }
286
+ if (facts.onlyChildOf) {
287
+ return refuse('only-child', target, `this element is the only child of \`<${facts.onlyChildOf}>\`, which may hand it props or a ref with \`cloneElement\`, and folding it would move those onto the \`${target}\` inside; convert it by hand if \`<${facts.onlyChildOf}>\` only renders its children`);
288
+ }
289
+ const attribute = [...facts.attributes.keys()][0];
290
+ if (attribute) {
291
+ return refuse('attr', attribute, `bestax ${renders} renders \`.${wrapper}\` with no attributes, so this element's \`${attribute}\` would be lost; keep it as markup`);
292
+ }
293
+ const props = folds.map(write => [
294
+ write.prop,
295
+ write.value ?? true,
296
+ ]);
297
+ const numbers = [];
298
+ for (const token of facts.tokens) {
299
+ if (token === wrapper)
300
+ continue;
301
+ const modifier = modifierFor(entry, token);
302
+ const taken = modifier?.writes.some(write => props.some(([prop]) => prop === write.prop));
303
+ if (!modifier || taken) {
304
+ return refuse('attr', 'className', `bestax ${renders} renders \`.${wrapper}\` with no class but its own and one of each of its modifiers, so \`${token}\` would be lost; keep this element as markup`);
305
+ }
306
+ for (const write of modifier.writes) {
307
+ props.push([write.prop, write.value ?? true]);
308
+ if (write.numeric)
309
+ numbers.push(write.prop);
310
+ }
311
+ }
312
+ if (facts.soleChildTarget !== target) {
313
+ return refuse('children', target, `bestax ${renders} renders \`.${wrapper}\` itself, so this element converts only around a single element that becomes a \`${target}\`, with nothing else beside it`);
314
+ }
315
+ return { conversion: null, fold: { target, props, numbers }, todos };
316
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAmSvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CA4VpB"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAoTvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CAqYpB"}
@@ -47,6 +47,22 @@ const JSX_FACTORY = /^\s*\*?\s*@jsx\s+(\S+)/m;
47
47
  const HEADER_PRAGMA = /^[\s*]*(?:@ts-(?:no)?check|@flow|@noflow|eslint-disable(?!-)|@jsx|@jsxImportSource|@jsxRuntime|@license|@preserve)\b/;
48
48
  /** Directives that act on the line after them, so must stay above it. */
49
49
  const NEXT_LINE_DIRECTIVE = /^[\s*]*(?:eslint-disable-next-line|@ts-expect-error|@ts-ignore|prettier-ignore)\b/;
50
+ /**
51
+ * A comment moved to sit after a JSX tag name. It has to be a block comment
52
+ * there: recast prints a line comment as `<// …`, which TypeScript reads as a
53
+ * closing tag.
54
+ */
55
+ function afterTagName(comment) {
56
+ if (comment.type !== 'CommentLine') {
57
+ return { ...comment, leading: false, trailing: true };
58
+ }
59
+ return {
60
+ type: 'CommentBlock',
61
+ value: ` ${comment.value.trim().replace(/\*\//g, '*\\/')} `,
62
+ leading: false,
63
+ trailing: true,
64
+ };
65
+ }
50
66
  /** A lowercase intrinsic tag: not a component, not a custom element. */
51
67
  const INTRINSIC = /^[a-z][a-z0-9]*$/;
52
68
  /** Subtrees whose tags are not HTML. */
@@ -325,10 +341,21 @@ export default function transform(fileInfo, api, options = {}) {
325
341
  if (child.type !== 'JSXElement')
326
342
  return [];
327
343
  const target = planned.get(child)?.conversion?.target ??
344
+ planned.get(child)?.fold?.target ??
328
345
  // A direct child is looked up in the element's own scope, the child's.
329
346
  bestaxTarget(child, elementPath);
330
347
  return target ? [target] : [];
331
348
  });
349
+ /**
350
+ * The one element an element holds, when it holds nothing else: no text
351
+ * React renders, and no comment, which folding the element would drop.
352
+ */
353
+ const soleChild = (element) => {
354
+ const content = (element.children ?? []).filter((child) => child.type !== 'JSXText' || reachesReact(child));
355
+ return content.length === 1 && content[0].type === 'JSXElement'
356
+ ? content[0]
357
+ : undefined;
358
+ };
332
359
  // For each element, the bestax components already in the file inside it:
333
360
  // `Field` and `Control` change how bestax's form controls render.
334
361
  const bestaxInside = new Map();
@@ -399,17 +426,19 @@ export default function transform(fileInfo, api, options = {}) {
399
426
  hasRef: attributes.has('ref'),
400
427
  hasChildren: (element.children ?? []).some(reachesReact),
401
428
  childTargets: childTargets(elementPath),
429
+ soleChildTarget: planned.get(soleChild(element))?.conversion?.target,
402
430
  bestaxInside: bestaxInside.get(element) ?? [],
403
431
  bestaxAround: surrounding.bestax,
404
432
  componentsAround: surrounding.other,
405
433
  onlyChildOf: onlyChildOf(elementPath, bestaxLocals),
406
434
  };
407
435
  let result = plan(facts);
408
- const converts = result.conversion !== null;
409
- if (className === null && result.conversion) {
436
+ const converts = result.conversion !== null || result.fold !== undefined;
437
+ const becomes = result.conversion?.target ?? result.fold?.target;
438
+ if (className === null && becomes) {
410
439
  // The same element with a static className would convert; with a
411
440
  // computed one, only a person can turn each condition into its prop.
412
- const target = result.conversion.target;
441
+ const target = becomes;
413
442
  result = {
414
443
  conversion: null,
415
444
  todos: [
@@ -421,8 +450,15 @@ export default function transform(fileInfo, api, options = {}) {
421
450
  ],
422
451
  };
423
452
  }
453
+ if (result.fold) {
454
+ // The wrapper's props join its child's conversion, which has not been
455
+ // applied yet: conversions are applied after every element is planned.
456
+ const inner = planned.get(soleChild(element)).conversion;
457
+ inner.props.push(...result.fold.props);
458
+ inner.numbers.push(...result.fold.numbers);
459
+ }
424
460
  planned.set(element, result);
425
- if (result.conversion || result.todos.length > 0) {
461
+ if (result.conversion || result.fold || result.todos.length > 0) {
426
462
  elements.unshift({ path: elementPath, plan: result, converts });
427
463
  }
428
464
  }
@@ -436,7 +472,7 @@ export default function transform(fileInfo, api, options = {}) {
436
472
  if (converting)
437
473
  addTodo(ctx, elements[0].path, rule, message);
438
474
  for (const element of elements) {
439
- element.plan = { ...element.plan, conversion: null };
475
+ element.plan = { ...element.plan, conversion: null, fold: undefined };
440
476
  }
441
477
  };
442
478
  const runtime = fileJsxRuntime(root, j) ??
@@ -482,6 +518,32 @@ export default function transform(fileInfo, api, options = {}) {
482
518
  }
483
519
  }
484
520
  for (const { path: elementPath, plan: result } of [...elements].reverse()) {
521
+ if (result.fold) {
522
+ // The child inside has converted already (innermost first), with the
523
+ // wrapper's props on it; the wrapper itself goes, its comments with the
524
+ // child: one on the wrapper moves to the child, and one inside the
525
+ // wrapper's tags moves inside the child's opening tag.
526
+ const wrapper = elementPath.node;
527
+ const inner = soleChild(wrapper);
528
+ const { openingElement, closingElement } = wrapper;
529
+ const inTags = [
530
+ openingElement,
531
+ openingElement.name,
532
+ ...(openingElement.attributes ?? []),
533
+ closingElement,
534
+ closingElement?.name,
535
+ ].flatMap((node) => node?.comments ?? []);
536
+ if (inTags.length) {
537
+ const name = inner.openingElement.name;
538
+ name.comments = [...(name.comments ?? []), ...inTags.map(afterTagName)];
539
+ }
540
+ if (wrapper.comments?.length) {
541
+ inner.comments = [...wrapper.comments, ...(inner.comments ?? [])];
542
+ }
543
+ elementPath.replace(inner);
544
+ ctx.dirty = true;
545
+ continue;
546
+ }
485
547
  const conversion = result.conversion;
486
548
  if (!conversion)
487
549
  continue;
@@ -492,10 +554,6 @@ export default function transform(fileInfo, api, options = {}) {
492
554
  for (const name of conversion.drop) {
493
555
  attrs.splice(attrs.indexOf(findAttr(element, name)), 1);
494
556
  }
495
- for (const name of conversion.numbers) {
496
- const attr = findAttr(element, name);
497
- attr.value = j.jsxExpressionContainer(j.numericLiteral(Number(attributeValue(attr))));
498
- }
499
557
  const classAttr = findAttr(element, 'className');
500
558
  const replacement = conversion.props.map(([name, value]) => makeAttr(j, name, value === true ? undefined : value));
501
559
  if (conversion.className) {
@@ -510,22 +568,16 @@ export default function transform(fileInfo, api, options = {}) {
510
568
  const carrier = replacement[0] ?? attrs.find((attr) => attr !== classAttr) ?? name;
511
569
  carrier.comments = [
512
570
  ...(carrier.comments ?? []),
513
- ...classAttr.comments.map((comment) => {
514
- if (carrier !== name)
515
- return comment;
516
- if (comment.type !== 'CommentLine') {
517
- return { ...comment, leading: false, trailing: true };
518
- }
519
- return {
520
- type: 'CommentBlock',
521
- value: ` ${comment.value.trim().replace(/\*\//g, '*\\/')} `,
522
- leading: false,
523
- trailing: true,
524
- };
525
- }),
571
+ ...classAttr.comments.map((comment) => carrier === name ? afterTagName(comment) : comment),
526
572
  ];
527
573
  }
528
574
  attrs.splice(attrs.indexOf(classAttr), 1, ...replacement);
575
+ // After the splice, so a prop the conversion wrote is found as well as
576
+ // an attribute the element already had.
577
+ for (const name of conversion.numbers) {
578
+ const attr = findAttr(element, name);
579
+ attr.value = j.jsxExpressionContainer(j.numericLiteral(Number(attributeValue(attr))));
580
+ }
529
581
  ctx.dirty = true;
530
582
  }
531
583
  // ---- 5. The bestax import ---------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-migrate",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
5
5
  "type": "module",
6
6
  "bin": {