@plumeria/compiler 0.25.0 → 0.25.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/dist/extract.js +272 -171
- package/package.json +1 -1
package/dist/extract.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.generatedTsMap = void 0;
|
|
|
7
7
|
exports.extractTSFile = extractTSFile;
|
|
8
8
|
exports.restoreAllOriginals = restoreAllOriginals;
|
|
9
9
|
exports.extractVueAndSvelte = extractVueAndSvelte;
|
|
10
|
+
const core_1 = require("@swc/core");
|
|
10
11
|
const fs_1 = __importDefault(require("fs"));
|
|
11
12
|
const path_1 = __importDefault(require("path"));
|
|
12
13
|
const generatedTsMap = new Map();
|
|
@@ -115,171 +116,267 @@ function isInHtmlText(code, position) {
|
|
|
115
116
|
}
|
|
116
117
|
return lastCloseTag > lastOpenTag && nextOpenTag > position;
|
|
117
118
|
}
|
|
118
|
-
function
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
const startIndex = match.index + match[0].length;
|
|
129
|
-
let parenCount = 1;
|
|
130
|
-
let currentIndex = startIndex;
|
|
131
|
-
let args = '';
|
|
132
|
-
while (parenCount > 0 && currentIndex < code.length) {
|
|
133
|
-
const char = code[currentIndex];
|
|
134
|
-
if (char === '(') {
|
|
135
|
-
parenCount++;
|
|
136
|
-
}
|
|
137
|
-
else if (char === ')') {
|
|
138
|
-
parenCount--;
|
|
119
|
+
function expressionToString(expr) {
|
|
120
|
+
switch (expr.type) {
|
|
121
|
+
case 'Identifier':
|
|
122
|
+
return expr.value;
|
|
123
|
+
case 'MemberExpression': {
|
|
124
|
+
const obj = expressionToString(expr.object);
|
|
125
|
+
if (obj && expr.property.type === 'Identifier') {
|
|
126
|
+
return `${obj}.${expr.property.value}`;
|
|
139
127
|
}
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'CallExpression': {
|
|
131
|
+
if (expr.callee.type !== 'Super' && expr.callee.type !== 'Import') {
|
|
132
|
+
const callee = expressionToString(expr.callee);
|
|
133
|
+
if (callee) {
|
|
134
|
+
const args = expr.arguments
|
|
135
|
+
.map((arg) => expressionToString(arg.expression))
|
|
136
|
+
.join(', ');
|
|
137
|
+
return `${callee}(${args})`;
|
|
138
|
+
}
|
|
142
139
|
}
|
|
143
|
-
|
|
140
|
+
break;
|
|
144
141
|
}
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
142
|
+
case 'ObjectExpression': {
|
|
143
|
+
const properties = expr.properties
|
|
144
|
+
.map((prop) => {
|
|
145
|
+
if ('key' in prop && prop.key && prop.key.type === 'Identifier') {
|
|
146
|
+
const key = prop.key.value;
|
|
147
|
+
const value = expressionToString(prop.value);
|
|
148
|
+
return `${key}: ${value}`;
|
|
149
|
+
}
|
|
150
|
+
return '[complex property]';
|
|
151
|
+
})
|
|
152
|
+
.join(', ');
|
|
153
|
+
console.warn(`css.props: Argument unsupported ${expr.type}: { ${properties} } Use css.create instead.`);
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
case 'StringLiteral':
|
|
157
|
+
return String(expr.value);
|
|
158
|
+
}
|
|
159
|
+
console.warn(`css.props: Argument unsupported ${expr.type}: Use css.create instead.`);
|
|
160
|
+
return '';
|
|
161
|
+
}
|
|
162
|
+
function extractCssProps(ast) {
|
|
163
|
+
const propsMatches = [];
|
|
164
|
+
try {
|
|
165
|
+
visit(ast, {
|
|
166
|
+
CallExpression: (node) => {
|
|
167
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
168
|
+
node.callee.object.type === 'Identifier' &&
|
|
169
|
+
node.callee.object.value === 'css' &&
|
|
170
|
+
node.callee.property.type === 'Identifier' &&
|
|
171
|
+
node.callee.property.value === 'props') {
|
|
172
|
+
const staticArgs = [];
|
|
173
|
+
const conditionalStyleObjects = [];
|
|
174
|
+
for (const arg of node.arguments) {
|
|
175
|
+
if (arg.expression) {
|
|
176
|
+
if (arg.expression.type === 'ConditionalExpression' ||
|
|
177
|
+
(arg.expression.type === 'BinaryExpression' &&
|
|
178
|
+
arg.expression.operator === '&&')) {
|
|
179
|
+
const styles = extractStyleObjectsFromExpression(arg.expression);
|
|
180
|
+
conditionalStyleObjects.push(...styles);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const argStr = expressionToString(arg.expression);
|
|
184
|
+
if (argStr) {
|
|
185
|
+
staticArgs.push(argStr);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (staticArgs.length > 0) {
|
|
191
|
+
propsMatches.push(`css.props(${staticArgs.join(', ')})`);
|
|
155
192
|
}
|
|
156
|
-
|
|
157
|
-
|
|
193
|
+
for (const styleObj of conditionalStyleObjects) {
|
|
194
|
+
if (styleObj &&
|
|
195
|
+
styleObj !== 'false' &&
|
|
196
|
+
styleObj !== 'null' &&
|
|
197
|
+
styleObj !== 'undefined') {
|
|
198
|
+
propsMatches.push(`css.props(${styleObj})`);
|
|
199
|
+
}
|
|
158
200
|
}
|
|
159
201
|
}
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
console.error(`Failed to parse code to extract css.props: ${e}`);
|
|
207
|
+
}
|
|
208
|
+
return propsMatches;
|
|
209
|
+
}
|
|
210
|
+
function extractStyleObjectsFromExpression(expression) {
|
|
211
|
+
switch (expression.type) {
|
|
212
|
+
case 'BinaryExpression':
|
|
213
|
+
if (expression.operator === '&&') {
|
|
214
|
+
return extractStyleObjectsFromExpression(expression.right);
|
|
160
215
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
216
|
+
break;
|
|
217
|
+
case 'ConditionalExpression':
|
|
218
|
+
return [
|
|
219
|
+
...extractStyleObjectsFromExpression(expression.consequent),
|
|
220
|
+
...extractStyleObjectsFromExpression(expression.alternate),
|
|
221
|
+
];
|
|
222
|
+
case 'BooleanLiteral':
|
|
223
|
+
case 'NullLiteral':
|
|
224
|
+
return [];
|
|
225
|
+
case 'Identifier':
|
|
226
|
+
if (expression.value === 'undefined') {
|
|
227
|
+
return [];
|
|
171
228
|
}
|
|
229
|
+
case 'ObjectExpression': {
|
|
230
|
+
const str = expressionToString(expression);
|
|
231
|
+
return str ? [str] : [];
|
|
172
232
|
}
|
|
173
233
|
}
|
|
174
|
-
|
|
234
|
+
const str = expressionToString(expression);
|
|
235
|
+
if (str) {
|
|
236
|
+
return [str];
|
|
237
|
+
}
|
|
238
|
+
return [];
|
|
175
239
|
}
|
|
176
|
-
function extractStaticStringLiteralVariable(
|
|
240
|
+
function extractStaticStringLiteralVariable(ast) {
|
|
177
241
|
const matches = [];
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
242
|
+
try {
|
|
243
|
+
visit(ast, {
|
|
244
|
+
VariableDeclaration: (node) => {
|
|
245
|
+
const allStringLiterals = node.declarations.length > 0 &&
|
|
246
|
+
node.declarations.every((decl) => decl.init && decl.init.type === 'StringLiteral');
|
|
247
|
+
if (allStringLiterals) {
|
|
248
|
+
const { code: extractedCode } = (0, core_1.printSync)({
|
|
249
|
+
type: 'Module',
|
|
250
|
+
body: [node],
|
|
251
|
+
span: { start: 0, end: 0, ctxt: 0 },
|
|
252
|
+
});
|
|
253
|
+
matches.push(extractedCode.trim());
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
console.error(`Failed to parse code to extract static string literal variables: ${e}`);
|
|
188
260
|
}
|
|
189
261
|
return matches.join('\n');
|
|
190
262
|
}
|
|
191
|
-
function
|
|
192
|
-
const
|
|
193
|
-
const regex = /
|
|
263
|
+
function extractCssPropsFromTemplate(code) {
|
|
264
|
+
const matches = [];
|
|
265
|
+
const regex = /css\.props\(([^)]*)\)/g;
|
|
194
266
|
let match;
|
|
195
|
-
while ((match = regex.exec(code))) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
267
|
+
while ((match = regex.exec(code)) !== null) {
|
|
268
|
+
const matchStart = match.index;
|
|
269
|
+
if (isInComment(code, matchStart) ||
|
|
270
|
+
isInString(code, matchStart) ||
|
|
271
|
+
isInHtmlText(code, matchStart)) {
|
|
199
272
|
continue;
|
|
200
273
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.keyframes\([\s\S]*?\);\s*))/g;
|
|
208
|
-
let match;
|
|
209
|
-
while ((match = regex.exec(code))) {
|
|
210
|
-
if (isInComment(code, match.index) ||
|
|
211
|
-
isInString(code, match.index) ||
|
|
212
|
-
isInHtmlText(code, match.index)) {
|
|
274
|
+
const scriptStartIndex = code.indexOf('<script');
|
|
275
|
+
const scriptEndIndex = code.indexOf('</script>');
|
|
276
|
+
if (scriptStartIndex !== -1 &&
|
|
277
|
+
scriptEndIndex !== -1 &&
|
|
278
|
+
match.index > scriptStartIndex &&
|
|
279
|
+
match.index < scriptEndIndex) {
|
|
213
280
|
continue;
|
|
214
281
|
}
|
|
215
|
-
|
|
282
|
+
const args = match[1];
|
|
283
|
+
if (args && !args.includes('{') && !args.includes('(')) {
|
|
284
|
+
matches.push(`css.props(${args})`);
|
|
285
|
+
}
|
|
216
286
|
}
|
|
217
|
-
return
|
|
287
|
+
return matches;
|
|
218
288
|
}
|
|
219
|
-
function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
289
|
+
function visit(node, visitor) {
|
|
290
|
+
if (!node)
|
|
291
|
+
return;
|
|
292
|
+
const visitorFunc = visitor[node.type];
|
|
293
|
+
if (visitorFunc) {
|
|
294
|
+
visitorFunc(node);
|
|
295
|
+
}
|
|
296
|
+
for (const key in node) {
|
|
297
|
+
if (typeof node[key] === 'object' && node[key] !== null) {
|
|
298
|
+
if (Array.isArray(node[key])) {
|
|
299
|
+
for (const child of node[key]) {
|
|
300
|
+
visit(child, visitor);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
visit(node[key], visitor);
|
|
305
|
+
}
|
|
228
306
|
}
|
|
229
|
-
cssCreateMatches.push(match[0]);
|
|
230
307
|
}
|
|
231
|
-
return cssCreateMatches.join('\n');
|
|
232
308
|
}
|
|
233
|
-
function
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
cssCreateMatches.push(match[0]);
|
|
309
|
+
function importDeclarationToString(node) {
|
|
310
|
+
const source = node.source.value;
|
|
311
|
+
const defaultImport = node.specifiers.find((s) => s.type === 'ImportDefaultSpecifier');
|
|
312
|
+
const namespaceImport = node.specifiers.find((s) => s.type === 'ImportNamespaceSpecifier');
|
|
313
|
+
const namedImports = node.specifiers.filter((s) => s.type === 'ImportSpecifier');
|
|
314
|
+
let importClause = '';
|
|
315
|
+
if (defaultImport) {
|
|
316
|
+
importClause += defaultImport.local.value;
|
|
244
317
|
}
|
|
245
|
-
|
|
318
|
+
if (namespaceImport) {
|
|
319
|
+
if (importClause)
|
|
320
|
+
importClause += ', ';
|
|
321
|
+
importClause += `* as ${namespaceImport.local.value}`;
|
|
322
|
+
}
|
|
323
|
+
if (namedImports.length > 0) {
|
|
324
|
+
if (importClause)
|
|
325
|
+
importClause += ', ';
|
|
326
|
+
const namedParts = namedImports.map((spec) => {
|
|
327
|
+
if (spec.imported && spec.imported.value !== spec.local.value) {
|
|
328
|
+
return `${spec.imported.value} as ${spec.local.value}`;
|
|
329
|
+
}
|
|
330
|
+
return spec.local.value;
|
|
331
|
+
});
|
|
332
|
+
importClause += `{ ${namedParts.join(', ')} }`;
|
|
333
|
+
}
|
|
334
|
+
if (importClause) {
|
|
335
|
+
return `import ${importClause} from '${source}';`;
|
|
336
|
+
}
|
|
337
|
+
return `import '${source}';`;
|
|
246
338
|
}
|
|
247
|
-
function
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
339
|
+
function extractImportDeclarations(ast) {
|
|
340
|
+
const importDeclarations = [];
|
|
341
|
+
try {
|
|
342
|
+
visit(ast, {
|
|
343
|
+
ImportDeclaration: (node) => {
|
|
344
|
+
importDeclarations.push(importDeclarationToString(node));
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
console.error(`Failed to parse code to extract import declarations: ${e}`);
|
|
258
350
|
}
|
|
259
|
-
return
|
|
351
|
+
return importDeclarations.join('\n');
|
|
260
352
|
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
353
|
+
function extractCssMethod(ast, methodName) {
|
|
354
|
+
const matches = [];
|
|
355
|
+
try {
|
|
356
|
+
visit(ast, {
|
|
357
|
+
VariableDeclaration: (node) => {
|
|
358
|
+
const containsCssMethod = node.declarations.some((decl) => decl.init &&
|
|
359
|
+
decl.init.type === 'CallExpression' &&
|
|
360
|
+
decl.init.callee.type === 'MemberExpression' &&
|
|
361
|
+
decl.init.callee.object.type === 'Identifier' &&
|
|
362
|
+
decl.init.callee.object.value === 'css' &&
|
|
363
|
+
decl.init.callee.property.type === 'Identifier' &&
|
|
364
|
+
decl.init.callee.property.value === methodName);
|
|
365
|
+
if (containsCssMethod && node.span) {
|
|
366
|
+
const { code: extractedCode } = (0, core_1.printSync)({
|
|
367
|
+
type: 'Module',
|
|
368
|
+
body: [node],
|
|
369
|
+
span: { start: 0, end: 0, ctxt: 0 },
|
|
370
|
+
});
|
|
371
|
+
matches.push(extractedCode.trim());
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
});
|
|
281
375
|
}
|
|
282
|
-
|
|
376
|
+
catch (e) {
|
|
377
|
+
console.error(`Failed to parse code to extract css.${methodName}: ${e}`);
|
|
378
|
+
}
|
|
379
|
+
return matches.join('\n');
|
|
283
380
|
}
|
|
284
381
|
async function extractVueAndSvelte(filePath) {
|
|
285
382
|
const ext = path_1.default.extname(filePath);
|
|
@@ -304,45 +401,47 @@ async function extractVueAndSvelte(filePath) {
|
|
|
304
401
|
}
|
|
305
402
|
}
|
|
306
403
|
const tsCode = contentLines.join('\n');
|
|
307
|
-
|
|
404
|
+
if (!tsCode.trim()) {
|
|
405
|
+
const tsPath = filePath.replace(ext, '.ts');
|
|
406
|
+
fs_1.default.writeFileSync(tsPath, '', 'utf8');
|
|
407
|
+
generatedTsMap.set(filePath, tsPath);
|
|
408
|
+
return tsPath;
|
|
409
|
+
}
|
|
410
|
+
const ast = (0, core_1.parseSync)(tsCode, {
|
|
411
|
+
syntax: 'typescript',
|
|
412
|
+
tsx: true,
|
|
413
|
+
});
|
|
414
|
+
const propsFromScript = extractCssProps(ast);
|
|
415
|
+
const propsFromTemplate = extractCssPropsFromTemplate(code);
|
|
416
|
+
const propsMatches = [...new Set([...propsFromScript, ...propsFromTemplate])];
|
|
308
417
|
const calls = propsMatches
|
|
309
418
|
.filter(Boolean)
|
|
310
419
|
.map((call) => `${call};`)
|
|
311
420
|
.join('\n');
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
const
|
|
315
|
-
const
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
const
|
|
319
|
-
const cssDefineConstsSection = extractCssDefineConsts(tsCode);
|
|
320
|
-
const cssDefineTokensSection = extractCssDefineTokens(tsCode);
|
|
421
|
+
const importSection = extractImportDeclarations(ast);
|
|
422
|
+
const staticVariableSection = extractStaticStringLiteralVariable(ast);
|
|
423
|
+
const cssCreateSection = extractCssMethod(ast, 'create');
|
|
424
|
+
const cssKeyframesSection = extractCssMethod(ast, 'keyframes');
|
|
425
|
+
const cssViewTransitionSection = extractCssMethod(ast, 'viewTransition');
|
|
426
|
+
const cssDefineConstsSection = extractCssMethod(ast, 'defineConsts');
|
|
427
|
+
const cssDefineTokensSection = extractCssMethod(ast, 'defineTokens');
|
|
321
428
|
let finalCode = '';
|
|
322
|
-
if (importSection)
|
|
429
|
+
if (importSection)
|
|
323
430
|
finalCode += importSection + '\n';
|
|
324
|
-
|
|
325
|
-
if (staticVariableSection) {
|
|
431
|
+
if (staticVariableSection)
|
|
326
432
|
finalCode += staticVariableSection + '\n';
|
|
327
|
-
|
|
328
|
-
if (cssKeyframesSection) {
|
|
433
|
+
if (cssKeyframesSection)
|
|
329
434
|
finalCode += cssKeyframesSection + '\n';
|
|
330
|
-
|
|
331
|
-
if (cssViewTransitionSection) {
|
|
435
|
+
if (cssViewTransitionSection)
|
|
332
436
|
finalCode += cssViewTransitionSection + '\n';
|
|
333
|
-
|
|
334
|
-
if (cssDefineConstsSection) {
|
|
437
|
+
if (cssDefineConstsSection)
|
|
335
438
|
finalCode += cssDefineConstsSection + '\n';
|
|
336
|
-
|
|
337
|
-
if (cssDefineTokensSection) {
|
|
439
|
+
if (cssDefineTokensSection)
|
|
338
440
|
finalCode += cssDefineTokensSection + '\n';
|
|
339
|
-
|
|
340
|
-
if (cssCreateSection) {
|
|
441
|
+
if (cssCreateSection)
|
|
341
442
|
finalCode += cssCreateSection + '\n';
|
|
342
|
-
|
|
343
|
-
if (calls) {
|
|
443
|
+
if (calls)
|
|
344
444
|
finalCode += calls + '\n';
|
|
345
|
-
}
|
|
346
445
|
const tsPath = filePath.replace(ext, '.ts');
|
|
347
446
|
fs_1.default.writeFileSync(tsPath, finalCode, 'utf8');
|
|
348
447
|
generatedTsMap.set(filePath, tsPath);
|
|
@@ -350,16 +449,18 @@ async function extractVueAndSvelte(filePath) {
|
|
|
350
449
|
}
|
|
351
450
|
async function extractTSFile(filePath) {
|
|
352
451
|
const code = fs_1.default.readFileSync(filePath, 'utf8');
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const
|
|
452
|
+
const ast = (0, core_1.parseSync)(code, {
|
|
453
|
+
syntax: 'typescript',
|
|
454
|
+
tsx: true,
|
|
455
|
+
});
|
|
456
|
+
const importSection = extractImportDeclarations(ast);
|
|
457
|
+
const staticVariableSection = extractStaticStringLiteralVariable(ast);
|
|
458
|
+
const cssCreateSection = extractCssMethod(ast, 'create');
|
|
459
|
+
const cssKeyframesSection = extractCssMethod(ast, 'keyframes');
|
|
460
|
+
const cssViewTransitionSection = extractCssMethod(ast, 'viewTransition');
|
|
461
|
+
const cssDefineConstsSection = extractCssMethod(ast, 'defineConsts');
|
|
462
|
+
const cssDefineTokensSection = extractCssMethod(ast, 'defineTokens');
|
|
463
|
+
const propsMatches = extractCssProps(ast);
|
|
363
464
|
const calls = propsMatches
|
|
364
465
|
.filter(Boolean)
|
|
365
466
|
.map((call) => `${call};`)
|