bestax-migrate 2.29.1 → 2.29.2
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/html/attributes.d.ts +12 -5
- package/dist/sources/_shared/html/attributes.d.ts.map +1 -1
- package/dist/sources/_shared/html/attributes.js +23 -1
- package/dist/sources/bulma-classes/html-rules.d.ts.map +1 -1
- package/dist/sources/bulma-classes/html-rules.js +9 -2
- package/dist/sources/bulma-classes/html.d.ts +14 -5
- package/dist/sources/bulma-classes/html.d.ts.map +1 -1
- package/dist/sources/bulma-classes/html.js +147 -28
- package/dist/sources/bulma-classes/project.d.ts +10 -2
- package/dist/sources/bulma-classes/project.d.ts.map +1 -1
- package/dist/sources/bulma-classes/project.js +17 -2
- package/dist/sources/bulma-classes/transform.d.ts +6 -0
- package/dist/sources/bulma-classes/transform.d.ts.map +1 -1
- package/dist/sources/bulma-classes/transform.js +11 -0
- package/package.json +2 -2
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
* passes through as written (`class` aside);
|
|
24
24
|
* - an `on…` attribute is code React can't run from a string, and a name
|
|
25
25
|
* JSX can't spell (`@click`, `x-on:click`) can't be written at all; both
|
|
26
|
-
* are handed back to the caller instead of emitted
|
|
26
|
+
* are handed back to the caller instead of emitted;
|
|
27
|
+
* - an attribute HTML gives the element no meaning for, which the browser
|
|
28
|
+
* ignores and React's types reject there (`type` on a `<textarea>`), is
|
|
29
|
+
* handed back too (`IGNORED`).
|
|
27
30
|
*/
|
|
28
31
|
import { type Element } from './parse.js';
|
|
29
32
|
export type PropValue = true | string | {
|
|
@@ -44,16 +47,20 @@ export interface Prop {
|
|
|
44
47
|
* Something the converter can't carry over as written, for the caller to
|
|
45
48
|
* report. Emitted: `unknown-attribute`, `javascript-url`, `style-important`
|
|
46
49
|
* (without its priority), and the element kinds. Not emitted:
|
|
47
|
-
* `attribute-name`, `event-handler`, `style` (the one
|
|
48
|
-
* quotes), `element-name` (its children are), and a
|
|
50
|
+
* `attribute-name`, `ignored-attribute`, `event-handler`, `style` (the one
|
|
51
|
+
* declaration it quotes), `element-name` (its children are), and a
|
|
52
|
+
* `conditional-comment`.
|
|
49
53
|
*/
|
|
50
54
|
export interface HtmlIssue {
|
|
51
|
-
kind: 'attribute-name' | 'event-handler' | 'unknown-attribute' | 'javascript-url' | 'style' | 'style-important' | 'custom-element' | 'obsolete-element' | 'unknown-element' | 'template' | 'element-name' | 'conditional-comment';
|
|
55
|
+
kind: 'attribute-name' | 'ignored-attribute' | 'event-handler' | 'unknown-attribute' | 'javascript-url' | 'style' | 'style-important' | 'custom-element' | 'obsolete-element' | 'unknown-element' | 'template' | 'element-name' | 'conditional-comment';
|
|
52
56
|
/** The attribute, tag or CSS property it is about, as written. */
|
|
53
57
|
token: string;
|
|
54
58
|
/** The attribute it is on, for its line. */
|
|
55
59
|
attribute?: string;
|
|
56
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* What a report quotes: a handler's code, a style, a declaration, the tag
|
|
62
|
+
* an ignored attribute was on.
|
|
63
|
+
*/
|
|
57
64
|
detail?: string;
|
|
58
65
|
/** For an `event-handler`, the React prop that takes a function. */
|
|
59
66
|
prop?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../../src/sources/_shared/html/attributes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../../src/sources/_shared/html/attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI7D,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,MAAM,WAAW,IAAI;IACnB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EACA,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,OAAO,GACP,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,UAAU,GACV,cAAc,GACd,qBAAqB,CAAC;IAC1B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAwD5C,CAAC;AA+CH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAMzD;AA8DD,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK5C;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG;IACnD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB,CA8GA;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,GAAG,KAAc,GAC7B,OAAO,CAET;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI1D"}
|
|
@@ -23,12 +23,16 @@
|
|
|
23
23
|
* passes through as written (`class` aside);
|
|
24
24
|
* - an `on…` attribute is code React can't run from a string, and a name
|
|
25
25
|
* JSX can't spell (`@click`, `x-on:click`) can't be written at all; both
|
|
26
|
-
* are handed back to the caller instead of emitted
|
|
26
|
+
* are handed back to the caller instead of emitted;
|
|
27
|
+
* - an attribute HTML gives the element no meaning for, which the browser
|
|
28
|
+
* ignores and React's types reject there (`type` on a `<textarea>`), is
|
|
29
|
+
* handed back too (`IGNORED`).
|
|
27
30
|
*/
|
|
28
31
|
import { find, hastToReact, html, svg } from 'property-information';
|
|
29
32
|
import { isElement, isText } from './parse.js';
|
|
30
33
|
import { styleObject } from './style.js';
|
|
31
34
|
import { attributeValue, jsString } from './text.js';
|
|
35
|
+
const HTML = 'http://www.w3.org/1999/xhtml';
|
|
32
36
|
const SVG = 'http://www.w3.org/2000/svg';
|
|
33
37
|
const MATHML = 'http://www.w3.org/1998/Math/MathML';
|
|
34
38
|
/**
|
|
@@ -106,6 +110,13 @@ const VALUE_NOT_TYPED = new Set([
|
|
|
106
110
|
'reset',
|
|
107
111
|
'submit',
|
|
108
112
|
]);
|
|
113
|
+
/**
|
|
114
|
+
* Attributes HTML gives these elements no meaning for, by tag: the browser
|
|
115
|
+
* ignores them, and React's types reject them there, so they are left out.
|
|
116
|
+
*/
|
|
117
|
+
const IGNORED = {
|
|
118
|
+
textarea: new Set(['type']),
|
|
119
|
+
};
|
|
109
120
|
/** What JSX can write as an attribute name (no namespace, no symbols). */
|
|
110
121
|
const JSX_NAME = /^[A-Za-z_$][\w$-]*$/;
|
|
111
122
|
/**
|
|
@@ -244,6 +255,17 @@ export function convertAttributes(element) {
|
|
|
244
255
|
add(attribute === 'class' ? 'className' : attribute, value, attribute);
|
|
245
256
|
continue;
|
|
246
257
|
}
|
|
258
|
+
if (element.namespaceURI === HTML &&
|
|
259
|
+
Object.hasOwn(IGNORED, tag) &&
|
|
260
|
+
IGNORED[tag].has(attribute.toLowerCase())) {
|
|
261
|
+
issues.push({
|
|
262
|
+
kind: 'ignored-attribute',
|
|
263
|
+
token: attribute,
|
|
264
|
+
attribute,
|
|
265
|
+
detail: tag,
|
|
266
|
+
});
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
247
269
|
if (tag === 'option' && attribute === 'selected' && selectOf(element)) {
|
|
248
270
|
continue; // The select carries it, as its `defaultValue`.
|
|
249
271
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EASjD,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAAkC,CAAC;AAE9E,8EAA8E;AAC9E,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAO5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAQxC,CAAC;
|
|
1
|
+
{"version":3,"file":"html-rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EASjD,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAAkC,CAAC;AAE9E,8EAA8E;AAC9E,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAO5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAQxC,CAAC;AA2CF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAAoC,CAAC;AAKhF,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAErE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAO/D"}
|
|
@@ -56,7 +56,7 @@ const EVENT_ATTRIBUTES = Object.values(html.property)
|
|
|
56
56
|
.map(info => info.attribute)
|
|
57
57
|
.filter(attribute => /^on[a-z]+$/.test(attribute));
|
|
58
58
|
const VOCABULARY = {
|
|
59
|
-
'html-head': new Set(['title', 'meta', 'link', 'style', 'base']),
|
|
59
|
+
'html-head': new Set(['title', 'meta', 'csp', 'link', 'style', 'base']),
|
|
60
60
|
'html-asset': new Set(ASSET_KINDS),
|
|
61
61
|
'html-script': new Set(SCRIPT_PATTERNS),
|
|
62
62
|
'html-document': new Set([
|
|
@@ -79,7 +79,14 @@ const VOCABULARY = {
|
|
|
79
79
|
'unknown',
|
|
80
80
|
]),
|
|
81
81
|
'html-url': new Set(['javascript', 'missing', 'relative']),
|
|
82
|
-
'html-attr': new Set([
|
|
82
|
+
'html-attr': new Set([
|
|
83
|
+
'ignored',
|
|
84
|
+
'important',
|
|
85
|
+
'name',
|
|
86
|
+
'stray',
|
|
87
|
+
'style',
|
|
88
|
+
'unknown',
|
|
89
|
+
]),
|
|
83
90
|
'html-parse': new Set(Object.values(ErrorCodes)),
|
|
84
91
|
'html-file': new Set(['exists', 'not-included', 'template-syntax']),
|
|
85
92
|
};
|
|
@@ -54,12 +54,21 @@ export declare function keepingMost(displays: ReadonlySet<string>): string;
|
|
|
54
54
|
*/
|
|
55
55
|
export declare const pageDisplayOf: DisplayOf;
|
|
56
56
|
/**
|
|
57
|
-
* The component a page becomes: its file's name in PascalCase
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
60
|
-
*
|
|
57
|
+
* The component a page becomes: its file's name in PascalCase and `Page`, so
|
|
58
|
+
* `hero.html` can't shadow bestax's `Hero`. A name starting with a digit
|
|
59
|
+
* starts with `Page` instead (`404.html` is `Page404`), and one with nothing
|
|
60
|
+
* to go by is `Page`. An `index.html` is named after its folder, which is
|
|
61
|
+
* what tells `docs/index.html` from `blog/index.html`, but for the site's home
|
|
62
|
+
* page: the `index.html` in a folder the run starts from (`roots`, the
|
|
63
|
+
* project's `runRoots`), with other pages beside it and none of them named
|
|
64
|
+
* `HomePage` already. Another spelling of the index beside it (`index.htm`)
|
|
65
|
+
* is no other page: it only competes for the name, and an `index.html` wins
|
|
66
|
+
* it, so one folder writes one `HomePage`. Only that page's folder is read
|
|
67
|
+
* for the pages beside it.
|
|
61
68
|
*/
|
|
62
|
-
export declare function componentName(file: string): string;
|
|
69
|
+
export declare function componentName(file: string, roots?: unknown): string;
|
|
70
|
+
/** The other HTML pages in a page's folder, by file name. */
|
|
71
|
+
export declare function pagesBeside(file: string): string[];
|
|
63
72
|
/**
|
|
64
73
|
* Where a page's module goes: beside it, `.tsx` when the package around it is
|
|
65
74
|
* TypeScript (a tsconfig, or a dependency on `typescript`), `.jsx` otherwise.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAEV,UAAU,EACV,aAAa,EACb,SAAS,EACT,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAexB,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,+BAA+B,CAAC;AAiEvC;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAYjE;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,EAAE,SAoB3B,CAAC;
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAEV,UAAU,EACV,aAAa,EACb,SAAS,EACT,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAexB,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,+BAA+B,CAAC;AAiEvC;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAYjE;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,EAAE,SAoB3B,CAAC;AAsBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAgBnE;AAYD,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBlD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAQR;AAsBD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAU3E;AA4KD,+EAA+E;AAC/E,eAAO,MAAM,YAAY,wCAAsC,CAAC;AAyxBhE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA4BjD;AAID,+EAA+E;AAC/E,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,2EAA2E;IAC3E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAWD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,aAAa,GAAG,SAAS,EACpC,OAAO,GAAE,gBAAqB,GAC7B,aAAa,CAsHf;AAgCD,yCAAyC;AACzC,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,aAAa,GAAG,SAAS,EACpC,OAAO,GAAE,gBAAqB,GAC7B,UAAU,CAGZ"}
|
|
@@ -40,7 +40,7 @@ import { bulmaDisplay, bulmaOutOfFlow, HELPER_DISPLAY } from './display.js';
|
|
|
40
40
|
import { bulmaBuildMessage, bulmaMediaMessage, bulmaStylesheetMessage, classifyAsset, extensionMessage, fontAwesomeMessage, jqueryMessage, PRIMARY_CLASS, scriptMessage, stylesheetMessage, webfontMessage, } from './html-assets.js';
|
|
41
41
|
import { htmlRuleId, NAVBAR_FIXED_CLASSES, THEME_CLASSES, } from './html-rules.js';
|
|
42
42
|
import { inNextApp, writesTypeScript } from './project.js';
|
|
43
|
-
import transform from './transform.js';
|
|
43
|
+
import transform, { FILE_RULES } from './transform.js';
|
|
44
44
|
const HTML_NS = 'http://www.w3.org/1999/xhtml';
|
|
45
45
|
function attributeOf(element, name) {
|
|
46
46
|
return element.attrs.find(attr => attr.name === name && !attr.prefix)?.value;
|
|
@@ -132,17 +132,8 @@ export const pageDisplayOf = element => {
|
|
|
132
132
|
return keepingMost(displays);
|
|
133
133
|
};
|
|
134
134
|
// ---- Naming and placing the module -----------------------------------------
|
|
135
|
-
/**
|
|
136
|
-
|
|
137
|
-
* for an `index.html`) and `Page`, so `hero.html` can't shadow bestax's
|
|
138
|
-
* `Hero`. A name starting with a digit starts with `Page` instead
|
|
139
|
-
* (`404.html` is `Page404`), and one with nothing to go by is `Page`.
|
|
140
|
-
*/
|
|
141
|
-
export function componentName(file) {
|
|
142
|
-
const stem = path.basename(file, path.extname(file));
|
|
143
|
-
const named = /^index$/i.test(stem)
|
|
144
|
-
? path.basename(path.dirname(path.resolve(file)))
|
|
145
|
-
: stem;
|
|
135
|
+
/** A page's name with nothing but its words, as a component's name. */
|
|
136
|
+
function pageName(named) {
|
|
146
137
|
const words = named.split(/[^\p{L}\p{Nd}]+/u).filter(Boolean);
|
|
147
138
|
const pascal = words
|
|
148
139
|
.map(word => {
|
|
@@ -159,6 +150,66 @@ export function componentName(file) {
|
|
|
159
150
|
name = `${pascal}Page`;
|
|
160
151
|
return /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u.test(name) ? name : 'Page';
|
|
161
152
|
}
|
|
153
|
+
const HOME = 'HomePage';
|
|
154
|
+
/**
|
|
155
|
+
* The component a page becomes: its file's name in PascalCase and `Page`, so
|
|
156
|
+
* `hero.html` can't shadow bestax's `Hero`. A name starting with a digit
|
|
157
|
+
* starts with `Page` instead (`404.html` is `Page404`), and one with nothing
|
|
158
|
+
* to go by is `Page`. An `index.html` is named after its folder, which is
|
|
159
|
+
* what tells `docs/index.html` from `blog/index.html`, but for the site's home
|
|
160
|
+
* page: the `index.html` in a folder the run starts from (`roots`, the
|
|
161
|
+
* project's `runRoots`), with other pages beside it and none of them named
|
|
162
|
+
* `HomePage` already. Another spelling of the index beside it (`index.htm`)
|
|
163
|
+
* is no other page: it only competes for the name, and an `index.html` wins
|
|
164
|
+
* it, so one folder writes one `HomePage`. Only that page's folder is read
|
|
165
|
+
* for the pages beside it.
|
|
166
|
+
*/
|
|
167
|
+
export function componentName(file, roots) {
|
|
168
|
+
const stem = path.basename(file, path.extname(file));
|
|
169
|
+
if (!/^index$/i.test(stem))
|
|
170
|
+
return pageName(stem);
|
|
171
|
+
const dir = path.dirname(path.resolve(file));
|
|
172
|
+
const atRoot = Array.isArray(roots) && roots.includes(dir);
|
|
173
|
+
const beside = atRoot ? pagesBeside(file) : [];
|
|
174
|
+
const rivals = beside.filter(isIndexPage);
|
|
175
|
+
const pages = beside.filter(sibling => !isIndexPage(sibling));
|
|
176
|
+
const own = indexRank(path.basename(file));
|
|
177
|
+
const home = pages.length > 0 &&
|
|
178
|
+
pages.every(page => pageName(path.basename(page, path.extname(page))) !== HOME) &&
|
|
179
|
+
rivals.every(rival => indexRank(rival) > own);
|
|
180
|
+
return home ? HOME : pageName(path.basename(dir));
|
|
181
|
+
}
|
|
182
|
+
/** Whether a page beside another is its folder's index, by another spelling. */
|
|
183
|
+
function isIndexPage(name) {
|
|
184
|
+
return /^index\.html?$/i.test(name);
|
|
185
|
+
}
|
|
186
|
+
/** Which of a folder's index pages is its home: `.html` first, then by name. */
|
|
187
|
+
function indexRank(name) {
|
|
188
|
+
return `${path.extname(name).toLowerCase() === '.html' ? 0 : 1}${name}`;
|
|
189
|
+
}
|
|
190
|
+
/** The other HTML pages in a page's folder, by file name. */
|
|
191
|
+
export function pagesBeside(file) {
|
|
192
|
+
const dir = path.dirname(path.resolve(file));
|
|
193
|
+
let names;
|
|
194
|
+
try {
|
|
195
|
+
names = fs.readdirSync(dir);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
const own = path.basename(file);
|
|
201
|
+
const isPage = (name) => {
|
|
202
|
+
try {
|
|
203
|
+
return fs.statSync(path.join(dir, name)).isFile();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
return names
|
|
210
|
+
.filter(name => name !== own && /\.html?$/i.test(name) && isPage(name))
|
|
211
|
+
.sort();
|
|
212
|
+
}
|
|
162
213
|
/**
|
|
163
214
|
* Where a page's module goes: beside it, `.tsx` when the package around it is
|
|
164
215
|
* TypeScript (a tsconfig, or a dependency on `typescript`), `.jsx` otherwise.
|
|
@@ -232,7 +283,7 @@ const SCRIPT_PATTERNS = [
|
|
|
232
283
|
[
|
|
233
284
|
'theme',
|
|
234
285
|
/data-theme|dataset\.theme|theme-(?:dark|light)|prefers-color-scheme/,
|
|
235
|
-
"switches Bulma's light and dark schemes: bestax's `Theme` writes `data-theme` on `<html>` from its `colorMode` (`light`, `dark` or `system`), so keep the choice in state, saved in `localStorage`, and pass it; `Theme` writes the attribute from an effect, after the first paint, so for a saved choice to paint first, keep a small inline script in the `<head>` of the app's index.html that reads it (or the OS's, with none saved) and writes `data-theme` before the app loads, and start the state from what that script wrote",
|
|
286
|
+
"switches Bulma's light and dark schemes: bestax's `Theme` writes `data-theme` on `<html>` from its `colorMode` (`light`, `dark` or `system`), so keep the choice in state, saved in `localStorage`, and pass it; `Theme` writes the attribute from an effect, after the first paint, so for a saved choice to paint first, keep a small inline script in the `<head>` of the app's index.html that reads it (or the OS's, with none saved) and writes `data-theme` before the app loads, and start the state from what that script wrote (the bestax-theming skill's `examples/dark-mode.tsx` has the script and the app's side)",
|
|
236
287
|
],
|
|
237
288
|
];
|
|
238
289
|
/**
|
|
@@ -265,7 +316,7 @@ function scriptNotes(script, page) {
|
|
|
265
316
|
return [
|
|
266
317
|
{
|
|
267
318
|
rule: htmlRuleId('html-script', 'json-ld'),
|
|
268
|
-
message: `structured data for search engines (JSON-LD) was dropped with the page's scripts:
|
|
319
|
+
message: `structured data for search engines (JSON-LD) was dropped with the page's scripts: data about the whole site, or about a single-page app's one page, goes in the app's index.html as it is, where a crawler that runs no JavaScript still reads it, and data that differs from page to page goes where the app sets each page's head, as \`<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }} />\`; the JSON is ${kept}`,
|
|
269
320
|
line,
|
|
270
321
|
endLine,
|
|
271
322
|
},
|
|
@@ -479,6 +530,11 @@ function assetNotes(page, root) {
|
|
|
479
530
|
}
|
|
480
531
|
return { notes, importsBulma };
|
|
481
532
|
}
|
|
533
|
+
/** A `<meta http-equiv>` that sets the page's Content Security Policy. */
|
|
534
|
+
function isCsp(meta) {
|
|
535
|
+
return ((attributeOf(meta, 'http-equiv') ?? '').trim().toLowerCase() ===
|
|
536
|
+
'content-security-policy');
|
|
537
|
+
}
|
|
482
538
|
/** What a `<meta>` is for: its `name`, `property`, `http-equiv` or charset. */
|
|
483
539
|
function metaKind(meta) {
|
|
484
540
|
if (attributeOf(meta, 'charset') !== undefined)
|
|
@@ -511,7 +567,17 @@ function headNotes(head, notes, page) {
|
|
|
511
567
|
});
|
|
512
568
|
break;
|
|
513
569
|
case 'meta':
|
|
514
|
-
|
|
570
|
+
if (isCsp(node)) {
|
|
571
|
+
notes.push({
|
|
572
|
+
rule: htmlRuleId('html-head', 'csp'),
|
|
573
|
+
message: "the page's `<head>` sets a Content Security Policy in a `<meta http-equiv>`, which a component can't carry: it was written for what this page loads, and copied into the app's index.html as it is, it can block what the app loads instead (a Vite dev server runs an inline script for React's fast refresh and opens a socket for hot reloading, and the build serves the app's own scripts, styles and fonts), so write the app's own policy, best sent as a response header, and try it under both the dev server and the build",
|
|
574
|
+
line,
|
|
575
|
+
endLine,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
metas.push(node);
|
|
580
|
+
}
|
|
515
581
|
break;
|
|
516
582
|
case 'link': {
|
|
517
583
|
const rel = (attributeOf(node, 'rel') ?? '').toLowerCase().split(/\s+/);
|
|
@@ -572,6 +638,12 @@ function headNotes(head, notes, page) {
|
|
|
572
638
|
}
|
|
573
639
|
/** Bulma's light and dark schemes, by `data-theme` value. */
|
|
574
640
|
const SCHEMES = new Set(['light', 'dark']);
|
|
641
|
+
/**
|
|
642
|
+
* Where a page's scheme goes in the app: on its `<html>`, which the first
|
|
643
|
+
* paint reads, since `Theme` writes the attribute from an effect, after it.
|
|
644
|
+
*/
|
|
645
|
+
const SCHEME_ON_HTML = "put it on the `<html>` in the app's index.html, where the first paint has it";
|
|
646
|
+
const SCHEME_TOGGLE = "for a scheme the visitor switches, bestax's `Theme colorMode` writes the choice only after that paint, so write a saved one before it too, as the `html-script:theme` recipe says and the bestax-theming skill's `examples/dark-mode.tsx` does";
|
|
575
647
|
function documentAttributeNotes(where, element, notes) {
|
|
576
648
|
if (!element)
|
|
577
649
|
return;
|
|
@@ -602,7 +674,7 @@ function documentAttributeNotes(where, element, notes) {
|
|
|
602
674
|
else if (THEME_CLASSES.includes(token)) {
|
|
603
675
|
notes.push({
|
|
604
676
|
rule: htmlRuleId('html-document', token),
|
|
605
|
-
message: `the page's \`<${where}>\` has \`${token}\`, which sets Bulma's ${token.slice(6)} scheme:
|
|
677
|
+
message: `the page's \`<${where}>\` has \`${token}\`, which sets Bulma's ${token.slice(6)} scheme: ${SCHEME_ON_HTML}; ${SCHEME_TOGGLE}`,
|
|
606
678
|
line,
|
|
607
679
|
});
|
|
608
680
|
}
|
|
@@ -623,9 +695,7 @@ function documentAttributeNotes(where, element, notes) {
|
|
|
623
695
|
const scheme = value.trim().toLowerCase();
|
|
624
696
|
notes.push({
|
|
625
697
|
rule: htmlRuleId('html-document', name),
|
|
626
|
-
message: `the page's \`<${where}>\` has \`data-theme="${quote(value)}"\`, which sets Bulma's color scheme:
|
|
627
|
-
? `, or render bestax's \`<Theme colorMode="${scheme}">\`, which writes it on \`<html>\``
|
|
628
|
-
: ''}`,
|
|
698
|
+
message: `the page's \`<${where}>\` has \`data-theme="${quote(value)}"\`, which sets Bulma's color scheme: ${SCHEME_ON_HTML}${SCHEMES.has(scheme) ? `; ${SCHEME_TOGGLE}` : ''}`,
|
|
629
699
|
line,
|
|
630
700
|
});
|
|
631
701
|
continue;
|
|
@@ -711,11 +781,26 @@ function convertedNote(issue) {
|
|
|
711
781
|
line,
|
|
712
782
|
};
|
|
713
783
|
case 'attribute-name':
|
|
784
|
+
// A name with no letter or digit in it is no directive: it is a stray
|
|
785
|
+
// character the browser read as an attribute (`<figure … \>`).
|
|
786
|
+
if (!/[\p{L}\p{N}]/u.test(token)) {
|
|
787
|
+
return {
|
|
788
|
+
rule: htmlRuleId('html-attr', 'stray'),
|
|
789
|
+
message: `\`${quote(token, 20)}\` in the tag is a stray character, a typo (such as \`\\>\` meant as \`/>\`) that the browser read as the name of an empty attribute: it was left out, so there is nothing to port, and it can go from the page too`,
|
|
790
|
+
line,
|
|
791
|
+
};
|
|
792
|
+
}
|
|
714
793
|
return {
|
|
715
794
|
rule: htmlRuleId('html-attr', 'name'),
|
|
716
795
|
message: `the attribute \`${token}\` was left out, since JSX can't write that name (a framework's directive, such as \`@click\` or \`:class\`, is code to port into the component), or the element already has it under another spelling`,
|
|
717
796
|
line,
|
|
718
797
|
};
|
|
798
|
+
case 'ignored-attribute':
|
|
799
|
+
return {
|
|
800
|
+
rule: htmlRuleId('html-attr', 'ignored'),
|
|
801
|
+
message: `\`${token}\` was left out: HTML gives a \`<${issue.detail}>\` no \`${token}\` attribute, so the browser ignored it, and React's types reject it there; there is nothing to port, unless a stylesheet or script of the page's selects on it`,
|
|
802
|
+
line,
|
|
803
|
+
};
|
|
719
804
|
case 'unknown-attribute':
|
|
720
805
|
return {
|
|
721
806
|
rule: htmlRuleId('html-attr', 'unknown'),
|
|
@@ -917,7 +1002,7 @@ function outsideCommentLines(comments) {
|
|
|
917
1002
|
});
|
|
918
1003
|
}
|
|
919
1004
|
function todoLine(note, page) {
|
|
920
|
-
const message = note.message
|
|
1005
|
+
const message = todoText(note.message);
|
|
921
1006
|
const at = note.line === null
|
|
922
1007
|
? ''
|
|
923
1008
|
: note.lines !== undefined
|
|
@@ -1081,7 +1166,7 @@ export function convertPage(file, source, collector, options = {}) {
|
|
|
1081
1166
|
// The transform retargets it under `--css`, as it would in a JSX file.
|
|
1082
1167
|
...(assets.importsBulma ? [BULMA_IMPORT] : []),
|
|
1083
1168
|
...notes.document.map(note => todoLine(note, page)),
|
|
1084
|
-
`export default function ${componentName(file)}() {`,
|
|
1169
|
+
`export default function ${componentName(file, options.runRoots)}() {`,
|
|
1085
1170
|
...contentLines(notes.content, page).map(line => ` ${line}`),
|
|
1086
1171
|
' return (',
|
|
1087
1172
|
];
|
|
@@ -1097,14 +1182,21 @@ export function convertPage(file, source, collector, options = {}) {
|
|
|
1097
1182
|
}
|
|
1098
1183
|
// The transform reads the module's path, so the gates for a server
|
|
1099
1184
|
// component or another JSX runtime apply to it; its report names the page.
|
|
1185
|
+
const planned = new Map();
|
|
1100
1186
|
const onPage = {
|
|
1101
|
-
add: entry =>
|
|
1102
|
-
|
|
1103
|
-
file,
|
|
1104
|
-
line: entry.line === null || entry.line < jsxStart
|
|
1187
|
+
add: entry => {
|
|
1188
|
+
const line = entry.line === null || entry.line < jsxStart
|
|
1105
1189
|
? null
|
|
1106
|
-
: emitted.htmlLineOf(entry.line - jsxStart + 1)
|
|
1107
|
-
|
|
1190
|
+
: emitted.htmlLineOf(entry.line - jsxStart + 1);
|
|
1191
|
+
// A file-level gate's TODO is about the whole page, so it gets no
|
|
1192
|
+
// page line of the element it sits on.
|
|
1193
|
+
const forFile = FILE_RULES.includes(entry.rule);
|
|
1194
|
+
if (line !== null && !forFile) {
|
|
1195
|
+
const text = todoText(entry.message);
|
|
1196
|
+
planned.set(text, [...(planned.get(text) ?? []), line]);
|
|
1197
|
+
}
|
|
1198
|
+
collector?.add({ ...entry, file, line });
|
|
1199
|
+
},
|
|
1108
1200
|
};
|
|
1109
1201
|
const { output } = runTransform(transform, outputPath, intermediate, onPage, {
|
|
1110
1202
|
...options,
|
|
@@ -1112,10 +1204,37 @@ export function convertPage(file, source, collector, options = {}) {
|
|
|
1112
1204
|
});
|
|
1113
1205
|
return {
|
|
1114
1206
|
outputPath,
|
|
1115
|
-
output: finishModule(output ?? intermediate),
|
|
1207
|
+
output: finishModule(withPageLines(output ?? intermediate, planned, page)),
|
|
1116
1208
|
intermediate,
|
|
1117
1209
|
};
|
|
1118
1210
|
}
|
|
1211
|
+
/** A TODO's message as its comment writes it, on one line. */
|
|
1212
|
+
function todoText(message) {
|
|
1213
|
+
return message.replace(/[\r\n\u2028\u2029]+/g, ' ').trim();
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* The planner's TODO lines, each with the page's lines it is about. The
|
|
1217
|
+
* transform writes one line for each message, however many elements share
|
|
1218
|
+
* it (five `.icon`s missing the same attribute), above the `return`, so the
|
|
1219
|
+
* lines go on after, the way the page's own notes carry theirs. Nothing from
|
|
1220
|
+
* the `return` on is read, since the page's text is there.
|
|
1221
|
+
*/
|
|
1222
|
+
function withPageLines(code, planned, page) {
|
|
1223
|
+
if (planned.size === 0)
|
|
1224
|
+
return code;
|
|
1225
|
+
const lines = code.split('\n');
|
|
1226
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1227
|
+
if (/^\s*return\b/.test(lines[i]))
|
|
1228
|
+
break;
|
|
1229
|
+
const todo = /^\s*\/\/ TODO\(bestax-migrate\): (.*)$/.exec(lines[i]);
|
|
1230
|
+
const on = todo ? planned.get(todo[1]) : undefined;
|
|
1231
|
+
if (!on)
|
|
1232
|
+
continue;
|
|
1233
|
+
const at = [...new Set(on)].sort((a, b) => a - b).join(', ');
|
|
1234
|
+
lines[i] = `${lines[i]} (${page}:${at})`;
|
|
1235
|
+
}
|
|
1236
|
+
return lines.join('\n');
|
|
1237
|
+
}
|
|
1119
1238
|
/** The `transformHtml` the CLI calls. */
|
|
1120
1239
|
export function transformHtml(file, source, collector, options = {}) {
|
|
1121
1240
|
const { outputPath, output } = convertPage(file, source, collector, options);
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* see from one file: which files a Next.js App Router may render as server
|
|
4
4
|
* components, which packages render JSX through a runtime other than React,
|
|
5
5
|
* and, for the module an HTML page becomes, which are written in TypeScript
|
|
6
|
-
* and which are Next.js apps, where that module imports no stylesheet
|
|
6
|
+
* and which are Next.js apps, where that module imports no stylesheet, and
|
|
7
|
+
* which folders the run starts from, where an `index.html` is the site's
|
|
8
|
+
* home page.
|
|
7
9
|
*
|
|
8
10
|
* Read once per run, from every package.json the run touches: the nearest one
|
|
9
11
|
* above each target, and every one below it, so a monorepo run from its root
|
|
10
|
-
* still finds `apps/web`.
|
|
12
|
+
* still finds `apps/web`. The folders come from the targets themselves.
|
|
11
13
|
*/
|
|
12
14
|
/** `jsxImportSource` values whose JSX is React's. */
|
|
13
15
|
export declare const REACT_RUNTIMES: ReadonlySet<string>;
|
|
@@ -42,6 +44,12 @@ export interface ProjectFacts {
|
|
|
42
44
|
serverComponentRoots: ServerComponentRoot[];
|
|
43
45
|
jsxRuntimes: JsxRuntime[];
|
|
44
46
|
packageLanguages: PackageLanguage[];
|
|
47
|
+
/**
|
|
48
|
+
* The folders the run starts from, absolute: each folder it names and each
|
|
49
|
+
* named file's folder, but for one inside another. Only an `index.html`
|
|
50
|
+
* in one of them can be the site's home page.
|
|
51
|
+
*/
|
|
52
|
+
runRoots: string[];
|
|
45
53
|
}
|
|
46
54
|
/**
|
|
47
55
|
* The JSX runtime a package declares: what its tsconfig's `jsxImportSource`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/project.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,CAK7C,CAAC;AAqBH,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC5C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmHD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACjD,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,CA8D9D;AAcD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAE1E;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAEnE"}
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* see from one file: which files a Next.js App Router may render as server
|
|
4
4
|
* components, which packages render JSX through a runtime other than React,
|
|
5
5
|
* and, for the module an HTML page becomes, which are written in TypeScript
|
|
6
|
-
* and which are Next.js apps, where that module imports no stylesheet
|
|
6
|
+
* and which are Next.js apps, where that module imports no stylesheet, and
|
|
7
|
+
* which folders the run starts from, where an `index.html` is the site's
|
|
8
|
+
* home page.
|
|
7
9
|
*
|
|
8
10
|
* Read once per run, from every package.json the run touches: the nearest one
|
|
9
11
|
* above each target, and every one below it, so a monorepo run from its root
|
|
10
|
-
* still finds `apps/web`.
|
|
12
|
+
* still finds `apps/web`. The folders come from the targets themselves.
|
|
11
13
|
*/
|
|
12
14
|
import fs from 'node:fs';
|
|
13
15
|
import path from 'node:path';
|
|
@@ -35,6 +37,11 @@ const SKIP_DIRS = new Set([
|
|
|
35
37
|
'.next',
|
|
36
38
|
'.e2e-tmp',
|
|
37
39
|
]);
|
|
40
|
+
/** Whether `dir` is a folder below `parent`. */
|
|
41
|
+
function isInside(dir, parent) {
|
|
42
|
+
const relative = path.relative(parent, dir);
|
|
43
|
+
return (relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative));
|
|
44
|
+
}
|
|
38
45
|
function nearestManifest(target) {
|
|
39
46
|
let dir = path.resolve(target);
|
|
40
47
|
if (fs.statSync(dir, { throwIfNoEntry: false })?.isFile()) {
|
|
@@ -162,6 +169,7 @@ export function runtimeOf(dir, deps) {
|
|
|
162
169
|
}
|
|
163
170
|
export function analyzeProject(targets) {
|
|
164
171
|
const manifests = new Set();
|
|
172
|
+
const starts = new Set();
|
|
165
173
|
for (const target of targets) {
|
|
166
174
|
const nearest = nearestManifest(target);
|
|
167
175
|
if (nearest)
|
|
@@ -169,6 +177,10 @@ export function analyzeProject(targets) {
|
|
|
169
177
|
const below = [];
|
|
170
178
|
if (fs.statSync(target, { throwIfNoEntry: false })?.isDirectory()) {
|
|
171
179
|
manifestsBelow(path.resolve(target), below);
|
|
180
|
+
starts.add(path.resolve(target));
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
starts.add(path.dirname(path.resolve(target)));
|
|
172
184
|
}
|
|
173
185
|
for (const manifest of below)
|
|
174
186
|
manifests.add(manifest);
|
|
@@ -177,6 +189,9 @@ export function analyzeProject(targets) {
|
|
|
177
189
|
serverComponentRoots: [],
|
|
178
190
|
jsxRuntimes: [],
|
|
179
191
|
packageLanguages: [],
|
|
192
|
+
runRoots: [...starts]
|
|
193
|
+
.filter(dir => ![...starts].some(other => isInside(dir, other)))
|
|
194
|
+
.sort(),
|
|
180
195
|
};
|
|
181
196
|
for (const manifest of [...manifests].sort()) {
|
|
182
197
|
let pkg;
|
|
@@ -20,5 +20,11 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { API, FileInfo } from 'jscodeshift';
|
|
22
22
|
import type { TransformOptions } from '../../types.js';
|
|
23
|
+
/**
|
|
24
|
+
* The rules of the gates that leave a whole file alone. Their TODO is about
|
|
25
|
+
* the file, though it sits on the first element that would convert, so no
|
|
26
|
+
* line of the file is where it came from.
|
|
27
|
+
*/
|
|
28
|
+
export declare const FILE_RULES: readonly ["jsx-runtime", "imports", "styled-jsx", "rsc"];
|
|
23
29
|
export default function transform(fileInfo: FileInfo, api: API, options?: TransformOptions): string | undefined;
|
|
24
30
|
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAkiCvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CAy9BpB"}
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAkiCvD;;;;GAIG;AACH,eAAO,MAAM,UAAU,0DAKb,CAAC;AAGX,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CAy9BpB"}
|
|
@@ -877,6 +877,17 @@ function onlyChildOf(elementPath, bestaxLocals) {
|
|
|
877
877
|
? name
|
|
878
878
|
: undefined;
|
|
879
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* The rules of the gates that leave a whole file alone. Their TODO is about
|
|
882
|
+
* the file, though it sits on the first element that would convert, so no
|
|
883
|
+
* line of the file is where it came from.
|
|
884
|
+
*/
|
|
885
|
+
export const FILE_RULES = [
|
|
886
|
+
'jsx-runtime',
|
|
887
|
+
'imports',
|
|
888
|
+
'styled-jsx',
|
|
889
|
+
'rsc',
|
|
890
|
+
];
|
|
880
891
|
export default function transform(fileInfo, api, options = {}) {
|
|
881
892
|
const source = fileInfo.source;
|
|
882
893
|
// Cheap pre-filter: no className and no stylesheet import, nothing to do.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bestax-migrate",
|
|
3
|
-
"version": "2.29.
|
|
3
|
+
"version": "2.29.2",
|
|
4
4
|
"description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"jscodeshift": "^17.3.0",
|
|
41
41
|
"parse5": "^7.3.0",
|
|
42
42
|
"property-information": "^7.2.0",
|
|
43
|
-
"@allxsmith/bestax-bulma": "^5.
|
|
43
|
+
"@allxsmith/bestax-bulma": "^5.40.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@jest/globals": "^30.0.0",
|