bestax-migrate 2.3.2 → 2.3.3
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/dist/sources/_shared/polymorphic.d.ts +15 -0
- package/dist/sources/_shared/polymorphic.d.ts.map +1 -1
- package/dist/sources/_shared/polymorphic.js +123 -13
- package/dist/sources/_shared/specials-utils.d.ts.map +1 -1
- package/dist/sources/_shared/specials-utils.js +3 -3
- package/package.json +2 -2
|
@@ -28,6 +28,21 @@
|
|
|
28
28
|
import type { ASTPath } from 'jscodeshift';
|
|
29
29
|
import { type TransformContext } from './jsx-utils.js';
|
|
30
30
|
export declare const AS_UNIONS: Record<string, readonly string[]>;
|
|
31
|
+
/**
|
|
32
|
+
* What to do with a link the element refuses. `carry` is true for an attribute
|
|
33
|
+
* that has to land ON the anchor to do anything (`target`, `download`, …) and
|
|
34
|
+
* false where the anchor itself IS the remedy (a bare `href`).
|
|
35
|
+
*
|
|
36
|
+
* Four answers, because "put an <a> inside" is wrong in three different ways:
|
|
37
|
+
* an anchor inside interactive content is invalid, an anchor inside a void
|
|
38
|
+
* element is impossible, and an anchor around a context-bound element puts it
|
|
39
|
+
* somewhere its parent may not be.
|
|
40
|
+
*
|
|
41
|
+
* Exported because `specials-utils.ts` reaches the same question from the plain
|
|
42
|
+
* markup side, and `bestax-migrate/CLAUDE.md` puts a rule two transforms need in
|
|
43
|
+
* `_shared/` rather than in one of them.
|
|
44
|
+
*/
|
|
45
|
+
export declare const nestOrClick: (rendered: string | undefined, carry?: boolean) => string;
|
|
31
46
|
/** The targets whose `as` this pass may believe. */
|
|
32
47
|
export declare function declaresAs(target: string): boolean;
|
|
33
48
|
/** The rows the type test holds to the library. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polymorphic.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/polymorphic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AA0BxB,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"polymorphic.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/polymorphic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AA0BxB,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAkB,CAAC;AAmK3E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,GACtB,UAAU,MAAM,GAAG,SAAS,EAC5B,eAAa,KACZ,MAmBF,CAAC;AAMF,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAQD,mDAAmD;AACnD,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAW,CAAC;AAC1D,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAuB,CAAC;AAuEpE,mDAAmD;AACnD,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAClD,CAAC;AAEpB;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAAkC,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAwH5C,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AASD,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAG3E;AAED,0DAA0D;AAC1D,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAoC,CAAC;AAE7E,6CAA6C;AAC7C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAC1C,CAAC;AAuLrB;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM;AACd;;;;;;;;;GASG;AACH,gBAAgB,UAAQ,GACvB,IAAI,CAsEN"}
|
|
@@ -84,6 +84,7 @@ const AS_ANY = new Set(['Button', 'Menu.Item', 'Navbar.Item', 'Navbar.Link']);
|
|
|
84
84
|
*/
|
|
85
85
|
const HREF_OK = {
|
|
86
86
|
Button: 'button',
|
|
87
|
+
'Dropdown.Item': 'a',
|
|
87
88
|
'Level.Item': 'div',
|
|
88
89
|
'Menu.Item': 'a',
|
|
89
90
|
'Navbar.Item': 'a',
|
|
@@ -106,7 +107,6 @@ const NO_HREF_HINT = {
|
|
|
106
107
|
// mapping said the right thing here before the entry moved into this table.
|
|
107
108
|
Delete: 'bestax `Delete` renders a <button> with no children and has no anchor form; wrap it in an <a>, or navigate in `onClick`',
|
|
108
109
|
'Card.Header.Icon': 'bestax `Card.Header.Icon` renders a <button>, so an <a> inside it would nest interactive elements; navigate in `onClick`, or wrap the whole icon in an <a>',
|
|
109
|
-
'Dropdown.Item': 'bestax `Dropdown.Item` declares no `href` and already renders an <a> by default, so an <a> inside would nest anchors; navigate in `onClick`',
|
|
110
110
|
};
|
|
111
111
|
/**
|
|
112
112
|
* Where to put a link on a target, for the attributes beside `href`. The same
|
|
@@ -117,12 +117,122 @@ const NO_HREF_HINT = {
|
|
|
117
117
|
const LINK_REMEDY = {
|
|
118
118
|
Delete: 'wrap it in an <a>, or navigate in `onClick`',
|
|
119
119
|
'Navbar.Dropdown': 'put it on the `<Navbar.Link>` inside',
|
|
120
|
-
//
|
|
121
|
-
//
|
|
120
|
+
// Already renders an interactive element, so "put an <a> inside" would nest
|
|
121
|
+
// one inside the other, which is invalid.
|
|
122
122
|
'Card.Header.Icon': 'navigate in `onClick`, or wrap the whole icon in an <a>',
|
|
123
|
-
'Dropdown.Item': 'navigate in `onClick`',
|
|
124
123
|
};
|
|
125
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Elements that may not CONTAIN an `<a>`, so "put an <a> inside" names markup
|
|
126
|
+
* the author cannot write.
|
|
127
|
+
*
|
|
128
|
+
* This is not the same question as "may an `<a>` contain it". Interactive
|
|
129
|
+
* content -- `button`, `input`, `details`, `iframe`, … -- may not be an `<a>`
|
|
130
|
+
* DESCENDANT, which rules out wrapping; only a subset also refuses an `<a>`
|
|
131
|
+
* child, which is what rules out nesting. `<details>` is the case that shows
|
|
132
|
+
* they differ: an `<a>` may not wrap one, and
|
|
133
|
+
* `<details><summary>…</summary><a href>…</a></details>` is ordinary valid
|
|
134
|
+
* markup. Conflating the two directions suppressed advice that was correct.
|
|
135
|
+
*
|
|
136
|
+
* So this set is only the second direction, read off each element's content
|
|
137
|
+
* model: `a` (transparent, but no `a` descendant), `button` (no interactive
|
|
138
|
+
* descendant), `select`/`textarea` (options and text only), `embed`/`input`
|
|
139
|
+
* (void), `iframe` (content model "nothing" — markup between the tags is not a
|
|
140
|
+
* usable child).
|
|
141
|
+
*
|
|
142
|
+
* `label` is deliberately NOT here, though it is interactive: its content model
|
|
143
|
+
* is phrasing content excluding labelable controls and nested labels, and an
|
|
144
|
+
* `<a>` is neither. It refuses to be WRAPPED, not to hold a link.
|
|
145
|
+
*
|
|
146
|
+
* `LINK_REMEDY` states the same thing per TARGET, for components that render
|
|
147
|
+
* such an element whatever `as` says; this states it per RENDERED ELEMENT, for
|
|
148
|
+
* the ones where the author's `as` chose it. `Dropdown.Item` needs both
|
|
149
|
+
* readings: it is a link by default and a `<button>` on request.
|
|
150
|
+
*/
|
|
151
|
+
const NO_ANCHOR_CHILD = new Set([
|
|
152
|
+
'a',
|
|
153
|
+
'button',
|
|
154
|
+
'embed',
|
|
155
|
+
'iframe',
|
|
156
|
+
'input',
|
|
157
|
+
'select',
|
|
158
|
+
'textarea',
|
|
159
|
+
]);
|
|
160
|
+
/**
|
|
161
|
+
* Elements an `<a>` may not WRAP, because they are interactive content and an
|
|
162
|
+
* `<a>` may have no interactive descendant. The complement of the set above
|
|
163
|
+
* rather than the same list: `details` and `label` refuse to be wrapped and
|
|
164
|
+
* accept an `<a>` child perfectly well, which is the whole reason the two
|
|
165
|
+
* questions need two sets.
|
|
166
|
+
*
|
|
167
|
+
* `audio` and `video` are deliberately absent -- interactive only with
|
|
168
|
+
* `controls`, which the tag alone does not say, so wrapping one is valid as far
|
|
169
|
+
* as this can tell.
|
|
170
|
+
*/
|
|
171
|
+
const NO_ANCHOR_WRAPPER = new Set([...NO_ANCHOR_CHILD, 'details', 'label']);
|
|
172
|
+
/**
|
|
173
|
+
* Void elements an `<a>` may actually WRAP. `<a><img></a>` is the canonical
|
|
174
|
+
* form, and it is the advice `Delete` already gives through `LINK_REMEDY` for
|
|
175
|
+
* the same reason. The plain-markup path reaches these: bloomer's `tag` is
|
|
176
|
+
* whatever literal the source wrote, so `<Help tag="img">` is one rewrite away.
|
|
177
|
+
*
|
|
178
|
+
* Deliberately short. Void-ness is necessary and not sufficient, and the two
|
|
179
|
+
* ways of getting that wrong are both invalid trees: `input` and `embed` are
|
|
180
|
+
* interactive (above), and the set below belongs somewhere an `<a>` cannot be.
|
|
181
|
+
*/
|
|
182
|
+
const WRAPPABLE_VOID = new Set(['br', 'hr', 'img', 'wbr']);
|
|
183
|
+
/**
|
|
184
|
+
* Void elements whose parent is fixed by the spec, so no `<a>` can sit between
|
|
185
|
+
* them and it: `base`, `link` and `meta` belong to `<head>`, `col` to
|
|
186
|
+
* `<colgroup>`, `source` and `track` to a media element, `param` to `<object>`,
|
|
187
|
+
* `area` to `<map>`.
|
|
188
|
+
*
|
|
189
|
+
* Nothing can be nested in them and nothing can wrap them, so the only honest
|
|
190
|
+
* remedy is to stop using the element for this.
|
|
191
|
+
*/
|
|
192
|
+
const CONTEXT_BOUND = new Set([
|
|
193
|
+
'area',
|
|
194
|
+
'base',
|
|
195
|
+
'col',
|
|
196
|
+
'link',
|
|
197
|
+
'meta',
|
|
198
|
+
'param',
|
|
199
|
+
'source',
|
|
200
|
+
'track',
|
|
201
|
+
]);
|
|
202
|
+
/**
|
|
203
|
+
* What to do with a link the element refuses. `carry` is true for an attribute
|
|
204
|
+
* that has to land ON the anchor to do anything (`target`, `download`, …) and
|
|
205
|
+
* false where the anchor itself IS the remedy (a bare `href`).
|
|
206
|
+
*
|
|
207
|
+
* Four answers, because "put an <a> inside" is wrong in three different ways:
|
|
208
|
+
* an anchor inside interactive content is invalid, an anchor inside a void
|
|
209
|
+
* element is impossible, and an anchor around a context-bound element puts it
|
|
210
|
+
* somewhere its parent may not be.
|
|
211
|
+
*
|
|
212
|
+
* Exported because `specials-utils.ts` reaches the same question from the plain
|
|
213
|
+
* markup side, and `bestax-migrate/CLAUDE.md` puts a rule two transforms need in
|
|
214
|
+
* `_shared/` rather than in one of them.
|
|
215
|
+
*/
|
|
216
|
+
export const nestOrClick = (rendered, carry = false) => {
|
|
217
|
+
if (rendered !== undefined && NO_ANCHOR_CHILD.has(rendered)) {
|
|
218
|
+
return 'navigate in `onClick`';
|
|
219
|
+
}
|
|
220
|
+
if (rendered !== undefined && CONTEXT_BOUND.has(rendered)) {
|
|
221
|
+
return carry
|
|
222
|
+
? 'move it to an element that can take it'
|
|
223
|
+
: 'use an element that can be a link';
|
|
224
|
+
}
|
|
225
|
+
if (rendered !== undefined &&
|
|
226
|
+
WRAPPABLE_VOID.has(rendered) &&
|
|
227
|
+
!NO_ANCHOR_WRAPPER.has(rendered)) {
|
|
228
|
+
return carry
|
|
229
|
+
? 'put it on an <a> wrapping this element'
|
|
230
|
+
: 'wrap it in an <a>';
|
|
231
|
+
}
|
|
232
|
+
return carry ? 'put it on an <a> inside' : 'put an <a> inside';
|
|
233
|
+
};
|
|
234
|
+
const remedyFor = (target, rendered) => LINK_REMEDY[target] ??
|
|
235
|
+
`${nestOrClick(rendered, true)}, or change the element`;
|
|
126
236
|
/** The targets whose `as` this pass may believe. */
|
|
127
237
|
export function declaresAs(target) {
|
|
128
238
|
return target in AS_UNIONS || AS_ANY.has(target);
|
|
@@ -193,8 +303,8 @@ const LINK_ATTR_ELEMENTS = {
|
|
|
193
303
|
*
|
|
194
304
|
* A target absent from `HREF_OK` needs no row: a component that takes no
|
|
195
305
|
* `href` at any `as` takes none of its siblings either -- verified for
|
|
196
|
-
* `
|
|
197
|
-
*
|
|
306
|
+
* `Card.FooterItem`, `Tabs.Item` and `Delete`, which is why this is derived
|
|
307
|
+
* from that table rather than being a second list to keep.
|
|
198
308
|
*/
|
|
199
309
|
const TARGET_LINK_ATTRS = {
|
|
200
310
|
'Level.Item': ['target'],
|
|
@@ -431,7 +541,7 @@ function dropInertHref(ctx, path, element, target, literal, elementKnown) {
|
|
|
431
541
|
if (rendered === undefined) {
|
|
432
542
|
if (defaultEl === ANCHOR)
|
|
433
543
|
return;
|
|
434
|
-
drop(`bestax \`${target}\` renders a <${defaultEl}> unless \`as\` says otherwise, and only its <a> form carries an \`href\` -- set \`as="a"\` to make this a link, or
|
|
544
|
+
drop(`bestax \`${target}\` renders a <${defaultEl}> unless \`as\` says otherwise, and only its <a> form carries an \`href\` -- set \`as="a"\` to make this a link, or ${nestOrClick(defaultEl)}`);
|
|
435
545
|
return;
|
|
436
546
|
}
|
|
437
547
|
if (rendered === ANCHOR)
|
|
@@ -441,8 +551,8 @@ function dropInertHref(ctx, path, element, target, literal, elementKnown) {
|
|
|
441
551
|
// anchor; on `Button` it gives a <button> that will not compile, and on
|
|
442
552
|
// `Level.Item` a <div> that compiles and quietly is not a link.
|
|
443
553
|
const remedy = defaultEl === ANCHOR
|
|
444
|
-
?
|
|
445
|
-
: `set \`as="a"\` to make this a link -- dropping the \`as\` gives you a <${defaultEl}> -- or
|
|
554
|
+
? `drop the \`as\` to make this a link, or ${nestOrClick(rendered)}`
|
|
555
|
+
: `set \`as="a"\` to make this a link -- dropping the \`as\` gives you a <${defaultEl}> -- or ${nestOrClick(rendered)}`;
|
|
446
556
|
drop(`\`href\` on \`as="${rendered}"\`: bestax gives an element the attributes of the tag \`as\` names, and a <${rendered}> takes no \`href\` (it navigated nowhere in the source either) -- ${remedy}`);
|
|
447
557
|
}
|
|
448
558
|
/**
|
|
@@ -487,7 +597,7 @@ function dropInertLinkAttrs(ctx, path, element, target, rendered) {
|
|
|
487
597
|
: !carriesLinks
|
|
488
598
|
? `bestax \`${target}\` is not a link at any \`as\`, so it takes no \`${name}\` either`
|
|
489
599
|
: `bestax \`${target}\` declares its own props rather than taking the element's, and \`${name}\` is not among them`;
|
|
490
|
-
addTodo(ctx, path, `prop:${name}`, `${because} -- ${was ? `it read \`${was}\`; ` : ''}${remedyFor(target)}`);
|
|
600
|
+
addTodo(ctx, path, `prop:${name}`, `${because} -- ${was ? `it read \`${was}\`; ` : ''}${remedyFor(target, rendered)}`);
|
|
491
601
|
ctx.dirty = true;
|
|
492
602
|
}
|
|
493
603
|
}
|
|
@@ -563,8 +673,8 @@ spreadCanCarryAs = false) {
|
|
|
563
673
|
// The element as it will render: the `as` if the target takes it, otherwise
|
|
564
674
|
// the component's own. Unknown for a dynamic `as`, and unknown for a target
|
|
565
675
|
// outside `HREF_OK` that was given no `as` -- the default element is only
|
|
566
|
-
// recorded for the
|
|
567
|
-
//
|
|
676
|
+
// recorded for the targets in that table. So this rule reaches an explicit
|
|
677
|
+
// accepted `as` on any target, plus those targets bare; elsewhere it
|
|
568
678
|
// declines rather than guesses.
|
|
569
679
|
const rendered = read.shadowed
|
|
570
680
|
? undefined
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specials-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/specials-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"specials-utils.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/specials-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* the modifier vocabulary is the one thing here that differs per source.
|
|
9
9
|
*/
|
|
10
10
|
import { addAttrOnce } from './props.js';
|
|
11
|
-
import { LINK_ATTRS, elementTakesLinkAttr, tagRejectsHref, } from './polymorphic.js';
|
|
11
|
+
import { LINK_ATTRS, elementTakesLinkAttr, nestOrClick, tagRejectsHref, } from './polymorphic.js';
|
|
12
12
|
import { addAttr, addTodo, attrSource, attributesOf, findAttr, literalValueOf, makeAttr, plainElement, removeAttr, } from './jsx-utils.js';
|
|
13
13
|
/** Pick a target based on a literal align-style prop, removing the prop. */
|
|
14
14
|
export function alignTarget(ctx, path, element, prop, targets, fallback) {
|
|
@@ -234,7 +234,7 @@ export function dropLinkAttrsForPlainTag(ctx, path, element, tag, where) {
|
|
|
234
234
|
if (href) {
|
|
235
235
|
const was = attrSource(ctx.j, href);
|
|
236
236
|
removeAttr(element, href);
|
|
237
|
-
addTodo(ctx, path, 'prop:href', `${where} became a plain <${tag}>, which takes no \`href\` — make it an <a>, or
|
|
237
|
+
addTodo(ctx, path, 'prop:href', `${where} became a plain <${tag}>, which takes no \`href\` — make it an <a>, or ${nestOrClick(tag)}${was ? ` — it read \`${was}\`` : ''}`);
|
|
238
238
|
ctx.dirty = true;
|
|
239
239
|
}
|
|
240
240
|
// Its siblings are judged against the same tag, each on its own, so a
|
|
@@ -247,7 +247,7 @@ export function dropLinkAttrsForPlainTag(ctx, path, element, tag, where) {
|
|
|
247
247
|
continue;
|
|
248
248
|
const was = attrSource(ctx.j, attr);
|
|
249
249
|
removeAttr(element, attr);
|
|
250
|
-
addTodo(ctx, path, `prop:${name}`, `${where} became a plain <${tag}>, which takes no \`${name}\`${was ? ` — it read \`${was}\`` : ''};
|
|
250
|
+
addTodo(ctx, path, `prop:${name}`, `${where} became a plain <${tag}>, which takes no \`${name}\`${was ? ` — it read \`${was}\`` : ''}; ${nestOrClick(tag, true)}, or change the element`);
|
|
251
251
|
ctx.dirty = true;
|
|
252
252
|
}
|
|
253
253
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bestax-migrate",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"chalk": "^6.0.0",
|
|
39
39
|
"commander": "^15.0.0",
|
|
40
40
|
"jscodeshift": "^17.3.0",
|
|
41
|
-
"@allxsmith/bestax-bulma": "^5.15.
|
|
41
|
+
"@allxsmith/bestax-bulma": "^5.15.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@jest/globals": "^30.0.0",
|