bestax-migrate 2.1.5 → 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.
- package/README.md +14 -8
- package/dist/cli.d.ts +53 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +159 -9
- package/dist/sources/_shared/imports.d.ts +46 -0
- package/dist/sources/_shared/imports.d.ts.map +1 -0
- package/dist/sources/_shared/imports.js +152 -0
- package/dist/sources/{react-bulma-components → _shared}/jsx-utils.d.ts +20 -12
- package/dist/sources/_shared/jsx-utils.d.ts.map +1 -0
- package/dist/sources/{react-bulma-components → _shared}/jsx-utils.js +15 -10
- package/dist/sources/_shared/make-styles-transform.d.ts +37 -0
- package/dist/sources/_shared/make-styles-transform.d.ts.map +1 -0
- package/dist/sources/_shared/make-styles-transform.js +440 -0
- package/dist/sources/_shared/props.d.ts +20 -0
- package/dist/sources/_shared/props.d.ts.map +1 -0
- package/dist/sources/{react-bulma-components → _shared}/props.js +11 -7
- package/dist/sources/_shared/specials-utils.d.ts +45 -0
- package/dist/sources/_shared/specials-utils.d.ts.map +1 -0
- package/dist/sources/_shared/specials-utils.js +124 -0
- package/dist/sources/rbx/deps.d.ts +18 -0
- package/dist/sources/rbx/deps.d.ts.map +1 -0
- package/dist/sources/rbx/deps.js +287 -0
- package/dist/sources/rbx/index.d.ts +3 -0
- package/dist/sources/rbx/index.d.ts.map +1 -0
- package/dist/sources/rbx/index.js +10 -0
- package/dist/sources/rbx/mapping.d.ts +49 -0
- package/dist/sources/rbx/mapping.d.ts.map +1 -0
- package/dist/sources/rbx/mapping.js +924 -0
- package/dist/sources/rbx/responsive.d.ts +30 -0
- package/dist/sources/rbx/responsive.d.ts.map +1 -0
- package/dist/sources/rbx/responsive.js +279 -0
- package/dist/sources/rbx/specials.d.ts +21 -0
- package/dist/sources/rbx/specials.d.ts.map +1 -0
- package/dist/sources/rbx/specials.js +706 -0
- package/dist/sources/rbx/styles.d.ts +21 -0
- package/dist/sources/rbx/styles.d.ts.map +1 -0
- package/dist/sources/rbx/styles.js +29 -0
- package/dist/sources/rbx/transform.d.ts +25 -0
- package/dist/sources/rbx/transform.d.ts.map +1 -0
- package/dist/sources/rbx/transform.js +911 -0
- package/dist/sources/react-bulma-components/deps.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/deps.js +16 -0
- package/dist/sources/react-bulma-components/responsive.d.ts +1 -1
- package/dist/sources/react-bulma-components/responsive.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/responsive.js +1 -1
- package/dist/sources/react-bulma-components/specials.d.ts +3 -9
- package/dist/sources/react-bulma-components/specials.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/specials.js +4 -91
- package/dist/sources/react-bulma-components/styles.d.ts +9 -9
- package/dist/sources/react-bulma-components/styles.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/styles.js +17 -389
- package/dist/sources/react-bulma-components/transform.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/transform.js +378 -101
- package/dist/sources/registry.d.ts.map +1 -1
- package/dist/sources/registry.js +2 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -7
- package/dist/sources/react-bulma-components/jsx-utils.d.ts.map +0 -1
- package/dist/sources/react-bulma-components/props.d.ts +0 -15
- package/dist/sources/react-bulma-components/props.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://socket.dev/npm/package/bestax-migrate/overview)
|
|
7
7
|
[](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)
|
|
8
|
+
[](https://www.bestpractices.dev/projects/14361)
|
|
8
9
|
[](https://www.npmjs.com/package/bestax-migrate#provenance)
|
|
9
10
|
[](https://github.com/allxsmith/bestax/blob/main/SECURITY.md)
|
|
10
11
|
|
|
@@ -12,9 +13,12 @@ Codemods that migrate existing React apps to [`@allxsmith/bestax-bulma`](https:/
|
|
|
12
13
|
|
|
13
14
|
Currently supported source libraries:
|
|
14
15
|
|
|
15
|
-
| Source | Status
|
|
16
|
-
| -------------------------------------------------------------------------------- |
|
|
17
|
-
| [`react-bulma-components`](https://github.com/couds/react-bulma-components) (v4) | ✅ All 32 components mapped (a few patterns are flagged as TODOs)
|
|
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
|
+
|
|
21
|
+
Pass the source library as the first argument: `bestax-migrate <source> <paths…>`.
|
|
18
22
|
|
|
19
23
|
## Requirements
|
|
20
24
|
|
|
@@ -29,6 +33,8 @@ the app being migrated — the source is read as text and is never executed.
|
|
|
29
33
|
```bash
|
|
30
34
|
# Preview what would change (no writes)
|
|
31
35
|
pnpm dlx bestax-migrate react-bulma-components src/ --dry
|
|
36
|
+
# …or, for an rbx app
|
|
37
|
+
pnpm dlx bestax-migrate rbx src/ --dry
|
|
32
38
|
|
|
33
39
|
# Apply the migration
|
|
34
40
|
pnpm dlx bestax-migrate react-bulma-components src/
|
|
@@ -38,15 +44,15 @@ npm and yarn work too: `npx bestax-migrate …` / `yarn dlx bestax-migrate …`.
|
|
|
38
44
|
|
|
39
45
|
The codemod uses [jscodeshift](https://github.com/facebook/jscodeshift) to:
|
|
40
46
|
|
|
41
|
-
- rewrite
|
|
47
|
+
- rewrite the source library's imports to `@allxsmith/bestax-bulma` (including destructuring and namespace imports)
|
|
42
48
|
- rename components and compound sub-components (`Form.Textarea` → `TextArea`, `Card.Footer.Item` → `Card.FooterItem`, `Hero.Footer` → `Hero.Foot`, …)
|
|
43
49
|
- convert props (`renderAs` → `as`, `loading` → `isLoading`, numeric spacing/text sizes → string unions, `textAlign="center"` → `textAlign="centered"`, …)
|
|
44
50
|
- flatten responsive breakpoint objects (`mobile={{ size: 4 }}` → `sizeMobile={4}`)
|
|
45
51
|
- restructure patterns bestax models differently (`Table.Container`, Navbar dropdowns, `Form.Help`, icon-font children → `<Icon name=…>`)
|
|
46
52
|
- 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'`
|
|
47
|
-
- update `package.json`: remove
|
|
53
|
+
- 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
|
|
48
54
|
|
|
49
|
-
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
|
|
55
|
+
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)), or let the [`bestax-migrate` Agent Skill](https://bestax.io/docs/skills/intro) walk them for you:
|
|
50
56
|
|
|
51
57
|
```bash
|
|
52
58
|
npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate
|
|
@@ -68,7 +74,7 @@ npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate
|
|
|
68
74
|
2. Search for `TODO(bestax-migrate)` and resolve each comment
|
|
69
75
|
3. Typecheck/build and review the rendered app
|
|
70
76
|
|
|
71
|
-
Full walkthrough: [react-bulma-components migration guide](https://bestax.io/docs/guides/getting-started/migration/react-bulma-components).
|
|
77
|
+
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).
|
|
72
78
|
|
|
73
79
|
## Hardened by default
|
|
74
80
|
|
|
@@ -99,4 +105,4 @@ Full disclosure of every field and control: [Telemetry guide](https://bestax.io/
|
|
|
99
105
|
|
|
100
106
|
## License
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
Source code licensed MIT
|
package/dist/cli.d.ts
CHANGED
|
@@ -22,6 +22,59 @@ export interface CliIo {
|
|
|
22
22
|
log: (message: string) => void;
|
|
23
23
|
error: (message: string) => void;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Matches an import of `name` at a specifier boundary, in every form a
|
|
27
|
+
* retained reference can take: a root or DEEP JavaScript import
|
|
28
|
+
* (`from 'rbx'`, `from 'rbx/base/theme'` — deep ones are kept with a TODO), a
|
|
29
|
+
* bindingless side-effect `import 'rbx'` (which the transform leaves untouched
|
|
30
|
+
* because there is nothing to rewrite), the CommonJS / dynamic forms
|
|
31
|
+
* `require('rbx')` and `import('rbx')` — neither of which the jscodeshift
|
|
32
|
+
* transform rewrites, so both survive the run as live references — and the
|
|
33
|
+
* Sass forms the stylesheet transform preserves in indented `.sass` files
|
|
34
|
+
* (`@import '~rbx/rbx'`).
|
|
35
|
+
*
|
|
36
|
+
* Matching only `from '<pkg>'` meant a file whose ONLY remaining reference was
|
|
37
|
+
* a deep or Sass import let the manifest pass drop the package with no
|
|
38
|
+
* warning. Matching a bare substring is the opposite error, and worse for a
|
|
39
|
+
* name as short as `rbx`: prose and a sibling package like `rbx-utils` both
|
|
40
|
+
* counted as imports.
|
|
41
|
+
*
|
|
42
|
+
* Comments are allowed wherever whitespace is, because a webpack magic comment
|
|
43
|
+
* sits exactly there: `import(/* webpackChunkName: "x" *\/ 'rbx')`.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Blank out comments while preserving strings, offsets, and line breaks.
|
|
47
|
+
*
|
|
48
|
+
* The import matcher needs to know whether a keyword is real code, and no
|
|
49
|
+
* lookbehind can tell it: `// import { Box } from 'rbx'` is not an import,
|
|
50
|
+
* while the `//` inside `const u = 'http://x'; require('rbx')` is not a
|
|
51
|
+
* comment. Comment bytes become spaces rather than being deleted so the
|
|
52
|
+
* caller's line lookup still lines up with the original text.
|
|
53
|
+
*
|
|
54
|
+
* Deliberately small: this is not a JavaScript lexer. It tracks quotes and the
|
|
55
|
+
* two comment forms, which is what the matcher needs, and it is applied to
|
|
56
|
+
* `.sass` and `.vue` files too, where `//` is also a comment.
|
|
57
|
+
*/
|
|
58
|
+
export declare function blankComments(text: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Matches an import of `name` at a specifier boundary, in every form a
|
|
61
|
+
* retained reference can take: a root or DEEP JavaScript import
|
|
62
|
+
* (`from 'rbx'`, `from 'rbx/base/theme'`), a bindingless side-effect
|
|
63
|
+
* `import 'rbx'`, a re-export, the CommonJS and dynamic forms `require('rbx')`
|
|
64
|
+
* and `import('rbx')` — none of which the jscodeshift transform rewrites, so
|
|
65
|
+
* all survive the run as live references — and the Sass form the stylesheet
|
|
66
|
+
* transform preserves in indented `.sass` files (`@import '~rbx/rbx'`).
|
|
67
|
+
*
|
|
68
|
+
* Run it over `blankComments(text)`, not the raw text: the keyword alternatives
|
|
69
|
+
* carry no comment awareness of their own by design, because that job needs a
|
|
70
|
+
* scanner rather than a lookbehind.
|
|
71
|
+
*
|
|
72
|
+
* Matching only `from '<pkg>'` meant a file whose ONLY remaining reference was
|
|
73
|
+
* a deep or Sass import let the manifest pass drop the package with no warning.
|
|
74
|
+
* Matching a bare substring is the opposite error, and worse for a name as
|
|
75
|
+
* short as `rbx`: prose and a sibling package like `rbx-utils` both counted.
|
|
76
|
+
*/
|
|
77
|
+
export declare function makeSourceImportRe(name: string): RegExp;
|
|
25
78
|
/**
|
|
26
79
|
* One-question consent prompt (readline — this package carries no interactive
|
|
27
80
|
* prompt dependency). Returns null when the question is cancelled (Ctrl-C /
|
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;AAqBxE,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;
|
|
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;AAqBxE,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;AA8JD;;;;;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"}
|
package/dist/cli.js
CHANGED
|
@@ -79,8 +79,132 @@ export function findPackageJsons(targets) {
|
|
|
79
79
|
}
|
|
80
80
|
return [...found].sort();
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Matches an import of `name` at a specifier boundary, in every form a
|
|
84
|
+
* retained reference can take: a root or DEEP JavaScript import
|
|
85
|
+
* (`from 'rbx'`, `from 'rbx/base/theme'` — deep ones are kept with a TODO), a
|
|
86
|
+
* bindingless side-effect `import 'rbx'` (which the transform leaves untouched
|
|
87
|
+
* because there is nothing to rewrite), the CommonJS / dynamic forms
|
|
88
|
+
* `require('rbx')` and `import('rbx')` — neither of which the jscodeshift
|
|
89
|
+
* transform rewrites, so both survive the run as live references — and the
|
|
90
|
+
* Sass forms the stylesheet transform preserves in indented `.sass` files
|
|
91
|
+
* (`@import '~rbx/rbx'`).
|
|
92
|
+
*
|
|
93
|
+
* Matching only `from '<pkg>'` meant a file whose ONLY remaining reference was
|
|
94
|
+
* a deep or Sass import let the manifest pass drop the package with no
|
|
95
|
+
* warning. Matching a bare substring is the opposite error, and worse for a
|
|
96
|
+
* name as short as `rbx`: prose and a sibling package like `rbx-utils` both
|
|
97
|
+
* counted as imports.
|
|
98
|
+
*
|
|
99
|
+
* Comments are allowed wherever whitespace is, because a webpack magic comment
|
|
100
|
+
* sits exactly there: `import(/* webpackChunkName: "x" *\/ 'rbx')`.
|
|
101
|
+
*/
|
|
102
|
+
/**
|
|
103
|
+
* Blank out comments while preserving strings, offsets, and line breaks.
|
|
104
|
+
*
|
|
105
|
+
* The import matcher needs to know whether a keyword is real code, and no
|
|
106
|
+
* lookbehind can tell it: `// import { Box } from 'rbx'` is not an import,
|
|
107
|
+
* while the `//` inside `const u = 'http://x'; require('rbx')` is not a
|
|
108
|
+
* comment. Comment bytes become spaces rather than being deleted so the
|
|
109
|
+
* caller's line lookup still lines up with the original text.
|
|
110
|
+
*
|
|
111
|
+
* Deliberately small: this is not a JavaScript lexer. It tracks quotes and the
|
|
112
|
+
* two comment forms, which is what the matcher needs, and it is applied to
|
|
113
|
+
* `.sass` and `.vue` files too, where `//` is also a comment.
|
|
114
|
+
*/
|
|
115
|
+
export function blankComments(text) {
|
|
116
|
+
let out = '';
|
|
117
|
+
let quote = null;
|
|
118
|
+
let i = 0;
|
|
119
|
+
while (i < text.length) {
|
|
120
|
+
const c = text[i];
|
|
121
|
+
const next = text[i + 1];
|
|
122
|
+
if (quote) {
|
|
123
|
+
if (c === '\\' && i + 1 < text.length) {
|
|
124
|
+
out += c + next;
|
|
125
|
+
i += 2;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (c === quote)
|
|
129
|
+
quote = null;
|
|
130
|
+
out += c;
|
|
131
|
+
i += 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
135
|
+
quote = c;
|
|
136
|
+
out += c;
|
|
137
|
+
i += 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (c === '/' && next === '/') {
|
|
141
|
+
while (i < text.length && text[i] !== '\n') {
|
|
142
|
+
out += ' ';
|
|
143
|
+
i += 1;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (c === '/' && next === '*') {
|
|
148
|
+
out += ' ';
|
|
149
|
+
i += 2;
|
|
150
|
+
while (i < text.length && !(text[i] === '*' && text[i + 1] === '/')) {
|
|
151
|
+
out += text[i] === '\n' ? '\n' : ' ';
|
|
152
|
+
i += 1;
|
|
153
|
+
}
|
|
154
|
+
if (i < text.length) {
|
|
155
|
+
out += ' ';
|
|
156
|
+
i += 2;
|
|
157
|
+
}
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
out += c;
|
|
161
|
+
i += 1;
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Matches an import of `name` at a specifier boundary, in every form a
|
|
167
|
+
* retained reference can take: a root or DEEP JavaScript import
|
|
168
|
+
* (`from 'rbx'`, `from 'rbx/base/theme'`), a bindingless side-effect
|
|
169
|
+
* `import 'rbx'`, a re-export, the CommonJS and dynamic forms `require('rbx')`
|
|
170
|
+
* and `import('rbx')` — none of which the jscodeshift transform rewrites, so
|
|
171
|
+
* all survive the run as live references — and the Sass form the stylesheet
|
|
172
|
+
* transform preserves in indented `.sass` files (`@import '~rbx/rbx'`).
|
|
173
|
+
*
|
|
174
|
+
* Run it over `blankComments(text)`, not the raw text: the keyword alternatives
|
|
175
|
+
* carry no comment awareness of their own by design, because that job needs a
|
|
176
|
+
* scanner rather than a lookbehind.
|
|
177
|
+
*
|
|
178
|
+
* Matching only `from '<pkg>'` meant a file whose ONLY remaining reference was
|
|
179
|
+
* a deep or Sass import let the manifest pass drop the package with no warning.
|
|
180
|
+
* Matching a bare substring is the opposite error, and worse for a name as
|
|
181
|
+
* short as `rbx`: prose and a sibling package like `rbx-utils` both counted.
|
|
182
|
+
*/
|
|
183
|
+
export function makeSourceImportRe(name) {
|
|
184
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
185
|
+
const spec = `['"](?:~|(?:\\.\\.?/)+node_modules/)?${escaped}(?:/[^'"]*)?['"]`;
|
|
186
|
+
// Not the tail of a longer identifier: `myrequire('rbx')` is not a require,
|
|
187
|
+
// and `foo.import(...)` is not an import.
|
|
188
|
+
const lead = String.raw `(?<![\w$.])`;
|
|
189
|
+
return new RegExp([
|
|
190
|
+
// A static import or re-export. The keyword is what separates a real
|
|
191
|
+
// specifier from a bare `from` in prose ("Migrated from 'rbx' in 2019").
|
|
192
|
+
// `[^;]` spans the newlines of a multi-line specifier list without
|
|
193
|
+
// running past the statement.
|
|
194
|
+
`${lead}(?:import|export)\\b[^;]*?\\bfrom\\s*${spec}`,
|
|
195
|
+
// A bindingless side-effect import, and the Sass form.
|
|
196
|
+
`${lead}import\\s*${spec}`,
|
|
197
|
+
`@import\\s*${spec}`,
|
|
198
|
+
// The dynamic and CommonJS forms, which appear mid-expression.
|
|
199
|
+
// `require.resolve('rbx')` is as live a reference as `require('rbx')`
|
|
200
|
+
// and is just as unrewritten by the transform.
|
|
201
|
+
`${lead}(?:import|require(?:\\.resolve)?)\\s*\\(\\s*${spec}`,
|
|
202
|
+
].join('|'));
|
|
203
|
+
}
|
|
82
204
|
function migrateFiles(source, files, reporter, io, options) {
|
|
83
205
|
let bulmaReferenced = false;
|
|
206
|
+
let sourceStillImported = false;
|
|
207
|
+
const sourceImportRe = makeSourceImportRe(source.name);
|
|
84
208
|
for (const file of files) {
|
|
85
209
|
const sourceText = fs.readFileSync(file, 'utf8');
|
|
86
210
|
const collector = reporter.startFile();
|
|
@@ -103,12 +227,23 @@ function migrateFiles(source, files, reporter, io, options) {
|
|
|
103
227
|
}
|
|
104
228
|
catch (error) {
|
|
105
229
|
io.error(chalk.red(`✖ ${file}: ${error.message}`));
|
|
230
|
+
// Read the signals off the ORIGINAL text before bailing. A parse
|
|
231
|
+
// failure in the only file importing the source library would
|
|
232
|
+
// otherwise let the manifest pass remove the package with no warning —
|
|
233
|
+
// the file still imports it, we just couldn't rewrite it.
|
|
234
|
+
if (/['"](?:~?bulma\/)/.test(sourceText))
|
|
235
|
+
bulmaReferenced = true;
|
|
236
|
+
if (sourceImportRe.test(blankComments(sourceText)))
|
|
237
|
+
sourceStillImported = true;
|
|
106
238
|
reporter.finishFile(file, false, collector.entries);
|
|
107
239
|
continue;
|
|
108
240
|
}
|
|
109
241
|
if (/['"](?:~?bulma\/)/.test(output ?? sourceText)) {
|
|
110
242
|
bulmaReferenced = true;
|
|
111
243
|
}
|
|
244
|
+
if (sourceImportRe.test(blankComments(output ?? sourceText))) {
|
|
245
|
+
sourceStillImported = true;
|
|
246
|
+
}
|
|
112
247
|
if (output !== null) {
|
|
113
248
|
if (options.print)
|
|
114
249
|
io.log(output);
|
|
@@ -117,7 +252,7 @@ function migrateFiles(source, files, reporter, io, options) {
|
|
|
117
252
|
}
|
|
118
253
|
reporter.finishFile(file, output !== null, collector.entries);
|
|
119
254
|
}
|
|
120
|
-
return bulmaReferenced;
|
|
255
|
+
return { bulmaReferenced, sourceStillImported };
|
|
121
256
|
}
|
|
122
257
|
/**
|
|
123
258
|
* Surface files in unparseable formats (.astro, .vue, …) that import the
|
|
@@ -126,13 +261,24 @@ function migrateFiles(source, files, reporter, io, options) {
|
|
|
126
261
|
function reportUnsupportedFiles(source, targets, reporter, extensions) {
|
|
127
262
|
const unsupported = UNSUPPORTED_EXTENSIONS.filter(ext => !extensions.includes(ext));
|
|
128
263
|
if (unsupported.length === 0)
|
|
129
|
-
return;
|
|
264
|
+
return false;
|
|
265
|
+
// Whether any unsupported file still references the source package. These
|
|
266
|
+
// are reported but never rewritten, so the reference survives the run —
|
|
267
|
+
// and the manifest pass must not remove the package out from under it.
|
|
268
|
+
let stillImported = false;
|
|
269
|
+
const importRe = makeSourceImportRe(source.name);
|
|
130
270
|
for (const file of collectFiles(targets, unsupported)) {
|
|
131
271
|
const text = fs.readFileSync(file, 'utf8');
|
|
132
|
-
|
|
272
|
+
// A substring match is not evidence of an import. `rbx` is three
|
|
273
|
+
// characters: prose in an .mdx file and a sibling package like
|
|
274
|
+
// `rbx-utils` both matched, which reported a file that imports nothing
|
|
275
|
+
// and pinned the dependency the manifest pass would otherwise remove.
|
|
276
|
+
const scanned = blankComments(text);
|
|
277
|
+
if (!importRe.test(scanned))
|
|
133
278
|
continue;
|
|
279
|
+
stillImported = true;
|
|
134
280
|
const collector = reporter.startFile();
|
|
135
|
-
const line =
|
|
281
|
+
const line = scanned.split('\n').findIndex(l => importRe.test(l)) + 1 || null;
|
|
136
282
|
collector.add({
|
|
137
283
|
file,
|
|
138
284
|
line,
|
|
@@ -141,8 +287,9 @@ function reportUnsupportedFiles(source, targets, reporter, extensions) {
|
|
|
141
287
|
});
|
|
142
288
|
reporter.finishFile(file, false, collector.entries);
|
|
143
289
|
}
|
|
290
|
+
return stillImported;
|
|
144
291
|
}
|
|
145
|
-
function migrateDependencies(source, targets, reporter, io, options,
|
|
292
|
+
function migrateDependencies(source, targets, reporter, io, options, deps) {
|
|
146
293
|
if (!options.deps || !source.updateDependencies)
|
|
147
294
|
return;
|
|
148
295
|
for (const pkgPath of findPackageJsons(targets)) {
|
|
@@ -153,7 +300,8 @@ function migrateDependencies(source, targets, reporter, io, options, bulmaRefere
|
|
|
153
300
|
const pkg = JSON.parse(raw);
|
|
154
301
|
const next = source.updateDependencies(pkgPath, pkg, collector, {
|
|
155
302
|
cssMode: options.cssMode,
|
|
156
|
-
bulmaReferenced,
|
|
303
|
+
bulmaReferenced: deps.bulmaReferenced,
|
|
304
|
+
sourceStillImported: deps.sourceStillImported,
|
|
157
305
|
});
|
|
158
306
|
if (next !== null) {
|
|
159
307
|
changed = true;
|
|
@@ -307,9 +455,11 @@ export function createCLI(io = { log: console.log, error: console.error }) {
|
|
|
307
455
|
cssMode: options.css,
|
|
308
456
|
};
|
|
309
457
|
const reporter = new Reporter();
|
|
310
|
-
const
|
|
311
|
-
reportUnsupportedFiles(source, targets, reporter, extensions);
|
|
312
|
-
|
|
458
|
+
const depSignals = migrateFiles(source, files, reporter, io, runOptions);
|
|
459
|
+
const unsupportedImports = reportUnsupportedFiles(source, targets, reporter, extensions);
|
|
460
|
+
if (unsupportedImports)
|
|
461
|
+
depSignals.sourceStillImported = true;
|
|
462
|
+
migrateDependencies(source, targets, reporter, io, runOptions, depSignals);
|
|
313
463
|
io.log(reporter.render(source.label + (runOptions.dry ? ' (dry run)' : '')));
|
|
314
464
|
displayStarNudge(io);
|
|
315
465
|
// Success path only: rule names and counts, never file/line/message.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import-rewriting mechanics shared by every source transform: collecting the
|
|
3
|
+
* names a file already binds, and handing out non-colliding local names for
|
|
4
|
+
* the bestax imports a transform wants to add.
|
|
5
|
+
*
|
|
6
|
+
* Source-agnostic: nothing here knows which library is being migrated.
|
|
7
|
+
*/
|
|
8
|
+
import type { ASTPath, Collection, JSCodeshift } from 'jscodeshift';
|
|
9
|
+
import type { TransformContext } from './jsx-utils.js';
|
|
10
|
+
export declare const nameOf: (node: any) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Every identifier the file already binds — variables, function and class
|
|
13
|
+
* declarations, parameters (including destructured ones), and imports other
|
|
14
|
+
* than the source library's own (those are pruned by the caller).
|
|
15
|
+
*
|
|
16
|
+
* Importing a bestax component under a name the file already uses would
|
|
17
|
+
* redeclare it, so these names drive the aliasing in `makeReserve`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function collectBoundNames(j: JSCodeshift, root: Collection<any>, skipImportSource: string): Set<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Build the `ctx.reserve` implementation: register a bestax import by its
|
|
22
|
+
* exported name and get back the local name to write in JSX — the plain name
|
|
23
|
+
* when it is free, otherwise `Bulma<Name>` (then `Bulma<Name>2`, …).
|
|
24
|
+
*/
|
|
25
|
+
export declare function makeReserve(ctx: TransformContext, bound: Set<string>): (importedName: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Tab-indented sources keep tabs when reprinted, so recast's output does not
|
|
28
|
+
* drift from the untouched lines around it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function prefersTabs(source: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* True when the identifier `name` at `path` really resolves to the binding
|
|
33
|
+
* the import/alias passes recorded, rather than a local that shadows it.
|
|
34
|
+
*
|
|
35
|
+
* Both passes key on identifier TEXT, so a nested `function F({ Card })`
|
|
36
|
+
* parameter looked exactly like the source library's `Card`: its JSX was
|
|
37
|
+
* rewritten to bestax's `Card.FooterItem` and the destructured parameter was
|
|
38
|
+
* renamed alongside it, silently repointing the code at a different object.
|
|
39
|
+
*
|
|
40
|
+
* `expected` is the scope the binding was collected in — the program scope for
|
|
41
|
+
* an import (they are always top-level), or the declaring scope of a
|
|
42
|
+
* `const { Item } = Card` alias, which the alias pass records because it walks
|
|
43
|
+
* declarators at any depth.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolvesToBinding(path: ASTPath<any>, name: string, expected: unknown): boolean;
|
|
46
|
+
//# sourceMappingURL=imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/imports.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,eAAO,MAAM,MAAM,GAAI,MAAM,GAAG,KAAG,MACyB,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,WAAW,EACd,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EACrB,gBAAgB,EAAE,MAAM,GACvB,GAAG,CAAC,MAAM,CAAC,CAmEb;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GACjB,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAiBlC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAQnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,GAChB,OAAO,CAST"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import-rewriting mechanics shared by every source transform: collecting the
|
|
3
|
+
* names a file already binds, and handing out non-colliding local names for
|
|
4
|
+
* the bestax imports a transform wants to add.
|
|
5
|
+
*
|
|
6
|
+
* Source-agnostic: nothing here knows which library is being migrated.
|
|
7
|
+
*/
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
9
|
+
export const nameOf = (node) => typeof node === 'string' ? node : String(node?.name ?? '');
|
|
10
|
+
/**
|
|
11
|
+
* Every identifier the file already binds — variables, function and class
|
|
12
|
+
* declarations, parameters (including destructured ones), and imports other
|
|
13
|
+
* than the source library's own (those are pruned by the caller).
|
|
14
|
+
*
|
|
15
|
+
* Importing a bestax component under a name the file already uses would
|
|
16
|
+
* redeclare it, so these names drive the aliasing in `makeReserve`.
|
|
17
|
+
*/
|
|
18
|
+
export function collectBoundNames(j, root, skipImportSource) {
|
|
19
|
+
const bound = new Set();
|
|
20
|
+
const collectPattern = (node) => {
|
|
21
|
+
if (!node)
|
|
22
|
+
return;
|
|
23
|
+
switch (node.type) {
|
|
24
|
+
case 'Identifier':
|
|
25
|
+
bound.add(node.name);
|
|
26
|
+
break;
|
|
27
|
+
case 'ObjectPattern':
|
|
28
|
+
for (const prop of node.properties ?? []) {
|
|
29
|
+
collectPattern(prop.value ?? prop.argument);
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
case 'ArrayPattern':
|
|
33
|
+
for (const el of node.elements ?? [])
|
|
34
|
+
collectPattern(el);
|
|
35
|
+
break;
|
|
36
|
+
case 'RestElement':
|
|
37
|
+
collectPattern(node.argument);
|
|
38
|
+
break;
|
|
39
|
+
case 'AssignmentPattern':
|
|
40
|
+
collectPattern(node.left);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
root.find(j.VariableDeclarator).forEach(path => collectPattern(path.node.id));
|
|
45
|
+
root.find(j.FunctionDeclaration).forEach(path => {
|
|
46
|
+
if (path.node.id)
|
|
47
|
+
bound.add(nameOf(path.node.id));
|
|
48
|
+
for (const param of path.node.params ?? [])
|
|
49
|
+
collectPattern(param);
|
|
50
|
+
});
|
|
51
|
+
root
|
|
52
|
+
.find(j.ClassDeclaration)
|
|
53
|
+
.forEach(path => path.node.id && bound.add(nameOf(path.node.id)));
|
|
54
|
+
// TypeScript declaration forms that occupy a name an import would collide
|
|
55
|
+
// with. An `enum Button` next to a generated `import { Button }` is a
|
|
56
|
+
// duplicate-identifier build break, and the alias pass could not see it.
|
|
57
|
+
// Interfaces and type aliases share the declaration space with an imported
|
|
58
|
+
// binding of the same name too, so they reserve as well — an unnecessary
|
|
59
|
+
// alias costs nothing, a missed one does not compile.
|
|
60
|
+
for (const kind of [
|
|
61
|
+
'TSEnumDeclaration',
|
|
62
|
+
'TSModuleDeclaration',
|
|
63
|
+
'TSInterfaceDeclaration',
|
|
64
|
+
'TSTypeAliasDeclaration',
|
|
65
|
+
]) {
|
|
66
|
+
root.find(j[kind]).forEach((path) => {
|
|
67
|
+
const id = path.node.id;
|
|
68
|
+
if (id && (id.type === 'Identifier' || id.type === 'StringLiteral')) {
|
|
69
|
+
bound.add(nameOf(id));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
root.find(j.FunctionExpression).forEach(path => {
|
|
74
|
+
for (const param of path.node.params ?? [])
|
|
75
|
+
collectPattern(param);
|
|
76
|
+
});
|
|
77
|
+
root.find(j.ArrowFunctionExpression).forEach(path => {
|
|
78
|
+
for (const param of path.node.params ?? [])
|
|
79
|
+
collectPattern(param);
|
|
80
|
+
});
|
|
81
|
+
root.find(j.ImportDeclaration).forEach(path => {
|
|
82
|
+
if (String(path.node.source.value) === skipImportSource)
|
|
83
|
+
return;
|
|
84
|
+
for (const spec of path.node.specifiers ?? []) {
|
|
85
|
+
if (spec.local)
|
|
86
|
+
bound.add(nameOf(spec.local));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return bound;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the `ctx.reserve` implementation: register a bestax import by its
|
|
93
|
+
* exported name and get back the local name to write in JSX — the plain name
|
|
94
|
+
* when it is free, otherwise `Bulma<Name>` (then `Bulma<Name>2`, …).
|
|
95
|
+
*/
|
|
96
|
+
export function makeReserve(ctx, bound) {
|
|
97
|
+
return (importedName) => {
|
|
98
|
+
const existing = ctx.needed.get(importedName);
|
|
99
|
+
if (existing)
|
|
100
|
+
return existing;
|
|
101
|
+
let local = importedName;
|
|
102
|
+
if (bound.has(local)) {
|
|
103
|
+
local = `Bulma${importedName}`;
|
|
104
|
+
let suffix = 2;
|
|
105
|
+
const locals = new Set(ctx.needed.values());
|
|
106
|
+
while (bound.has(local) || locals.has(local)) {
|
|
107
|
+
local = `Bulma${importedName}${suffix}`;
|
|
108
|
+
suffix += 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
ctx.needed.set(importedName, local);
|
|
112
|
+
return local;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Tab-indented sources keep tabs when reprinted, so recast's output does not
|
|
117
|
+
* drift from the untouched lines around it.
|
|
118
|
+
*/
|
|
119
|
+
export function prefersTabs(source) {
|
|
120
|
+
let tabs = 0;
|
|
121
|
+
let spaces = 0;
|
|
122
|
+
for (const line of source.split('\n')) {
|
|
123
|
+
if (line.startsWith('\t'))
|
|
124
|
+
tabs += 1;
|
|
125
|
+
else if (line.startsWith(' '))
|
|
126
|
+
spaces += 1;
|
|
127
|
+
}
|
|
128
|
+
return tabs > spaces;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* True when the identifier `name` at `path` really resolves to the binding
|
|
132
|
+
* the import/alias passes recorded, rather than a local that shadows it.
|
|
133
|
+
*
|
|
134
|
+
* Both passes key on identifier TEXT, so a nested `function F({ Card })`
|
|
135
|
+
* parameter looked exactly like the source library's `Card`: its JSX was
|
|
136
|
+
* rewritten to bestax's `Card.FooterItem` and the destructured parameter was
|
|
137
|
+
* renamed alongside it, silently repointing the code at a different object.
|
|
138
|
+
*
|
|
139
|
+
* `expected` is the scope the binding was collected in — the program scope for
|
|
140
|
+
* an import (they are always top-level), or the declaring scope of a
|
|
141
|
+
* `const { Item } = Card` alias, which the alias pass records because it walks
|
|
142
|
+
* declarators at any depth.
|
|
143
|
+
*/
|
|
144
|
+
export function resolvesToBinding(path, name, expected) {
|
|
145
|
+
if (!expected)
|
|
146
|
+
return true;
|
|
147
|
+
const declaring = path.scope?.lookup(name);
|
|
148
|
+
// An unresolvable name keeps the old behaviour rather than silently
|
|
149
|
+
// skipping work: a miss here means no rewrite at all, which is worse than
|
|
150
|
+
// the shadowing case it guards against.
|
|
151
|
+
return !declaring || declaring === expected;
|
|
152
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Small AST helpers shared by
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Small AST helpers shared by every source's transform passes. All functions
|
|
3
|
+
* operate on the babel/tsx AST that jscodeshift's `tsx` parser produces, via
|
|
4
|
+
* the `j` builder API.
|
|
5
|
+
*
|
|
6
|
+
* Nothing here may know which source library is being migrated — this module
|
|
7
|
+
* is imported by all of them (`react-bulma-components`, `rbx`, …), so any
|
|
8
|
+
* library-specific table belongs in that source's own `mapping.ts`.
|
|
5
9
|
*/
|
|
6
10
|
import type { JSCodeshift } from 'jscodeshift';
|
|
7
11
|
import type { ASTPath } from 'jscodeshift';
|
|
@@ -10,7 +14,7 @@ export interface TransformContext {
|
|
|
10
14
|
j: JSCodeshift;
|
|
11
15
|
file: string;
|
|
12
16
|
collector: TodoCollector | undefined;
|
|
13
|
-
/**
|
|
17
|
+
/** Source-library top-level import names that must survive the rewrite. */
|
|
14
18
|
retained: Set<string>;
|
|
15
19
|
/** bestax-bulma imports: imported name → local name (aliased on conflict). */
|
|
16
20
|
needed: Map<string, string>;
|
|
@@ -26,7 +30,10 @@ export interface TransformContext {
|
|
|
26
30
|
* Navbar.Item becomes Navbar.DropdownMenu).
|
|
27
31
|
*/
|
|
28
32
|
overrides: WeakMap<object, string>;
|
|
29
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Resolves a JSX name node to its canonical source-library path (set by the
|
|
35
|
+
* source's transform).
|
|
36
|
+
*/
|
|
30
37
|
resolve?: (name: any) => string[] | null;
|
|
31
38
|
dirty: boolean;
|
|
32
39
|
}
|
|
@@ -57,13 +64,14 @@ export type LiteralValue = {
|
|
|
57
64
|
export declare function literalValueOf(attr: any): LiteralValue;
|
|
58
65
|
export type Booleanish = 'truthy' | 'falsy' | 'expression';
|
|
59
66
|
/**
|
|
60
|
-
* Classify a JSX attribute by the truthiness
|
|
61
|
-
* runtime (`!!value`): every statically-known literal (boolean,
|
|
62
|
-
* number) resolves to `'truthy'`/`'falsy'`; only a genuine
|
|
63
|
-
* `'expression'`. This is the single place
|
|
64
|
-
* a "booleanish" prop (Button `remove`, Heading
|
|
65
|
-
* `booleanToProp`, the `active` ladders, Field
|
|
66
|
-
*
|
|
67
|
+
* Classify a JSX attribute by the truthiness the source library evaluates it
|
|
68
|
+
* with at runtime (`!!value`): every statically-known literal (boolean,
|
|
69
|
+
* string, or number) resolves to `'truthy'`/`'falsy'`; only a genuine
|
|
70
|
+
* expression is `'expression'`. This is the single place every call site that
|
|
71
|
+
* branches on a "booleanish" prop (RBC's Button `remove`, Heading
|
|
72
|
+
* `heading`/`subtitle`, `booleanToProp`, the `active` ladders, Field
|
|
73
|
+
* `multiline`; rbx's bare-boolean modifiers) agrees on what counts as
|
|
74
|
+
* resolvable, so they can't drift out of sync with each other.
|
|
67
75
|
*/
|
|
68
76
|
export declare function resolveBooleanish(attr: any): Booleanish;
|
|
69
77
|
/** Create `name` (bare boolean) or `name="value"` attribute. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/jsx-utils.ts"],"names":[],"mappings":"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"}
|