bestax-migrate 2.3.9 → 2.5.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 (49) hide show
  1. package/README.md +21 -17
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +31 -7
  4. package/dist/sources/_shared/bestax-import.d.ts +6 -3
  5. package/dist/sources/_shared/bestax-import.d.ts.map +1 -1
  6. package/dist/sources/_shared/bestax-import.js +5 -4
  7. package/dist/sources/_shared/deps-common.d.ts +6 -1
  8. package/dist/sources/_shared/deps-common.d.ts.map +1 -1
  9. package/dist/sources/_shared/deps-common.js +20 -3
  10. package/dist/sources/_shared/jsx-utils.d.ts +28 -0
  11. package/dist/sources/_shared/jsx-utils.d.ts.map +1 -1
  12. package/dist/sources/_shared/jsx-utils.js +59 -1
  13. package/dist/sources/_shared/props.d.ts.map +1 -1
  14. package/dist/sources/_shared/props.js +2 -2
  15. package/dist/sources/bloomer/transform.d.ts.map +1 -1
  16. package/dist/sources/bloomer/transform.js +3 -1
  17. package/dist/sources/bulma-classes/class-map.d.ts +182 -0
  18. package/dist/sources/bulma-classes/class-map.d.ts.map +1 -0
  19. package/dist/sources/bulma-classes/class-map.js +1131 -0
  20. package/dist/sources/bulma-classes/deps.d.ts +14 -0
  21. package/dist/sources/bulma-classes/deps.d.ts.map +1 -0
  22. package/dist/sources/bulma-classes/deps.js +56 -0
  23. package/dist/sources/bulma-classes/index.d.ts +3 -0
  24. package/dist/sources/bulma-classes/index.d.ts.map +1 -0
  25. package/dist/sources/bulma-classes/index.js +35 -0
  26. package/dist/sources/bulma-classes/plan.d.ts +59 -0
  27. package/dist/sources/bulma-classes/plan.d.ts.map +1 -0
  28. package/dist/sources/bulma-classes/plan.js +241 -0
  29. package/dist/sources/bulma-classes/project.d.ts +40 -0
  30. package/dist/sources/bulma-classes/project.d.ts.map +1 -0
  31. package/dist/sources/bulma-classes/project.js +203 -0
  32. package/dist/sources/bulma-classes/rules.d.ts +16 -0
  33. package/dist/sources/bulma-classes/rules.d.ts.map +1 -0
  34. package/dist/sources/bulma-classes/rules.js +53 -0
  35. package/dist/sources/bulma-classes/styles.d.ts +13 -0
  36. package/dist/sources/bulma-classes/styles.d.ts.map +1 -0
  37. package/dist/sources/bulma-classes/styles.js +18 -0
  38. package/dist/sources/bulma-classes/transform.d.ts +22 -0
  39. package/dist/sources/bulma-classes/transform.d.ts.map +1 -0
  40. package/dist/sources/bulma-classes/transform.js +526 -0
  41. package/dist/sources/rbx/transform.d.ts.map +1 -1
  42. package/dist/sources/rbx/transform.js +3 -1
  43. package/dist/sources/react-bulma-components/transform.d.ts.map +1 -1
  44. package/dist/sources/react-bulma-components/transform.js +3 -1
  45. package/dist/sources/registry.d.ts.map +1 -1
  46. package/dist/sources/registry.js +2 -0
  47. package/dist/types.d.ts +18 -0
  48. package/dist/types.d.ts.map +1 -1
  49. package/package.json +3 -2
package/README.md CHANGED
@@ -11,15 +11,16 @@
11
11
 
12
12
  Codemods 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**.
13
13
 
14
- Currently supported source libraries:
14
+ Currently supported sources:
15
15
 
16
- | Source | Status |
17
- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
18
- | [`react-bulma-components`](https://github.com/couds/react-bulma-components) (v4) | ✅ All 32 components mapped (a few patterns are flagged as TODOs) |
19
- | [`rbx`](https://github.com/dfee/rbx) (v2) | ✅ Full export surface mapped (a few patterns are flagged as TODOs) |
20
- | [`bloomer`](https://github.com/AlgusDark/bloomer) (0.6) | ✅ All 108 exports mapped (Font Awesome 4 icons and Bulma 0.4's `Nav` are flagged) |
16
+ | Source | Status |
17
+ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
18
+ | [`react-bulma-components`](https://github.com/couds/react-bulma-components) (v4) | ✅ All 32 components mapped (a few patterns are flagged as TODOs) |
19
+ | [`rbx`](https://github.com/dfee/rbx) (v2) | ✅ Full export surface mapped (a few patterns are flagged as TODOs) |
20
+ | [`bloomer`](https://github.com/AlgusDark/bloomer) (0.6) | ✅ All 108 exports mapped (Font Awesome 4 icons and Bulma 0.4's `Nav` are flagged) |
21
+ | `bulma-classes`: Bulma's classes on plain JSX, no library | ✅ Converts an element only when bestax renders the same markup; the rest is flagged |
21
22
 
22
- Pass the source library as the first argument: `bestax-migrate <source> <paths…>`.
23
+ Pass the source as the first argument: `bestax-migrate <source> <paths…>`.
23
24
 
24
25
  ## Requirements
25
26
 
@@ -37,6 +38,8 @@ pnpm dlx bestax-migrate react-bulma-components src/ --dry
37
38
  # …or, for an rbx or bloomer app
38
39
  pnpm dlx bestax-migrate rbx src/ --dry
39
40
  pnpm dlx bestax-migrate bloomer src/ --dry
41
+ # …or, for an app that writes Bulma's classes on plain JSX
42
+ pnpm dlx bestax-migrate bulma-classes src/ --dry
40
43
 
41
44
  # Apply the migration
42
45
  pnpm dlx bestax-migrate react-bulma-components src/
@@ -50,11 +53,12 @@ The codemod uses [jscodeshift](https://github.com/facebook/jscodeshift) to:
50
53
  - 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`)
51
54
  - convert props (`renderAs` → `as`, `loading` → `isLoading`, numeric spacing/text sizes → string unions, `textAlign="center"` → `textAlign="centered"`, …)
52
55
  - flatten responsive breakpoint objects (`mobile={{ size: 4 }}` → `sizeMobile={4}`) and bloomer's `isDisplay`/`isHidden` strings, arrays and objects (`isHidden="touch"` → `visibilityTouch="hidden"`)
56
+ - 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
53
57
  - restructure patterns bestax models differently (`Table.Container`, Navbar dropdowns, `Form.Help`, icon-font children → `<Icon name=…>`)
54
58
  - 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'`
55
- - 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
59
+ - 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
56
60
 
57
- Anything 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)), or let the [`bestax-migrate` Agent Skill](https://bestax.io/docs/skills/intro) walk them for you:
61
+ Anything 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:
58
62
 
59
63
  ```bash
60
64
  npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate
@@ -62,13 +66,13 @@ npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate
62
66
 
63
67
  ## Options
64
68
 
65
- | Flag | Description |
66
- | -------------------- | -------------------------------------------------------------- |
67
- | `--dry`, `-d` | Report what would change without writing files |
68
- | `--print`, `-p` | Print transformed sources to stdout |
69
- | `--extensions`, `-e` | File extensions to include (default `js,jsx,ts,tsx,scss,sass`) |
70
- | `--css <mode>` | Stylesheet target: `bestax` (default), `bulma`, or `keep` |
71
- | `--no-deps` | Skip updating package.json dependencies |
69
+ | Flag | Description |
70
+ | -------------------- | ---------------------------------------------------------------------------------------------- |
71
+ | `--dry`, `-d` | Report what would change without writing files |
72
+ | `--print`, `-p` | Print transformed sources to stdout |
73
+ | `--extensions`, `-e` | File extensions to include (default `js,jsx,ts,tsx,scss,sass`) |
74
+ | `--css <mode>` | Stylesheet target: `bestax`, `bulma`, or `keep` (default `bestax`; `keep` for `bulma-classes`) |
75
+ | `--no-deps` | Skip updating package.json dependencies |
72
76
 
73
77
  ## After the codemod
74
78
 
@@ -76,7 +80,7 @@ npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate
76
80
  2. Search for `TODO(bestax-migrate)` and resolve each comment
77
81
  3. Typecheck/build and review the rendered app
78
82
 
79
- Full 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).
83
+ Full 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).
80
84
 
81
85
  ## Hardened by default
82
86
 
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;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,EAAW,eAAe,EAAE,MAAM,YAAY,CAAC;AAoB3D,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAkBV;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;AAoKD;;;;;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,CAkHT"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;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,EAAW,eAAe,EAAE,MAAM,YAAY,CAAC;AAoB3D,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAkBV;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;AA4LD;;;;;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,CA0HT"}
package/dist/cli.js CHANGED
@@ -209,7 +209,7 @@ export function sourcePackage(source) {
209
209
  function importsSource(importRe, text) {
210
210
  return importRe !== null && importRe.test(blankComments(text));
211
211
  }
212
- function migrateFiles(source, files, reporter, io, options) {
212
+ function migrateFiles(source, files, reporter, io, options, project) {
213
213
  let bulmaReferenced = false;
214
214
  let sourceStillImported = false;
215
215
  const pkg = sourcePackage(source);
@@ -230,6 +230,7 @@ function migrateFiles(source, files, reporter, io, options) {
230
230
  }
231
231
  else {
232
232
  output = runTransform(source.transform, file, sourceText, collector, {
233
+ ...project,
233
234
  cssMode: options.cssMode,
234
235
  }).output;
235
236
  }
@@ -268,10 +269,31 @@ function migrateFiles(source, files, reporter, io, options) {
268
269
  * source library, so a migration never silently skips them.
269
270
  */
270
271
  function reportUnsupportedFiles(source, targets, reporter, extensions) {
271
- const unsupported = UNSUPPORTED_EXTENSIONS.filter(ext => !extensions.includes(ext));
272
+ const unsupported = UNSUPPORTED_EXTENSIONS.filter(ext => !extensions.includes(ext) &&
273
+ (source.unsupportedExtensions?.includes(ext) ?? true));
272
274
  const pkg = sourcePackage(source);
273
- if (unsupported.length === 0 || pkg === null)
275
+ if (unsupported.length === 0)
274
276
  return false;
277
+ if (pkg === null) {
278
+ // No package to look for: the source says what it would have converted.
279
+ const find = source.findUnsupportedReference;
280
+ if (!find)
281
+ return false;
282
+ for (const file of collectFiles(targets, unsupported)) {
283
+ const line = find(fs.readFileSync(file, 'utf8'));
284
+ if (line === null)
285
+ continue;
286
+ const collector = reporter.startFile();
287
+ collector.add({
288
+ file,
289
+ line,
290
+ rule: 'unsupported-file',
291
+ message: `has markup the ${source.name} source would convert, but ${path.extname(file)} files cannot be parsed by the codemod — migrate this file by hand`,
292
+ });
293
+ reporter.finishFile(file, false, collector.entries);
294
+ }
295
+ return false;
296
+ }
275
297
  // Whether any unsupported file still references the source package. These
276
298
  // are reported but never rewritten, so the reference survives the run —
277
299
  // and the manifest pass must not remove the package out from under it.
@@ -429,7 +451,7 @@ export function createCLI(io = { log: console.log, error: console.error }) {
429
451
  .option('-d, --dry', 'dry run — report what would change without writing', false)
430
452
  .option('-p, --print', 'print transformed sources to stdout', false)
431
453
  .option('-e, --extensions <list>', 'comma-separated file extensions to include', 'js,jsx,ts,tsx,scss,sass')
432
- .option('--css <mode>', `stylesheet target: ${CSS_MODES.join(', ')}`, 'bestax')
454
+ .option('--css <mode>', `stylesheet target: ${CSS_MODES.join(', ')} (default bestax; keep for bulma-classes)`)
433
455
  .option('--no-deps', 'skip updating package.json dependencies')
434
456
  .option('--telemetry', 'enable anonymous usage telemetry (https://bestax.io/docs/guides/telemetry)')
435
457
  .option('--no-telemetry', 'disable anonymous usage telemetry')
@@ -440,7 +462,8 @@ export function createCLI(io = { log: console.log, error: console.error }) {
440
462
  program.error('', { exitCode: 1 });
441
463
  return;
442
464
  }
443
- if (!CSS_MODES.includes(options.css)) {
465
+ const cssMode = options.css ?? source.defaultCssMode ?? 'bestax';
466
+ if (!CSS_MODES.includes(cssMode)) {
444
467
  io.error(`${chalk.red('Unknown --css mode')} "${options.css}". Valid modes: ${CSS_MODES.join(', ')}`);
445
468
  program.error('', { exitCode: 1 });
446
469
  return;
@@ -462,10 +485,11 @@ export function createCLI(io = { log: console.log, error: console.error }) {
462
485
  dry: Boolean(options.dry),
463
486
  print: Boolean(options.print),
464
487
  deps: options.deps !== false,
465
- cssMode: options.css,
488
+ cssMode,
466
489
  };
467
490
  const reporter = new Reporter();
468
- const depSignals = migrateFiles(source, files, reporter, io, runOptions);
491
+ const project = source.analyzeProject?.(targets) ?? {};
492
+ const depSignals = migrateFiles(source, files, reporter, io, runOptions, project);
469
493
  const unsupportedImports = reportUnsupportedFiles(source, targets, reporter, extensions);
470
494
  if (unsupportedImports)
471
495
  depSignals.sourceStillImported = true;
@@ -32,10 +32,13 @@ export declare function buildBestaxImport(ctx: TransformContext, state: BestaxIm
32
32
  */
33
33
  export declare function bestaxValueLocals(ctx: TransformContext, state: BestaxImportState): Set<string>;
34
34
  /**
35
- * Merge `fresh` into the existing bestax import, or insert it before
36
- * `before` when there is none.
35
+ * Merge `fresh` into the existing bestax import, or insert it through
36
+ * `anchor` when there is none. An AST path is an anchor: the fresh import
37
+ * goes before it.
37
38
  */
38
- export declare function placeBestaxImport(state: BestaxImportState, fresh: any | null, before: any): void;
39
+ export declare function placeBestaxImport(state: BestaxImportState, fresh: any | null, anchor: {
40
+ insertBefore(node: any): unknown;
41
+ }): void;
39
42
  /**
40
43
  * A pruned declaration takes its comments with it — a licence header, an
41
44
  * eslint directive. Hand them to `carrier` (the bestax import that survives),
@@ -1 +1 @@
1
- {"version":3,"file":"bestax-import.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/bestax-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,eAAO,MAAM,MAAM,4BAA4B,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,QAAQ,EAAE,GAAG,GAAG,SAAS,CAAC;IAC1B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,6DAA6D;IAC7D,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,GAAG,GACR,iBAAiB,CA+CnB;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,GAAG,IAAI,CAgBZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,CAAC,MAAM,CAAC,CASb;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,GAAG,GAAG,IAAI,EACjB,MAAM,EAAE,GAAG,GACV,IAAI,CAyBN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,GAAG,EACT,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,GAAG,GAAG,IAAI,GAClB,IAAI,CAsBN"}
1
+ {"version":3,"file":"bestax-import.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/bestax-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,eAAO,MAAM,MAAM,4BAA4B,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,QAAQ,EAAE,GAAG,GAAG,SAAS,CAAC;IAC1B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,6DAA6D;IAC7D,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,GAAG,GACR,iBAAiB,CA+CnB;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,GAAG,IAAI,CAgBZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,CAAC,MAAM,CAAC,CASb;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,GAAG,GAAG,IAAI,EACjB,MAAM,EAAE;IAAE,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAA;CAAE,GAC3C,IAAI,CAyBN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,GAAG,EACT,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,GAAG,GAAG,IAAI,GAClB,IAAI,CAsBN"}
@@ -79,14 +79,15 @@ export function bestaxValueLocals(ctx, state) {
79
79
  .map(([, local]) => local));
80
80
  }
81
81
  /**
82
- * Merge `fresh` into the existing bestax import, or insert it before
83
- * `before` when there is none.
82
+ * Merge `fresh` into the existing bestax import, or insert it through
83
+ * `anchor` when there is none. An AST path is an anchor: the fresh import
84
+ * goes before it.
84
85
  */
85
- export function placeBestaxImport(state, fresh, before) {
86
+ export function placeBestaxImport(state, fresh, anchor) {
86
87
  if (!fresh)
87
88
  return;
88
89
  if (!state.existing) {
89
- before.insertBefore(fresh);
90
+ anchor.insertBefore(fresh);
90
91
  return;
91
92
  }
92
93
  const current = state.existing.node.specifiers ?? [];
@@ -21,7 +21,12 @@ export interface Manifest {
21
21
  result(): Record<string, unknown> | null;
22
22
  }
23
23
  export declare function openManifest(filePath: string, pkg: Record<string, unknown>, collector: TodoCollector | undefined): Manifest;
24
- /** @allxsmith/bestax-bulma comes in as a runtime dependency. */
24
+ /**
25
+ * @allxsmith/bestax-bulma comes in as a runtime dependency. An older major
26
+ * already declared is reported, not raised: the migrated code is written for
27
+ * the current one, and moving the app's existing bestax code across majors is
28
+ * the app's own step.
29
+ */
25
30
  export declare function addBestax(manifest: Manifest): void;
26
31
  export interface BulmaOutcome {
27
32
  /** The declared range before any bump, or null when none was declared. */
@@ -1 +1 @@
1
- {"version":3,"file":"deps-common.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/deps-common.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,eAAO,MAAM,WAAW,WAAW,CAAC;AAIpC,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,KAAK,OAAO,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC3D,qEAAqE;IACrE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yDAAyD;IACzD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,EAAE,aAAa,GAAG,SAAS,GACnC,QAAQ,CAiBV;AAED,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAclD;AAED,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,OAAO,GAAG,SAAS,GACnC,YAAY,CA2Bd;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAqBzD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAexD"}
1
+ {"version":3,"file":"deps-common.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/deps-common.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,eAAO,MAAM,WAAW,WAAW,CAAC;AAIpC,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,KAAK,OAAO,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC3D,qEAAqE;IACrE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yDAAyD;IACzD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,EAAE,aAAa,GAAG,SAAS,GACnC,QAAQ,CAiBV;AAaD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAmBlD;AAED,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,OAAO,GAAG,SAAS,GACnC,YAAY,CA2Bd;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAqBzD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAexD"}
@@ -26,14 +26,31 @@ export function openManifest(filePath, pkg, collector) {
26
26
  result: () => changes.length > 0 ? next : null,
27
27
  };
28
28
  }
29
- /** @allxsmith/bestax-bulma comes in as a runtime dependency. */
29
+ /** Whether every alternative of a plain range names a major below `major`. */
30
+ function majorBelow(range, major) {
31
+ const majors = range
32
+ .split('||')
33
+ .map(set => set.trim().match(/^[~^=v\s]*(\d+)(?:[.\s]|$)/)?.[1]);
34
+ return (majors.length > 0 &&
35
+ majors.every(found => found !== undefined && Number(found) < major));
36
+ }
37
+ /**
38
+ * @allxsmith/bestax-bulma comes in as a runtime dependency. An older major
39
+ * already declared is reported, not raised: the migrated code is written for
40
+ * the current one, and moving the app's existing bestax code across majors is
41
+ * the app's own step.
42
+ */
30
43
  export function addBestax(manifest) {
31
44
  const dependencies = (manifest.next.dependencies ??= {});
32
- if (!dependencies['@allxsmith/bestax-bulma'] &&
33
- !manifest.section('devDependencies')?.['@allxsmith/bestax-bulma']) {
45
+ const declared = dependencies['@allxsmith/bestax-bulma'] ??
46
+ manifest.section('devDependencies')?.['@allxsmith/bestax-bulma'];
47
+ if (declared === undefined) {
34
48
  dependencies['@allxsmith/bestax-bulma'] = BESTAX_RANGE;
35
49
  manifest.note(`added @allxsmith/bestax-bulma ${BESTAX_RANGE} to dependencies`);
36
50
  }
51
+ else if (majorBelow(declared, 5)) {
52
+ manifest.report('peer-deps', `@allxsmith/bestax-bulma ${declared} is older than the ${BESTAX_RANGE} the migrated code is written for; upgrade it before installing (the bestax-bulma upgrade guides cover each major)`);
53
+ }
37
54
  }
38
55
  /**
39
56
  * Bump a pre-1 Bulma range; add one only when sources still reference
@@ -98,8 +98,36 @@ export type Booleanish = 'truthy' | 'falsy' | 'expression';
98
98
  * resolvable, so they can't drift out of sync with each other.
99
99
  */
100
100
  export declare function resolveBooleanish(attr: any): Booleanish;
101
+ /**
102
+ * A JSX attribute value holding `value`. A JSX attribute string has no
103
+ * escapes, so the printer's `\"` would end the string early and its `\\` would
104
+ * double a backslash: a value holding either goes in an expression
105
+ * (`name={"…"}`), where the escaping means what it says.
106
+ */
107
+ export declare function jsxStringValue(j: JSCodeshift, value: string): any;
101
108
  /** Create `name` (bare boolean) or `name="value"` attribute. */
102
109
  export declare function makeAttr(j: JSCodeshift, name: string, value?: string): any;
110
+ /**
111
+ * Call on the root just before `toSource`. recast reuses the original text of
112
+ * whatever an edit left alone, but it cannot patch a JSX element the source
113
+ * wrapped in parentheses (the usual `return ( … )`), so an edit anywhere in
114
+ * one reprints the whole element. Its printer trims the whitespace at the
115
+ * edges of every text child and decodes entities, so `</b> ends` came back as
116
+ * `</b>ends` and `&lt;` as a raw `<`: visible text changed, and some files no
117
+ * longer parsed. Dropping the parenthesized marker from the node and from
118
+ * recast's copy of the original lets it patch; the parentheses themselves are
119
+ * still in the reused text.
120
+ */
121
+ export declare function forgetJsxParens(j: JSCodeshift, root: any): void;
122
+ /**
123
+ * Call on the root just before `toSource`. When a statement is added at the
124
+ * top level (a new import), recast reprints the program: it reuses each
125
+ * directive's original text, semicolon included, and then adds a semicolon of
126
+ * its own, so `'use client';` came back as `'use client';;`. A new directive
127
+ * node has no original text to reuse, and carrying the raw string keeps its
128
+ * quotes as written.
129
+ */
130
+ export declare function reprintDirectives(j: JSCodeshift, root: any): void;
103
131
  /**
104
132
  * Attach a `// TODO(bestax-migrate): ...` leading comment to the closest
105
133
  * enclosing statement (comments inside JSX children are not valid JS, so the
@@ -1 +1 @@
1
- {"version":3,"file":"jsx-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/jsx-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jsx-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/jsx-utils.ts"],"names":[],"mappings":"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"}
@@ -148,9 +148,67 @@ export function resolveBooleanish(attr) {
148
148
  return 'expression';
149
149
  return literal.value ? 'truthy' : 'falsy';
150
150
  }
151
+ /**
152
+ * A JSX attribute value holding `value`. A JSX attribute string has no
153
+ * escapes, so the printer's `\"` would end the string early and its `\\` would
154
+ * double a backslash: a value holding either goes in an expression
155
+ * (`name={"…"}`), where the escaping means what it says.
156
+ */
157
+ export function jsxStringValue(j, value) {
158
+ const literal = j.stringLiteral(value);
159
+ return /["\\]/.test(value) ? j.jsxExpressionContainer(literal) : literal;
160
+ }
151
161
  /** Create `name` (bare boolean) or `name="value"` attribute. */
152
162
  export function makeAttr(j, name, value) {
153
- return j.jsxAttribute(j.jsxIdentifier(name), value === undefined ? null : j.stringLiteral(value));
163
+ if (value === undefined)
164
+ return j.jsxAttribute(j.jsxIdentifier(name), null);
165
+ return j.jsxAttribute(j.jsxIdentifier(name), jsxStringValue(j, value));
166
+ }
167
+ /**
168
+ * Call on the root just before `toSource`. recast reuses the original text of
169
+ * whatever an edit left alone, but it cannot patch a JSX element the source
170
+ * wrapped in parentheses (the usual `return ( … )`), so an edit anywhere in
171
+ * one reprints the whole element. Its printer trims the whitespace at the
172
+ * edges of every text child and decodes entities, so `</b> ends` came back as
173
+ * `</b>ends` and `&lt;` as a raw `<`: visible text changed, and some files no
174
+ * longer parsed. Dropping the parenthesized marker from the node and from
175
+ * recast's copy of the original lets it patch; the parentheses themselves are
176
+ * still in the reused text.
177
+ */
178
+ export function forgetJsxParens(j, root) {
179
+ const clear = (node) => {
180
+ for (const copy of [node, node.original]) {
181
+ if (copy?.extra?.parenthesized) {
182
+ delete copy.extra.parenthesized;
183
+ delete copy.extra.parenStart;
184
+ }
185
+ }
186
+ };
187
+ root.find(j.JSXElement).forEach((path) => clear(path.node));
188
+ root.find(j.JSXFragment).forEach((path) => clear(path.node));
189
+ }
190
+ /**
191
+ * Call on the root just before `toSource`. When a statement is added at the
192
+ * top level (a new import), recast reprints the program: it reuses each
193
+ * directive's original text, semicolon included, and then adds a semicolon of
194
+ * its own, so `'use client';` came back as `'use client';;`. A new directive
195
+ * node has no original text to reuse, and carrying the raw string keeps its
196
+ * quotes as written.
197
+ */
198
+ export function reprintDirectives(j, root) {
199
+ const program = root.find(j.Program).paths()[0]?.node;
200
+ if (!program?.directives?.length)
201
+ return;
202
+ program.directives = program.directives.map((directive) => {
203
+ const literal = j.directiveLiteral(directive.value.value);
204
+ const raw = directive.value.extra?.raw;
205
+ if (typeof raw === 'string') {
206
+ literal.extra = { raw, rawValue: directive.value.value };
207
+ }
208
+ const fresh = j.directive(literal);
209
+ fresh.comments = directive.comments;
210
+ return fresh;
211
+ });
154
212
  }
155
213
  /**
156
214
  * Attach a `// TODO(bestax-migrate): ...` leading comment to the closest
@@ -1 +1 @@
1
- {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/props.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,GAAG,GACR,IAAI,CAmBN;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACnB,IAAI,CAoBN;AAED,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,CAqLN;AAED;;;;GAIG;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,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GACzC,IAAI,CAQN"}
1
+ {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/props.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAUL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,GAAG,GACR,IAAI,CAmBN;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACnB,IAAI,CAoBN;AAED,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,CAqLN;AAED;;;;GAIG;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,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GACzC,IAAI,CAQN"}
@@ -6,7 +6,7 @@
6
6
  * imported, so each source keeps its own `UNIVERSAL_PROPS` in its `mapping.ts`
7
7
  * while sharing this interpreter.
8
8
  */
9
- import { addAttr, addTodo, attributesOf, findAttr, literalValueOf, makeAttr, removeAttr, resolveBooleanish, } from './jsx-utils.js';
9
+ import { addAttr, addTodo, attributesOf, findAttr, jsxStringValue, literalValueOf, makeAttr, removeAttr, resolveBooleanish, } from './jsx-utils.js';
10
10
  /* eslint-disable @typescript-eslint/no-explicit-any */
11
11
  /**
12
12
  * Add a converted attribute unless the target name is already present — two
@@ -51,7 +51,7 @@ export function mergeClass(ctx, path, element, cls, originalName) {
51
51
  const classes = literal.value.split(/\s+/).filter(Boolean);
52
52
  if (!classes.includes(cls))
53
53
  classes.push(cls);
54
- existing.value = j.stringLiteral(classes.join(' '));
54
+ existing.value = jsxStringValue(j, classes.join(' '));
55
55
  return;
56
56
  }
57
57
  addTodo(ctx, path, `prop:${originalName}`, `\`${originalName}\` becomes the \`${cls}\` class, but \`className\` is dynamic here; add \`${cls}\` to it by hand`);
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bloomer/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AA8CvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CA4uBpB"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bloomer/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAgDvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CA8uBpB"}
@@ -22,7 +22,7 @@
22
22
  * value-reference passes below build those from the mapping's `target`.
23
23
  */
24
24
  import { HELPERLESS_TARGETS, MAPPING, NO_CLASSNAME_TARGETS, UNIVERSAL_PROPS, helperClassHint, resolveMapping, } from './mapping.js';
25
- import { addTodo, attributesOf, jsxNameParts, literalValueOf, removeAttr, renameElement, } from '../_shared/jsx-utils.js';
25
+ import { addTodo, attributesOf, forgetJsxParens, jsxNameParts, literalValueOf, removeAttr, renameElement, reprintDirectives, } from '../_shared/jsx-utils.js';
26
26
  import { applyPropAction, applyUniversalProps, mergeClass, } from '../_shared/props.js';
27
27
  import { enforcePolymorphicProps } from '../_shared/polymorphic.js';
28
28
  import { bestaxValueLocals, buildBestaxImport, carryPrunedComments, placeBestaxImport, seedBestaxImport, } from '../_shared/bestax-import.js';
@@ -644,6 +644,8 @@ export default function transform(fileInfo, api, options = {}) {
644
644
  // import rewrite, so the drop is visible in the file and not only the report.
645
645
  if (!ctx.dirty)
646
646
  return undefined;
647
+ forgetJsxParens(j, root);
648
+ reprintDirectives(j, root);
647
649
  // Double quotes match the dominant JSX-attribute convention; users run
648
650
  // their own formatter afterwards anyway. Tab-indented sources keep tabs so
649
651
  // reprinted nodes don't drift from the untouched lines around them.