bestax-migrate 2.1.6 → 2.2.1
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 +13 -8
- package/dist/cli.d.ts +53 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +159 -9
- package/dist/sources/_shared/imports.d.ts +46 -0
- package/dist/sources/_shared/imports.d.ts.map +1 -0
- package/dist/sources/_shared/imports.js +152 -0
- package/dist/sources/{react-bulma-components → _shared}/jsx-utils.d.ts +20 -12
- package/dist/sources/_shared/jsx-utils.d.ts.map +1 -0
- package/dist/sources/{react-bulma-components → _shared}/jsx-utils.js +15 -10
- package/dist/sources/_shared/make-styles-transform.d.ts +37 -0
- package/dist/sources/_shared/make-styles-transform.d.ts.map +1 -0
- package/dist/sources/_shared/make-styles-transform.js +440 -0
- package/dist/sources/_shared/props.d.ts +20 -0
- package/dist/sources/_shared/props.d.ts.map +1 -0
- package/dist/sources/{react-bulma-components → _shared}/props.js +11 -7
- package/dist/sources/_shared/semver-range.d.ts +31 -0
- package/dist/sources/_shared/semver-range.d.ts.map +1 -0
- package/dist/sources/_shared/semver-range.js +186 -0
- package/dist/sources/_shared/specials-utils.d.ts +45 -0
- package/dist/sources/_shared/specials-utils.d.ts.map +1 -0
- package/dist/sources/_shared/specials-utils.js +124 -0
- package/dist/sources/rbx/deps.d.ts +18 -0
- package/dist/sources/rbx/deps.d.ts.map +1 -0
- package/dist/sources/rbx/deps.js +192 -0
- package/dist/sources/rbx/index.d.ts +3 -0
- package/dist/sources/rbx/index.d.ts.map +1 -0
- package/dist/sources/rbx/index.js +10 -0
- package/dist/sources/rbx/mapping.d.ts +49 -0
- package/dist/sources/rbx/mapping.d.ts.map +1 -0
- package/dist/sources/rbx/mapping.js +924 -0
- package/dist/sources/rbx/responsive.d.ts +30 -0
- package/dist/sources/rbx/responsive.d.ts.map +1 -0
- package/dist/sources/rbx/responsive.js +279 -0
- package/dist/sources/rbx/specials.d.ts +21 -0
- package/dist/sources/rbx/specials.d.ts.map +1 -0
- package/dist/sources/rbx/specials.js +706 -0
- package/dist/sources/rbx/styles.d.ts +21 -0
- package/dist/sources/rbx/styles.d.ts.map +1 -0
- package/dist/sources/rbx/styles.js +29 -0
- package/dist/sources/rbx/transform.d.ts +25 -0
- package/dist/sources/rbx/transform.d.ts.map +1 -0
- package/dist/sources/rbx/transform.js +911 -0
- package/dist/sources/react-bulma-components/deps.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/deps.js +17 -3
- package/dist/sources/react-bulma-components/responsive.d.ts +1 -1
- package/dist/sources/react-bulma-components/responsive.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/responsive.js +1 -1
- package/dist/sources/react-bulma-components/specials.d.ts +3 -9
- package/dist/sources/react-bulma-components/specials.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/specials.js +4 -91
- package/dist/sources/react-bulma-components/styles.d.ts +9 -9
- package/dist/sources/react-bulma-components/styles.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/styles.js +17 -389
- package/dist/sources/react-bulma-components/transform.d.ts.map +1 -1
- package/dist/sources/react-bulma-components/transform.js +378 -101
- package/dist/sources/registry.d.ts.map +1 -1
- package/dist/sources/registry.js +2 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -7
- package/dist/sources/react-bulma-components/jsx-utils.d.ts.map +0 -1
- package/dist/sources/react-bulma-components/props.d.ts +0 -15
- package/dist/sources/react-bulma-components/props.d.ts.map +0 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Small AST helpers shared by
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Small AST helpers shared by every source's transform passes. All functions
|
|
3
|
+
* operate on the babel/tsx AST that jscodeshift's `tsx` parser produces, via
|
|
4
|
+
* the `j` builder API.
|
|
5
|
+
*
|
|
6
|
+
* Nothing here may know which source library is being migrated — this module
|
|
7
|
+
* is imported by all of them (`react-bulma-components`, `rbx`, …), so any
|
|
8
|
+
* library-specific table belongs in that source's own `mapping.ts`.
|
|
5
9
|
*/
|
|
6
10
|
/** Flatten a JSXIdentifier / JSXMemberExpression chain into name parts. */
|
|
7
11
|
export function jsxNameParts(name) {
|
|
@@ -71,13 +75,14 @@ export function literalValueOf(attr) {
|
|
|
71
75
|
return { kind: 'expression' };
|
|
72
76
|
}
|
|
73
77
|
/**
|
|
74
|
-
* Classify a JSX attribute by the truthiness
|
|
75
|
-
* runtime (`!!value`): every statically-known literal (boolean,
|
|
76
|
-
* number) resolves to `'truthy'`/`'falsy'`; only a genuine
|
|
77
|
-
* `'expression'`. This is the single place
|
|
78
|
-
* a "booleanish" prop (Button `remove`, Heading
|
|
79
|
-
* `booleanToProp`, the `active` ladders, Field
|
|
80
|
-
*
|
|
78
|
+
* Classify a JSX attribute by the truthiness the source library evaluates it
|
|
79
|
+
* with at runtime (`!!value`): every statically-known literal (boolean,
|
|
80
|
+
* string, or number) resolves to `'truthy'`/`'falsy'`; only a genuine
|
|
81
|
+
* expression is `'expression'`. This is the single place every call site that
|
|
82
|
+
* branches on a "booleanish" prop (RBC's Button `remove`, Heading
|
|
83
|
+
* `heading`/`subtitle`, `booleanToProp`, the `active` ladders, Field
|
|
84
|
+
* `multiline`; rbx's bare-boolean modifiers) agrees on what counts as
|
|
85
|
+
* resolvable, so they can't drift out of sync with each other.
|
|
81
86
|
*/
|
|
82
87
|
export function resolveBooleanish(attr) {
|
|
83
88
|
const literal = literalValueOf(attr);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stylesheet migration, shared by every source: Bulma 0.9-era Sass
|
|
3
|
+
* (`@import` + `$var !default` overrides, `_all` aggregator partials) →
|
|
4
|
+
* Bulma v1 modules (`@use "bulma/sass" with (…)`), plus the bestax extras.
|
|
5
|
+
*
|
|
6
|
+
* Sass has no jscodeshift parser, so this is a conservative line-based text
|
|
7
|
+
* transform: it only rewrites patterns it can prove safe and leaves a
|
|
8
|
+
* `// TODO(bestax-migrate): …` everywhere else (line comments are valid in
|
|
9
|
+
* both SCSS and indented Sass).
|
|
10
|
+
*
|
|
11
|
+
* Everything about Bulma itself is source-independent — the only per-source
|
|
12
|
+
* parts are which package's own stylesheet specifiers to retire and which
|
|
13
|
+
* migration guide to link, so those arrive through `StylesConfig`.
|
|
14
|
+
*/
|
|
15
|
+
import type { StylesTransform } from '../../types.js';
|
|
16
|
+
export interface StylesConfig {
|
|
17
|
+
/** npm package name of the source library, e.g. `rbx`. */
|
|
18
|
+
packageName: string;
|
|
19
|
+
/** URL of that source's migration guide, linked from every TODO. */
|
|
20
|
+
guideUrl: string;
|
|
21
|
+
/**
|
|
22
|
+
* Regex fragments (not literals) for the path suffixes that, together with
|
|
23
|
+
* the bare package name, count as the package's *root* stylesheet rather
|
|
24
|
+
* than one of its partials — these are replaced with a Bulma v1 root
|
|
25
|
+
* instead of being dropped.
|
|
26
|
+
*/
|
|
27
|
+
rootStylesheetSuffixes: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the stylesheet transform for one source library.
|
|
31
|
+
*
|
|
32
|
+
* `packageName` drives two regexes — one matching any `@import` of that
|
|
33
|
+
* package, one narrowing to its *root* stylesheet (which becomes a Bulma v1
|
|
34
|
+
* root rather than being dropped). Everything else is Bulma-side and shared.
|
|
35
|
+
*/
|
|
36
|
+
export declare function makeStylesTransform(config: StylesConfig): StylesTransform;
|
|
37
|
+
//# sourceMappingURL=make-styles-transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"make-styles-transform.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/make-styles-transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC;AAyMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CA6UzE"}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stylesheet migration, shared by every source: Bulma 0.9-era Sass
|
|
3
|
+
* (`@import` + `$var !default` overrides, `_all` aggregator partials) →
|
|
4
|
+
* Bulma v1 modules (`@use "bulma/sass" with (…)`), plus the bestax extras.
|
|
5
|
+
*
|
|
6
|
+
* Sass has no jscodeshift parser, so this is a conservative line-based text
|
|
7
|
+
* transform: it only rewrites patterns it can prove safe and leaves a
|
|
8
|
+
* `// TODO(bestax-migrate): …` everywhere else (line comments are valid in
|
|
9
|
+
* both SCSS and indented Sass).
|
|
10
|
+
*
|
|
11
|
+
* Everything about Bulma itself is source-independent — the only per-source
|
|
12
|
+
* parts are which package's own stylesheet specifiers to retire and which
|
|
13
|
+
* migration guide to link, so those arrive through `StylesConfig`.
|
|
14
|
+
*/
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
const TODO = 'TODO(bestax-migrate)';
|
|
17
|
+
const EXTRAS_USE = "@use '@allxsmith/bestax-bulma/scss/extras';";
|
|
18
|
+
/** Bulma v1 sass tree — directories that replaced the 0.9 `_all` partials. */
|
|
19
|
+
const V1_DIRS = new Set([
|
|
20
|
+
'utilities',
|
|
21
|
+
'base',
|
|
22
|
+
'elements',
|
|
23
|
+
'form',
|
|
24
|
+
'components',
|
|
25
|
+
'grid',
|
|
26
|
+
'layout',
|
|
27
|
+
'helpers',
|
|
28
|
+
'themes',
|
|
29
|
+
]);
|
|
30
|
+
/** Known Bulma v1 leaf partials (path after `bulma/sass/`). */
|
|
31
|
+
const V1_LEAVES = new Set([
|
|
32
|
+
'utilities/initial-variables',
|
|
33
|
+
'utilities/derived-variables',
|
|
34
|
+
'utilities/css-variables',
|
|
35
|
+
'utilities/mixins',
|
|
36
|
+
'utilities/functions',
|
|
37
|
+
'utilities/controls',
|
|
38
|
+
'utilities/extends',
|
|
39
|
+
'themes/light',
|
|
40
|
+
'themes/dark',
|
|
41
|
+
'themes/setup',
|
|
42
|
+
]);
|
|
43
|
+
/**
|
|
44
|
+
* The 0.9 root imports that become `@use "bulma/sass"`. The specifier may be
|
|
45
|
+
* bare (`bulma/bulma`), tilde-prefixed (webpack), or a relative path into
|
|
46
|
+
* node_modules (`../../node_modules/bulma/bulma`, common under Parcel) —
|
|
47
|
+
* relative prefixes are preserved in the emitted `@use`.
|
|
48
|
+
*/
|
|
49
|
+
const ROOT_IMPORT = /^(\s*)@import\s+(['"])((?:\.\.?\/)+node_modules\/|~)?bulma\/(?:bulma(?:\.sass|\.scss)?|css\/bulma(?:\.min)?\.css)\2\s*;?\s*$/;
|
|
50
|
+
/** 0.9 partial imports under bulma/sass/… (same prefix forms as the root). */
|
|
51
|
+
const PARTIAL_IMPORT = /^(\s*)@import\s+(['"])((?:\.\.?\/)+node_modules\/|~)?bulma\/sass\/([\w/-]+)\2\s*;?\s*$/;
|
|
52
|
+
/** A preserved path prefix for the rewritten `@use` (tilde never survives). */
|
|
53
|
+
function keptPrefix(prefix) {
|
|
54
|
+
return prefix && prefix !== '~' ? prefix : '';
|
|
55
|
+
}
|
|
56
|
+
/** Any other line that still `@import`s something bulma-ish. */
|
|
57
|
+
const OTHER_BULMA_IMPORT = /^\s*@import\s+['"][^'"]*bulma[^'"]*['"]/;
|
|
58
|
+
/**
|
|
59
|
+
* Third-party Bulma extension packages (`bulma-checkradio`, `bulma-switch`,
|
|
60
|
+
* …) — 0.9-era add-ons whose v1 compatibility varies; several are covered
|
|
61
|
+
* by the bestax extras. The `bulma-` package name must start at a specifier
|
|
62
|
+
* segment boundary (right after the quote/`~`, or after a `/`) so this does
|
|
63
|
+
* not also match a name that merely *contains* `bulma-`, like
|
|
64
|
+
* `react-bulma-components` (see EXTENSION_IMPORT's own regression test).
|
|
65
|
+
*/
|
|
66
|
+
const EXTENSION_IMPORT = /^\s*@import\s+['"](?:~|[^'"]*\/)?bulma-([\w-]+?)(?:\/|\.|['"])/;
|
|
67
|
+
/**
|
|
68
|
+
* The source library's own stylesheet. This is not a third-party extension:
|
|
69
|
+
* it is the library being migrated away from, and `deps.ts` removes its
|
|
70
|
+
* package.json entry in the same run, so leaving the import in place breaks
|
|
71
|
+
* the Sass build. Any `react-bulma-components/…` specifier is dead the same
|
|
72
|
+
* way — the documented v3 setup paths (the bundled CSS, the "advanced" Sass
|
|
73
|
+
* entry point), but also deep partials and extensionless forms — so, like
|
|
74
|
+
* `transform.ts`, we match on the package prefix rather than enumerating
|
|
75
|
+
* shapes. The prefix may be bare, `~`-prefixed, or a relative node_modules
|
|
76
|
+
* path (the Parcel form `ROOT_IMPORT` also supports).
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* The subset of RBC stylesheet imports that are the library's own *root*: the
|
|
80
|
+
* bare package specifier, the documented Sass entry point (`src/index`), and
|
|
81
|
+
* the bundled v3 CSS (`dist/react-bulma-components(.min).css`). These pull in
|
|
82
|
+
* the whole library, which `bulma/sass` supersedes — so when the file already
|
|
83
|
+
* has a Bulma root, dropping one of these loses nothing. A deep RBC partial
|
|
84
|
+
* (`src/components/navbar.sass`) is NOT a root: `bulma/sass` doesn't carry a
|
|
85
|
+
* given partial's styles, so removing one silently would drop CSS. We flag
|
|
86
|
+
* those instead (the package's "never a silent skip" rule).
|
|
87
|
+
*/
|
|
88
|
+
/**
|
|
89
|
+
* A Bulma module root already pulled in via `@use` — the file's own
|
|
90
|
+
* `@use 'bulma/sass'` (any prefix, configured or not) or the bestax bundle
|
|
91
|
+
* (`scss/bestax`, which itself loads `bulma/sass with (…)`). When one is
|
|
92
|
+
* present we must not emit a second root: a duplicate `bulma/sass` namespace,
|
|
93
|
+
* or reconfiguring an already-loaded module, is a hard Sass error.
|
|
94
|
+
*/
|
|
95
|
+
const USE_BULMA_ROOT = /^\s*@use\s+(['"])(?:~|(?:\.\.?\/)+node_modules\/)?(?:bulma\/sass|@allxsmith\/bestax-bulma\/(?:src\/)?scss\/bestax)\1/;
|
|
96
|
+
/** Any `$name: value;` declaration (with or without `!default`). */
|
|
97
|
+
const VAR_DECL = /^\s*\$([\w-]+)\s*:\s*(.+?)\s*(!default)?\s*;\s*$/;
|
|
98
|
+
/**
|
|
99
|
+
* Strips Sass block comments (slash-star … star-slash spans) from a value
|
|
100
|
+
* before it is analyzed for foldability or top-level commas. A comment can
|
|
101
|
+
* carry an unbalanced quote (an apostrophe in `user's`) or a stray `(`/`$`
|
|
102
|
+
* that would otherwise fool the character scanners into mis-reading the
|
|
103
|
+
* value's structure; the comment is inert to Sass, so removing it for
|
|
104
|
+
* analysis is safe. The emitted value still carries the comment verbatim.
|
|
105
|
+
*
|
|
106
|
+
* The scan tracks quote state first and only recognizes a block comment
|
|
107
|
+
* outside a string, in one pass — a bare regex would treat a slash-star …
|
|
108
|
+
* star-slash-shaped span that straddles two quoted strings (opening marker in
|
|
109
|
+
* one string, closing marker in the next) as a comment and delete the real
|
|
110
|
+
* top-level comma between them, so a genuine list would fold unparenthesized.
|
|
111
|
+
* An unterminated comment consumes the rest of the value.
|
|
112
|
+
*/
|
|
113
|
+
function stripSassComments(value) {
|
|
114
|
+
let result = '';
|
|
115
|
+
let quote = null;
|
|
116
|
+
let escaped = false;
|
|
117
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
118
|
+
const char = value[i];
|
|
119
|
+
if (quote) {
|
|
120
|
+
result += char;
|
|
121
|
+
if (escaped) {
|
|
122
|
+
escaped = false;
|
|
123
|
+
}
|
|
124
|
+
else if (char === '\\') {
|
|
125
|
+
escaped = true;
|
|
126
|
+
}
|
|
127
|
+
else if (char === quote) {
|
|
128
|
+
quote = null;
|
|
129
|
+
}
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (char === '/' && value[i + 1] === '*') {
|
|
133
|
+
const end = value.indexOf('*/', i + 2);
|
|
134
|
+
if (end === -1)
|
|
135
|
+
break; // unterminated comment — drop the rest
|
|
136
|
+
i = end + 1; // resume after the closing */
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (char === '"' || char === "'")
|
|
140
|
+
quote = char;
|
|
141
|
+
result += char;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A value is fold-safe for `with (…)` when it is a plain literal — no
|
|
147
|
+
* function calls, interpolation, variable references, or at-rules. Hex
|
|
148
|
+
* colors (`#ff6b35`) are fine; `#{…}` interpolation is not. Block comments are
|
|
149
|
+
* ignored for this test — their contents don't make the value non-literal.
|
|
150
|
+
*/
|
|
151
|
+
function isFoldableValue(value) {
|
|
152
|
+
return !/[()$@]|#\{/.test(stripSassComments(value));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Whether `value` has a comma outside any quoted string — a bare Sass list
|
|
156
|
+
* (`'Nunito', sans-serif`) that must be parenthesized before it can sit
|
|
157
|
+
* inside `with (…)`, or Dart Sass reads the comma as an argument separator
|
|
158
|
+
* instead of a list delimiter. Block comments are stripped first so a quote or
|
|
159
|
+
* comma inside one (an apostrophe in `user's`) can't skew the scan.
|
|
160
|
+
*/
|
|
161
|
+
function hasTopLevelComma(value) {
|
|
162
|
+
let quote = null;
|
|
163
|
+
let escaped = false;
|
|
164
|
+
for (const char of stripSassComments(value)) {
|
|
165
|
+
if (escaped) {
|
|
166
|
+
escaped = false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (char === '\\') {
|
|
170
|
+
escaped = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (quote) {
|
|
174
|
+
if (char === quote)
|
|
175
|
+
quote = null;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (char === '"' || char === "'") {
|
|
179
|
+
quote = char;
|
|
180
|
+
}
|
|
181
|
+
else if (char === ',') {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
/** Formats a folded value for the `with (…)` clause, parenthesizing a bare list. */
|
|
188
|
+
function formatFoldedValue(value) {
|
|
189
|
+
return hasTopLevelComma(value) ? `(${value})` : value;
|
|
190
|
+
}
|
|
191
|
+
function report(collector, file, line, rule, message) {
|
|
192
|
+
collector?.add({ file, line, rule, message });
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Build the stylesheet transform for one source library.
|
|
196
|
+
*
|
|
197
|
+
* `packageName` drives two regexes — one matching any `@import` of that
|
|
198
|
+
* package, one narrowing to its *root* stylesheet (which becomes a Bulma v1
|
|
199
|
+
* root rather than being dropped). Everything else is Bulma-side and shared.
|
|
200
|
+
*/
|
|
201
|
+
export function makeStylesTransform(config) {
|
|
202
|
+
const { packageName, guideUrl: GUIDE } = config;
|
|
203
|
+
const pkg = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
204
|
+
// Already regex fragments — see StylesConfig.
|
|
205
|
+
const roots = config.rootStylesheetSuffixes.join('|');
|
|
206
|
+
/**
|
|
207
|
+
* Any @import of the source package's own stylesheets. The path after the
|
|
208
|
+
* package name is optional: `@import '~rbx'` resolves through the package's
|
|
209
|
+
* `style`/`sass` field and is a plausible spelling for a short package name,
|
|
210
|
+
* and SOURCE_ROOT_STYLESHEET below already accepts that bare form — so
|
|
211
|
+
* requiring the slash here made the bare case unreachable.
|
|
212
|
+
*/
|
|
213
|
+
const SOURCE_STYLE_IMPORT = new RegExp(`^(\\s*)@import\\s+(['"])((?:\\.\\.?/)+node_modules/|~)?${pkg}(?:/[^'"]*)?\\2\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
|
|
214
|
+
/** Cheap "is this file even about us?" pre-filter (see the guard below). */
|
|
215
|
+
const SOURCE_MENTION = new RegExp(pkg);
|
|
216
|
+
/** …narrowed to the ones that stand in for a whole Bulma root. */
|
|
217
|
+
const SOURCE_ROOT_STYLESHEET = new RegExp(`^\\s*@import\\s+(['"])(?:(?:\\.\\.?/)+node_modules/|~)?${pkg}${roots ? `(?:${roots})?` : ''}\\1\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
|
|
218
|
+
const transformStyles = (filePath, source, collector, options) => {
|
|
219
|
+
const cssMode = options.cssMode ?? 'bestax';
|
|
220
|
+
// Cheap pre-filter. It must accept a file that names only the SOURCE
|
|
221
|
+
// package: rbx's documented Sass entry is `@import '~rbx/rbx'` and rbx
|
|
222
|
+
// pulls Bulma in itself, so such a file contains no "bulma" substring at
|
|
223
|
+
// all. Bailing on it left a dead import behind with no TODO and no report
|
|
224
|
+
// entry while deps.ts deleted the package in the same run — a silent
|
|
225
|
+
// build break, which is exactly what this package promises never to do.
|
|
226
|
+
if (!/bulma/.test(source) && !SOURCE_MENTION.test(source))
|
|
227
|
+
return null;
|
|
228
|
+
// Indented-syntax files: flag only — rewriting without a parser is unsafe.
|
|
229
|
+
if (path.extname(filePath) === '.sass') {
|
|
230
|
+
if (source.includes(`${TODO}`))
|
|
231
|
+
return null;
|
|
232
|
+
report(collector, filePath, 1, 'sass', `indented-syntax file references Bulma; convert its @import lines to @use "bulma/sass" by hand — see ${GUIDE}`);
|
|
233
|
+
return `// ${TODO}: convert Bulma 0.9 @import lines to @use "bulma/sass" with (…) — see ${GUIDE}\n${source}`;
|
|
234
|
+
}
|
|
235
|
+
const lines = source.split('\n');
|
|
236
|
+
const out = [];
|
|
237
|
+
let changed = false;
|
|
238
|
+
let extrasAdded = source.includes('@allxsmith/bestax-bulma/scss');
|
|
239
|
+
// Pass 1: locate the file's Bulma root and the safe leading variable
|
|
240
|
+
// overrides that fold into it. A real `bulma/…` @import root wins; otherwise
|
|
241
|
+
// the RBC stylesheet, which we rewrite into a root the same way — so a file
|
|
242
|
+
// that starts from RBC and one that starts from a bulma @import converge on
|
|
243
|
+
// the identical shape. A pre-existing `@use` root means we create no new one.
|
|
244
|
+
const rootImportIndex = lines.findIndex(line => ROOT_IMPORT.test(line));
|
|
245
|
+
// DELIBERATELY any source specifier, not just the root stylesheet. A
|
|
246
|
+
// reviewer flagged that a lone deep partial (`~rbx/base/helpers/badge`) is
|
|
247
|
+
// rewritten into a full `@use 'bulma/sass'` as though it were the whole
|
|
248
|
+
// framework. That is the intended behaviour, and it predates rbx: the
|
|
249
|
+
// react-bulma-components suite asserts it by name ("regardless of
|
|
250
|
+
// specifier shape"). The reasoning holds for both sources — every one of
|
|
251
|
+
// these imports is dead once deps.ts removes the package, and a file that
|
|
252
|
+
// styled itself from the library needs SOME Bulma root afterwards, so
|
|
253
|
+
// emitting one beats dropping it and leaving the file unstyled.
|
|
254
|
+
const sourceRootIndex = lines.findIndex(line => SOURCE_STYLE_IMPORT.test(line) && !line.includes(TODO));
|
|
255
|
+
const hasUseBulmaRoot = lines.some(line => USE_BULMA_ROOT.test(line));
|
|
256
|
+
const foldTargetIndex = hasUseBulmaRoot
|
|
257
|
+
? -1
|
|
258
|
+
: rootImportIndex !== -1
|
|
259
|
+
? rootImportIndex
|
|
260
|
+
: sourceRootIndex;
|
|
261
|
+
const foldableVars = [];
|
|
262
|
+
const unsafeVarLines = [];
|
|
263
|
+
if (foldTargetIndex !== -1) {
|
|
264
|
+
for (let i = 0; i < foldTargetIndex; i += 1) {
|
|
265
|
+
const line = lines[i];
|
|
266
|
+
const match = line.match(VAR_DECL);
|
|
267
|
+
if (match && isFoldableValue(match[2])) {
|
|
268
|
+
foldableVars.push({
|
|
269
|
+
index: i,
|
|
270
|
+
name: match[1],
|
|
271
|
+
value: match[2].trim(),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
else if (/^\s*\$[\w-]+\s*:/.test(line)) {
|
|
275
|
+
unsafeVarLines.push(i);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const folded = new Set(foldableVars.map(v => v.index));
|
|
280
|
+
/**
|
|
281
|
+
* Emit a Bulma module root at `indent` (folding the leading var overrides
|
|
282
|
+
* gathered above into `with (…)`, flagging any unsafe ones), then, in
|
|
283
|
+
* bestax mode, the extras. `prefix` is a preserved relative-path prefix
|
|
284
|
+
* (raw-file toolchains resolve paths, not package specifiers) or ''.
|
|
285
|
+
*/
|
|
286
|
+
const emitBulmaRoot = (indent, prefix, lineNo) => {
|
|
287
|
+
const bulmaSass = `${prefix}bulma/sass`;
|
|
288
|
+
if (foldableVars.length > 0) {
|
|
289
|
+
out.push(`${indent}@use '${bulmaSass}' with (`);
|
|
290
|
+
foldableVars.forEach(({ name, value }, index) => {
|
|
291
|
+
const comma = index < foldableVars.length - 1 ? ',' : '';
|
|
292
|
+
out.push(`${indent} $${name}: ${formatFoldedValue(value)}${comma}`);
|
|
293
|
+
});
|
|
294
|
+
out.push(`${indent});`);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
out.push(`${indent}@use '${bulmaSass}';`);
|
|
298
|
+
}
|
|
299
|
+
if (unsafeVarLines.length > 0) {
|
|
300
|
+
out.push(`${indent}// ${TODO}: the variable override(s) above use computed values; move them into the @use "bulma/sass" with (…) configuration by hand`);
|
|
301
|
+
report(collector, filePath, lineNo, 'sass', 'variable overrides with computed values could not be folded into `with (…)`');
|
|
302
|
+
}
|
|
303
|
+
if (cssMode === 'bestax' && !extrasAdded) {
|
|
304
|
+
out.push(prefix
|
|
305
|
+
? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';`
|
|
306
|
+
: `${indent}${EXTRAS_USE}`);
|
|
307
|
+
extrasAdded = true;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
311
|
+
const line = lines[i];
|
|
312
|
+
if (i === rootImportIndex) {
|
|
313
|
+
const rootMatch = line.match(ROOT_IMPORT);
|
|
314
|
+
// A path-prefixed root import means the toolchain resolves raw file
|
|
315
|
+
// paths, not package specifiers — point at the shipped files directly.
|
|
316
|
+
emitBulmaRoot(rootMatch?.[1] ?? '', keptPrefix(rootMatch?.[3]), i + 1);
|
|
317
|
+
changed = true;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (folded.has(i)) {
|
|
321
|
+
changed = true; // folded into with(...) above
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const partial = line.match(PARTIAL_IMPORT);
|
|
325
|
+
if (partial) {
|
|
326
|
+
const [, indent, , rawPrefix, importPath] = partial;
|
|
327
|
+
const prefix = keptPrefix(rawPrefix);
|
|
328
|
+
// Partial-only files (modular builds with no root import) still need
|
|
329
|
+
// the extras for the bestax components' styling; the extras tree only
|
|
330
|
+
// reads Bulma utilities, never configures them, so this is load-safe.
|
|
331
|
+
const pushExtras = () => {
|
|
332
|
+
if (cssMode !== 'bestax' || extrasAdded || rootImportIndex !== -1) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
out.push(prefix
|
|
336
|
+
? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';`
|
|
337
|
+
: `${indent}${EXTRAS_USE}`);
|
|
338
|
+
extrasAdded = true;
|
|
339
|
+
};
|
|
340
|
+
const segments = importPath.split('/');
|
|
341
|
+
const last = segments[segments.length - 1].replace(/^_/, '');
|
|
342
|
+
const dir = segments[0];
|
|
343
|
+
if ((last === 'all' || last === 'index') && V1_DIRS.has(dir)) {
|
|
344
|
+
out.push(`${indent}@use '${prefix}bulma/sass/${dir}';`);
|
|
345
|
+
pushExtras();
|
|
346
|
+
changed = true;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const leaf = segments.map(s => s.replace(/^_/, '')).join('/');
|
|
350
|
+
if (V1_DIRS.has(leaf) || V1_LEAVES.has(leaf)) {
|
|
351
|
+
out.push(`${indent}@use '${prefix}bulma/sass/${leaf}';`);
|
|
352
|
+
pushExtras();
|
|
353
|
+
changed = true;
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
out.push(`${indent}// ${TODO}: this Bulma 0.9 partial path no longer exists in Bulma v1; find its replacement under bulma/sass/ — see ${GUIDE}`);
|
|
357
|
+
out.push(line);
|
|
358
|
+
report(collector, filePath, i + 1, 'sass', `Bulma 0.9 partial path \`bulma/sass/${importPath}\` has no direct v1 equivalent`);
|
|
359
|
+
changed = true;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const sourceStyle = line.match(SOURCE_STYLE_IMPORT);
|
|
363
|
+
if (sourceStyle && !line.includes(TODO)) {
|
|
364
|
+
const indent = sourceStyle[1];
|
|
365
|
+
const prefix = keptPrefix(sourceStyle[3]);
|
|
366
|
+
if (i === sourceRootIndex &&
|
|
367
|
+
rootImportIndex === -1 &&
|
|
368
|
+
!hasUseBulmaRoot) {
|
|
369
|
+
// The library's own stylesheet never resolves post-migration (deps.ts
|
|
370
|
+
// removes react-bulma-components in the same run), and it is this
|
|
371
|
+
// file's only Bulma root, so rewrite it into one — the same shape the
|
|
372
|
+
// @import root path emits, folding any leading var overrides. Emitting
|
|
373
|
+
// a real `bulma/sass` (+ extras) rather than the hard-configured
|
|
374
|
+
// bestax bundle keeps this convergent with the @import path and avoids
|
|
375
|
+
// reconfiguring `bulma/sass` if a themed root exists elsewhere.
|
|
376
|
+
emitBulmaRoot(indent, prefix, i + 1);
|
|
377
|
+
if (cssMode === 'keep') {
|
|
378
|
+
// The replacement is unavoidable even in keep mode: RBC's own
|
|
379
|
+
// stylesheet is a v3 (Bulma 0.9) asset the migrated v1 components
|
|
380
|
+
// can't use. What changed depends on whether the manifest step ran.
|
|
381
|
+
const depsRan = options.deps !== false;
|
|
382
|
+
const detail = depsRan
|
|
383
|
+
? 'its package.json entry is removed, so the old import no longer resolves; install bulma@^1'
|
|
384
|
+
: 'it targets Bulma 0.9, not the v1 your components now use; --no-deps kept the dependency, so install bulma@^1 alongside it';
|
|
385
|
+
out.push(`${indent}// ${TODO}: replaced ${packageName}'s own stylesheet with @use 'bulma/sass' — ${detail} — see ${GUIDE}`);
|
|
386
|
+
report(collector, filePath, i + 1, 'sass', depsRan
|
|
387
|
+
? `replaced ${packageName}'s stylesheet import with bulma/sass; the package is removed from dependencies, so the old import would not resolve`
|
|
388
|
+
: `replaced ${packageName}'s stylesheet import with bulma/sass; it is a Bulma 0.9 asset the migrated v1 components can't use (--no-deps left the package in place)`);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
// bestax/bulma modes rewrite the file's root without a TODO — still
|
|
392
|
+
// report it so the migration summary reflects the restructured root.
|
|
393
|
+
report(collector, filePath, i + 1, 'sass', `replaced ${packageName}'s stylesheet import with a Bulma v1 @use root`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
// A Bulma root already covers this file (a `bulma/…` @import we
|
|
398
|
+
// convert, the file's own `@use` root, or an earlier RBC line we
|
|
399
|
+
// rewrote). In bestax mode keep that root and add only the extras —
|
|
400
|
+
// never a second root, never the configured bundle that would
|
|
401
|
+
// reconfigure an already-loaded module.
|
|
402
|
+
if (cssMode === 'bestax' && !extrasAdded) {
|
|
403
|
+
out.push(prefix
|
|
404
|
+
? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';`
|
|
405
|
+
: `${indent}${EXTRAS_USE}`);
|
|
406
|
+
extrasAdded = true;
|
|
407
|
+
}
|
|
408
|
+
// Dropping the RBC line is only safe for its root/index stylesheet,
|
|
409
|
+
// which `bulma/sass` supersedes. A deep RBC partial can carry styles
|
|
410
|
+
// `bulma/sass` doesn't, so removing it silently would lose CSS — flag
|
|
411
|
+
// it with a TODO + report entry instead (never a silent skip).
|
|
412
|
+
if (!SOURCE_ROOT_STYLESHEET.test(line)) {
|
|
413
|
+
out.push(`${indent}// ${TODO}: dropped a ${packageName} stylesheet partial that has no Bulma v1 root equivalent; port any styles it carried beyond Bulma's own by hand — see ${GUIDE}`);
|
|
414
|
+
report(collector, filePath, i + 1, 'sass', `${packageName} stylesheet partial dropped; port any styles it carried beyond Bulma’s own by hand`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
changed = true;
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (OTHER_BULMA_IMPORT.test(line) && !line.includes(TODO)) {
|
|
421
|
+
const extension = line.match(EXTENSION_IMPORT);
|
|
422
|
+
if (extension) {
|
|
423
|
+
out.push(`// ${TODO}: bulma-${extension[1]} is a Bulma 0.9-era extension — check its Bulma v1 compatibility; the bestax extras already style Radio/Checkbox and the advanced form controls — see ${GUIDE}`);
|
|
424
|
+
out.push(line);
|
|
425
|
+
report(collector, filePath, i + 1, 'sass', `third-party Bulma extension \`bulma-${extension[1]}\` left in place; verify it against Bulma v1 or replace it with the bestax extras`);
|
|
426
|
+
changed = true;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
out.push(`// ${TODO}: Bulma v1 uses @use instead of @import — see ${GUIDE}`);
|
|
430
|
+
out.push(line);
|
|
431
|
+
report(collector, filePath, i + 1, 'sass', 'unrecognized Bulma @import left in place; convert to @use by hand');
|
|
432
|
+
changed = true;
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
out.push(line);
|
|
436
|
+
}
|
|
437
|
+
return changed ? out.join('\n') : null;
|
|
438
|
+
};
|
|
439
|
+
return transformStyles;
|
|
440
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prop-level conversion: applies a PropAction to a single attribute, plus the
|
|
3
|
+
* universal modifier-prop pass shared by every mapped component.
|
|
4
|
+
*
|
|
5
|
+
* Source-agnostic — the universal table is passed in by the caller rather than
|
|
6
|
+
* imported, so each source keeps its own `UNIVERSAL_PROPS` in its `mapping.ts`
|
|
7
|
+
* while sharing this interpreter.
|
|
8
|
+
*/
|
|
9
|
+
import type { ASTPath } from 'jscodeshift';
|
|
10
|
+
import type { PropAction } from '../../types.js';
|
|
11
|
+
import { type TransformContext } from './jsx-utils.js';
|
|
12
|
+
/** Apply one PropAction to `attr` on `element`. */
|
|
13
|
+
export declare function applyPropAction(ctx: TransformContext, path: ASTPath<any>, element: any, attr: any, action: PropAction): void;
|
|
14
|
+
/**
|
|
15
|
+
* Apply the source library's universal modifier-prop conversions to every
|
|
16
|
+
* attribute that was not already handled by the component's own prop map.
|
|
17
|
+
* `universalProps` is the calling source's `UNIVERSAL_PROPS` table.
|
|
18
|
+
*/
|
|
19
|
+
export declare function applyUniversalProps(ctx: TransformContext, path: ASTPath<any>, element: any, handled: Set<string>, universalProps: Record<string, PropAction>): void;
|
|
20
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/props.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AA6BxB,mDAAmD;AACnD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GACjB,IAAI,CA6HN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GACzC,IAAI,CAQN"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prop-level conversion: applies a PropAction to a single attribute, plus the
|
|
3
3
|
* universal modifier-prop pass shared by every mapped component.
|
|
4
|
+
*
|
|
5
|
+
* Source-agnostic — the universal table is passed in by the caller rather than
|
|
6
|
+
* imported, so each source keeps its own `UNIVERSAL_PROPS` in its `mapping.ts`
|
|
7
|
+
* while sharing this interpreter.
|
|
4
8
|
*/
|
|
5
|
-
import { UNIVERSAL_PROPS } from './mapping.js';
|
|
6
9
|
import { addAttr, addTodo, attributesOf, findAttr, literalValueOf, makeAttr, removeAttr, resolveBooleanish, } from './jsx-utils.js';
|
|
7
10
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8
11
|
/**
|
|
9
12
|
* Add a converted attribute unless the target name is already present — two
|
|
10
|
-
*
|
|
11
|
-
* and a silent duplicate would be invalid JSX.
|
|
13
|
+
* source props can map onto one bestax prop (e.g. RBC's `textTransform` +
|
|
14
|
+
* `italic`), and a silent duplicate would be invalid JSX.
|
|
12
15
|
*/
|
|
13
16
|
function addConverted(ctx, path, element, originalName, name, value) {
|
|
14
17
|
if (findAttr(element, name)) {
|
|
@@ -109,15 +112,16 @@ export function applyPropAction(ctx, path, element, attr, action) {
|
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
/**
|
|
112
|
-
* Apply the universal
|
|
113
|
-
* was not already handled by the component's own prop map.
|
|
115
|
+
* Apply the source library's universal modifier-prop conversions to every
|
|
116
|
+
* attribute that was not already handled by the component's own prop map.
|
|
117
|
+
* `universalProps` is the calling source's `UNIVERSAL_PROPS` table.
|
|
114
118
|
*/
|
|
115
|
-
export function applyUniversalProps(ctx, path, element, handled) {
|
|
119
|
+
export function applyUniversalProps(ctx, path, element, handled, universalProps) {
|
|
116
120
|
for (const attr of [...attributesOf(element)]) {
|
|
117
121
|
const name = attr.name.name;
|
|
118
122
|
if (handled.has(name))
|
|
119
123
|
continue;
|
|
120
|
-
const action =
|
|
124
|
+
const action = universalProps[name];
|
|
121
125
|
if (!action)
|
|
122
126
|
continue;
|
|
123
127
|
applyPropAction(ctx, path, element, attr, action);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal semver-range reading for the manifest passes, shared by every source.
|
|
3
|
+
*
|
|
4
|
+
* Not a semver implementation: the workspace deliberately carries no `semver`
|
|
5
|
+
* dependency for this, and the two questions the passes ask are narrow. Both
|
|
6
|
+
* are answered conservatively, so an unrecognised shape is left alone rather
|
|
7
|
+
* than guessed at. The one thing this file must never do is rewrite a value it
|
|
8
|
+
* does not understand, so every accepting path below goes through one grammar.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* True only when `range` PROVABLY admits no version >= 1.0.0.
|
|
12
|
+
*
|
|
13
|
+
* The first version of this matched a leading `0` and nothing else, so a range
|
|
14
|
+
* written as comparators (`>=0.7 <1`) was left on 0.x and then reported as
|
|
15
|
+
* already v1. It lived in the rbx source only; the react-bulma-components
|
|
16
|
+
* manifest pass kept the regex until review found the unported half.
|
|
17
|
+
* This walks each `||` alternative and its comparators: a set is pre-v1 when
|
|
18
|
+
* some comparator caps it below 1.0.0 and none of them opens it at 1 or above.
|
|
19
|
+
*
|
|
20
|
+
* Conservative by design: an unrecognised shape returns false and the range is
|
|
21
|
+
* left alone (and reported as such). Bumping a range that might already admit
|
|
22
|
+
* v1 would be the best-guess rewrite this package refuses to make.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isPreV1(range: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* True when every comparator in every alternative parses to a semver major,
|
|
27
|
+
* so the headline can tell "already v1" apart from "not a version range at
|
|
28
|
+
* all" (`latest`, a git URL) rather than calling both v1.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isRecognisedRange(range: string): boolean;
|
|
31
|
+
//# sourceMappingURL=semver-range.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver-range.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/semver-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4BH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAG9C;AAgGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBxD"}
|