bestax-migrate 2.9.0 → 2.10.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/dist/sources/bulma-classes/class-map.d.ts +38 -2
- package/dist/sources/bulma-classes/class-map.d.ts.map +1 -1
- package/dist/sources/bulma-classes/class-map.js +77 -3
- package/dist/sources/bulma-classes/plan.d.ts +32 -0
- package/dist/sources/bulma-classes/plan.d.ts.map +1 -1
- package/dist/sources/bulma-classes/plan.js +124 -13
- package/dist/sources/bulma-classes/rules.d.ts.map +1 -1
- package/dist/sources/bulma-classes/rules.js +2 -0
- package/dist/sources/bulma-classes/transform.d.ts.map +1 -1
- package/dist/sources/bulma-classes/transform.js +125 -35
- package/package.json +1 -1
|
@@ -40,6 +40,38 @@ export interface Modifier {
|
|
|
40
40
|
* `Table isResponsive`).
|
|
41
41
|
*/
|
|
42
42
|
export type RootStatus = 'mapped' | 'todo' | 'plain' | 'fold';
|
|
43
|
+
/**
|
|
44
|
+
* An element whose only child the target renders itself (the `<select>`
|
|
45
|
+
* inside `.select`), so the two convert together: the target is written
|
|
46
|
+
* where the child was, and the element goes.
|
|
47
|
+
*/
|
|
48
|
+
export interface Absorbs {
|
|
49
|
+
/** The child's tag. */
|
|
50
|
+
readonly tag: string;
|
|
51
|
+
/**
|
|
52
|
+
* Where the target puts the attributes it is given. On the child
|
|
53
|
+
* (`SelectBase`): the child's become the target's, and the element may
|
|
54
|
+
* carry none but a `key`. On the element (`Breadcrumb`): the element's
|
|
55
|
+
* stay, and the child may carry none.
|
|
56
|
+
*/
|
|
57
|
+
readonly attributesOn: 'child' | 'element';
|
|
58
|
+
/** The child's classes, as the target's props; any other class refuses. */
|
|
59
|
+
readonly modifiers?: Readonly<Record<string, Modifier>>;
|
|
60
|
+
/**
|
|
61
|
+
* A bare child attribute that one of the element's modifiers writes as a
|
|
62
|
+
* prop (`multiple`, beside `is-multiple`). Each converts only beside the
|
|
63
|
+
* other, and the attribute goes, since the prop renders it.
|
|
64
|
+
*/
|
|
65
|
+
readonly pairs?: Readonly<Record<string, string>>;
|
|
66
|
+
/**
|
|
67
|
+
* A child attribute the target reads under another name, only beside a
|
|
68
|
+
* paired attribute (`size` as `multipleSize`, beside `multiple`).
|
|
69
|
+
*/
|
|
70
|
+
readonly renames?: Readonly<Record<string, {
|
|
71
|
+
readonly to: string;
|
|
72
|
+
readonly beside: string;
|
|
73
|
+
}>>;
|
|
74
|
+
}
|
|
43
75
|
export interface RootEntry {
|
|
44
76
|
readonly status: RootStatus;
|
|
45
77
|
/**
|
|
@@ -97,6 +129,8 @@ export interface RootEntry {
|
|
|
97
129
|
* modifiers add their props beside these.
|
|
98
130
|
*/
|
|
99
131
|
readonly folds?: readonly PropWrite[];
|
|
132
|
+
/** The target renders the element's only child itself. */
|
|
133
|
+
readonly absorbs?: Absorbs;
|
|
100
134
|
/** The target takes no helper props, so every helper class stays a class. */
|
|
101
135
|
readonly noHelpers?: boolean;
|
|
102
136
|
/**
|
|
@@ -105,8 +139,10 @@ export interface RootEntry {
|
|
|
105
139
|
*/
|
|
106
140
|
readonly ownClassOnly?: boolean;
|
|
107
141
|
/**
|
|
108
|
-
* Attributes the target types as numbers
|
|
109
|
-
*
|
|
142
|
+
* Attributes the target types as numbers, among the ones it is given (the
|
|
143
|
+
* child's, when it `absorbs` the child and puts them there). A numeric
|
|
144
|
+
* string (`value="40"`) becomes a number, which renders the same; any
|
|
145
|
+
* other string refuses.
|
|
110
146
|
*/
|
|
111
147
|
readonly numberAttrs?: readonly string[];
|
|
112
148
|
/** Attributes the target drops: on these tags, or on all tags except these. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,MAAM,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,IAAI,CAAC;IAClD,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACxD,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAC7B,+EAA+E;QAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC
|
|
1
|
+
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -774,6 +774,55 @@ export const ROOTS = {
|
|
|
774
774
|
],
|
|
775
775
|
passThrough: ['disabled', 'readOnly', 'rows', 'ref'],
|
|
776
776
|
},
|
|
777
|
+
// `SelectBase` renders `.select` and the `<select>` inside it together, and
|
|
778
|
+
// gives the `<select>` every attribute it is given.
|
|
779
|
+
select: {
|
|
780
|
+
...BASE,
|
|
781
|
+
target: 'SelectBase',
|
|
782
|
+
tag: 'div',
|
|
783
|
+
textColor: null,
|
|
784
|
+
bgColor: 'backgroundColor',
|
|
785
|
+
modifiers: {
|
|
786
|
+
...tokens('is-', ['small', 'medium', 'large'], 'size'),
|
|
787
|
+
...flags({
|
|
788
|
+
'is-rounded': 'isRounded',
|
|
789
|
+
'is-loading': 'isLoading',
|
|
790
|
+
'is-active': 'isActive',
|
|
791
|
+
'is-fullwidth': 'isFullwidth',
|
|
792
|
+
'is-multiple': 'multiple',
|
|
793
|
+
}),
|
|
794
|
+
},
|
|
795
|
+
omits: Object.fromEntries(COMPONENT_COLORS.map(color => [
|
|
796
|
+
`is-${color}`,
|
|
797
|
+
'`color` renders `has-text-<color>` on the select as well',
|
|
798
|
+
])),
|
|
799
|
+
absorbs: {
|
|
800
|
+
tag: 'select',
|
|
801
|
+
attributesOn: 'child',
|
|
802
|
+
modifiers: flags({
|
|
803
|
+
'is-hovered': 'isHovered',
|
|
804
|
+
'is-focused': 'isFocused',
|
|
805
|
+
}),
|
|
806
|
+
pairs: { multiple: 'is-multiple' },
|
|
807
|
+
renames: { size: { to: 'multipleSize', beside: 'multiple' } },
|
|
808
|
+
},
|
|
809
|
+
numberAttrs: ['multipleSize'],
|
|
810
|
+
adoptsIdFrom: ['Field'],
|
|
811
|
+
ownProps: [
|
|
812
|
+
'color',
|
|
813
|
+
'size',
|
|
814
|
+
'isRounded',
|
|
815
|
+
'isLoading',
|
|
816
|
+
'isActive',
|
|
817
|
+
'isHovered',
|
|
818
|
+
'isFocused',
|
|
819
|
+
'isFullwidth',
|
|
820
|
+
'isFullWidth',
|
|
821
|
+
'multiple',
|
|
822
|
+
'multipleSize',
|
|
823
|
+
],
|
|
824
|
+
passThrough: ['disabled', 'ref'],
|
|
825
|
+
},
|
|
777
826
|
footer: {
|
|
778
827
|
...BASE,
|
|
779
828
|
target: 'Footer',
|
|
@@ -1088,13 +1137,29 @@ export const ROOTS = {
|
|
|
1088
1137
|
},
|
|
1089
1138
|
ownProps: ['size', 'isSpaced', 'as', 'hasSkeleton', 'textColor', 'bgColor'],
|
|
1090
1139
|
},
|
|
1140
|
+
// `Breadcrumb` renders the bare `<ul>` inside it, and its `aria-label`
|
|
1141
|
+
// comes before the attributes it is given, which replace it.
|
|
1142
|
+
breadcrumb: {
|
|
1143
|
+
...BASE,
|
|
1144
|
+
target: 'Breadcrumb',
|
|
1145
|
+
tag: 'nav',
|
|
1146
|
+
// Breadcrumb types no color prop at all.
|
|
1147
|
+
textColor: null,
|
|
1148
|
+
bgColor: null,
|
|
1149
|
+
modifiers: {
|
|
1150
|
+
...tokens('is-', ['centered', 'right'], 'alignment'),
|
|
1151
|
+
...tokens('has-', ['arrow', 'bullet', 'dot', 'succeeds'], 'separator', '-separator'),
|
|
1152
|
+
...tokens('is-', ['small', 'medium', 'large'], 'size'),
|
|
1153
|
+
},
|
|
1154
|
+
defaults: { 'aria-label': 'breadcrumbs' },
|
|
1155
|
+
absorbs: { tag: 'ul', attributesOn: 'element' },
|
|
1156
|
+
ownProps: ['alignment', 'separator', 'size'],
|
|
1157
|
+
},
|
|
1091
1158
|
// ---- Families bestax has but that do not map element by element yet ------
|
|
1092
|
-
breadcrumb: todo('Breadcrumb', 'bestax `Breadcrumb` renders the `<ul>` itself and adds an `aria-label`'),
|
|
1093
1159
|
checkbox: todo('Checkbox', "bestax `Checkbox` renders its own styled markup, not Bulma's"),
|
|
1094
1160
|
checkboxes: todo('Checkboxes', 'bestax `Checkboxes` renders its own `.field` and `.control` wrappers'),
|
|
1095
1161
|
radio: todo('Radio', "bestax `Radio` renders its own styled markup, not Bulma's"),
|
|
1096
1162
|
radios: todo('Radios', 'bestax `Radios` renders its own `.field` and `.control` wrappers'),
|
|
1097
|
-
select: todo('Select', 'bestax `Select` renders the `.select` wrapper and the `<select>` together'),
|
|
1098
1163
|
file: todo('File', 'bestax `File` renders the whole `.file-label` tree itself'),
|
|
1099
1164
|
'file-label': part(),
|
|
1100
1165
|
'file-input': part(),
|
|
@@ -1257,6 +1322,7 @@ export const FORWARDS_REF = [
|
|
|
1257
1322
|
'Control',
|
|
1258
1323
|
'InputBase',
|
|
1259
1324
|
'TextAreaBase',
|
|
1325
|
+
'SelectBase',
|
|
1260
1326
|
];
|
|
1261
1327
|
/**
|
|
1262
1328
|
* Plain tags bestax wraps, for an element with helper classes and no root
|
|
@@ -1419,9 +1485,17 @@ export const PASSTHROUGH = [
|
|
|
1419
1485
|
why: 'a Bulma helper with no bestax prop',
|
|
1420
1486
|
match: /^(?:is-display-.+|is-visibility-.+|is-overflow-.+|is-position-.+|is-float-.+|is-clear-.+|has-radius-.+|has-text-weight-extrabold|is-align-content-(?:baseline|start|end)|is-align-items-self-(?:start|end)|is-offset-0(?:-[a-z]+)?)$/,
|
|
1421
1487
|
},
|
|
1488
|
+
{
|
|
1489
|
+
why: 'a `.breadcrumb` separator, which converts only on its own `.breadcrumb`',
|
|
1490
|
+
match: /^has-[a-z]+-separator$/,
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
why: "`.select`'s `is-multiple`, which converts only on its own `.select`, around a `<select multiple>`",
|
|
1494
|
+
match: /^is-multiple$/,
|
|
1495
|
+
},
|
|
1422
1496
|
{
|
|
1423
1497
|
why: 'a modifier of markup this source leaves alone, or one bestax has no prop for',
|
|
1424
|
-
match: /^(?:has-addons-.+|has-
|
|
1498
|
+
match: /^(?:has-addons-.+|has-dropdown(?:-up)?|has-fixed-size|has-icons-(?:left|right)|has-name|has-(?:spaced-)?navbar-fixed-(?:top|bottom)(?:-desktop)?|has-shadow|is-arrowless|is-boxed|is-center|is-current|is-delete|is-disabled|is-empty|is-expanded|is-fixed-(?:top|bottom)(?:-desktop)?|is-flexible|is-grouped(?:-.+)?|is-halfheight|is-horizontal|is-left|is-(?:lower|upper)-(?:alpha|roman)|is-responsive|is-selected|is-tab|is-toggle(?:-rounded)?|is-transparent|is-underlined|is-up|is-wrapped)$/,
|
|
1425
1499
|
},
|
|
1426
1500
|
];
|
|
1427
1501
|
/**
|
|
@@ -33,6 +33,11 @@ export interface ElementFacts {
|
|
|
33
33
|
* element and nothing else (not even whitespace React would render).
|
|
34
34
|
*/
|
|
35
35
|
soleChildTarget?: string;
|
|
36
|
+
/**
|
|
37
|
+
* That only child as written, when it is a plain HTML element: what an
|
|
38
|
+
* entry that `absorbs` it reads.
|
|
39
|
+
*/
|
|
40
|
+
soleChild?: ChildFacts;
|
|
36
41
|
/** The bestax components already in the file inside this element. */
|
|
37
42
|
bestaxInside?: readonly string[];
|
|
38
43
|
/** The bestax components already in the file around this element. */
|
|
@@ -49,6 +54,20 @@ export interface ElementFacts {
|
|
|
49
54
|
*/
|
|
50
55
|
onlyChildOf?: string;
|
|
51
56
|
}
|
|
57
|
+
export interface ChildFacts {
|
|
58
|
+
tag: string;
|
|
59
|
+
/**
|
|
60
|
+
* Its static classes, or null when its `className` is computed. Left out
|
|
61
|
+
* when it has no `className` at all: an empty one still renders `class=""`.
|
|
62
|
+
*/
|
|
63
|
+
tokens?: readonly string[] | null;
|
|
64
|
+
/**
|
|
65
|
+
* Its attributes but `className`, read as `ElementFacts.attributes` is,
|
|
66
|
+
* except that a number literal (`size={3}`) is that number.
|
|
67
|
+
*/
|
|
68
|
+
attributes: ReadonlyMap<string, string | number | true | null>;
|
|
69
|
+
hasSpread: boolean;
|
|
70
|
+
}
|
|
52
71
|
export interface Todo {
|
|
53
72
|
rule: string;
|
|
54
73
|
message: string;
|
|
@@ -67,6 +86,19 @@ export interface Conversion {
|
|
|
67
86
|
* a number (`minCol={4}`), because the target types them as numbers.
|
|
68
87
|
*/
|
|
69
88
|
numbers: string[];
|
|
89
|
+
/**
|
|
90
|
+
* The element's only child, which the target renders itself: the target is
|
|
91
|
+
* written in the child's place, with the element's props and attributes
|
|
92
|
+
* first, then the child's, and the element goes.
|
|
93
|
+
*/
|
|
94
|
+
absorbs?: {
|
|
95
|
+
/** What the child's classes become, in place of its `className`. */
|
|
96
|
+
props: Array<[name: string, value: string | true]>;
|
|
97
|
+
/** Child attributes the target reads under another name. */
|
|
98
|
+
renames: Array<[from: string, to: string]>;
|
|
99
|
+
/** Child attributes a prop above renders instead. */
|
|
100
|
+
drop: string[];
|
|
101
|
+
};
|
|
70
102
|
}
|
|
71
103
|
export interface Plan {
|
|
72
104
|
conversion: Conversion | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAC/D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE;QACR,oEAAoE;QACpE,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACnD,4DAA4D;QAC5D,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3C,qDAAqD;QACrD,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AA+BD,wBAAgB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CA0S9C"}
|
|
@@ -96,21 +96,34 @@ export function plan(facts) {
|
|
|
96
96
|
if (facts.onlyChildOf) {
|
|
97
97
|
return refuse('only-child', target, `this element is the only child of \`<${facts.onlyChildOf}>\`, which may hand it props or a ref with \`cloneElement\` (next/link's legacy behavior, a tooltip, a Radix \`asChild\` trigger) that bestax \`${target}\` would not take the same way; convert it by hand if \`<${facts.onlyChildOf}>\` only renders its children`);
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
// The attributes the target is given: the element's, or its only child's
|
|
100
|
+
// when the target renders that child itself and puts them there.
|
|
101
|
+
let attributes = facts.attributes;
|
|
102
|
+
let absorbed;
|
|
103
|
+
if (entry.absorbs) {
|
|
104
|
+
const outcome = absorb(facts, root, entry, target, refuse);
|
|
105
|
+
if ('todos' in outcome)
|
|
106
|
+
return outcome;
|
|
107
|
+
({ attributes, absorbed } = outcome);
|
|
108
|
+
}
|
|
109
|
+
const renamed = new Set(absorbed?.renames.map(([, to]) => to));
|
|
110
|
+
if (attributes.has('dangerouslySetInnerHTML')) {
|
|
100
111
|
return refuse('attr', 'dangerouslySetInnerHTML', `\`dangerouslySetInnerHTML\` sets the element's content directly, and some bestax components render content of their own beside \`children\`, which React rejects; keep this element as markup`);
|
|
101
112
|
}
|
|
102
|
-
for (const name of
|
|
113
|
+
for (const name of attributes.keys()) {
|
|
114
|
+
if (renamed.has(name))
|
|
115
|
+
continue;
|
|
103
116
|
const readAsProp = entry.ownProps?.includes(name) || HELPER_PROPS.has(name);
|
|
104
117
|
if (readAsProp && !entry.passThrough?.includes(name)) {
|
|
105
118
|
return refuse('attr', name, `\`${name}\` is also a bestax \`${target}\` prop, which would read it differently; rename or drop the attribute, then re-run`);
|
|
106
119
|
}
|
|
107
120
|
}
|
|
108
|
-
const missing = Object.entries(entry.defaults ?? {}).filter(([name]) => !
|
|
121
|
+
const missing = Object.entries(entry.defaults ?? {}).filter(([name]) => !attributes.has(name));
|
|
109
122
|
const drop = [];
|
|
110
123
|
for (const name of entry.untypedAttrs ?? []) {
|
|
111
|
-
if (!
|
|
124
|
+
if (!attributes.has(name))
|
|
112
125
|
continue;
|
|
113
|
-
if (entry.defaults?.[name] ===
|
|
126
|
+
if (entry.defaults?.[name] === attributes.get(name)) {
|
|
114
127
|
drop.push(name);
|
|
115
128
|
continue;
|
|
116
129
|
}
|
|
@@ -118,7 +131,7 @@ export function plan(facts) {
|
|
|
118
131
|
}
|
|
119
132
|
const numbers = [];
|
|
120
133
|
for (const name of entry.numberAttrs ?? []) {
|
|
121
|
-
const value =
|
|
134
|
+
const value = attributes.get(name);
|
|
122
135
|
if (typeof value !== 'string')
|
|
123
136
|
continue;
|
|
124
137
|
// Only a string that is already the number's own spelling: `040`, `1.50`
|
|
@@ -134,7 +147,7 @@ export function plan(facts) {
|
|
|
134
147
|
if (entry.providesContext && facts.bestaxInside?.length) {
|
|
135
148
|
return refuse('context', target, `bestax \`${target}\` tells the bestax form controls inside it to skip wrappers of their own, and this element already holds \`${facts.bestaxInside[0]}\`, which could render differently inside it; keep this element as markup, or convert it and check that component by hand`);
|
|
136
149
|
}
|
|
137
|
-
if (entry.adoptsIdFrom && !
|
|
150
|
+
if (entry.adoptsIdFrom && !attributes.has('id')) {
|
|
138
151
|
// Context follows the render tree, not the file: a component of the app
|
|
139
152
|
// around the element can render a labelled `Field` around it just as well.
|
|
140
153
|
const around = facts.bestaxAround?.find(name => entry.adoptsIdFrom.includes(name)) ??
|
|
@@ -148,18 +161,14 @@ export function plan(facts) {
|
|
|
148
161
|
(!wraps.when || tokens.includes(wraps.when)) &&
|
|
149
162
|
(facts.hasChildren || wraps.whenEmpty) &&
|
|
150
163
|
!facts.childTargets?.some(child => wraps.unless.includes(child))) {
|
|
151
|
-
|
|
152
|
-
const list = parts.length > 1
|
|
153
|
-
? `${parts.slice(0, -1).join(', ')} or ${parts[parts.length - 1]}`
|
|
154
|
-
: parts[0];
|
|
155
|
-
return refuse('children', target, `bestax \`${target}\` renders its children inside a \`.${wraps.in}\` of its own unless one of them is a ${list}, so this element stays markup`);
|
|
164
|
+
return refuse('children', target, `bestax \`${target}\` renders its children inside a \`.${wraps.in}\` of its own unless one of them is a ${orList(wraps.unless)}, so this element stays markup`);
|
|
156
165
|
}
|
|
157
166
|
if (missing.length > 0) {
|
|
158
167
|
const list = missing.map(([name, value]) => `\`${name}="${value}"\``);
|
|
159
168
|
return refuse('defaults', target, `bestax \`${target}\` renders ${list.join(' and ')} when the element does not set ${missing.length === 1 ? 'it' : 'them'}; add ${missing.length === 1 ? 'it' : 'them'} here if that is what you want, then re-run`);
|
|
160
169
|
}
|
|
161
170
|
for (const [name, tags] of Object.entries(entry.dropsAttr ?? {})) {
|
|
162
|
-
if (
|
|
171
|
+
if (attributes.has(name) && inTagSet(tags, tag)) {
|
|
163
172
|
// Bulma greys out `.button[disabled]` on any tag, so there it is not
|
|
164
173
|
// inert: dropping it changes how the element looks.
|
|
165
174
|
const visible = name === 'disabled';
|
|
@@ -256,10 +265,112 @@ export function plan(facts) {
|
|
|
256
265
|
className: rest.length > 0 ? rest.join(' ') : null,
|
|
257
266
|
drop,
|
|
258
267
|
numbers,
|
|
268
|
+
...(absorbed ? { absorbs: absorbed } : {}),
|
|
259
269
|
},
|
|
260
270
|
todos,
|
|
261
271
|
};
|
|
262
272
|
}
|
|
273
|
+
/** `a`, `a or b`, `a, b or c`, each in backticks. */
|
|
274
|
+
function orList(names) {
|
|
275
|
+
const quoted = names.map(name => `\`${name}\``);
|
|
276
|
+
return quoted.length > 1
|
|
277
|
+
? `${quoted.slice(0, -1).join(', ')} or ${quoted[quoted.length - 1]}`
|
|
278
|
+
: quoted[0];
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The only child an entry's target renders itself (`.select`'s `<select>`):
|
|
282
|
+
* what its classes become, and the attributes the target is given. It
|
|
283
|
+
* converts with the element only when the target would render it exactly
|
|
284
|
+
* as written.
|
|
285
|
+
*/
|
|
286
|
+
function absorb(facts, root, entry, target, refuse) {
|
|
287
|
+
const spec = entry.absorbs;
|
|
288
|
+
const child = facts.soleChild;
|
|
289
|
+
const itself = `bestax \`${target}\` renders the <${spec.tag}> inside \`.${root}\` itself`;
|
|
290
|
+
if (child?.tag !== spec.tag) {
|
|
291
|
+
return refuse('children', target, `${itself}, so this element converts only around a single <${spec.tag}>, with nothing else beside it`);
|
|
292
|
+
}
|
|
293
|
+
if (child.hasSpread) {
|
|
294
|
+
return refuse('spread', target, `the <${spec.tag}> inside spreads props, which bestax \`${target}\` may read differently than the <${spec.tag}> did; convert the two to \`${target}\` by hand`);
|
|
295
|
+
}
|
|
296
|
+
if (child.tokens === null) {
|
|
297
|
+
return refuse('dynamic-class', target, `the <${spec.tag}> inside has a computed \`className\`, and the codemod converts static class strings only; convert the two to bestax \`${target}\` by hand, turning each condition into its prop`);
|
|
298
|
+
}
|
|
299
|
+
if (child.tokens?.length === 0) {
|
|
300
|
+
return refuse('attr', 'className', `the <${spec.tag}> inside has an empty \`className\`, which renders \`class=""\`, and bestax \`${target}\` renders it with no class attribute; drop the empty \`className\`, then re-run`);
|
|
301
|
+
}
|
|
302
|
+
const modifiers = spec.modifiers ?? {};
|
|
303
|
+
const props = [];
|
|
304
|
+
for (const token of child.tokens ?? []) {
|
|
305
|
+
const modifier = Object.hasOwn(modifiers, token)
|
|
306
|
+
? modifiers[token]
|
|
307
|
+
: undefined;
|
|
308
|
+
if (!modifier) {
|
|
309
|
+
const allowed = Object.keys(modifiers);
|
|
310
|
+
return refuse('attr', 'className', `${itself}, with no class on it${allowed.length > 0 ? ` but ${orList(allowed)}` : ''}, so its \`${token}\` would be lost; keep this element as markup`);
|
|
311
|
+
}
|
|
312
|
+
for (const write of modifier.writes) {
|
|
313
|
+
props.push([write.prop, write.value ?? true]);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (spec.attributesOn === 'element') {
|
|
317
|
+
const name = [...child.attributes.keys()][0];
|
|
318
|
+
if (name !== undefined) {
|
|
319
|
+
return refuse('attr', name, `${itself}, with no attributes, so its \`${name}\` would be lost; keep this element as markup`);
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
attributes: facts.attributes,
|
|
323
|
+
absorbed: { props, renames: [], drop: [] },
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// The target puts what it is given on the child, so the element can carry
|
|
327
|
+
// nothing but its `key`, which stays with the component in its place.
|
|
328
|
+
const own = [...facts.attributes.keys()].find(name => name !== 'key');
|
|
329
|
+
if (own !== undefined) {
|
|
330
|
+
return refuse('attr', own, `bestax \`${target}\` puts the attributes it is given on the <${spec.tag}> inside \`.${root}\`, so this element's \`${own}\` would move there; move it onto the <${spec.tag}> if that is what you want, then re-run`);
|
|
331
|
+
}
|
|
332
|
+
if (child.attributes.has('key')) {
|
|
333
|
+
return refuse('attr', 'key', `the <${spec.tag}> inside has a \`key\`, which would move up to bestax \`${target}\` in place of this element's; keep this element as markup`);
|
|
334
|
+
}
|
|
335
|
+
const drop = [];
|
|
336
|
+
for (const [name, token] of Object.entries(spec.pairs ?? {})) {
|
|
337
|
+
const withClass = facts.tokens.includes(token);
|
|
338
|
+
if (withClass && child.attributes.get(name) === true) {
|
|
339
|
+
drop.push(name);
|
|
340
|
+
}
|
|
341
|
+
else if (withClass || child.attributes.has(name)) {
|
|
342
|
+
return refuse('attr', name, `bestax \`${target}\` renders \`${name}\` on the <${spec.tag}> and \`.${token}\` on this element together, from one prop, so the two convert only as a pair, with \`${name}\` written bare; keep this element as markup`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// A number literal is carried over as written, like any other expression.
|
|
346
|
+
const given = (value) => typeof value === 'number' ? null : value;
|
|
347
|
+
const attributes = new Map();
|
|
348
|
+
const renames = [];
|
|
349
|
+
for (const [name, value] of child.attributes) {
|
|
350
|
+
if (drop.includes(name))
|
|
351
|
+
continue;
|
|
352
|
+
const rename = spec.renames && Object.hasOwn(spec.renames, name)
|
|
353
|
+
? spec.renames[name]
|
|
354
|
+
: undefined;
|
|
355
|
+
if (!rename) {
|
|
356
|
+
attributes.set(name, given(value));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
// `SelectBase` writes `multipleSize` back as `size` only when it holds a
|
|
360
|
+
// number, and an expression may not: only a literal converts. A string
|
|
361
|
+
// one is held to a number's spelling below, with the target's numbers.
|
|
362
|
+
if (!drop.includes(rename.beside) ||
|
|
363
|
+
(typeof value !== 'number' && typeof value !== 'string')) {
|
|
364
|
+
return refuse('attr', name, `bestax \`${target}\` writes the <${spec.tag}>'s \`${name}\` only beside \`${rename.beside}\`, and only from a number in \`${rename.to}\`, so it converts only as a number written out (\`${name}={4}\`); keep this element as markup, or convert it by hand if \`${name}\` is always a number`);
|
|
365
|
+
}
|
|
366
|
+
if (child.attributes.has(rename.to)) {
|
|
367
|
+
return refuse('attr', rename.to, `\`${rename.to}\` is also a bestax \`${target}\` prop, which would read it differently; rename or drop the attribute, then re-run`);
|
|
368
|
+
}
|
|
369
|
+
renames.push([name, rename.to]);
|
|
370
|
+
attributes.set(rename.to, given(value));
|
|
371
|
+
}
|
|
372
|
+
return { attributes, absorbed: { props, renames, drop } };
|
|
373
|
+
}
|
|
263
374
|
/**
|
|
264
375
|
* A wrapper the component inside it renders from a prop (`.table-container`
|
|
265
376
|
* from `Table isResponsive`). It folds into that component only when it is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAapC,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAapC,CAAC;AAyBH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
|
@@ -44,6 +44,8 @@ const VOCABULARY = new Set([
|
|
|
44
44
|
'dangerouslySetInnerHTML',
|
|
45
45
|
// Refused where the target drops its own class for one it is given.
|
|
46
46
|
'className',
|
|
47
|
+
// Refused on the child a target renders itself.
|
|
48
|
+
'key',
|
|
47
49
|
]);
|
|
48
50
|
export function inVocabulary(token) {
|
|
49
51
|
return VOCABULARY.has(token);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AA8YvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CAwZpB"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* 5. write the bestax import, after the file's last import
|
|
18
18
|
*/
|
|
19
19
|
import path from 'node:path';
|
|
20
|
-
import { addTodo, findAttr, forgetJsxParens, jsxNameParts, literalValueOf, makeAttr, renameElement, reprintDirectives, } from '../_shared/jsx-utils.js';
|
|
20
|
+
import { addTodo, findAttr, forgetJsxParens, jsxNameParts, literalValueOf, makeAttr, removeAttr, renameElement, reprintDirectives, } from '../_shared/jsx-utils.js';
|
|
21
21
|
import { collectBoundNames, makeReserve, prefersTabs, resolvesToBinding, } from '../_shared/imports.js';
|
|
22
22
|
import { rewriteStylesheetImports } from '../_shared/css-imports.js';
|
|
23
23
|
import { BESTAX, buildBestaxImport, placeBestaxImport, seedBestaxImport, } from '../_shared/bestax-import.js';
|
|
@@ -63,6 +63,27 @@ function afterTagName(comment) {
|
|
|
63
63
|
trailing: true,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Put `props`, then what stays in `className`, where an element's
|
|
68
|
+
* `className` was. A comment on the className goes with whatever takes its
|
|
69
|
+
* place: the first new attribute, else the next one along, else the tag name.
|
|
70
|
+
*/
|
|
71
|
+
function writeClassName(j, element, props, className) {
|
|
72
|
+
const attrs = element.openingElement.attributes;
|
|
73
|
+
const classAttr = findAttr(element, 'className');
|
|
74
|
+
const replacement = props.map(([name, value]) => makeAttr(j, name, value === true ? undefined : value));
|
|
75
|
+
if (className)
|
|
76
|
+
replacement.push(makeAttr(j, 'className', className));
|
|
77
|
+
if (classAttr.comments?.length) {
|
|
78
|
+
const name = element.openingElement.name;
|
|
79
|
+
const carrier = replacement[0] ?? attrs.find((attr) => attr !== classAttr) ?? name;
|
|
80
|
+
carrier.comments = [
|
|
81
|
+
...(carrier.comments ?? []),
|
|
82
|
+
...classAttr.comments.map((comment) => carrier === name ? afterTagName(comment) : comment),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
attrs.splice(attrs.indexOf(classAttr), 1, ...replacement);
|
|
86
|
+
}
|
|
66
87
|
/** A lowercase intrinsic tag: not a component, not a custom element. */
|
|
67
88
|
const INTRINSIC = /^[a-z][a-z0-9]*$/;
|
|
68
89
|
/** Subtrees whose tags are not HTML. */
|
|
@@ -142,6 +163,34 @@ function attributeName(attr) {
|
|
|
142
163
|
? `${attr.name.namespace.name}:${attr.name.name.name}`
|
|
143
164
|
: attr.name.name;
|
|
144
165
|
}
|
|
166
|
+
/** An element's attributes but `className`, as the planner reads them. */
|
|
167
|
+
function attributesBesides(element, classAttr, read) {
|
|
168
|
+
const attributes = new Map();
|
|
169
|
+
for (const attr of element.openingElement.attributes ?? []) {
|
|
170
|
+
if (attr.type !== 'JSXAttribute' || attr === classAttr)
|
|
171
|
+
continue;
|
|
172
|
+
attributes.set(attributeName(attr), read(attr));
|
|
173
|
+
}
|
|
174
|
+
return attributes;
|
|
175
|
+
}
|
|
176
|
+
/** A child's attribute as `ChildFacts` reads it: a number literal is that number. */
|
|
177
|
+
function childAttributeValue(attr) {
|
|
178
|
+
const literal = literalValueOf(attr);
|
|
179
|
+
return literal.kind === 'number' ? literal.value : attributeValue(attr);
|
|
180
|
+
}
|
|
181
|
+
function hasSpread(element) {
|
|
182
|
+
return (element.openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute');
|
|
183
|
+
}
|
|
184
|
+
/** The comments inside an element's tags, on the tags and their names. */
|
|
185
|
+
function tagComments(element) {
|
|
186
|
+
const { openingElement, closingElement } = element;
|
|
187
|
+
return [
|
|
188
|
+
openingElement,
|
|
189
|
+
openingElement.name,
|
|
190
|
+
closingElement,
|
|
191
|
+
closingElement?.name,
|
|
192
|
+
].flatMap((node) => node?.comments ?? []);
|
|
193
|
+
}
|
|
145
194
|
/** Every comment in the file (recast hangs them on the nodes). */
|
|
146
195
|
function commentsOf(root, j) {
|
|
147
196
|
const comments = new Set();
|
|
@@ -245,6 +294,25 @@ function reachesReact(child) {
|
|
|
245
294
|
return isContent(child);
|
|
246
295
|
return /[^ \t\r\n]/.test(child.value) || !/[\r\n]/.test(child.value);
|
|
247
296
|
}
|
|
297
|
+
/** A plain HTML child as the planner reads it; nothing for a component. */
|
|
298
|
+
function childFacts(child) {
|
|
299
|
+
const name = child.openingElement.name;
|
|
300
|
+
if (name.type !== 'JSXIdentifier' || !INTRINSIC.test(name.name)) {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
const classAttr = findAttr(child, 'className');
|
|
304
|
+
const className = classAttr && staticClassName(classAttr);
|
|
305
|
+
return {
|
|
306
|
+
tag: name.name,
|
|
307
|
+
...(classAttr && {
|
|
308
|
+
tokens: className === null
|
|
309
|
+
? null
|
|
310
|
+
: [...new Set(className.split(/\s+/).filter(Boolean))],
|
|
311
|
+
}),
|
|
312
|
+
attributes: attributesBesides(child, classAttr, childAttributeValue),
|
|
313
|
+
hasSpread: hasSpread(child),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
248
316
|
function insideForeignContent(elementPath) {
|
|
249
317
|
let current = elementPath.parent;
|
|
250
318
|
while (current) {
|
|
@@ -408,25 +476,22 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
408
476
|
const classAttr = findAttr(element, 'className');
|
|
409
477
|
if (!classAttr)
|
|
410
478
|
continue;
|
|
411
|
-
const attributes =
|
|
412
|
-
for (const attr of element.openingElement.attributes ?? []) {
|
|
413
|
-
if (attr.type !== 'JSXAttribute' || attr === classAttr)
|
|
414
|
-
continue;
|
|
415
|
-
attributes.set(attributeName(attr), attributeValue(attr));
|
|
416
|
-
}
|
|
479
|
+
const attributes = attributesBesides(element, classAttr, attributeValue);
|
|
417
480
|
const className = staticClassName(classAttr);
|
|
418
481
|
const surrounding = around(elementPath);
|
|
482
|
+
const sole = soleChild(element);
|
|
419
483
|
const facts = {
|
|
420
484
|
tag: name.name,
|
|
421
485
|
tokens: className === null
|
|
422
486
|
? classTokensOf(classAttr.value)
|
|
423
487
|
: [...new Set(className.split(/\s+/).filter(Boolean))],
|
|
424
488
|
attributes,
|
|
425
|
-
hasSpread: (element
|
|
489
|
+
hasSpread: hasSpread(element),
|
|
426
490
|
hasRef: attributes.has('ref'),
|
|
427
491
|
hasChildren: (element.children ?? []).some(reachesReact),
|
|
428
492
|
childTargets: childTargets(elementPath),
|
|
429
|
-
soleChildTarget: planned.get(
|
|
493
|
+
soleChildTarget: planned.get(sole)?.conversion?.target,
|
|
494
|
+
soleChild: sole && childFacts(sole),
|
|
430
495
|
bestaxInside: bestaxInside.get(element) ?? [],
|
|
431
496
|
bestaxAround: surrounding.bestax,
|
|
432
497
|
componentsAround: surrounding.other,
|
|
@@ -525,14 +590,10 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
525
590
|
// wrapper's tags moves inside the child's opening tag.
|
|
526
591
|
const wrapper = elementPath.node;
|
|
527
592
|
const inner = soleChild(wrapper);
|
|
528
|
-
const { openingElement, closingElement } = wrapper;
|
|
529
593
|
const inTags = [
|
|
530
|
-
|
|
531
|
-
openingElement.
|
|
532
|
-
|
|
533
|
-
closingElement,
|
|
534
|
-
closingElement?.name,
|
|
535
|
-
].flatMap((node) => node?.comments ?? []);
|
|
594
|
+
...tagComments(wrapper),
|
|
595
|
+
...(wrapper.openingElement.attributes ?? []).flatMap((attr) => attr.comments ?? []),
|
|
596
|
+
];
|
|
536
597
|
if (inTags.length) {
|
|
537
598
|
const name = inner.openingElement.name;
|
|
538
599
|
name.comments = [...(name.comments ?? []), ...inTags.map(afterTagName)];
|
|
@@ -548,34 +609,63 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
548
609
|
if (!conversion)
|
|
549
610
|
continue;
|
|
550
611
|
const element = elementPath.node;
|
|
612
|
+
// A target that renders the element's only child itself is written in
|
|
613
|
+
// that child's place, so the child's children stay where they are.
|
|
614
|
+
const child = conversion.absorbs ? soleChild(element) : undefined;
|
|
615
|
+
// The element's tags go, and so do the child's tag names: their comments
|
|
616
|
+
// move to the name that stays. The child's tags themselves stay, and
|
|
617
|
+
// keep their own.
|
|
618
|
+
const inTags = child
|
|
619
|
+
? [
|
|
620
|
+
...tagComments(element),
|
|
621
|
+
...[child.openingElement.name, child.closingElement?.name].flatMap((node) => node?.comments ?? []),
|
|
622
|
+
]
|
|
623
|
+
: [];
|
|
624
|
+
if (child) {
|
|
625
|
+
// Renamed before the drops below, which name each attribute as the
|
|
626
|
+
// component is given it.
|
|
627
|
+
const { renames, drop } = conversion.absorbs;
|
|
628
|
+
for (const name of drop)
|
|
629
|
+
removeAttr(child, findAttr(child, name));
|
|
630
|
+
for (const [from, to] of renames) {
|
|
631
|
+
findAttr(child, from).name = j.jsxIdentifier(to);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
551
634
|
const [head, ...rest] = conversion.target.split('.');
|
|
552
635
|
renameElement(j, element, [ctx.reserve(head), ...rest].join('.'));
|
|
553
|
-
const attrs = element.openingElement.attributes;
|
|
554
636
|
for (const name of conversion.drop) {
|
|
555
|
-
|
|
637
|
+
const holder = findAttr(element, name) ? element : child;
|
|
638
|
+
removeAttr(holder, findAttr(holder, name));
|
|
556
639
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
if (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
...(carrier.comments ?? []),
|
|
571
|
-
...classAttr.comments.map((comment) => carrier === name ? afterTagName(comment) : comment),
|
|
640
|
+
writeClassName(j, element, conversion.props, conversion.className);
|
|
641
|
+
let written = element;
|
|
642
|
+
if (child) {
|
|
643
|
+
child.openingElement.name = element.openingElement.name;
|
|
644
|
+
if (child.closingElement) {
|
|
645
|
+
child.closingElement.name = element.closingElement.name;
|
|
646
|
+
}
|
|
647
|
+
if (findAttr(child, 'className')) {
|
|
648
|
+
writeClassName(j, child, conversion.absorbs.props, null);
|
|
649
|
+
}
|
|
650
|
+
child.openingElement.attributes = [
|
|
651
|
+
...(element.openingElement.attributes ?? []),
|
|
652
|
+
...(child.openingElement.attributes ?? []),
|
|
572
653
|
];
|
|
654
|
+
// A comment on the element moves to the component in its place.
|
|
655
|
+
if (inTags.length) {
|
|
656
|
+
const name = child.openingElement.name;
|
|
657
|
+
name.comments = [...(name.comments ?? []), ...inTags.map(afterTagName)];
|
|
658
|
+
}
|
|
659
|
+
if (element.comments?.length) {
|
|
660
|
+
child.comments = [...element.comments, ...(child.comments ?? [])];
|
|
661
|
+
}
|
|
662
|
+
elementPath.replace(child);
|
|
663
|
+
written = child;
|
|
573
664
|
}
|
|
574
|
-
attrs.splice(attrs.indexOf(classAttr), 1, ...replacement);
|
|
575
665
|
// After the splice, so a prop the conversion wrote is found as well as
|
|
576
666
|
// an attribute the element already had.
|
|
577
667
|
for (const name of conversion.numbers) {
|
|
578
|
-
const attr = findAttr(
|
|
668
|
+
const attr = findAttr(written, name);
|
|
579
669
|
attr.value = j.jsxExpressionContainer(j.numericLiteral(Number(attributeValue(attr))));
|
|
580
670
|
}
|
|
581
671
|
ctx.dirty = true;
|