bestax-migrate 2.26.0 → 2.28.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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +12 -6
  4. package/dist/sources/_shared/deps-common.d.ts +2 -0
  5. package/dist/sources/_shared/deps-common.d.ts.map +1 -1
  6. package/dist/sources/_shared/deps-common.js +3 -1
  7. package/dist/sources/_shared/polymorphic.d.ts.map +1 -1
  8. package/dist/sources/_shared/polymorphic.js +16 -1
  9. package/dist/sources/bloomer/mapping.d.ts.map +1 -1
  10. package/dist/sources/bloomer/mapping.js +9 -4
  11. package/dist/sources/bloomer/specials.d.ts.map +1 -1
  12. package/dist/sources/bloomer/specials.js +30 -3
  13. package/dist/sources/bulma-classes/class-map.d.ts +41 -10
  14. package/dist/sources/bulma-classes/class-map.d.ts.map +1 -1
  15. package/dist/sources/bulma-classes/class-map.js +69 -13
  16. package/dist/sources/bulma-classes/glyph.d.ts +20 -0
  17. package/dist/sources/bulma-classes/glyph.d.ts.map +1 -1
  18. package/dist/sources/bulma-classes/glyph.js +64 -0
  19. package/dist/sources/bulma-classes/html-assets.d.ts +87 -0
  20. package/dist/sources/bulma-classes/html-assets.d.ts.map +1 -0
  21. package/dist/sources/bulma-classes/html-assets.js +246 -0
  22. package/dist/sources/bulma-classes/html-rules.d.ts +5 -0
  23. package/dist/sources/bulma-classes/html-rules.d.ts.map +1 -1
  24. package/dist/sources/bulma-classes/html-rules.js +14 -2
  25. package/dist/sources/bulma-classes/html.d.ts +12 -4
  26. package/dist/sources/bulma-classes/html.d.ts.map +1 -1
  27. package/dist/sources/bulma-classes/html.js +224 -49
  28. package/dist/sources/bulma-classes/plan.d.ts +40 -1
  29. package/dist/sources/bulma-classes/plan.d.ts.map +1 -1
  30. package/dist/sources/bulma-classes/plan.js +160 -24
  31. package/dist/sources/bulma-classes/project.d.ts +10 -2
  32. package/dist/sources/bulma-classes/project.d.ts.map +1 -1
  33. package/dist/sources/bulma-classes/project.js +17 -8
  34. package/dist/sources/bulma-classes/transform.d.ts +2 -1
  35. package/dist/sources/bulma-classes/transform.d.ts.map +1 -1
  36. package/dist/sources/bulma-classes/transform.js +231 -33
  37. package/dist/sources/rbx/mapping.d.ts +10 -0
  38. package/dist/sources/rbx/mapping.d.ts.map +1 -1
  39. package/dist/sources/rbx/mapping.js +13 -7
  40. package/dist/sources/react-bulma-components/mapping.d.ts.map +1 -1
  41. package/dist/sources/react-bulma-components/mapping.js +19 -5
  42. package/package.json +4 -3
@@ -68,6 +68,8 @@ const FA_MODIFIERS = new Set([
68
68
  'fa-sharp',
69
69
  'fa-classic',
70
70
  ]);
71
+ /** The class Font Awesome's script puts on each `<svg>` it draws. */
72
+ const DRAWN = 'svg-inline--fa';
71
73
  /** Material Design Icons' classes that modify a glyph rather than name one. */
72
74
  const MDI_MODIFIERS = new Set([
73
75
  'mdi-18px',
@@ -123,6 +125,68 @@ export function readGlyph(glyph) {
123
125
  }
124
126
  return undefined;
125
127
  }
128
+ /**
129
+ * The glyph of Font Awesome's own markup, `<i class="fas fa-home"
130
+ * aria-hidden="true">`: an `<i>` that carries that attribute and nothing
131
+ * else, and that `readGlyph` reads once it's set aside. Undefined for any
132
+ * other `<i>`, one that `readGlyph` reads as it is included.
133
+ */
134
+ export function readHiddenGlyph(glyph) {
135
+ const hidden = glyph?.attributes.get('aria-hidden');
136
+ if (glyph?.attributes.size !== 1 || (hidden !== 'true' && hidden !== true)) {
137
+ return undefined;
138
+ }
139
+ return readGlyph({ ...glyph, attributes: new Map() });
140
+ }
141
+ /**
142
+ * A glyph as the props `Icon` is given, in the order they're written: one
143
+ * feature as a string, and more than one as a list.
144
+ */
145
+ export function glyphProps(glyph) {
146
+ const { features } = glyph;
147
+ return [
148
+ ['library', glyph.library],
149
+ ['name', glyph.name],
150
+ ...(glyph.variant ? [['variant', glyph.variant]] : []),
151
+ ...(features
152
+ ? [
153
+ ['features', features.length === 1 ? features[0] : features],
154
+ ]
155
+ : []),
156
+ ];
157
+ }
158
+ /**
159
+ * The glyph Font Awesome's script drew an `<svg class="svg-inline--fa">` for,
160
+ * as the props `Icon` renders the `<i>` it was drawn from: the name from its
161
+ * `data-icon` (else its one class naming a glyph), the style from its
162
+ * `data-prefix`, and its other classes but the width one the script adds.
163
+ * For advice only: `Icon` renders that `<i>`, never the `<svg>`.
164
+ */
165
+ export function readDrawnGlyph(svg) {
166
+ if (svg?.tag !== 'svg' || !svg.tokens?.includes(DRAWN))
167
+ return undefined;
168
+ const tokens = svg.tokens.filter(token => token !== DRAWN && !/^fa-w-\d+$/.test(token));
169
+ const prefix = svg.attributes.get('data-prefix');
170
+ const style = typeof prefix === 'string' && Object.hasOwn(FA_STYLES, prefix)
171
+ ? prefix
172
+ : 'fas';
173
+ const icon = svg.attributes.get('data-icon');
174
+ const named = typeof icon === 'string' && /^[a-z0-9-]+$/.test(icon)
175
+ ? {
176
+ name: icon,
177
+ features: tokens.filter(token => token !== `fa-${icon}`),
178
+ }
179
+ : nameIn(tokens, 'fa-', FA_MODIFIERS, style);
180
+ if (!named)
181
+ return undefined;
182
+ const variant = FA_STYLES[style];
183
+ return {
184
+ library: 'fa',
185
+ name: named.name,
186
+ ...(variant && { variant }),
187
+ ...(named.features.length > 0 && { features: named.features }),
188
+ };
189
+ }
126
190
  /**
127
191
  * The one class among `tokens` that names a glyph (`fa-home`), without its
128
192
  * prefix, and the rest but `base`, as features. Undefined unless exactly one
@@ -0,0 +1,87 @@
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 type { CssMode } from '../../types.js';
12
+ export type Loads = 'stylesheet' | 'script';
13
+ export type Asset =
14
+ /** Bulma's stylesheet; `build` names one of its other builds. */
15
+ {
16
+ kind: 'bulma';
17
+ build: string | null;
18
+ version: string | null;
19
+ } | {
20
+ kind: 'font-awesome';
21
+ major: number | null;
22
+ kit: boolean;
23
+ }
24
+ /** `name` is the package, as the URL spells it (`bulma-carousel`). */
25
+ | {
26
+ kind: 'bulma-extension';
27
+ name: string;
28
+ } | {
29
+ kind: 'jquery';
30
+ } | {
31
+ kind: 'webfont';
32
+ icons: 'material-icons' | 'material-symbols' | null;
33
+ } | {
34
+ kind: 'stylesheet';
35
+ } | {
36
+ kind: 'script';
37
+ };
38
+ export declare function classifyAsset(url: string, loads: Loads): Asset;
39
+ export declare const GUIDE_0_9_TO_1 = "https://bestax.io/docs/guides/getting-started/migration/bulma-0-9-to-1";
40
+ /** A primary color class: `is-primary`, `has-text-primary-dark`, … */
41
+ export declare const PRIMARY_CLASS: RegExp;
42
+ export interface BulmaFacts {
43
+ /** The URL, as the TODO quotes it. */
44
+ quoted: string;
45
+ version: string | null;
46
+ css: CssMode;
47
+ /** Whether the page's markup has a primary color class. */
48
+ usesPrimary: boolean;
49
+ /** Whether the page's module goes into a Next.js app. */
50
+ nextjs?: boolean;
51
+ }
52
+ /**
53
+ * What a page's link to Bulma's standard stylesheet leaves to do. Under
54
+ * `keep` it is only reported. Under `bestax` and `bulma` the module imports
55
+ * the stylesheet in its place, so what is left is the move to Bulma 1 (for a
56
+ * page made for an older one, or one whose URL doesn't say) and, under
57
+ * `bestax`, its primary color: nothing at all for a Bulma 1 page with no
58
+ * primary class, which then has no note. A Next.js app is the exception: its
59
+ * Pages Router takes a global stylesheet only in `pages/_app`, so there the
60
+ * module imports none, and the note says where it goes.
61
+ */
62
+ export declare function bulmaStylesheetMessage(facts: BulmaFacts): string | null;
63
+ /**
64
+ * A link to Bulma's stylesheet for some media only (`print`), which an
65
+ * import, applying to every medium, can't stand for.
66
+ */
67
+ export declare function bulmaMediaMessage(quoted: string, version: string | null, media: string): string;
68
+ /** One of Bulma's other builds, which no `--css` mode imports for the page. */
69
+ export declare function bulmaBuildMessage(build: string, quoted: string): string;
70
+ export declare function fontAwesomeMessage(asset: Extract<Asset, {
71
+ kind: 'font-awesome';
72
+ }>, quoted: string): string;
73
+ /**
74
+ * The extensions bestax has a component for, by package (a scoped one by its
75
+ * name alone), with the component that does what the extension did.
76
+ */
77
+ export declare const EXTENSION_COMPONENTS: Readonly<Record<string, string>>;
78
+ export declare function extensionMessage(name: string, quoted: string[], loads: ReadonlySet<Loads>, css: CssMode): string;
79
+ export declare function jqueryMessage(quoted: string): string;
80
+ export declare function webfontMessage(asset: Extract<Asset, {
81
+ kind: 'webfont';
82
+ }>, quoted: string): string;
83
+ /** Where a stylesheet or script is, read beside the page. */
84
+ export type Place = 'beside' | 'missing' | 'elsewhere';
85
+ export declare function stylesheetMessage(quoted: string, place: Place, target: string): string;
86
+ export declare function scriptMessage(quoted: string, place: Place, target: string): string;
87
+ //# sourceMappingURL=html-assets.d.ts.map
@@ -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>\`: the codemod keeps that \`fa\` on each icon it converts (\`variant="fa"\`), which ${major} styles, but bestax's \`Icon\` given no \`variant\` writes \`fas fa-<name>\`, which ${major} doesn't, so for icons written from here on, ${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
+ }
@@ -20,6 +20,11 @@ export declare const NAVBAR_FIXED_CLASSES: readonly string[];
20
20
  export declare const THEME_CLASSES: readonly string[];
21
21
  /** The patterns an inline script is checked for, each with its own recipe. */
22
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[];
23
28
  export declare const HTML_KINDS: ReadonlySet<string>;
24
29
  /** Whether a token is one an id of this kind may carry. */
25
30
  export declare function inHtmlVocabulary(kind: string, token: string): boolean;
@@ -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;AAqCF,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"}
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"}
@@ -38,14 +38,26 @@ export const SCRIPT_PATTERNS = [
38
38
  'modal',
39
39
  'theme',
40
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
+ ];
41
54
  /** Every HTML event-handler attribute, as written (`onclick`). */
42
55
  const EVENT_ATTRIBUTES = Object.values(html.property)
43
56
  .map(info => info.attribute)
44
57
  .filter(attribute => /^on[a-z]+$/.test(attribute));
45
58
  const VOCABULARY = {
46
59
  'html-head': new Set(['title', 'meta', 'link', 'style', 'base']),
47
- // Reported at the kind level until the asset vocabulary lands.
48
- 'html-asset': new Set(),
60
+ 'html-asset': new Set(ASSET_KINDS),
49
61
  'html-script': new Set(SCRIPT_PATTERNS),
50
62
  'html-document': new Set([
51
63
  ...NAVBAR_FIXED_CLASSES,
@@ -11,10 +11,16 @@
11
11
  * What a component can't carry becomes a `TODO(bestax-migrate)` line and a
12
12
  * report entry under the `html-*` rules (`html-rules.ts`): the head, the
13
13
  * `<html>` and `<body>` attributes, scripts (dropped, since a component runs
14
- * none; their code stays in the page), and what the converter couldn't write
15
- * as it was. Document-level ones sit above the component, the rest above its
16
- * `return`, where the planner's own go. A report entry names the page and
17
- * its line, never the module's.
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.
18
24
  *
19
25
  * Nothing is ever overwritten: a module already beside the page stops it
20
26
  * (`html-file:exists`), so a second run changes nothing, and the page itself
@@ -65,6 +71,8 @@ export declare function outputPathFor(file: string, options?: TransformOptions):
65
71
  * advice names the page's own (`-e html` takes no `.htm` page).
66
72
  */
67
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\";";
68
76
  /**
69
77
  * The module as written, after the planner: a number attribute on a plain
70
78
  * element as a number (`tabIndex="-1"` as `tabIndex={-1}`), which React's
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;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;AAiDvC;;;;;;;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;AAqrBD;;;;;;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,CAsGf;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"}
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"}