bestax-migrate 2.25.7 → 2.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/cli.d.ts +9 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +98 -9
- package/dist/sources/_shared/deps-common.d.ts +2 -0
- package/dist/sources/_shared/deps-common.d.ts.map +1 -1
- package/dist/sources/_shared/deps-common.js +3 -1
- package/dist/sources/_shared/html/whitespace.d.ts +21 -0
- package/dist/sources/_shared/html/whitespace.d.ts.map +1 -1
- package/dist/sources/_shared/html/whitespace.js +12 -6
- package/dist/sources/bulma-classes/class-map.d.ts +10 -0
- package/dist/sources/bulma-classes/class-map.d.ts.map +1 -1
- package/dist/sources/bulma-classes/class-map.js +25 -0
- package/dist/sources/bulma-classes/display.d.ts +11 -1
- package/dist/sources/bulma-classes/display.d.ts.map +1 -1
- package/dist/sources/bulma-classes/display.js +33 -1
- package/dist/sources/bulma-classes/html-assets.d.ts +87 -0
- package/dist/sources/bulma-classes/html-assets.d.ts.map +1 -0
- package/dist/sources/bulma-classes/html-assets.js +246 -0
- package/dist/sources/bulma-classes/html-rules.d.ts +32 -0
- package/dist/sources/bulma-classes/html-rules.d.ts.map +1 -0
- package/dist/sources/bulma-classes/html-rules.js +101 -0
- package/dist/sources/bulma-classes/html.d.ts +92 -0
- package/dist/sources/bulma-classes/html.d.ts.map +1 -0
- package/dist/sources/bulma-classes/html.js +1123 -0
- package/dist/sources/bulma-classes/index.d.ts.map +1 -1
- package/dist/sources/bulma-classes/index.js +4 -0
- package/dist/sources/bulma-classes/project.d.ts +22 -2
- package/dist/sources/bulma-classes/project.d.ts.map +1 -1
- package/dist/sources/bulma-classes/project.js +34 -3
- package/dist/sources/rbx/mapping.js +1 -1
- package/dist/sources/react-bulma-components/mapping.js +1 -1
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-assets.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html-assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stylesheets and scripts a Bulma page loads, read from their URLs: what
|
|
3
|
+
* each one is (`html-asset:<kind>`, `ASSET_KINDS` in `html-rules.ts`) and what
|
|
4
|
+
* to do about it now that a component renders the page. Pure: the caller
|
|
5
|
+
* reads the page, decides where a note goes and whether Bulma's stylesheet
|
|
6
|
+
* becomes an import.
|
|
7
|
+
*
|
|
8
|
+
* A message names bestax's component for an extension only where one does
|
|
9
|
+
* what the extension did; each claim here was read off the component.
|
|
10
|
+
*/
|
|
11
|
+
import { FONT_AWESOME_PEER_RANGE } from '../_shared/deps-common.js';
|
|
12
|
+
/** A URL's path, without its query and fragment. */
|
|
13
|
+
function pathOf(url) {
|
|
14
|
+
return url.trim().replace(/[?#].*$/, '');
|
|
15
|
+
}
|
|
16
|
+
function hostOf(url) {
|
|
17
|
+
return url.trim().match(/^(?:[a-z][a-z\d+.-]*:)?\/\/([^/?#]+)/i)?.[1] ?? null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Bulma's own stylesheets: the standard one, and the other builds Bulma 1
|
|
21
|
+
* ships under `css/versions/` and Bulma 0.9 shipped beside it (`bulma-rtl`).
|
|
22
|
+
*/
|
|
23
|
+
const BULMA_BUILD = /(?:^|[/\\])bulma(?:-(rtl|no-dark-mode|no-helpers-prefixed|no-helpers|prefixed))?(?:\.min)?\.css$/i;
|
|
24
|
+
/** `bulma@0.9.4` (npm CDNs) and `bulma/0.9.4/` (cdnjs). */
|
|
25
|
+
const BULMA_VERSION = /(?:^|[/@])bulma(?:@|\/)v?(\d+(?:\.\d+){0,2})(?=\/|$)/i;
|
|
26
|
+
const FONT_AWESOME = /font-?awesome/i;
|
|
27
|
+
const FONT_AWESOME_MAJOR = [
|
|
28
|
+
/(?:fontawesome-(?:free|pro)|font-awesome)(?:@|\/)v?(\d+)/i,
|
|
29
|
+
/fontawesome\.com\/releases\/v(\d+)/i,
|
|
30
|
+
];
|
|
31
|
+
const FONT_AWESOME_KIT = /(?:^|\/\/)kit\.fontawesome\.com\//i;
|
|
32
|
+
/** A package whose name starts `bulma-`, as a path segment or a file. */
|
|
33
|
+
const EXTENSION = /(?:^|[/\\])((?:@creativebulma\/)?bulma-[a-z\d]+(?:-[a-z\d]+)*)(?=@|[/\\]|(?:\.min)?\.(?:css|js)$)/i;
|
|
34
|
+
/** jQuery itself, not a plugin: `jquery-3.7.1.min.js`, `jquery@3`. */
|
|
35
|
+
const JQUERY = /(?:^|[/\\])jquery(?:-\d+(?:\.\d+)*)?(?:\.slim)?(?:\.min)?\.js$|(?:^|\/)jquery@[\d.]+$/i;
|
|
36
|
+
/** Hosts that serve a web font's stylesheet. */
|
|
37
|
+
const WEBFONT_HOSTS = new Set([
|
|
38
|
+
'fonts.googleapis.com',
|
|
39
|
+
'fonts.bunny.net',
|
|
40
|
+
'use.typekit.net',
|
|
41
|
+
'fonts.cdnfonts.com',
|
|
42
|
+
'api.fontshare.com',
|
|
43
|
+
]);
|
|
44
|
+
export function classifyAsset(url, loads) {
|
|
45
|
+
const urlPath = pathOf(url);
|
|
46
|
+
if (loads === 'stylesheet') {
|
|
47
|
+
const build = BULMA_BUILD.exec(urlPath);
|
|
48
|
+
if (build) {
|
|
49
|
+
return {
|
|
50
|
+
kind: 'bulma',
|
|
51
|
+
build: build[1]?.toLowerCase() ?? null,
|
|
52
|
+
version: BULMA_VERSION.exec(urlPath)?.[1] ?? null,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (FONT_AWESOME.test(url)) {
|
|
57
|
+
const major = FONT_AWESOME_MAJOR.map(pattern => pattern.exec(urlPath)).find(Boolean)?.[1];
|
|
58
|
+
return {
|
|
59
|
+
kind: 'font-awesome',
|
|
60
|
+
major: major === undefined ? null : Number(major),
|
|
61
|
+
kit: FONT_AWESOME_KIT.test(url.trim()),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const extension = EXTENSION.exec(urlPath)?.[1];
|
|
65
|
+
if (extension)
|
|
66
|
+
return { kind: 'bulma-extension', name: extension };
|
|
67
|
+
if (loads === 'script') {
|
|
68
|
+
return JQUERY.test(urlPath) ? { kind: 'jquery' } : { kind: 'script' };
|
|
69
|
+
}
|
|
70
|
+
const host = hostOf(url)?.toLowerCase();
|
|
71
|
+
if (host && WEBFONT_HOSTS.has(host)) {
|
|
72
|
+
let family = url.replace(/\+/g, ' ');
|
|
73
|
+
try {
|
|
74
|
+
family = decodeURIComponent(family);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// A malformed escape: read the families as written.
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
kind: 'webfont',
|
|
81
|
+
icons: /family=Material Symbols/i.test(family)
|
|
82
|
+
? 'material-symbols'
|
|
83
|
+
: /family=Material Icons/i.test(family)
|
|
84
|
+
? 'material-icons'
|
|
85
|
+
: null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return { kind: 'stylesheet' };
|
|
89
|
+
}
|
|
90
|
+
// ---- Bulma's stylesheet ------------------------------------------------------
|
|
91
|
+
export const GUIDE_0_9_TO_1 = 'https://bestax.io/docs/guides/getting-started/migration/bulma-0-9-to-1';
|
|
92
|
+
/** Whether a version Bulma's URL names is older than 1. */
|
|
93
|
+
function preV1(version) {
|
|
94
|
+
return Number(version.split('.')[0]) < 1;
|
|
95
|
+
}
|
|
96
|
+
/** A primary color class: `is-primary`, `has-text-primary-dark`, … */
|
|
97
|
+
export const PRIMARY_CLASS = /^(?:is|has-text|has-background)-primary(?:-|$)/;
|
|
98
|
+
/**
|
|
99
|
+
* What a page's link to Bulma's standard stylesheet leaves to do. Under
|
|
100
|
+
* `keep` it is only reported. Under `bestax` and `bulma` the module imports
|
|
101
|
+
* the stylesheet in its place, so what is left is the move to Bulma 1 (for a
|
|
102
|
+
* page made for an older one, or one whose URL doesn't say) and, under
|
|
103
|
+
* `bestax`, its primary color: nothing at all for a Bulma 1 page with no
|
|
104
|
+
* primary class, which then has no note. A Next.js app is the exception: its
|
|
105
|
+
* Pages Router takes a global stylesheet only in `pages/_app`, so there the
|
|
106
|
+
* module imports none, and the note says where it goes.
|
|
107
|
+
*/
|
|
108
|
+
export function bulmaStylesheetMessage(facts) {
|
|
109
|
+
const { quoted, version, css, usesPrimary, nextjs = false } = facts;
|
|
110
|
+
const named = version === null ? 'Bulma' : `Bulma ${version}`;
|
|
111
|
+
if (css === 'keep') {
|
|
112
|
+
return `the page loads ${named} from \`${quoted}\`, and a component doesn't: load Bulma once for the app, from its entry (\`import 'bulma/css/bulma.min.css'\`, with \`bulma${version === null ? '' : `@${version}`}\` installed) or a \`<link>\` in its index.html`;
|
|
113
|
+
}
|
|
114
|
+
const said = [];
|
|
115
|
+
if (version === null) {
|
|
116
|
+
said.push(`the URL doesn't say which Bulma it is, so if it predates Bulma 1, read the Bulma 0.9 to 1 guide (${GUIDE_0_9_TO_1}) for what changed`);
|
|
117
|
+
}
|
|
118
|
+
else if (preV1(version)) {
|
|
119
|
+
said.push(`the page was made for ${named}, so read the Bulma 0.9 to 1 guide (${GUIDE_0_9_TO_1}) for what changed`);
|
|
120
|
+
}
|
|
121
|
+
if (css === 'bestax' && usesPrimary) {
|
|
122
|
+
said.push("bestax's bundle builds Bulma with bestax blue as its primary, so the page's primary colors (`is-primary` and its kind) turn from Bulma's turquoise to blue: to keep them, set the `--bulma-primary-*` variables, `--bulma-primary-invert-l` among them (the bestax-migrate skill's `references/css-migration.md` says which), or use `--css bulma`");
|
|
123
|
+
}
|
|
124
|
+
if (nextjs) {
|
|
125
|
+
const target = css === 'bestax'
|
|
126
|
+
? "`import '@allxsmith/bestax-bulma/bestax.css'`"
|
|
127
|
+
: "`import 'bulma/css/bulma.min.css'` (with `bulma` in package.json) and `import '@allxsmith/bestax-bulma/extras.css'`";
|
|
128
|
+
return [
|
|
129
|
+
`the page loads ${named} from \`${quoted}\`, and in a Next.js app a global stylesheet is imported once, from the root layout (App Router) or \`pages/_app\` (Pages Router, which takes one nowhere else), so the module imports none: write ${target} there`,
|
|
130
|
+
...said,
|
|
131
|
+
].join('; and ');
|
|
132
|
+
}
|
|
133
|
+
if (said.length === 0)
|
|
134
|
+
return null;
|
|
135
|
+
const imported = css === 'bestax'
|
|
136
|
+
? "the module imports bestax's bundle in its place (`@allxsmith/bestax-bulma/bestax.css`), which is Bulma 1 with bestax's extras"
|
|
137
|
+
: "the module imports Bulma's stylesheet in its place (`bulma/css/bulma.min.css`, with bestax's `extras.css`), and `--css bulma` moves the app to Bulma 1";
|
|
138
|
+
return `the page loaded ${named} from \`${quoted}\`, and ${imported}: ${said.join('; and ')}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A link to Bulma's stylesheet for some media only (`print`), which an
|
|
142
|
+
* import, applying to every medium, can't stand for.
|
|
143
|
+
*/
|
|
144
|
+
export function bulmaMediaMessage(quoted, version, media) {
|
|
145
|
+
const named = version === null ? 'Bulma' : `Bulma ${version}`;
|
|
146
|
+
return `the page loads ${named} from \`${quoted}\` for \`media="${media}"\` only, and a component doesn't: load it once for the app from a \`<link>\` in its index.html with the same \`media\`; the codemod writes an import only for a link with no media query, since an import applies to every medium`;
|
|
147
|
+
}
|
|
148
|
+
/** One of Bulma's other builds, which no `--css` mode imports for the page. */
|
|
149
|
+
export function bulmaBuildMessage(build, quoted) {
|
|
150
|
+
return `the page loads Bulma's \`${build}\` build from \`${quoted}\`, and a component doesn't: load it once for the app, from its entry or a \`<link>\` in its index.html; the codemod writes an import only for Bulma's standard stylesheet (bestax's own builds, Bulma with its extras, are under \`@allxsmith/bestax-bulma/versions/\`)`;
|
|
151
|
+
}
|
|
152
|
+
// ---- Font Awesome ------------------------------------------------------------
|
|
153
|
+
const ICON_LOADS_NO_FONT = "bestax's `Icon` loads no font of its own";
|
|
154
|
+
const INSTALL_FONT_AWESOME = `install \`@fortawesome/fontawesome-free\` (bestax-bulma's optional peer range is \`${FONT_AWESOME_PEER_RANGE}\`) and import its \`css/all.min.css\` from the app's entry`;
|
|
155
|
+
export function fontAwesomeMessage(asset, quoted) {
|
|
156
|
+
const { major, kit } = asset;
|
|
157
|
+
if (kit) {
|
|
158
|
+
return `the page loads a Font Awesome kit from \`${quoted}\`, whose version the URL doesn't say: ${ICON_LOADS_NO_FONT}, so keep loading the kit once for the app, from its index.html, or ${INSTALL_FONT_AWESOME}`;
|
|
159
|
+
}
|
|
160
|
+
if (major === null) {
|
|
161
|
+
return `the page loads Font Awesome from \`${quoted}\`, whose version the URL doesn't say: ${ICON_LOADS_NO_FONT} and writes the classes Font Awesome 5 and later read (\`fas fa-<name>\`), so keep loading it once for the app, or ${INSTALL_FONT_AWESOME}, with \`css/v4-shims.min.css\` beside it if the page's names are Font Awesome 4's (\`fa fa-<name>\`)`;
|
|
162
|
+
}
|
|
163
|
+
const loads = `the page loads Font Awesome ${major} from \`${quoted}\``;
|
|
164
|
+
if (major <= 4) {
|
|
165
|
+
return `${loads}, whose classes are \`fa fa-<name>\`, and bestax's \`Icon\` writes \`fas fa-<name>\`, which ${major} doesn't style: ${INSTALL_FONT_AWESOME}, then either import \`css/v4-shims.min.css\` beside it, so the page's ${major} names keep working, or move them to the current names (\`fa-envelope-o\` is \`envelope\` with \`variant="regular"\`)`;
|
|
166
|
+
}
|
|
167
|
+
if (major === 5) {
|
|
168
|
+
return `${loads}: ${ICON_LOADS_NO_FONT} and writes the \`fas fa-<name>\` classes 5 reads, so the \`<link>\` keeps working from the app's index.html; installed from npm, \`@fortawesome/fontawesome-free\` takes 6 or 7 (bestax-bulma's optional peer range is \`${FONT_AWESOME_PEER_RANGE}\`, and an older one fails \`npm install\` with ERESOLVE), which still read the 5 names`;
|
|
169
|
+
}
|
|
170
|
+
if (major <= 7) {
|
|
171
|
+
return `${loads}: ${ICON_LOADS_NO_FONT}, so keep loading it once for the app, from a \`<link>\` in its index.html, or ${INSTALL_FONT_AWESOME}`;
|
|
172
|
+
}
|
|
173
|
+
return `${loads}: ${ICON_LOADS_NO_FONT}, and bestax-bulma's optional peer range for it is \`${FONT_AWESOME_PEER_RANGE}\`, so keep loading this one from a \`<link>\` in the app's index.html, where no peer range applies`;
|
|
174
|
+
}
|
|
175
|
+
// ---- Bulma extensions --------------------------------------------------------
|
|
176
|
+
/**
|
|
177
|
+
* The extensions bestax has a component for, by package (a scoped one by its
|
|
178
|
+
* name alone), with the component that does what the extension did.
|
|
179
|
+
*/
|
|
180
|
+
export const EXTENSION_COMPONENTS = {
|
|
181
|
+
'bulma-accordion': '`Collapses`, with a `Collapse` for each item',
|
|
182
|
+
'bulma-badge': '`Badge`',
|
|
183
|
+
'bulma-calendar': '`DateInput` (and `TimeInput`, `DateTimeInput` and `DateRangeInput`)',
|
|
184
|
+
'bulma-carousel': '`Carousel`, with a `CarouselItem` for each slide',
|
|
185
|
+
'bulma-checkradio': '`Checkbox` and `Radio`, which draw their own box',
|
|
186
|
+
'bulma-collapsible': '`Collapse` (`Collapses` for an accordion)',
|
|
187
|
+
'bulma-pageloader': '`Loading` (`isFullPage` for one over the whole page)',
|
|
188
|
+
'bulma-quickview': '`Sidebar`',
|
|
189
|
+
'bulma-slider': '`Slider`',
|
|
190
|
+
'bulma-steps': '`Steps`',
|
|
191
|
+
'bulma-switch': '`Switch`',
|
|
192
|
+
'bulma-tagsinput': '`Taginput`',
|
|
193
|
+
'bulma-timeline': '`Timeline`',
|
|
194
|
+
'bulma-toast': '`Toast` (`toast.show()` from code, with a `ToastContainer` rendered once)',
|
|
195
|
+
'bulma-tooltip': '`Tooltip`',
|
|
196
|
+
};
|
|
197
|
+
export function extensionMessage(name, quoted, loads, css) {
|
|
198
|
+
const from = `from ${quoted.map(url => `\`${url}\``).join(' and ')}`;
|
|
199
|
+
const bare = name.replace(/^@[^/]+\//, '').toLowerCase();
|
|
200
|
+
if (bare === 'bulma-social') {
|
|
201
|
+
return `the page loads bulma-social, a Bulma extension for brand-colored buttons, ${from}, and bestax has no component for it: keep loading it once for the app (\`bulma-social\` from npm, imported from its entry, or the \`<link>\` in its index.html), since its classes (\`is-twitter\`, \`is-github\` and the rest) style Bulma's \`.button\`, which bestax's \`Button\` renders, so they go on \`Button\` through \`className\``;
|
|
202
|
+
}
|
|
203
|
+
if (bare === 'bulma-extensions') {
|
|
204
|
+
return `the page loads bulma-extensions, a bundle of Bulma extensions, ${from}: bestax has components for several of them (the bestax-migrate skill's \`references/bulma-classes/unmappables.md\` lists which), so render those in place of the extensions' markup and scripts, and keep loading the bundle only while the app still uses one bestax has no component for`;
|
|
205
|
+
}
|
|
206
|
+
const component = EXTENSION_COMPONENTS[bare];
|
|
207
|
+
if (component) {
|
|
208
|
+
return `the page loads ${name}, a Bulma extension, ${from}, and bestax has a component for what it does: ${component}, whose styles ship in bestax's \`extras.css\` and \`bestax.css\`; render that in place of the extension's markup${loads.has('script') ? ' and script' : ''}, and stop loading the extension once nothing the app keeps uses its classes`;
|
|
209
|
+
}
|
|
210
|
+
return `the page loads ${name}, a Bulma extension, ${from}, and a component doesn't: keep loading it once for the app (from npm, imported from its entry, or a \`<link>\` in its index.html) while the page's markup uses its classes, which go on bestax's components through \`className\`${css === 'keep' ? '' : ', and check it works with Bulma 1, which an extension can predate'}`;
|
|
211
|
+
}
|
|
212
|
+
// ---- Everything else ---------------------------------------------------------
|
|
213
|
+
export function jqueryMessage(quoted) {
|
|
214
|
+
return `the page loads jQuery from \`${quoted}\`, and a component runs no page scripts: React renders the page now, so what the page's scripts did with jQuery (toggling classes, handlers, showing and hiding) becomes state and event props in the component; load jQuery in the app only if a library the app keeps still needs it`;
|
|
215
|
+
}
|
|
216
|
+
export function webfontMessage(asset, quoted) {
|
|
217
|
+
if (asset.icons !== null) {
|
|
218
|
+
const name = asset.icons === 'material-icons'
|
|
219
|
+
? "Google's Material Icons"
|
|
220
|
+
: "Google's Material Symbols";
|
|
221
|
+
return `the page loads ${name}, an icon font, from \`${quoted}\`: bestax's \`Icon\` writes its classes with \`library="${asset.icons}"\` and loads no font of its own, so keep the \`<link>\` in the app's index.html, or install the \`${asset.icons}\` package and import its stylesheet from the entry`;
|
|
222
|
+
}
|
|
223
|
+
return `the page loads a web font's stylesheet from \`${quoted}\`, and a component doesn't: keep the \`<link>\` in the app's index.html, with the preconnects that go with it, or self-host the font and import it from the app's entry`;
|
|
224
|
+
}
|
|
225
|
+
export function stylesheetMessage(quoted, place, target) {
|
|
226
|
+
if (place === 'beside') {
|
|
227
|
+
// Beside the page is inside its folder, so this never climbs out of it.
|
|
228
|
+
const specifier = `./${target.replace(/^(?:\.\/)+/, '')}`;
|
|
229
|
+
return `the page's own stylesheet \`${quoted}\` is beside it, and a component doesn't load it: import it once for the app, in the order the page loads it, so its rules still win over Bulma's where they did (a module beside the page imports it as \`${specifier}\`), or move its rules into the app's stylesheet`;
|
|
230
|
+
}
|
|
231
|
+
// Only what the page's folder shows: a `<base href>` may have sent the
|
|
232
|
+
// browser somewhere else, so nothing here says the page never loaded it.
|
|
233
|
+
if (place === 'missing') {
|
|
234
|
+
return `the page loads the stylesheet \`${quoted}\`, which isn't beside the page (no \`${target}\` in its folder): load the stylesheet it meant once for the app, or drop it`;
|
|
235
|
+
}
|
|
236
|
+
return `the page loads the stylesheet \`${quoted}\`, and a component doesn't: load it once for the app, from its entry or a \`<link>\` in its index.html`;
|
|
237
|
+
}
|
|
238
|
+
export function scriptMessage(quoted, place, target) {
|
|
239
|
+
if (place === 'beside') {
|
|
240
|
+
return `the page's own script \`${quoted}\` is beside it, and a component runs no page scripts: port what it does into the component (state, effects, event handlers); its code is still in \`${target}\``;
|
|
241
|
+
}
|
|
242
|
+
if (place === 'missing') {
|
|
243
|
+
return `the page loads the script \`${quoted}\`, which isn't beside the page (no \`${target}\` in its folder): find the one it meant and port what it does into the component, or drop it`;
|
|
244
|
+
}
|
|
245
|
+
return `the page loads the script \`${quoted}\`, and a component runs no page scripts: load it in the app if the app still needs it, or replace what it does with React code`;
|
|
246
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule ids for what the HTML input reports: the parts of a page a component
|
|
3
|
+
* can't carry, and what the converter couldn't write as it was.
|
|
4
|
+
*
|
|
5
|
+
* A page is the app's own text, as its class strings are, so an id carries
|
|
6
|
+
* only fixed names, never a URL, a title, a class of the app's or a line of
|
|
7
|
+
* its code: `kind:token`, the token from a closed vocabulary per kind (a tag
|
|
8
|
+
* the HTML spec names, an event attribute from `property-information`'s
|
|
9
|
+
* table, one of parse5's error codes, one of the names here). A token outside
|
|
10
|
+
* it is dropped and the id is the bare kind, as `ruleId` does, so a gap costs
|
|
11
|
+
* detail and never a telemetry event: the worker takes an id of up to 64
|
|
12
|
+
* characters, and an id that would be longer is the bare kind too.
|
|
13
|
+
*
|
|
14
|
+
* Apart from `rules.ts` because none of it is about a Bulma class: the
|
|
15
|
+
* planner's vocabulary is the class map's, and this one is the page's.
|
|
16
|
+
*/
|
|
17
|
+
/** The classes Bulma reads on `<html>` or `<body>` to pad for a navbar. */
|
|
18
|
+
export declare const NAVBAR_FIXED_CLASSES: readonly string[];
|
|
19
|
+
/** Bulma's classes that set a light or dark scheme on what they're on. */
|
|
20
|
+
export declare const THEME_CLASSES: readonly string[];
|
|
21
|
+
/** The patterns an inline script is checked for, each with its own recipe. */
|
|
22
|
+
export declare const SCRIPT_PATTERNS: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* What a stylesheet or script the page loads is: Bulma's own stylesheet,
|
|
25
|
+
* Font Awesome, a Bulma extension, jQuery, a web font, or any other.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ASSET_KINDS: readonly string[];
|
|
28
|
+
export declare const HTML_KINDS: ReadonlySet<string>;
|
|
29
|
+
/** Whether a token is one an id of this kind may carry. */
|
|
30
|
+
export declare function inHtmlVocabulary(kind: string, token: string): boolean;
|
|
31
|
+
export declare function htmlRuleId(kind: string, token?: string): string;
|
|
32
|
+
//# sourceMappingURL=html-rules.d.ts.map
|
|
@@ -0,0 +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;AAoCF,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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule ids for what the HTML input reports: the parts of a page a component
|
|
3
|
+
* can't carry, and what the converter couldn't write as it was.
|
|
4
|
+
*
|
|
5
|
+
* A page is the app's own text, as its class strings are, so an id carries
|
|
6
|
+
* only fixed names, never a URL, a title, a class of the app's or a line of
|
|
7
|
+
* its code: `kind:token`, the token from a closed vocabulary per kind (a tag
|
|
8
|
+
* the HTML spec names, an event attribute from `property-information`'s
|
|
9
|
+
* table, one of parse5's error codes, one of the names here). A token outside
|
|
10
|
+
* it is dropped and the id is the bare kind, as `ruleId` does, so a gap costs
|
|
11
|
+
* detail and never a telemetry event: the worker takes an id of up to 64
|
|
12
|
+
* characters, and an id that would be longer is the bare kind too.
|
|
13
|
+
*
|
|
14
|
+
* Apart from `rules.ts` because none of it is about a Bulma class: the
|
|
15
|
+
* planner's vocabulary is the class map's, and this one is the page's.
|
|
16
|
+
*/
|
|
17
|
+
import { ErrorCodes } from 'parse5';
|
|
18
|
+
import { html } from 'property-information';
|
|
19
|
+
/** The classes Bulma reads on `<html>` or `<body>` to pad for a navbar. */
|
|
20
|
+
export const NAVBAR_FIXED_CLASSES = [
|
|
21
|
+
'has-navbar-fixed-top',
|
|
22
|
+
'has-navbar-fixed-top-desktop',
|
|
23
|
+
'has-navbar-fixed-top-touch',
|
|
24
|
+
'has-navbar-fixed-bottom',
|
|
25
|
+
'has-navbar-fixed-bottom-desktop',
|
|
26
|
+
'has-navbar-fixed-bottom-touch',
|
|
27
|
+
'has-spaced-navbar-fixed-top',
|
|
28
|
+
'has-spaced-navbar-fixed-bottom',
|
|
29
|
+
];
|
|
30
|
+
/** Bulma's classes that set a light or dark scheme on what they're on. */
|
|
31
|
+
export const THEME_CLASSES = ['theme-dark', 'theme-light'];
|
|
32
|
+
/** The patterns an inline script is checked for, each with its own recipe. */
|
|
33
|
+
export const SCRIPT_PATTERNS = [
|
|
34
|
+
'burger',
|
|
35
|
+
'carousel',
|
|
36
|
+
'dismiss',
|
|
37
|
+
'json-ld',
|
|
38
|
+
'modal',
|
|
39
|
+
'theme',
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* What a stylesheet or script the page loads is: Bulma's own stylesheet,
|
|
43
|
+
* Font Awesome, a Bulma extension, jQuery, a web font, or any other.
|
|
44
|
+
*/
|
|
45
|
+
export const ASSET_KINDS = [
|
|
46
|
+
'bulma',
|
|
47
|
+
'bulma-extension',
|
|
48
|
+
'font-awesome',
|
|
49
|
+
'jquery',
|
|
50
|
+
'script',
|
|
51
|
+
'stylesheet',
|
|
52
|
+
'webfont',
|
|
53
|
+
];
|
|
54
|
+
/** Every HTML event-handler attribute, as written (`onclick`). */
|
|
55
|
+
const EVENT_ATTRIBUTES = Object.values(html.property)
|
|
56
|
+
.map(info => info.attribute)
|
|
57
|
+
.filter(attribute => /^on[a-z]+$/.test(attribute));
|
|
58
|
+
const VOCABULARY = {
|
|
59
|
+
'html-head': new Set(['title', 'meta', 'link', 'style', 'base']),
|
|
60
|
+
'html-asset': new Set(ASSET_KINDS),
|
|
61
|
+
'html-script': new Set(SCRIPT_PATTERNS),
|
|
62
|
+
'html-document': new Set([
|
|
63
|
+
...NAVBAR_FIXED_CLASSES,
|
|
64
|
+
...THEME_CLASSES,
|
|
65
|
+
'class',
|
|
66
|
+
'data-theme',
|
|
67
|
+
'dir',
|
|
68
|
+
'id',
|
|
69
|
+
'lang',
|
|
70
|
+
'style',
|
|
71
|
+
]),
|
|
72
|
+
'html-event': new Set(EVENT_ATTRIBUTES),
|
|
73
|
+
'html-element': new Set([
|
|
74
|
+
'conditional-comment',
|
|
75
|
+
'custom',
|
|
76
|
+
'name',
|
|
77
|
+
'obsolete',
|
|
78
|
+
'template',
|
|
79
|
+
'unknown',
|
|
80
|
+
]),
|
|
81
|
+
'html-url': new Set(['javascript', 'missing', 'relative']),
|
|
82
|
+
'html-attr': new Set(['important', 'name', 'style', 'unknown']),
|
|
83
|
+
'html-parse': new Set(Object.values(ErrorCodes)),
|
|
84
|
+
'html-file': new Set(['exists', 'not-included', 'template-syntax']),
|
|
85
|
+
};
|
|
86
|
+
export const HTML_KINDS = new Set(Object.keys(VOCABULARY));
|
|
87
|
+
/** The longest rule id the telemetry worker takes. */
|
|
88
|
+
const MAX_RULE_LENGTH = 64;
|
|
89
|
+
/** Whether a token is one an id of this kind may carry. */
|
|
90
|
+
export function inHtmlVocabulary(kind, token) {
|
|
91
|
+
return VOCABULARY[kind]?.has(token) ?? false;
|
|
92
|
+
}
|
|
93
|
+
export function htmlRuleId(kind, token) {
|
|
94
|
+
if (!HTML_KINDS.has(kind)) {
|
|
95
|
+
throw new Error(`not an HTML rule kind: ${kind}`);
|
|
96
|
+
}
|
|
97
|
+
if (token === undefined || !inHtmlVocabulary(kind, token))
|
|
98
|
+
return kind;
|
|
99
|
+
const id = `${kind}:${token}`;
|
|
100
|
+
return id.length <= MAX_RULE_LENGTH ? id : kind;
|
|
101
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Bulma HTML page → a React module, written beside it.
|
|
3
|
+
*
|
|
4
|
+
* The page is parsed the way a browser builds it (`_shared/html/`), its body
|
|
5
|
+
* becomes the JSX a component returns, laid out with Bulma's displays so the
|
|
6
|
+
* whitespace beside a block, flex or grid box goes, and then the bulma-classes
|
|
7
|
+
* transform runs on that module unchanged, so the HTML converts exactly as
|
|
8
|
+
* the same markup written as JSX would. A number attribute on a plain element
|
|
9
|
+
* is written as a number last, since the planner reads attributes as strings.
|
|
10
|
+
*
|
|
11
|
+
* What a component can't carry becomes a `TODO(bestax-migrate)` line and a
|
|
12
|
+
* report entry under the `html-*` rules (`html-rules.ts`): the head, the
|
|
13
|
+
* `<html>` and `<body>` attributes, scripts (dropped, since a component runs
|
|
14
|
+
* none; their code stays in the page), the stylesheets and scripts it loads
|
|
15
|
+
* (`html-assets.ts` says what each is), and what the converter couldn't
|
|
16
|
+
* write as it was. Document-level ones sit above the component, the rest
|
|
17
|
+
* above its `return`, where the planner's own go. A report entry names the
|
|
18
|
+
* page and its line, never the module's.
|
|
19
|
+
*
|
|
20
|
+
* Under `--css bestax` or `--css bulma` the page's link to Bulma's stylesheet
|
|
21
|
+
* becomes `import 'bulma/css/bulma.min.css'` at the top of the module, which
|
|
22
|
+
* the transform's stylesheet pass then retargets exactly as it would in a JSX
|
|
23
|
+
* file, so the CLI's manifest step reads the module the same way too.
|
|
24
|
+
*
|
|
25
|
+
* Nothing is ever overwritten: a module already beside the page stops it
|
|
26
|
+
* (`html-file:exists`), so a second run changes nothing, and the page itself
|
|
27
|
+
* stays as it was. A page with no Bulma component class writes nothing (a
|
|
28
|
+
* Vite `index.html` is a page like any other), and a server template
|
|
29
|
+
* (`{{`, `{%`, `<?php`, `<%`) is refused rather than read as HTML.
|
|
30
|
+
*/
|
|
31
|
+
import type { HtmlResult, TodoCollector, TodoEntry, TransformOptions } from '../../types.js';
|
|
32
|
+
import { type DisplayOf } from '../_shared/html/whitespace.js';
|
|
33
|
+
/**
|
|
34
|
+
* One display that keeps every run of whitespace any of `displays` would.
|
|
35
|
+
* An inline box keeps the runs beside it, `none` (or a box out of the flow)
|
|
36
|
+
* leaves them to what is past it, and a block drops them, so the result sits
|
|
37
|
+
* inline if any of them does, and is no box if any is, before it is a block.
|
|
38
|
+
* Inside, flowing on the line keeps the most and laying children out as boxes
|
|
39
|
+
* the least.
|
|
40
|
+
*/
|
|
41
|
+
export declare function keepingMost(displays: ReadonlySet<string>): string;
|
|
42
|
+
/**
|
|
43
|
+
* An element's display on a Bulma page: its inline `style`'s when CSS reads
|
|
44
|
+
* it, else what Bulma's classes give it at each viewport (its tag's own where
|
|
45
|
+
* no rule reaches), else its tag's own. Bulma's display helpers are
|
|
46
|
+
* `!important`, so beside one an inline display is one case among theirs.
|
|
47
|
+
* A box Bulma takes out of the flow is beside nothing, so `none` counts too.
|
|
48
|
+
* Where the cases differ, the one display kept is the one that keeps every
|
|
49
|
+
* run any of them would (`keepingMost`): whitespace beside an element goes
|
|
50
|
+
* only when every case drops it.
|
|
51
|
+
*
|
|
52
|
+
* The page's own stylesheets are out of reach, as they are for the
|
|
53
|
+
* converter: a class of the page's that changes a display is the limit.
|
|
54
|
+
*/
|
|
55
|
+
export declare const pageDisplayOf: DisplayOf;
|
|
56
|
+
/**
|
|
57
|
+
* The component a page becomes: its file's name in PascalCase (its folder's
|
|
58
|
+
* for an `index.html`) and `Page`, so `hero.html` can't shadow bestax's
|
|
59
|
+
* `Hero`. A name starting with a digit starts with `Page` instead
|
|
60
|
+
* (`404.html` is `Page404`), and one with nothing to go by is `Page`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function componentName(file: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Where a page's module goes: beside it, `.tsx` when the package around it is
|
|
65
|
+
* TypeScript (a tsconfig, or a dependency on `typescript`), `.jsx` otherwise.
|
|
66
|
+
*/
|
|
67
|
+
export declare function outputPathFor(file: string, options?: TransformOptions): string;
|
|
68
|
+
/**
|
|
69
|
+
* For a page a folder walk found but left out: whether to say so. `-e`
|
|
70
|
+
* matches an extension exactly, as it does for every other file, so the
|
|
71
|
+
* advice names the page's own (`-e html` takes no `.htm` page).
|
|
72
|
+
*/
|
|
73
|
+
export declare function excludedHtml(file: string, source: string): TodoEntry | null;
|
|
74
|
+
/** The import a page's Bulma `<link>` becomes, before `--css` retargets it. */
|
|
75
|
+
export declare const BULMA_IMPORT = "import \"bulma/css/bulma.min.css\";";
|
|
76
|
+
/**
|
|
77
|
+
* The module as written, after the planner: a number attribute on a plain
|
|
78
|
+
* element as a number (`tabIndex="-1"` as `tabIndex={-1}`), which React's
|
|
79
|
+
* types want and React renders the same, when it is spelled the way it
|
|
80
|
+
* renders; a component's are the planner's. And a blank line after the
|
|
81
|
+
* imports, which the transform puts straight above the component.
|
|
82
|
+
*/
|
|
83
|
+
export declare function finishModule(code: string): string;
|
|
84
|
+
/** A page as a module: the one written, and the one before the planner ran. */
|
|
85
|
+
export interface ConvertedPage extends HtmlResult {
|
|
86
|
+
/** The page's content as plain JSX, before the bulma-classes transform. */
|
|
87
|
+
intermediate: string | null;
|
|
88
|
+
}
|
|
89
|
+
export declare function convertPage(file: string, source: string, collector: TodoCollector | undefined, options?: TransformOptions): ConvertedPage;
|
|
90
|
+
/** The `transformHtml` the CLI calls. */
|
|
91
|
+
export declare function transformHtml(file: string, source: string, collector: TodoCollector | undefined, options?: TransformOptions): HtmlResult;
|
|
92
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +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;AAIF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBlD;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;AAivBhE;;;;;;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,CAgHf;AAED,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"}
|