@plumeria/codemod 18.2.19 → 18.2.20
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 +48 -9
- package/dist/cli.js +5 -3
- package/dist/migrate.js +3 -1
- package/dist/release.d.ts +2 -0
- package/dist/release.js +295 -38
- package/dist/transforms/adopt-styles.d.ts +2 -0
- package/dist/transforms/adopt-styles.js +303 -10
- package/dist/transforms/css-modules.d.ts +5 -1
- package/dist/transforms/css-modules.js +59 -5
- package/dist/transforms/from-plumeria.d.ts +17 -1
- package/dist/transforms/from-plumeria.js +276 -10
- package/dist/transforms/release-styles.d.ts +4 -0
- package/dist/transforms/release-styles.js +466 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,6 +134,7 @@ export function Card({ width }: { width: number }) {
|
|
|
134
134
|
/* Card.tsx — after */
|
|
135
135
|
- import * as css from '@plumeria/core';
|
|
136
136
|
+ import styles from './Card.module.css';
|
|
137
|
+
+ export { styles };
|
|
137
138
|
|
|
138
139
|
- export const styles = css.create({
|
|
139
140
|
- base: { fontSize: 12 },
|
|
@@ -143,14 +144,13 @@ export function Card({ width }: { width: number }) {
|
|
|
143
144
|
- },
|
|
144
145
|
- size: (width: number) => ({ width }),
|
|
145
146
|
- });
|
|
146
|
-
+ export { styles };
|
|
147
147
|
|
|
148
148
|
export function Card({ width }: { width: number }) {
|
|
149
149
|
- return <div classStyle={[styles.base, styles.card, styles.size(width)]} />;
|
|
150
150
|
+ return (
|
|
151
151
|
+ <div
|
|
152
|
-
+ className={
|
|
153
|
-
+ style={{ '--styles-size-width': width }}
|
|
152
|
+
+ className={[styles.base, styles.card, styles.size].join(' ')}
|
|
153
|
+
+ style={{ ['--styles-size-width' as string]: width }}
|
|
154
154
|
+ />
|
|
155
155
|
+ );
|
|
156
156
|
}
|
|
@@ -162,15 +162,41 @@ equivalent, so each parameter becomes a CSS custom property named
|
|
|
162
162
|
values move to the inline `style` prop. If a `style` prop already exists, the
|
|
163
163
|
custom properties are merged into it.
|
|
164
164
|
|
|
165
|
-
An array
|
|
166
|
-
|
|
167
|
-
so the falsy branch drops out at runtime:
|
|
165
|
+
An array with no condition in it collapses into one class that `composes` its
|
|
166
|
+
members, so nothing is duplicated:
|
|
168
167
|
|
|
169
168
|
```diff
|
|
169
|
+
- <div classStyle={[styles.base, styles.card]} />
|
|
170
|
+
+ <div className={styles.baseCard} />
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Otherwise the array is joined as it stands. `filter` is added only when a
|
|
174
|
+
condition can make a member falsy, so that branch drops out at runtime:
|
|
175
|
+
|
|
176
|
+
```diff
|
|
177
|
+
- <div classStyle={[styles.base, styles.card, styles.size(width)]} />
|
|
178
|
+
+ <div className={[styles.base, styles.card, styles.size].join(' ')} style={{ … }} />
|
|
179
|
+
|
|
170
180
|
- <div classStyle={[styles.base, active && styles.active]} />
|
|
171
181
|
+ <div className={[styles.base, active && styles.active].filter(Boolean).join(' ')} />
|
|
172
182
|
```
|
|
173
183
|
|
|
184
|
+
`classStyle={[b, a]}` gives `a` the last word, while a stylesheet gives it to
|
|
185
|
+
whichever rule is written later. The export reproduces the array order by
|
|
186
|
+
emitting the classes in an order that satisfies every call site at once. Where
|
|
187
|
+
two call sites compose the same pair in opposite orders, the one that cannot be
|
|
188
|
+
satisfied carries an extra class holding only the disputed declarations, applied
|
|
189
|
+
under the same condition as the style that has to win:
|
|
190
|
+
|
|
191
|
+
```diff
|
|
192
|
+
- <div classStyle={[styles.raised, flat && styles.surface]} />
|
|
193
|
+
+ <div className={[styles.raised, flat && styles.surface, flat && styles.surfaceOverRaised].filter(Boolean).join(' ')} />
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Order is only forced where the two classes actually disagree, measured per
|
|
197
|
+
at-rule and per selector. Anything left unsettled is reported as
|
|
198
|
+
`composition-order`.
|
|
199
|
+
|
|
174
200
|
### Global styles
|
|
175
201
|
|
|
176
202
|
`css.createTheme`, `css.keyframes`, and `css.viewTransition` produce rules that
|
|
@@ -195,12 +221,25 @@ src/Card.tsx
|
|
|
195
221
|
```
|
|
196
222
|
|
|
197
223
|
Constructs that cannot be resolved statically — dynamic values, computed keys,
|
|
198
|
-
runtime function calls, object spreads
|
|
199
|
-
|
|
200
|
-
exists is reported as `target-exists` and will not be
|
|
224
|
+
runtime function calls, and object spreads — are reported and left in place,
|
|
225
|
+
together with every file whose definitions they still need. A target
|
|
226
|
+
`*.module.css` that already exists is reported as `target-exists` and will not be
|
|
227
|
+
overwritten.
|
|
228
|
+
|
|
229
|
+
Several `css.create` calls in one file are not reported: they are written to the
|
|
230
|
+
same stylesheet, and a key an earlier call claimed is renamed.
|
|
201
231
|
|
|
202
232
|
The exit code is 1 while anything remains, so the command composes with a script.
|
|
203
233
|
|
|
234
|
+
The migration is idempotent — the first run converts, every run after it is a
|
|
235
|
+
fixed point:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
f(f(x)) = f(x)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Clear a report and run again, and only the newly resolvable files move.
|
|
242
|
+
|
|
204
243
|
Start with `-d, --dry-run` to preview the export without writing files:
|
|
205
244
|
|
|
206
245
|
```sh
|
package/dist/cli.js
CHANGED
|
@@ -331,7 +331,7 @@ async function migrateFromCssModules(options) {
|
|
|
331
331
|
console.log(line);
|
|
332
332
|
return 1;
|
|
333
333
|
}
|
|
334
|
-
function releaseConfig(modules, themes, animations, statics) {
|
|
334
|
+
function releaseConfig(modules, themes, animations, statics, values, complete) {
|
|
335
335
|
return [
|
|
336
336
|
{ ignores: IGNORES },
|
|
337
337
|
{
|
|
@@ -347,7 +347,7 @@ function releaseConfig(modules, themes, animations, statics) {
|
|
|
347
347
|
rules: {
|
|
348
348
|
'codemod/release-styles': [
|
|
349
349
|
'error',
|
|
350
|
-
{ modules, themes, animations, statics },
|
|
350
|
+
{ modules, themes, animations, statics, values, complete },
|
|
351
351
|
],
|
|
352
352
|
},
|
|
353
353
|
},
|
|
@@ -365,6 +365,8 @@ async function migrateFromPlumeria(options) {
|
|
|
365
365
|
return 0;
|
|
366
366
|
}
|
|
367
367
|
for (const sheet of planned.stylesheets) {
|
|
368
|
+
if (sheet.reports.length > 0)
|
|
369
|
+
continue;
|
|
368
370
|
console.log(` ${relative(sheet.source)} -> ${relative(sheet.target)}`);
|
|
369
371
|
}
|
|
370
372
|
if (planned.global) {
|
|
@@ -372,7 +374,7 @@ async function migrateFromPlumeria(options) {
|
|
|
372
374
|
}
|
|
373
375
|
const config = {
|
|
374
376
|
overrideConfigFile: true,
|
|
375
|
-
overrideConfig: releaseConfig(planned.modules, planned.themes, planned.animations, planned.statics),
|
|
377
|
+
overrideConfig: releaseConfig(planned.modules, planned.themes, planned.animations, planned.statics, planned.values, planned.complete),
|
|
376
378
|
errorOnUnmatchedPattern: false,
|
|
377
379
|
};
|
|
378
380
|
const preview = await new eslint_1.ESLint(config).lintFiles(targets);
|
package/dist/migrate.js
CHANGED
|
@@ -83,10 +83,12 @@ function plan(targets) {
|
|
|
83
83
|
const converted = (0, css_modules_1.convertStylesheet)(fs.readFileSync(source, 'utf-8'));
|
|
84
84
|
const target = (0, exports.targetPath)(source);
|
|
85
85
|
stylesheets.push({ source, target, reports: converted.reports });
|
|
86
|
-
modules[
|
|
86
|
+
modules[source] = {
|
|
87
87
|
source: `./${path.basename(target, '.ts')}`,
|
|
88
|
+
target,
|
|
88
89
|
names: converted.names,
|
|
89
90
|
composes: converted.composes,
|
|
91
|
+
functions: converted.functions,
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
return { stylesheets, modules };
|
package/dist/release.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface ReleasePlan {
|
|
|
12
12
|
themes: Record<string, string[]>;
|
|
13
13
|
animations: Record<string, string[]>;
|
|
14
14
|
statics: Record<string, string[]>;
|
|
15
|
+
values: Record<string, Record<string, unknown>>;
|
|
16
|
+
complete: boolean;
|
|
15
17
|
global?: {
|
|
16
18
|
target: string;
|
|
17
19
|
css: string;
|
package/dist/release.js
CHANGED
|
@@ -42,6 +42,8 @@ const path = __importStar(require("node:path"));
|
|
|
42
42
|
const parser_1 = require("@typescript-eslint/parser");
|
|
43
43
|
const resolve_1 = require("./resolve");
|
|
44
44
|
const from_plumeria_1 = require("./transforms/from-plumeria");
|
|
45
|
+
const GLOBAL_OPEN = '/* Generated from css.createTheme, css.keyframes, and css.viewTransition by @plumeria/codemod */';
|
|
46
|
+
const GLOBAL_CLOSE = '/* End of @plumeria/codemod generated styles */';
|
|
45
47
|
const EXTENSION = /\.(?:[cm]?[jt]sx?)$/;
|
|
46
48
|
const IGNORED = new Set([
|
|
47
49
|
'node_modules',
|
|
@@ -75,6 +77,44 @@ const findSources = (targets) => {
|
|
|
75
77
|
}
|
|
76
78
|
return found.sort();
|
|
77
79
|
};
|
|
80
|
+
const STYLE_PROP = 'classStyle';
|
|
81
|
+
const memberOf = (node) => {
|
|
82
|
+
if (node?.type !== 'MemberExpression' || node.object.type !== 'Identifier')
|
|
83
|
+
return undefined;
|
|
84
|
+
const key = node.computed
|
|
85
|
+
? node.property.type === 'Literal'
|
|
86
|
+
? String(node.property.value)
|
|
87
|
+
: undefined
|
|
88
|
+
: node.property.name;
|
|
89
|
+
return key === undefined ? undefined : { object: node.object.name, key };
|
|
90
|
+
};
|
|
91
|
+
const slotOf = (node) => {
|
|
92
|
+
const member = memberOf(node);
|
|
93
|
+
if (member)
|
|
94
|
+
return [member];
|
|
95
|
+
if (node?.type === 'LogicalExpression')
|
|
96
|
+
return slotOf(node.right);
|
|
97
|
+
if (node?.type === 'ConditionalExpression')
|
|
98
|
+
return [...slotOf(node.consequent), ...slotOf(node.alternate)];
|
|
99
|
+
return [];
|
|
100
|
+
};
|
|
101
|
+
const walk = (node, visit) => {
|
|
102
|
+
if (!node || typeof node !== 'object')
|
|
103
|
+
return;
|
|
104
|
+
if (Array.isArray(node)) {
|
|
105
|
+
for (const child of node)
|
|
106
|
+
walk(child, visit);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (typeof node.type !== 'string')
|
|
110
|
+
return;
|
|
111
|
+
visit(node);
|
|
112
|
+
for (const key of Object.keys(node)) {
|
|
113
|
+
if (key === 'parent' || key === 'loc' || key === 'range')
|
|
114
|
+
continue;
|
|
115
|
+
walk(node[key], visit);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
78
118
|
const releasedPath = (source) => source.replace(/(?:\.styles)?\.[^.]+$/, '.module.css');
|
|
79
119
|
exports.releasedPath = releasedPath;
|
|
80
120
|
const globalPath = (targets) => {
|
|
@@ -95,12 +135,34 @@ function planRelease(targets) {
|
|
|
95
135
|
const themes = {};
|
|
96
136
|
const animations = {};
|
|
97
137
|
const statics = {};
|
|
98
|
-
const globalRules = [];
|
|
99
138
|
const sources = findSources(targets);
|
|
100
139
|
const sourceText = new Map(sources.map((source) => [source, fs.readFileSync(source, 'utf8')]));
|
|
101
140
|
const themeValues = new Map();
|
|
102
141
|
const animationValues = new Map();
|
|
103
142
|
const staticValues = new Map();
|
|
143
|
+
const reportsBySource = new Map();
|
|
144
|
+
const globalBySource = new Map();
|
|
145
|
+
const themeKeys = new Map();
|
|
146
|
+
const animationKeys = new Map();
|
|
147
|
+
const staticKeys = new Map();
|
|
148
|
+
const dependencies = new Map();
|
|
149
|
+
const note = (source, reports) => {
|
|
150
|
+
if (reports.length === 0)
|
|
151
|
+
return;
|
|
152
|
+
reportsBySource.set(source, [
|
|
153
|
+
...(reportsBySource.get(source) ?? []),
|
|
154
|
+
...reports,
|
|
155
|
+
]);
|
|
156
|
+
};
|
|
157
|
+
const addGlobal = (source, css) => {
|
|
158
|
+
const trimmed = css.trim();
|
|
159
|
+
if (trimmed.length === 0)
|
|
160
|
+
return;
|
|
161
|
+
globalBySource.set(source, [
|
|
162
|
+
...(globalBySource.get(source) ?? []),
|
|
163
|
+
trimmed,
|
|
164
|
+
]);
|
|
165
|
+
};
|
|
104
166
|
for (const source of sources) {
|
|
105
167
|
try {
|
|
106
168
|
const extracted = (0, from_plumeria_1.extractPlumeriaStatics)(sourceText.get(source));
|
|
@@ -116,8 +178,6 @@ function planRelease(targets) {
|
|
|
116
178
|
if (Object.keys(extracted.bindings).length === 0)
|
|
117
179
|
continue;
|
|
118
180
|
themeValues.set(source, extracted.bindings);
|
|
119
|
-
themes[source] = Object.keys(extracted.bindings);
|
|
120
|
-
globalRules.push(extracted.globalCss.trim());
|
|
121
181
|
}
|
|
122
182
|
catch {
|
|
123
183
|
}
|
|
@@ -152,11 +212,14 @@ function planRelease(targets) {
|
|
|
152
212
|
for (const specifier of node.specifiers) {
|
|
153
213
|
if (specifier.type === 'ImportSpecifier') {
|
|
154
214
|
const imported = specifier.imported.name ?? specifier.imported.value;
|
|
155
|
-
if (available[imported])
|
|
215
|
+
if (available[imported]) {
|
|
156
216
|
result[specifier.local.name] = available[imported];
|
|
217
|
+
dependencies.set(source, (dependencies.get(source) ?? new Set()).add(target));
|
|
218
|
+
}
|
|
157
219
|
}
|
|
158
220
|
else if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
159
221
|
result[specifier.local.name] = available;
|
|
222
|
+
dependencies.set(source, (dependencies.get(source) ?? new Set()).add(target));
|
|
160
223
|
}
|
|
161
224
|
}
|
|
162
225
|
}
|
|
@@ -178,13 +241,26 @@ function planRelease(targets) {
|
|
|
178
241
|
}
|
|
179
242
|
return merged;
|
|
180
243
|
};
|
|
244
|
+
for (const source of sources) {
|
|
245
|
+
try {
|
|
246
|
+
const extracted = (0, from_plumeria_1.extractPlumeriaThemes)(sourceText.get(source));
|
|
247
|
+
note(source, extracted.reports);
|
|
248
|
+
if (Object.keys(extracted.bindings).length === 0)
|
|
249
|
+
continue;
|
|
250
|
+
themeKeys.set(source, Object.keys(extracted.bindings));
|
|
251
|
+
addGlobal(source, extracted.globalCss);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
}
|
|
255
|
+
}
|
|
181
256
|
for (const source of sources) {
|
|
182
257
|
try {
|
|
183
258
|
const extracted = (0, from_plumeria_1.extractPlumeriaStatics)(sourceText.get(source), importedPlumeriaValues(source));
|
|
259
|
+
note(source, extracted.reports);
|
|
184
260
|
if (Object.keys(extracted.bindings).length === 0)
|
|
185
261
|
continue;
|
|
186
262
|
staticValues.set(source, extracted.bindings);
|
|
187
|
-
|
|
263
|
+
staticKeys.set(source, Object.keys(extracted.bindings));
|
|
188
264
|
}
|
|
189
265
|
catch {
|
|
190
266
|
}
|
|
@@ -195,59 +271,231 @@ function planRelease(targets) {
|
|
|
195
271
|
...importedPlumeriaValues(source),
|
|
196
272
|
...(themeValues.get(source) ?? {}),
|
|
197
273
|
});
|
|
274
|
+
note(source, extracted.reports);
|
|
198
275
|
if (Object.keys(extracted.bindings).length === 0)
|
|
199
276
|
continue;
|
|
200
277
|
animationValues.set(source, extracted.bindings);
|
|
201
|
-
|
|
278
|
+
animationKeys.set(source, [
|
|
202
279
|
...extracted.keyframes,
|
|
203
280
|
...extracted.viewTransitions,
|
|
204
|
-
];
|
|
205
|
-
|
|
281
|
+
]);
|
|
282
|
+
addGlobal(source, extracted.globalCss);
|
|
206
283
|
}
|
|
207
284
|
catch {
|
|
208
285
|
}
|
|
209
286
|
}
|
|
287
|
+
const createBindings = new Map();
|
|
210
288
|
for (const source of sources) {
|
|
211
|
-
let converted;
|
|
212
289
|
try {
|
|
213
|
-
|
|
290
|
+
const ast = (0, parser_1.parse)(sourceText.get(source), {
|
|
291
|
+
sourceType: 'module',
|
|
292
|
+
ecmaFeatures: { jsx: true },
|
|
293
|
+
});
|
|
294
|
+
const declared = new Set();
|
|
295
|
+
for (const raw of ast.body) {
|
|
296
|
+
const statement = raw.type === 'ExportNamedDeclaration' ? raw.declaration : raw;
|
|
297
|
+
if (statement?.type !== 'VariableDeclaration')
|
|
298
|
+
continue;
|
|
299
|
+
for (const declaration of statement.declarations) {
|
|
300
|
+
if (declaration.id.type === 'Identifier' &&
|
|
301
|
+
declaration.init?.type === 'CallExpression' &&
|
|
302
|
+
declaration.init.callee.type === 'MemberExpression' &&
|
|
303
|
+
declaration.init.callee.property?.name === 'create')
|
|
304
|
+
declared.add(declaration.id.name);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (declared.size > 0)
|
|
308
|
+
createBindings.set(source, declared);
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const compositions = new Map();
|
|
314
|
+
for (const source of sources) {
|
|
315
|
+
let ast;
|
|
316
|
+
try {
|
|
317
|
+
ast = (0, parser_1.parse)(sourceText.get(source), {
|
|
318
|
+
sourceType: 'module',
|
|
319
|
+
ecmaFeatures: { jsx: true },
|
|
320
|
+
loc: true,
|
|
321
|
+
range: true,
|
|
322
|
+
});
|
|
214
323
|
}
|
|
215
324
|
catch {
|
|
216
325
|
continue;
|
|
217
326
|
}
|
|
218
|
-
|
|
327
|
+
const owners = new Map();
|
|
328
|
+
for (const binding of createBindings.get(source) ?? [])
|
|
329
|
+
owners.set(binding, { source, binding });
|
|
330
|
+
for (const node of ast.body) {
|
|
331
|
+
if (node.type !== 'ImportDeclaration')
|
|
332
|
+
continue;
|
|
333
|
+
const target = (0, resolve_1.resolveSourcePath)(String(node.source.value), source);
|
|
334
|
+
const declared = target ? createBindings.get(target) : undefined;
|
|
335
|
+
if (!target || !declared)
|
|
336
|
+
continue;
|
|
337
|
+
for (const specifier of node.specifiers) {
|
|
338
|
+
if (specifier.type !== 'ImportSpecifier')
|
|
339
|
+
continue;
|
|
340
|
+
const imported = specifier.imported.name ?? specifier.imported.value;
|
|
341
|
+
if (declared.has(imported))
|
|
342
|
+
owners.set(specifier.local.name, {
|
|
343
|
+
source: target,
|
|
344
|
+
binding: imported,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
walk(ast.body, (node) => {
|
|
349
|
+
if (node.type !== 'MemberExpression' ||
|
|
350
|
+
!node.computed ||
|
|
351
|
+
node.property.type === 'Literal' ||
|
|
352
|
+
node.object.type !== 'Identifier')
|
|
353
|
+
return;
|
|
354
|
+
const owner = owners.get(node.object.name);
|
|
355
|
+
if (!owner)
|
|
356
|
+
return;
|
|
357
|
+
note(owner.source, [
|
|
358
|
+
{
|
|
359
|
+
line: node.loc.start.line,
|
|
360
|
+
column: node.loc.start.column + 1,
|
|
361
|
+
kind: 'dynamic-style-access',
|
|
362
|
+
hint: `\`${node.object.name}\` is read with a computed key, which has no class name until it runs.`,
|
|
363
|
+
},
|
|
364
|
+
]);
|
|
365
|
+
});
|
|
366
|
+
walk(ast.body, (node) => {
|
|
367
|
+
if (node.type !== 'JSXAttribute' ||
|
|
368
|
+
node.name?.name !== STYLE_PROP ||
|
|
369
|
+
node.value?.type !== 'JSXExpressionContainer')
|
|
370
|
+
return;
|
|
371
|
+
const expression = node.value.expression;
|
|
372
|
+
if (expression?.type !== 'ArrayExpression' ||
|
|
373
|
+
expression.elements.length < 2)
|
|
374
|
+
return;
|
|
375
|
+
const slots = expression.elements.map(slotOf);
|
|
376
|
+
if (slots.some((slot) => slot.length === 0))
|
|
377
|
+
return;
|
|
378
|
+
const owners_ = slots.flat().map((part) => owners.get(part.object));
|
|
379
|
+
if (owners_.some((candidate) => !candidate))
|
|
380
|
+
return;
|
|
381
|
+
const owner = owners_[0].source;
|
|
382
|
+
if (owners_.some((candidate) => candidate.source !== owner))
|
|
383
|
+
return;
|
|
384
|
+
const named = slots.map((slot) => slot.map((part) => ({
|
|
385
|
+
binding: owners.get(part.object).binding,
|
|
386
|
+
key: part.key,
|
|
387
|
+
})));
|
|
388
|
+
const collapsible = expression.elements.every((element) => memberOf(element)) &&
|
|
389
|
+
named.every((slot) => slot.length === 1);
|
|
390
|
+
compositions.set(owner, [
|
|
391
|
+
...(compositions.get(owner) ?? []),
|
|
392
|
+
{
|
|
393
|
+
parts: collapsible ? named.map((slot) => slot[0]) : [],
|
|
394
|
+
slots: named,
|
|
395
|
+
file: source,
|
|
396
|
+
line: node.loc.start.line,
|
|
397
|
+
column: node.loc.start.column + 1,
|
|
398
|
+
},
|
|
399
|
+
]);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
const converted = new Map();
|
|
403
|
+
for (const source of sources) {
|
|
404
|
+
let module;
|
|
405
|
+
try {
|
|
406
|
+
module = (0, from_plumeria_1.convertPlumeriaModule)(sourceText.get(source), importedPlumeriaValues(source), compositions.get(source) ?? []);
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (!module)
|
|
219
412
|
continue;
|
|
220
413
|
const target = (0, exports.releasedPath)(source);
|
|
221
|
-
|
|
222
|
-
|
|
414
|
+
converted.set(source, module);
|
|
415
|
+
note(source, module.reports);
|
|
223
416
|
if (fs.existsSync(target)) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
417
|
+
note(source, [
|
|
418
|
+
{
|
|
419
|
+
line: 0,
|
|
420
|
+
column: 0,
|
|
421
|
+
kind: 'target-exists',
|
|
422
|
+
hint: `${path.basename(target)} already exists and was not overwritten.`,
|
|
423
|
+
},
|
|
424
|
+
]);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const blocked = new Set(reportsBySource.keys());
|
|
428
|
+
for (let changed = true; changed;) {
|
|
429
|
+
changed = false;
|
|
430
|
+
for (const source of blocked) {
|
|
431
|
+
for (const dependency of dependencies.get(source) ?? []) {
|
|
432
|
+
if (blocked.has(dependency))
|
|
433
|
+
continue;
|
|
434
|
+
blocked.add(dependency);
|
|
435
|
+
note(dependency, [
|
|
436
|
+
{
|
|
437
|
+
line: 0,
|
|
438
|
+
column: 0,
|
|
439
|
+
kind: 'blocked-dependency',
|
|
440
|
+
hint: `${path.relative(path.dirname(dependency), source)} still needs these definitions.`,
|
|
441
|
+
},
|
|
442
|
+
]);
|
|
443
|
+
changed = true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const globalRules = [];
|
|
448
|
+
const values = {};
|
|
449
|
+
for (const source of sources) {
|
|
450
|
+
const reports = reportsBySource.get(source) ?? [];
|
|
451
|
+
const module = converted.get(source);
|
|
452
|
+
if (module) {
|
|
453
|
+
stylesheets.push({
|
|
454
|
+
source,
|
|
455
|
+
target: (0, exports.releasedPath)(source),
|
|
456
|
+
css: module.css,
|
|
457
|
+
reports,
|
|
229
458
|
});
|
|
230
459
|
}
|
|
231
|
-
|
|
232
|
-
source,
|
|
233
|
-
target,
|
|
234
|
-
css: converted.css,
|
|
235
|
-
reports,
|
|
236
|
-
});
|
|
237
|
-
if (reports.length === 0) {
|
|
238
|
-
modules[source] = {
|
|
239
|
-
source: specifier,
|
|
240
|
-
target,
|
|
241
|
-
binding: converted.binding,
|
|
242
|
-
...(converted.definitionOnly ? { definitionOnly: true } : {}),
|
|
243
|
-
...(Object.keys(converted.aliases).length > 0
|
|
244
|
-
? { aliases: converted.aliases }
|
|
245
|
-
: {}),
|
|
246
|
-
...(Object.keys(converted.functions).length > 0
|
|
247
|
-
? { functions: converted.functions }
|
|
248
|
-
: {}),
|
|
249
|
-
};
|
|
460
|
+
else if (reports.length > 0) {
|
|
461
|
+
stylesheets.push({ source, target: '', css: '', reports });
|
|
250
462
|
}
|
|
463
|
+
if (blocked.has(source))
|
|
464
|
+
continue;
|
|
465
|
+
const resolved = {
|
|
466
|
+
...(staticValues.get(source) ?? {}),
|
|
467
|
+
...(themeValues.get(source) ?? {}),
|
|
468
|
+
...(animationValues.get(source) ?? {}),
|
|
469
|
+
};
|
|
470
|
+
if (Object.keys(resolved).length > 0)
|
|
471
|
+
values[source] = resolved;
|
|
472
|
+
globalRules.push(...(globalBySource.get(source) ?? []));
|
|
473
|
+
if (themeKeys.has(source))
|
|
474
|
+
themes[source] = themeKeys.get(source);
|
|
475
|
+
if (animationKeys.has(source))
|
|
476
|
+
animations[source] = animationKeys.get(source);
|
|
477
|
+
if (staticKeys.has(source))
|
|
478
|
+
statics[source] = staticKeys.get(source);
|
|
479
|
+
if (!module)
|
|
480
|
+
continue;
|
|
481
|
+
modules[source] = {
|
|
482
|
+
source: `./${path.basename((0, exports.releasedPath)(source))}`,
|
|
483
|
+
target: (0, exports.releasedPath)(source),
|
|
484
|
+
binding: module.binding,
|
|
485
|
+
...(module.definitionOnly ? { definitionOnly: true } : {}),
|
|
486
|
+
...(Object.keys(module.aliases).length > 0
|
|
487
|
+
? { aliases: module.aliases }
|
|
488
|
+
: {}),
|
|
489
|
+
...(Object.keys(module.functions).length > 0
|
|
490
|
+
? { functions: module.functions }
|
|
491
|
+
: {}),
|
|
492
|
+
...(Object.keys(module.merges).length > 0
|
|
493
|
+
? { merges: module.merges }
|
|
494
|
+
: {}),
|
|
495
|
+
...(Object.keys(module.overrides).length > 0
|
|
496
|
+
? { overrides: module.overrides }
|
|
497
|
+
: {}),
|
|
498
|
+
};
|
|
251
499
|
}
|
|
252
500
|
return {
|
|
253
501
|
stylesheets,
|
|
@@ -255,10 +503,12 @@ function planRelease(targets) {
|
|
|
255
503
|
themes,
|
|
256
504
|
animations,
|
|
257
505
|
statics,
|
|
506
|
+
values,
|
|
507
|
+
complete: stylesheets.every((sheet) => sheet.reports.length === 0),
|
|
258
508
|
global: globalRules.length > 0
|
|
259
509
|
? {
|
|
260
510
|
target: globalPath(targets),
|
|
261
|
-
css:
|
|
511
|
+
css: `${GLOBAL_OPEN}\n${globalRules.join('\n\n')}\n${GLOBAL_CLOSE}\n`,
|
|
262
512
|
}
|
|
263
513
|
: undefined,
|
|
264
514
|
};
|
|
@@ -274,6 +524,13 @@ function writeRelease(plan) {
|
|
|
274
524
|
const previous = fs.existsSync(plan.global.target)
|
|
275
525
|
? fs.readFileSync(plan.global.target, 'utf8')
|
|
276
526
|
: '';
|
|
527
|
+
const opening = previous.indexOf(GLOBAL_OPEN);
|
|
528
|
+
const closing = previous.lastIndexOf(GLOBAL_CLOSE);
|
|
529
|
+
if (opening !== -1 && closing > opening) {
|
|
530
|
+
const kept = `${previous.slice(0, opening)}${previous.slice(closing + GLOBAL_CLOSE.length)}`;
|
|
531
|
+
fs.writeFileSync(plan.global.target, `${kept.replace(/\n+$/, '\n')}${plan.global.css}`, 'utf8');
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
277
534
|
const separator = previous.length > 0 && !previous.endsWith('\n') ? '\n\n' : '';
|
|
278
535
|
fs.writeFileSync(plan.global.target, `${previous}${separator}${plan.global.css}`, 'utf8');
|
|
279
536
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
export interface ModuleMap {
|
|
3
3
|
source: string;
|
|
4
|
+
target?: string;
|
|
4
5
|
names: Record<string, string>;
|
|
5
6
|
composes?: Record<string, string[]>;
|
|
7
|
+
functions?: Record<string, string[]>;
|
|
6
8
|
}
|
|
7
9
|
export interface AdoptStylesOptions {
|
|
8
10
|
modules: Record<string, ModuleMap>;
|