@plumeria/compiler 0.25.0 → 0.25.2

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 (3) hide show
  1. package/dist/extract.js +274 -183
  2. package/dist/index.js +173 -152
  3. package/package.json +2 -2
package/dist/extract.js CHANGED
@@ -7,7 +7,8 @@ exports.generatedTsMap = void 0;
7
7
  exports.extractTSFile = extractTSFile;
8
8
  exports.restoreAllOriginals = restoreAllOriginals;
9
9
  exports.extractVueAndSvelte = extractVueAndSvelte;
10
- const fs_1 = __importDefault(require("fs"));
10
+ const core_1 = require("@swc/core");
11
+ const promises_1 = require("fs/promises");
11
12
  const path_1 = __importDefault(require("path"));
12
13
  const generatedTsMap = new Map();
13
14
  exports.generatedTsMap = generatedTsMap;
@@ -115,177 +116,273 @@ function isInHtmlText(code, position) {
115
116
  }
116
117
  return lastCloseTag > lastOpenTag && nextOpenTag > position;
117
118
  }
118
- function extractCssProps(code) {
119
- const propsMatches = [];
120
- const regex = /css\.props\s*\(/g;
121
- let match;
122
- while ((match = regex.exec(code))) {
123
- if (isInComment(code, match.index) ||
124
- isInString(code, match.index) ||
125
- isInHtmlText(code, match.index)) {
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
- if (parenCount > 0 || char !== ')') {
141
- args += char;
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
- currentIndex++;
140
+ break;
141
+ }
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 '';
144
155
  }
145
- if (parenCount === 0) {
146
- const originalArgs = args.split(/\s*,\s*(?![^(]*\))/);
147
- const staticArgs = [];
148
- const conditionalStyleObjects = [];
149
- for (const arg of originalArgs) {
150
- const trimmedArg = arg.trim();
151
- if (trimmedArg) {
152
- if (trimmedArg.includes('&&') || trimmedArg.includes('?')) {
153
- const styles = parseCssPropsArguments(trimmedArg);
154
- conditionalStyleObjects.push(...styles);
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
+ async function extractCssProps(ast) {
163
+ const propsMatches = [];
164
+ try {
165
+ await visit(ast, {
166
+ CallExpression: async (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 = await 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
- else {
157
- staticArgs.push(trimmedArg);
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
- if (staticArgs.length > 0) {
162
- propsMatches.push(`css.props(${staticArgs.join(', ')})`);
163
- }
164
- for (const styleObj of conditionalStyleObjects) {
165
- if (styleObj &&
166
- styleObj !== 'false' &&
167
- styleObj !== 'null' &&
168
- styleObj !== 'undefined') {
169
- propsMatches.push(`css.props(${styleObj})`);
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
- return propsMatches;
234
+ const str = expressionToString(expression);
235
+ if (str) {
236
+ return [str];
237
+ }
238
+ return [];
175
239
  }
176
- function extractStaticStringLiteralVariable(code) {
240
+ async function extractStaticStringLiteralVariable(ast) {
177
241
  const matches = [];
178
- const regex = /\b(?:var|let|const)\s+[a-zA-Z_$][\w$]*\s*=\s*(['"])(.*?)\1\s*;?/gm;
179
- let match;
180
- while ((match = regex.exec(code))) {
181
- const index = match.index;
182
- if (isInComment(code, index) ||
183
- isInString(code, index) ||
184
- isInHtmlText(code, index)) {
185
- continue;
242
+ try {
243
+ for (const node of ast.body) {
244
+ if (node.type === 'VariableDeclaration') {
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 } = await (0, core_1.print)({
249
+ type: 'Module',
250
+ body: [node],
251
+ span: { start: 0, end: 0, ctxt: 0 },
252
+ });
253
+ matches.push(extractedCode.trim());
254
+ }
255
+ }
186
256
  }
187
- matches.push(match[0]);
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 extractCssCreate(code) {
192
- const cssCreateMatches = [];
193
- const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.create\([\s\S]*?\);\s*))/g;
263
+ function extractCssPropsFromTemplate(code) {
264
+ const matches = [];
265
+ const regex = /css\.props\(([^)]*)\)/g;
194
266
  let match;
195
- while ((match = regex.exec(code))) {
196
- if (isInComment(code, match.index) ||
197
- isInString(code, match.index) ||
198
- isInHtmlText(code, match.index)) {
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
- cssCreateMatches.push(match[0]);
202
- }
203
- return cssCreateMatches.join('\n');
204
- }
205
- function extractCssKeyframes(code) {
206
- const cssCreateMatches = [];
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
- cssCreateMatches.push(match[0]);
282
+ const args = match[1];
283
+ if (args && !args.includes('{') && !args.includes('(')) {
284
+ matches.push(`css.props(${args})`);
285
+ }
216
286
  }
217
- return cssCreateMatches.join('\n');
287
+ return matches;
218
288
  }
219
- function extractCssViewTransition(code) {
220
- const cssCreateMatches = [];
221
- const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.viewTransition\([\s\S]*?\);\s*))/g;
222
- let match;
223
- while ((match = regex.exec(code))) {
224
- if (isInComment(code, match.index) ||
225
- isInString(code, match.index) ||
226
- isInHtmlText(code, match.index)) {
227
- continue;
289
+ async function visit(node, visitor) {
290
+ if (!node)
291
+ return;
292
+ const visitorFunc = visitor[node.type];
293
+ if (visitorFunc) {
294
+ await 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
+ await visit(child, visitor);
301
+ }
302
+ }
303
+ else {
304
+ await visit(node[key], visitor);
305
+ }
228
306
  }
229
- cssCreateMatches.push(match[0]);
230
307
  }
231
- return cssCreateMatches.join('\n');
232
308
  }
233
- function extractCssDefineConsts(code) {
234
- const cssCreateMatches = [];
235
- const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.defineConsts\([\s\S]*?\);\s*))/g;
236
- let match;
237
- while ((match = regex.exec(code))) {
238
- if (isInComment(code, match.index) ||
239
- isInString(code, match.index) ||
240
- isInHtmlText(code, match.index)) {
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;
317
+ }
318
+ if (namespaceImport) {
319
+ if (importClause)
320
+ importClause += ', ';
321
+ importClause += `* as ${namespaceImport.local.value}`;
244
322
  }
245
- return cssCreateMatches.join('\n');
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 extractCssDefineTokens(code) {
248
- const cssCreateMatches = [];
249
- const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.defineTokens\([\s\S]*?\);\s*))/g;
250
- let match;
251
- while ((match = regex.exec(code))) {
252
- if (isInComment(code, match.index) ||
253
- isInString(code, match.index) ||
254
- isInHtmlText(code, match.index)) {
255
- continue;
256
- }
257
- cssCreateMatches.push(match[0]);
339
+ async function extractImportDeclarations(ast) {
340
+ const importDeclarations = [];
341
+ try {
342
+ await 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 cssCreateMatches.join('\n');
351
+ return importDeclarations.join('\n');
260
352
  }
261
- function parseCssPropsArguments(args) {
262
- const results = [];
263
- const splitArgs = args.split(/\s*,\s*(?![^(]*\))/);
264
- for (const arg of splitArgs) {
265
- if (arg.includes('&&')) {
266
- const match = arg.match(/&&\s*([^\s,]+)/);
267
- if (match) {
268
- results.push(match[1]);
269
- continue;
270
- }
271
- }
272
- if (arg.includes('?')) {
273
- const match = arg.match(/([^?]+)\?([^:]+):(.+)$/);
274
- if (match) {
275
- results.push(match[2].trim());
276
- results.push(match[3].trim());
277
- continue;
353
+ async function extractCssMethod(ast, methodName) {
354
+ const matches = [];
355
+ try {
356
+ for (const node of ast.body) {
357
+ if (node.type === 'VariableDeclaration') {
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 } = await (0, core_1.print)({
367
+ type: 'Module',
368
+ body: [node],
369
+ span: { start: 0, end: 0, ctxt: 0 },
370
+ });
371
+ matches.push(extractedCode.trim());
372
+ }
278
373
  }
279
374
  }
280
- results.push(arg.trim());
281
375
  }
282
- return results;
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);
286
383
  if (!(ext === '.svelte' || ext === '.vue'))
287
384
  return filePath;
288
- const code = fs_1.default.readFileSync(filePath, 'utf8');
385
+ const code = await (0, promises_1.readFile)(filePath, 'utf8');
289
386
  const lines = code.split(/\r?\n/);
290
387
  let inScript = false;
291
388
  const contentLines = [];
@@ -304,62 +401,63 @@ async function extractVueAndSvelte(filePath) {
304
401
  }
305
402
  }
306
403
  const tsCode = contentLines.join('\n');
307
- const propsMatches = [...extractCssProps(tsCode), ...extractCssProps(code)];
404
+ const tsPath = filePath.replace(ext, '.ts');
405
+ if (!tsCode.trim()) {
406
+ generatedTsMap.set(filePath, '');
407
+ return tsPath;
408
+ }
409
+ const ast = await (0, core_1.parse)(tsCode, {
410
+ syntax: 'typescript',
411
+ tsx: true,
412
+ });
413
+ const propsFromScript = await extractCssProps(ast);
414
+ const propsFromTemplate = extractCssPropsFromTemplate(code);
415
+ const propsMatches = [...new Set([...propsFromScript, ...propsFromTemplate])];
308
416
  const calls = propsMatches
309
417
  .filter(Boolean)
310
418
  .map((call) => `${call};`)
311
419
  .join('\n');
312
- const importRegex = /^(\s*import\s[^;]+;\s*)+/m;
313
- const importMatch = tsCode.match(importRegex);
314
- const importSection = importMatch ? importMatch[0] : '';
315
- const staticVariableSection = extractStaticStringLiteralVariable(tsCode);
316
- const cssCreateSection = extractCssCreate(tsCode);
317
- const cssKeyframesSection = extractCssKeyframes(tsCode);
318
- const cssViewTransitionSection = extractCssViewTransition(tsCode);
319
- const cssDefineConstsSection = extractCssDefineConsts(tsCode);
320
- const cssDefineTokensSection = extractCssDefineTokens(tsCode);
420
+ const importSection = await extractImportDeclarations(ast);
421
+ const staticVariableSection = await extractStaticStringLiteralVariable(ast);
422
+ const cssCreateSection = await extractCssMethod(ast, 'create');
423
+ const cssKeyframesSection = await extractCssMethod(ast, 'keyframes');
424
+ const cssViewTransitionSection = await extractCssMethod(ast, 'viewTransition');
425
+ const cssDefineConstsSection = await extractCssMethod(ast, 'defineConsts');
426
+ const cssDefineTokensSection = await extractCssMethod(ast, 'defineTokens');
321
427
  let finalCode = '';
322
- if (importSection) {
428
+ if (importSection)
323
429
  finalCode += importSection + '\n';
324
- }
325
- if (staticVariableSection) {
430
+ if (staticVariableSection)
326
431
  finalCode += staticVariableSection + '\n';
327
- }
328
- if (cssKeyframesSection) {
432
+ if (cssKeyframesSection)
329
433
  finalCode += cssKeyframesSection + '\n';
330
- }
331
- if (cssViewTransitionSection) {
434
+ if (cssViewTransitionSection)
332
435
  finalCode += cssViewTransitionSection + '\n';
333
- }
334
- if (cssDefineConstsSection) {
436
+ if (cssDefineConstsSection)
335
437
  finalCode += cssDefineConstsSection + '\n';
336
- }
337
- if (cssDefineTokensSection) {
438
+ if (cssDefineTokensSection)
338
439
  finalCode += cssDefineTokensSection + '\n';
339
- }
340
- if (cssCreateSection) {
440
+ if (cssCreateSection)
341
441
  finalCode += cssCreateSection + '\n';
342
- }
343
- if (calls) {
442
+ if (calls)
344
443
  finalCode += calls + '\n';
345
- }
346
- const tsPath = filePath.replace(ext, '.ts');
347
- fs_1.default.writeFileSync(tsPath, finalCode, 'utf8');
348
- generatedTsMap.set(filePath, tsPath);
444
+ generatedTsMap.set(filePath, finalCode);
349
445
  return tsPath;
350
446
  }
351
447
  async function extractTSFile(filePath) {
352
- const code = fs_1.default.readFileSync(filePath, 'utf8');
353
- const importRegex = /^(?:\s*import\s[^;]+;\s*)+/m;
354
- const importMatch = code.match(importRegex);
355
- const importSection = importMatch ? importMatch[0] : '';
356
- const staticVariableSection = extractStaticStringLiteralVariable(code);
357
- const cssCreateSection = extractCssCreate(code);
358
- const cssKeyframesSection = extractCssKeyframes(code);
359
- const cssViewTransitionSection = extractCssViewTransition(code);
360
- const cssDefineConstsSection = extractCssDefineConsts(code);
361
- const cssDefineTokensSection = extractCssDefineTokens(code);
362
- const propsMatches = extractCssProps(code);
448
+ const code = await (0, promises_1.readFile)(filePath, 'utf8');
449
+ const ast = await (0, core_1.parse)(code, {
450
+ syntax: 'typescript',
451
+ tsx: true,
452
+ });
453
+ const importSection = await extractImportDeclarations(ast);
454
+ const staticVariableSection = await extractStaticStringLiteralVariable(ast);
455
+ const cssCreateSection = await extractCssMethod(ast, 'create');
456
+ const cssKeyframesSection = await extractCssMethod(ast, 'keyframes');
457
+ const cssViewTransitionSection = await extractCssMethod(ast, 'viewTransition');
458
+ const cssDefineConstsSection = await extractCssMethod(ast, 'defineConsts');
459
+ const cssDefineTokensSection = await extractCssMethod(ast, 'defineTokens');
460
+ const propsMatches = await extractCssProps(ast);
363
461
  const calls = propsMatches
364
462
  .filter(Boolean)
365
463
  .map((call) => `${call};`)
@@ -380,18 +478,11 @@ async function extractTSFile(filePath) {
380
478
  if (cssCreateSection)
381
479
  finalCode += cssCreateSection + '\n';
382
480
  finalCode += calls;
383
- const ext = path_1.default.extname(filePath);
384
- const tempFilePath = filePath.replace(ext, '-temp.ts');
385
- fs_1.default.writeFileSync(tempFilePath, finalCode, 'utf8');
386
- generatedTsMap.set(filePath, tempFilePath);
481
+ const tempFilePath = filePath.replace(path_1.default.extname(filePath), '-temp.ts');
482
+ generatedTsMap.set(filePath, finalCode);
387
483
  return tempFilePath;
388
484
  }
389
485
  async function restoreAllOriginals() {
390
- for (const [originalPath, genPath] of generatedTsMap.entries()) {
391
- if (genPath !== originalPath && fs_1.default.existsSync(genPath)) {
392
- fs_1.default.unlinkSync(genPath);
393
- }
394
- }
395
486
  generatedTsMap.clear();
396
487
  }
397
488
  process.on('uncaughtException', async (error) => {
package/dist/index.js CHANGED
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const path_1 = __importDefault(require("path"));
7
- const fs_1 = require("fs");
8
7
  const promises_1 = require("fs/promises");
9
8
  const postcss_1 = __importDefault(require("postcss"));
10
9
  const postcss_combine_media_query_1 = __importDefault(require("postcss-combine-media-query"));
@@ -14,7 +13,7 @@ const core_1 = require("@swc/core");
14
13
  const find_up_1 = require("find-up");
15
14
  const processors_1 = require("@plumeria/core/processors");
16
15
  const extract_1 = require("./extract");
17
- async function generateStats(buildTime) {
16
+ async function generateStats(buildTime, coreFilePath) {
18
17
  const cssCode = await (0, promises_1.readFile)(coreFilePath, 'utf8');
19
18
  const cssSize = Buffer.byteLength(cssCode, 'utf8');
20
19
  let rules = 0;
@@ -48,177 +47,199 @@ async function generateStats(buildTime) {
48
47
  console.log(`Build time: ${buildTime.toFixed(2)}s`);
49
48
  console.log('────────────────────────────\n');
50
49
  }
51
- let projectRoot;
52
- const workspaceRootFile = (0, find_up_1.findUpSync)((directory) => {
53
- const pnpmWsPath = path_1.default.join(directory, 'pnpm-workspace.yaml');
54
- if ((0, fs_1.existsSync)(pnpmWsPath)) {
55
- return pnpmWsPath;
56
- }
57
- const pkgJsonPath = path_1.default.join(directory, 'package.json');
58
- if ((0, fs_1.existsSync)(pkgJsonPath)) {
50
+ async function main() {
51
+ let projectRoot;
52
+ const workspaceRootFile = await (0, find_up_1.findUp)(async (directory) => {
53
+ const pnpmWsPath = path_1.default.join(directory, 'pnpm-workspace.yaml');
54
+ try {
55
+ await (0, promises_1.access)(pnpmWsPath);
56
+ return pnpmWsPath;
57
+ }
58
+ catch {
59
+ }
60
+ const pkgJsonPath = path_1.default.join(directory, 'package.json');
59
61
  try {
60
- const pkgJson = JSON.parse((0, fs_1.readFileSync)(pkgJsonPath, 'utf-8'));
62
+ await (0, promises_1.access)(pkgJsonPath);
63
+ const pkgJson = JSON.parse(await (0, promises_1.readFile)(pkgJsonPath, 'utf-8'));
61
64
  if (pkgJson.workspaces) {
62
65
  return pkgJsonPath;
63
66
  }
64
67
  }
65
- catch (err) {
66
- console.error(err);
68
+ catch {
67
69
  }
68
- }
69
- return undefined;
70
- });
71
- if (workspaceRootFile) {
72
- projectRoot = path_1.default.dirname(workspaceRootFile);
73
- }
74
- else {
75
- const singleProjectRootFile = (0, find_up_1.findUpSync)('package.json');
76
- if (singleProjectRootFile) {
77
- projectRoot = path_1.default.dirname(singleProjectRootFile);
70
+ return undefined;
71
+ });
72
+ if (workspaceRootFile) {
73
+ projectRoot = path_1.default.dirname(workspaceRootFile);
78
74
  }
79
75
  else {
80
- projectRoot = process.cwd();
76
+ const singleProjectRootFile = await (0, find_up_1.findUp)('package.json');
77
+ if (singleProjectRootFile) {
78
+ projectRoot = path_1.default.dirname(singleProjectRootFile);
79
+ }
80
+ else {
81
+ projectRoot = process.cwd();
82
+ }
81
83
  }
82
- }
83
- let coreFilePath;
84
- const coreSourcePackageJsonPath = path_1.default.join(process.cwd(), 'package.json');
85
- const coreSourcePackageJson = JSON.parse((0, fs_1.readFileSync)(coreSourcePackageJsonPath, 'utf-8'));
86
- const dependencies = {
87
- ...coreSourcePackageJson.dependencies,
88
- ...coreSourcePackageJson.devDependencies,
89
- };
90
- const coreVersion = dependencies['@plumeria/core'];
91
- const resolvedCorePackageJsonPath = require.resolve('@plumeria/core/package.json', {
92
- paths: [projectRoot, process.cwd()],
93
- });
94
- if (workspaceRootFile) {
95
- if (coreVersion.includes('workspace')) {
96
- coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
84
+ let coreFilePath;
85
+ const coreSourcePackageJsonPath = path_1.default.join(process.cwd(), 'package.json');
86
+ const coreSourcePackageJson = JSON.parse(await (0, promises_1.readFile)(coreSourcePackageJsonPath, 'utf-8'));
87
+ const dependencies = {
88
+ ...coreSourcePackageJson.dependencies,
89
+ ...coreSourcePackageJson.devDependencies,
90
+ };
91
+ const coreVersion = dependencies['@plumeria/core'];
92
+ const resolvedCorePackageJsonPath = require.resolve('@plumeria/core/package.json', {
93
+ paths: [projectRoot, process.cwd()],
94
+ });
95
+ if (workspaceRootFile) {
96
+ if (coreVersion.includes('workspace')) {
97
+ coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
98
+ }
99
+ else {
100
+ const corePackageJson = JSON.parse(await (0, promises_1.readFile)(resolvedCorePackageJsonPath, 'utf-8'));
101
+ const exactCoreVersion = corePackageJson.version;
102
+ coreFilePath = path_1.default.join(projectRoot, 'node_modules', '.pnpm', `@plumeria+core@${exactCoreVersion}`, 'node_modules', '@plumeria', 'core', 'stylesheet.css');
103
+ }
97
104
  }
98
105
  else {
99
- const corePackageJson = JSON.parse((0, fs_1.readFileSync)(resolvedCorePackageJsonPath, 'utf-8'));
100
- const exactCoreVersion = corePackageJson.version;
101
- coreFilePath = path_1.default.join(projectRoot, 'node_modules', '.pnpm', `@plumeria+core@${exactCoreVersion}`, 'node_modules', '@plumeria', 'core', 'stylesheet.css');
102
- }
103
- }
104
- else {
105
- coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
106
- }
107
- const cleanUp = async () => {
108
- if (process.env.CI && (0, fs_1.existsSync)(coreFilePath)) {
109
- (0, fs_1.unlinkSync)(coreFilePath);
110
- console.log('File deleted successfully');
111
- }
112
- try {
113
- await (0, promises_1.writeFile)(coreFilePath, '', 'utf-8');
114
- }
115
- catch (err) {
116
- console.error('An error occurred:', err);
117
- }
118
- };
119
- function isCSS(filePath) {
120
- if ((0, fs_1.statSync)(filePath).isDirectory()) {
121
- return false;
106
+ coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
122
107
  }
123
- const code = (0, fs_1.readFileSync)(filePath, 'utf8');
124
- const ast = (0, core_1.parseSync)(code, {
125
- syntax: 'typescript',
126
- tsx: filePath.endsWith('.tsx'),
127
- decorators: false,
128
- dynamicImport: true,
129
- });
130
- let found = false;
131
- function visit(node) {
132
- if (node.type === 'MemberExpression' && node.property?.value) {
133
- if (node.object?.type === 'Identifier' && node.object.value === 'css') {
134
- if (node.property.value === 'props') {
135
- found = true;
108
+ const cleanUp = async () => {
109
+ if (process.env.CI) {
110
+ try {
111
+ await (0, promises_1.access)(coreFilePath);
112
+ await (0, promises_1.unlink)(coreFilePath);
113
+ console.log('File deleted successfully');
114
+ }
115
+ catch (error) {
116
+ if (error.code !== 'ENOENT') {
117
+ console.error(`Error deleting ${coreFilePath}:`, error);
136
118
  }
137
119
  }
138
120
  }
139
- for (const key in node) {
140
- const value = node[key];
141
- if (value && typeof value === 'object') {
142
- if (Array.isArray(value)) {
143
- for (const item of value) {
144
- visit(item);
121
+ try {
122
+ await (0, promises_1.writeFile)(coreFilePath, '', 'utf-8');
123
+ }
124
+ catch (err) {
125
+ console.error('An error occurred:', err);
126
+ }
127
+ };
128
+ async function isCSS(code, filePath) {
129
+ if (!code.includes('css.props')) {
130
+ return false;
131
+ }
132
+ const ast = await (0, core_1.parse)(code, {
133
+ syntax: 'typescript',
134
+ tsx: filePath.endsWith('.tsx'),
135
+ decorators: false,
136
+ dynamicImport: true,
137
+ });
138
+ let found = false;
139
+ function visit(node) {
140
+ if (node.type === 'MemberExpression' && node.property?.value) {
141
+ if (node.object?.type === 'Identifier' && node.object.value === 'css') {
142
+ if (node.property.value === 'props') {
143
+ found = true;
145
144
  }
146
145
  }
147
- else {
148
- visit(value);
146
+ }
147
+ for (const key in node) {
148
+ const value = node[key];
149
+ if (value && typeof value === 'object') {
150
+ if (Array.isArray(value)) {
151
+ for (const item of value) {
152
+ visit(item);
153
+ }
154
+ }
155
+ else {
156
+ visit(value);
157
+ }
149
158
  }
150
159
  }
151
160
  }
152
- }
153
- visit(ast);
154
- return found;
155
- }
156
- async function optimizeCSS() {
157
- const cssCode = await (0, promises_1.readFile)(coreFilePath, 'utf8');
158
- const merged = (0, postcss_1.default)([(0, postcss_combine_media_query_1.default)()]).process(cssCode, {
159
- from: coreFilePath,
160
- to: coreFilePath,
161
- });
162
- const light = (0, lightningcss_1.transform)({
163
- filename: coreFilePath,
164
- code: Buffer.from(merged.css),
165
- minify: process.env.NODE_ENV === 'production',
166
- targets: {
167
- safari: 16,
168
- edge: 110,
169
- firefox: 110,
170
- chrome: 110,
171
- },
172
- });
173
- const optimizedCss = Buffer.from(light.code).toString('utf-8');
174
- await (0, promises_1.writeFile)(coreFilePath, optimizedCss, 'utf-8');
175
- }
176
- (async () => {
177
- const startTime = performance.now();
178
- await cleanUp();
179
- const scanRoot = process.cwd();
180
- const files = (0, fs_1.globSync)('**/*.{js,jsx,ts,tsx,vue,svelte}', {
181
- cwd: scanRoot,
182
- exclude: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.next/**'],
183
- });
184
- const projectName = path_1.default.basename(projectRoot);
185
- const filesSupportExtensions = [];
186
- for (const file of files) {
187
- const ext = path_1.default.extname(file);
188
- if (ext === '.vue' || ext === '.svelte') {
189
- const tsFile = await (0, extract_1.extractVueAndSvelte)(file);
190
- filesSupportExtensions.push(tsFile);
191
- }
192
- else {
193
- const tempFile = await (0, extract_1.extractTSFile)(file);
194
- filesSupportExtensions.push(tempFile);
161
+ visit(ast);
162
+ return found;
163
+ }
164
+ async function optimizeCSS() {
165
+ const cssCode = await (0, promises_1.readFile)(coreFilePath, 'utf8');
166
+ const merged = (0, postcss_1.default)([(0, postcss_combine_media_query_1.default)()]).process(cssCode, {
167
+ from: coreFilePath,
168
+ to: coreFilePath,
169
+ });
170
+ const light = (0, lightningcss_1.transform)({
171
+ filename: coreFilePath,
172
+ code: Buffer.from(merged.css),
173
+ minify: process.env.NODE_ENV === 'production',
174
+ targets: {
175
+ safari: 16,
176
+ edge: 110,
177
+ firefox: 110,
178
+ chrome: 110,
179
+ },
180
+ });
181
+ const optimizedCss = Buffer.from(light.code).toString('utf-8');
182
+ await (0, promises_1.writeFile)(coreFilePath, optimizedCss, 'utf-8');
183
+ }
184
+ (async () => {
185
+ const startTime = performance.now();
186
+ await cleanUp();
187
+ const scanRoot = process.cwd();
188
+ const files = [];
189
+ for await (const entry of (0, promises_1.glob)('**/*.{js,jsx,ts,tsx,vue,svelte}', {
190
+ cwd: scanRoot,
191
+ exclude: [
192
+ '**/node_modules/**',
193
+ '**/dist/**',
194
+ '**/build/**',
195
+ '**/.next/**',
196
+ ],
197
+ })) {
198
+ files.push(entry);
195
199
  }
196
- }
197
- const styleFiles = filesSupportExtensions
198
- .filter((file) => isCSS(file))
199
- .sort();
200
- const tempToOriginalMap = new Map();
201
- for (const [original, temp] of extract_1.generatedTsMap.entries()) {
202
- tempToOriginalMap.set(temp, original);
203
- }
204
- for (let i = 0; i < styleFiles.length; i++) {
205
- await (0, execute_1.execute)(path_1.default.resolve(styleFiles[i]));
206
- if (process.argv.includes('--paths')) {
207
- const originalFile = tempToOriginalMap.get(styleFiles[i]);
208
- console.log(`✅: ${projectName}/${path_1.default.relative(projectRoot, originalFile)}`);
200
+ const projectName = path_1.default.basename(projectRoot);
201
+ const tempToOriginalMap = new Map();
202
+ const filesSupportExtensions = await Promise.all(files.map(async (file) => {
203
+ const ext = path_1.default.extname(file);
204
+ let tempFile;
205
+ if (ext === '.vue' || ext === '.svelte') {
206
+ tempFile = await (0, extract_1.extractVueAndSvelte)(file);
207
+ }
208
+ else {
209
+ tempFile = await (0, extract_1.extractTSFile)(file);
210
+ }
211
+ tempToOriginalMap.set(tempFile, file);
212
+ return tempFile;
213
+ }));
214
+ const styleFiles = await Promise.all(filesSupportExtensions.map(async (file) => {
215
+ const originalFile = tempToOriginalMap.get(file);
216
+ const code = extract_1.generatedTsMap.get(originalFile);
217
+ const isCssFile = code ? await isCSS(code, file) : false;
218
+ return isCssFile ? file : null;
219
+ }))
220
+ .then((results) => results.filter(Boolean))
221
+ .then((results) => results.sort());
222
+ for (const file of styleFiles) {
223
+ const originalFile = tempToOriginalMap.get(file);
224
+ const code = extract_1.generatedTsMap.get(originalFile);
225
+ if (code) {
226
+ await (0, promises_1.writeFile)(file, code, 'utf8');
227
+ await (0, execute_1.execute)(path_1.default.resolve(file));
228
+ if (process.argv.includes('--paths')) {
229
+ console.log(`✅: ${projectName}/${path_1.default.relative(projectRoot, originalFile)}`);
230
+ }
231
+ await (0, promises_1.unlink)(file);
232
+ }
209
233
  }
210
- }
211
- for (let i = 0; i < styleFiles.length; i++) {
212
234
  await (0, processors_1.buildGlobal)(coreFilePath);
213
- }
214
- for (let i = 0; i < styleFiles.length; i++) {
215
235
  await (0, processors_1.buildProps)(coreFilePath);
216
- }
217
- await optimizeCSS();
218
- await (0, extract_1.restoreAllOriginals)();
219
- if (process.argv.includes('--stats')) {
220
- const endTime = performance.now();
221
- const buildTime = (endTime - startTime) / 1000;
222
- await generateStats(buildTime);
223
- }
224
- })();
236
+ await optimizeCSS();
237
+ await (0, extract_1.restoreAllOriginals)();
238
+ if (process.argv.includes('--stats')) {
239
+ const endTime = performance.now();
240
+ const buildTime = (endTime - startTime) / 1000;
241
+ await generateStats(buildTime, coreFilePath);
242
+ }
243
+ })();
244
+ }
245
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/compiler",
3
- "version": "0.25.0",
3
+ "version": "0.25.2",
4
4
  "description": "Plumeria Rust-based compiler",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  "lightningcss": "^1.30.2",
22
22
  "postcss": "^8.5.6",
23
23
  "postcss-combine-media-query": "^2.1.0",
24
- "rscute": "^1.0.0"
24
+ "rscute": "^1.0.2"
25
25
  },
26
26
  "publishConfig": {
27
27
  "access": "public"