bestax-migrate 2.1.3 → 2.1.4

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.
@@ -55,6 +55,17 @@ export type LiteralValue = {
55
55
  };
56
56
  /** Extract the literal value of a JSX attribute, if it has one. */
57
57
  export declare function literalValueOf(attr: any): LiteralValue;
58
+ export type Booleanish = 'truthy' | 'falsy' | 'expression';
59
+ /**
60
+ * Classify a JSX attribute by the truthiness RBC evaluates it with at
61
+ * runtime (`!!value`): every statically-known literal (boolean, string, or
62
+ * number) resolves to `'truthy'`/`'falsy'`; only a genuine expression is
63
+ * `'expression'`. This is the single place the six call sites that branch on
64
+ * a "booleanish" prop (Button `remove`, Heading `heading`/`subtitle`,
65
+ * `booleanToProp`, the `active` ladders, Field `multiline`) agree on what
66
+ * counts as resolvable, so they can't drift out of sync with each other.
67
+ */
68
+ export declare function resolveBooleanish(attr: any): Booleanish;
58
69
  /** Create `name` (bare boolean) or `name="value"` attribute. */
59
70
  export declare function makeAttr(j: JSCodeshift, name: string, value?: string): any;
60
71
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"jsx-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/jsx-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAMpD,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,WAAW,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,aAAa,GAAG,SAAS,CAAC;IACrC,uEAAuE;IACvE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,8EAA8E;IAC9E,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B;;;;OAIG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,IAAI,CASvD;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAOhE;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAC3B,CAAC,EAAE,WAAW,EACd,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM,GACb,IAAI,CAKN;AAED,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,CAIhD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAEpE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI,CAIxD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI,CAGrD;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3B,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY,CActD;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,CAK1E;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,IAAI,CAuCN;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAC1B,CAAC,EAAE,WAAW,EACd,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,KAAK,EAAE,GAAG,EAAE,EACZ,QAAQ,EAAE,GAAG,EAAE,EACf,WAAW,UAAQ,GAClB,GAAG,CAcL"}
1
+ {"version":3,"file":"jsx-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/jsx-utils.ts"],"names":[],"mappings":"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"}
@@ -70,6 +70,21 @@ export function literalValueOf(attr) {
70
70
  }
71
71
  return { kind: 'expression' };
72
72
  }
73
+ /**
74
+ * Classify a JSX attribute by the truthiness RBC evaluates it with at
75
+ * runtime (`!!value`): every statically-known literal (boolean, string, or
76
+ * number) resolves to `'truthy'`/`'falsy'`; only a genuine expression is
77
+ * `'expression'`. This is the single place the six call sites that branch on
78
+ * a "booleanish" prop (Button `remove`, Heading `heading`/`subtitle`,
79
+ * `booleanToProp`, the `active` ladders, Field `multiline`) agree on what
80
+ * counts as resolvable, so they can't drift out of sync with each other.
81
+ */
82
+ export function resolveBooleanish(attr) {
83
+ const literal = literalValueOf(attr);
84
+ if (literal.kind === 'expression')
85
+ return 'expression';
86
+ return literal.value ? 'truthy' : 'falsy';
87
+ }
73
88
  /** Create `name` (bare boolean) or `name="value"` attribute. */
74
89
  export function makeAttr(j, name, value) {
75
90
  return j.jsxAttribute(j.jsxIdentifier(name), value === undefined ? null : j.stringLiteral(value));
@@ -1 +1 @@
1
- {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/props.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AA6BxB,mDAAmD;AACnD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GACjB,IAAI,CA4HN;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GACnB,IAAI,CAQN"}
1
+ {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/props.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AA6BxB,mDAAmD;AACnD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GACjB,IAAI,CA6HN;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GACnB,IAAI,CAQN"}
@@ -3,7 +3,7 @@
3
3
  * universal modifier-prop pass shared by every mapped component.
4
4
  */
5
5
  import { UNIVERSAL_PROPS } from './mapping.js';
6
- import { addAttr, addTodo, attributesOf, findAttr, literalValueOf, makeAttr, removeAttr, } from './jsx-utils.js';
6
+ import { addAttr, addTodo, attributesOf, findAttr, literalValueOf, makeAttr, removeAttr, resolveBooleanish, } from './jsx-utils.js';
7
7
  /* eslint-disable @typescript-eslint/no-explicit-any */
8
8
  /**
9
9
  * Add a converted attribute unless the target name is already present — two
@@ -56,12 +56,13 @@ export function applyPropAction(ctx, path, element, attr, action) {
56
56
  }
57
57
  if (action.booleanToProp) {
58
58
  const { name, value } = action.booleanToProp;
59
- if (literal.kind === 'boolean' && literal.value === true) {
59
+ const resolved = resolveBooleanish(attr);
60
+ if (resolved === 'truthy') {
60
61
  removeAttr(element, attr);
61
62
  addConverted(ctx, path, element, originalName, name, value);
62
63
  ctx.dirty = true;
63
64
  }
64
- else if (literal.kind === 'boolean' && literal.value === false) {
65
+ else if (resolved === 'falsy') {
65
66
  removeAttr(element, attr);
66
67
  ctx.dirty = true;
67
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"specials.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/specials.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAUL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AA21BD,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,GACX,aAAa,CAIf;AAED,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAGjE,CAAC"}
1
+ {"version":3,"file":"specials.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/specials.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAWL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAo3BD,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,GACX,aAAa,CAIf;AAED,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAGjE,CAAC"}
@@ -8,7 +8,7 @@
8
8
  * element `replaced` when it substituted the node itself.
9
9
  */
10
10
  import { RESPONSIVE_BREAKPOINTS, UNIVERSAL_PROPS } from './mapping.js';
11
- import { addAttr, addTodo, attributesOf, buildJsxName, findAttr, literalValueOf, makeAttr, plainElement, removeAttr, } from './jsx-utils.js';
11
+ import { addAttr, addTodo, attributesOf, buildJsxName, findAttr, literalValueOf, makeAttr, plainElement, removeAttr, resolveBooleanish, } from './jsx-utils.js';
12
12
  /** Pick a target based on a literal align-style prop, removing the prop. */
13
13
  function alignTarget(ctx, path, element, prop, targets, fallback) {
14
14
  const attr = findAttr(element, prop);
@@ -141,14 +141,14 @@ const SPECIALS = {
141
141
  const attr = findAttr(element, 'remove');
142
142
  if (!attr)
143
143
  return {};
144
- const literal = literalValueOf(attr);
145
- if (literal.kind !== 'expression') {
144
+ const resolved = resolveBooleanish(attr);
145
+ if (resolved !== 'expression') {
146
146
  // A statically-known value always renders the same at runtime: truthy
147
147
  // (`remove`, `remove={true}`, `remove="true"`) → `<Delete />`; falsy
148
148
  // (`remove={false}`, `remove=""`, `remove={0}`) → just drop the prop.
149
149
  removeAttr(element, attr);
150
150
  ctx.dirty = true;
151
- return literal.value ? { target: 'Delete' } : {};
151
+ return resolved === 'truthy' ? { target: 'Delete' } : {};
152
152
  }
153
153
  addTodo(ctx, path, 'prop:remove', '`remove` has a dynamic value; this can render as either a Button or a Delete cross — split the branch by hand');
154
154
  return {};
@@ -172,14 +172,18 @@ const SPECIALS = {
172
172
  heading(ctx, path, element) {
173
173
  const headingAttr = findAttr(element, 'heading');
174
174
  const subtitleAttr = findAttr(element, 'subtitle');
175
- const headingLit = headingAttr ? literalValueOf(headingAttr) : undefined;
176
- const subtitleLit = subtitleAttr ? literalValueOf(subtitleAttr) : undefined;
177
- const headingDynamic = headingLit?.kind === 'expression';
178
- const subtitleDynamic = subtitleLit?.kind === 'expression';
175
+ const headingResolved = headingAttr
176
+ ? resolveBooleanish(headingAttr)
177
+ : undefined;
178
+ const subtitleResolved = subtitleAttr
179
+ ? resolveBooleanish(subtitleAttr)
180
+ : undefined;
181
+ const headingDynamic = headingResolved === 'expression';
182
+ const subtitleDynamic = subtitleResolved === 'expression';
179
183
  // A resolvable literal (boolean/string/number) collapses to its runtime
180
184
  // truthiness; an expression stays dynamic.
181
- const headingTruthy = !!headingLit && headingLit.kind !== 'expression' && !!headingLit.value;
182
- const subtitleTruthy = !!subtitleLit && subtitleLit.kind !== 'expression' && !!subtitleLit.value;
185
+ const headingTruthy = headingResolved === 'truthy';
186
+ const subtitleTruthy = subtitleResolved === 'truthy';
183
187
  // Dynamic values can't be resolved to a target: leave the prop on the
184
188
  // element (so its expression survives for hand-splitting) plus a TODO.
185
189
  if (subtitleDynamic) {
@@ -205,11 +209,11 @@ const SPECIALS = {
205
209
  // A resolvable literal `heading` that didn't collapse (falsy, or truthy
206
210
  // but blocked by a dynamic subtitle) behaves as if the prop were absent —
207
211
  // drop it. A dynamic `heading` stays put (its TODO is already filed above).
208
- if (headingLit && !headingDynamic) {
212
+ if (headingAttr && !headingDynamic) {
209
213
  removeAttr(element, headingAttr);
210
214
  ctx.dirty = true;
211
215
  }
212
- if (subtitleLit && !subtitleDynamic) {
216
+ if (subtitleAttr && !subtitleDynamic) {
213
217
  removeAttr(element, subtitleAttr);
214
218
  ctx.dirty = true;
215
219
  return { target: subtitleTruthy ? 'SubTitle' : 'Title' };
@@ -313,35 +317,55 @@ const SPECIALS = {
313
317
  if ((kind && kind.kind !== 'string') ||
314
318
  (align && align.kind !== 'string')) {
315
319
  addTodo(ctx, path, 'prop:kind', 'dynamic Field kind/align; map to the bestax `grouped` / `hasAddons` props by hand');
316
- return {};
320
+ // This handler owns `multiline` end-to-end; without this, the mapping's
321
+ // fallback `multiline: { drop: true }` prop action would silently strip
322
+ // a dynamic `multiline` the moment kind/align themselves are dynamic.
323
+ return { handledProps: ['multiline'] };
317
324
  }
318
- for (const attr of [kindAttr, alignAttr, multilineAttr]) {
325
+ // `multiline` is a value, not just presence: a falsy literal drops it
326
+ // (same as it being absent) and a dynamic value must survive on the
327
+ // element — so, unlike `kind`/`align`, it's only stripped once resolved.
328
+ const multilineResolved = multilineAttr
329
+ ? resolveBooleanish(multilineAttr)
330
+ : null;
331
+ const multilineDynamic = multilineResolved === 'expression';
332
+ const multilineTruthy = multilineResolved === 'truthy';
333
+ const kindOrAlignPresent = Boolean(kindAttr || alignAttr);
334
+ for (const attr of [kindAttr, alignAttr]) {
319
335
  if (attr)
320
336
  removeAttr(element, attr);
321
337
  }
322
- ctx.dirty = true;
338
+ if (multilineAttr && !multilineDynamic) {
339
+ removeAttr(element, multilineAttr);
340
+ }
341
+ if (kindOrAlignPresent || (multilineAttr && !multilineDynamic)) {
342
+ ctx.dirty = true;
343
+ }
323
344
  const alignValue = align && align.kind === 'string'
324
345
  ? { center: 'centered', right: 'right' }[align.value]
325
346
  : undefined;
347
+ if (multilineDynamic) {
348
+ addTodo(ctx, path, 'prop:multiline', '`multiline` has a dynamic value; resolve the bestax `grouped`/`hasAddons` combination by hand');
349
+ }
326
350
  if (kind && kind.kind === 'string' && kind.value === 'addons') {
327
351
  addAttr(element, makeAttr(ctx.j, 'hasAddons', alignValue));
328
- if (multilineAttr) {
352
+ if (multilineTruthy) {
329
353
  addTodo(ctx, path, 'prop:multiline', "`multiline` only combines with kind='group' in Bulma; dropped from this addons Field");
330
354
  }
331
- return {};
355
+ return { handledProps: ['multiline'] };
332
356
  }
333
357
  // kind='group' (or a stray multiline/align without kind)
334
- if (multilineAttr) {
358
+ if (multilineTruthy) {
335
359
  addAttr(element, makeAttr(ctx.j, 'grouped', 'multiline'));
336
360
  if (alignValue) {
337
361
  addTodo(ctx, path, 'prop:align', 'bestax `grouped` takes one value; choose between multiline and ' +
338
362
  alignValue);
339
363
  }
340
364
  }
341
- else {
365
+ else if (kindOrAlignPresent) {
342
366
  addAttr(element, makeAttr(ctx.j, 'grouped', alignValue));
343
367
  }
344
- return {};
368
+ return { handledProps: ['multiline'] };
345
369
  },
346
370
  /** Form.Label → plain <label className="label">. */
347
371
  'plain-label'(ctx, path, element) {
@@ -472,18 +496,14 @@ const SPECIALS = {
472
496
  const activeAttr = findAttr(element, 'active');
473
497
  let className;
474
498
  if (activeAttr) {
475
- const literal = literalValueOf(activeAttr);
476
- if (literal.kind === 'boolean' && literal.value === true) {
499
+ const resolved = resolveBooleanish(activeAttr);
500
+ if (resolved === 'truthy') {
477
501
  className = 'is-active';
478
- removeAttr(element, activeAttr);
479
- }
480
- else if (literal.kind === 'boolean') {
481
- removeAttr(element, activeAttr);
482
502
  }
483
- else {
503
+ else if (resolved === 'expression') {
484
504
  addTodo(ctx, path, 'prop:active', "dynamic Panel.Tabs.Tab active; set className={active ? 'is-active' : undefined} by hand");
485
- removeAttr(element, activeAttr);
486
505
  }
506
+ removeAttr(element, activeAttr);
487
507
  }
488
508
  className = mergeClassName(ctx, path, element, className, 'Panel.Tabs.Tab');
489
509
  const rest = stripModifierProps(ctx, path, attributesOf(element), 'Panel.Tabs.Tab');
@@ -497,10 +517,10 @@ const SPECIALS = {
497
517
  const activeAttr = findAttr(element, 'active');
498
518
  let liClass;
499
519
  if (activeAttr) {
500
- const literal = literalValueOf(activeAttr);
501
- if (literal.kind === 'boolean' && literal.value === true)
520
+ const resolved = resolveBooleanish(activeAttr);
521
+ if (resolved === 'truthy')
502
522
  liClass = 'is-active';
503
- else if (literal.kind !== 'boolean') {
523
+ else if (resolved === 'expression') {
504
524
  addTodo(ctx, path, 'prop:active', "dynamic Breadcrumb.Item active; set the li className={active ? 'is-active' : undefined} by hand");
505
525
  }
506
526
  removeAttr(element, activeAttr);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-migrate",
3
- "version": "2.1.3",
3
+ "version": "2.1.4",
4
4
  "description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,7 +51,7 @@
51
51
  "react-dom": "^19.2.8",
52
52
  "ts-jest": "^29.4.12",
53
53
  "typescript": "^6.0.3",
54
- "@allxsmith/bestax-bulma": "^5.11.2"
54
+ "@allxsmith/bestax-bulma": "^5.11.4"
55
55
  },
56
56
  "publishConfig": {
57
57
  "access": "public"