@plumeria/compiler 0.13.0 → 0.14.6
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 +197 -0
- package/dist/index.js +23 -6
- package/package.json +1 -1
package/dist/extract.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const originalCodeMap = new Map();
|
|
6
|
+
const generatedTsMap = new Map();
|
|
7
|
+
function isInComment(code, position) {
|
|
8
|
+
const beforePosition = code.substring(0, position);
|
|
9
|
+
const lines = beforePosition.split('\n');
|
|
10
|
+
const currentLine = lines[lines.length - 1];
|
|
11
|
+
const singleLineCommentIndex = currentLine.indexOf('//');
|
|
12
|
+
if (singleLineCommentIndex !== -1) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
let inMultiLineComment = false;
|
|
16
|
+
let i = 0;
|
|
17
|
+
while (i < position) {
|
|
18
|
+
if (code.substring(i, i + 2) === '/*') {
|
|
19
|
+
inMultiLineComment = true;
|
|
20
|
+
i += 2;
|
|
21
|
+
}
|
|
22
|
+
else if (code.substring(i, i + 2) === '*/') {
|
|
23
|
+
inMultiLineComment = false;
|
|
24
|
+
i += 2;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
i++;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return inMultiLineComment;
|
|
31
|
+
}
|
|
32
|
+
function extractCssProps(code) {
|
|
33
|
+
const propsMatches = [];
|
|
34
|
+
const regex = /css\.props\s*\(/g;
|
|
35
|
+
let match;
|
|
36
|
+
while ((match = regex.exec(code))) {
|
|
37
|
+
if (isInComment(code, match.index)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const startIndex = match.index + match[0].length;
|
|
41
|
+
let parenCount = 1;
|
|
42
|
+
let currentIndex = startIndex;
|
|
43
|
+
let args = '';
|
|
44
|
+
while (parenCount > 0 && currentIndex < code.length) {
|
|
45
|
+
const char = code[currentIndex];
|
|
46
|
+
if (char === '(') {
|
|
47
|
+
parenCount++;
|
|
48
|
+
}
|
|
49
|
+
else if (char === ')') {
|
|
50
|
+
parenCount--;
|
|
51
|
+
}
|
|
52
|
+
if (parenCount > 0 || char !== ')') {
|
|
53
|
+
args += char;
|
|
54
|
+
}
|
|
55
|
+
currentIndex++;
|
|
56
|
+
}
|
|
57
|
+
if (parenCount === 0) {
|
|
58
|
+
const normalizedArgs = args.replace(/\s+/g, ' ').trim();
|
|
59
|
+
const cleanArgs = parseCssPropsArguments(normalizedArgs);
|
|
60
|
+
if (cleanArgs.length > 0) {
|
|
61
|
+
propsMatches.push(`css.props(${cleanArgs.join(', ')})`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return propsMatches;
|
|
66
|
+
}
|
|
67
|
+
function extractCssCreate(code) {
|
|
68
|
+
const cssCreateMatches = [];
|
|
69
|
+
const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.create\([\s\S]*?\);\s*))/g;
|
|
70
|
+
let match;
|
|
71
|
+
while ((match = regex.exec(code))) {
|
|
72
|
+
if (isInComment(code, match.index)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
cssCreateMatches.push(match[0]);
|
|
76
|
+
}
|
|
77
|
+
return cssCreateMatches.join('\n');
|
|
78
|
+
}
|
|
79
|
+
function parseCssPropsArguments(args) {
|
|
80
|
+
const results = [];
|
|
81
|
+
const splitArgs = args.split(/\s*,\s*(?![^(]*\))/);
|
|
82
|
+
for (const arg of splitArgs) {
|
|
83
|
+
if (arg.includes('&&')) {
|
|
84
|
+
const match = arg.match(/&&\s*([^\s,]+)/);
|
|
85
|
+
if (match) {
|
|
86
|
+
results.push(match[1]);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (arg.includes('?')) {
|
|
91
|
+
const match = arg.match(/([^?]+)\?([^:]+):(.+)$/);
|
|
92
|
+
if (match) {
|
|
93
|
+
results.push(match[2].trim());
|
|
94
|
+
results.push(match[3].trim());
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
results.push(arg.trim());
|
|
99
|
+
}
|
|
100
|
+
return results;
|
|
101
|
+
}
|
|
102
|
+
function extractVueAndSvelte(filePath) {
|
|
103
|
+
const ext = path.extname(filePath);
|
|
104
|
+
if (!(ext === '.svelte' || ext === '.vue'))
|
|
105
|
+
return filePath;
|
|
106
|
+
const code = fs.readFileSync(filePath, 'utf8');
|
|
107
|
+
originalCodeMap.set(filePath, code);
|
|
108
|
+
const lines = code.split(/\r?\n/);
|
|
109
|
+
let inScript = false;
|
|
110
|
+
const contentLines = [];
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
const trimmed = line.trim();
|
|
113
|
+
if (!inScript && /^<script\b/.test(trimmed)) {
|
|
114
|
+
inScript = true;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (inScript && /^<\/script>/.test(trimmed)) {
|
|
118
|
+
inScript = false;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (inScript) {
|
|
122
|
+
contentLines.push(line);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const tsCode = contentLines.join('\n');
|
|
126
|
+
const propsMatches = [...extractCssProps(tsCode), ...extractCssProps(code)];
|
|
127
|
+
const calls = propsMatches
|
|
128
|
+
.filter(Boolean)
|
|
129
|
+
.map((call) => `${call};`)
|
|
130
|
+
.join('\n');
|
|
131
|
+
const importRegex = /^(\s*import\s[^;]+;\s*)+/m;
|
|
132
|
+
const importMatch = tsCode.match(importRegex);
|
|
133
|
+
const importSection = importMatch ? importMatch[0] : '';
|
|
134
|
+
const stylesSection = extractCssCreate(tsCode);
|
|
135
|
+
let finalCode = '';
|
|
136
|
+
if (importSection) {
|
|
137
|
+
finalCode += importSection + '\n';
|
|
138
|
+
}
|
|
139
|
+
if (stylesSection) {
|
|
140
|
+
finalCode += stylesSection + '\n';
|
|
141
|
+
}
|
|
142
|
+
if (calls) {
|
|
143
|
+
finalCode += calls + '\n';
|
|
144
|
+
}
|
|
145
|
+
const tsPath = filePath.replace(ext, '.ts');
|
|
146
|
+
fs.writeFileSync(tsPath, finalCode, 'utf8');
|
|
147
|
+
generatedTsMap.set(filePath, tsPath);
|
|
148
|
+
return tsPath;
|
|
149
|
+
}
|
|
150
|
+
async function extractAndInjectStyleProps(filePath) {
|
|
151
|
+
const original = fs.readFileSync(filePath, 'utf8');
|
|
152
|
+
originalCodeMap.set(filePath, original);
|
|
153
|
+
const importRegex = /^(?:\s*import\s[^;]+;\s*)+/m;
|
|
154
|
+
const importMatch = original.match(importRegex);
|
|
155
|
+
const importSection = importMatch ? importMatch[0] : '';
|
|
156
|
+
const cssCreateSection = extractCssCreate(original);
|
|
157
|
+
const propsMatches = extractCssProps(original);
|
|
158
|
+
const calls = propsMatches
|
|
159
|
+
.filter(Boolean)
|
|
160
|
+
.map((call) => `${call};`)
|
|
161
|
+
.join('\n');
|
|
162
|
+
let finalCode = '';
|
|
163
|
+
if (importSection)
|
|
164
|
+
finalCode += importSection + '\n';
|
|
165
|
+
if (cssCreateSection)
|
|
166
|
+
finalCode += cssCreateSection + '\n';
|
|
167
|
+
finalCode += calls;
|
|
168
|
+
fs.writeFileSync(filePath, finalCode, 'utf8');
|
|
169
|
+
}
|
|
170
|
+
async function restoreAllOriginals() {
|
|
171
|
+
for (const [originalPath, genPath] of generatedTsMap.entries()) {
|
|
172
|
+
if (genPath !== originalPath && fs.existsSync(genPath)) {
|
|
173
|
+
fs.unlinkSync(genPath);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
generatedTsMap.clear();
|
|
177
|
+
for (const [filePath, backup] of originalCodeMap.entries()) {
|
|
178
|
+
fs.writeFileSync(filePath, backup, 'utf8');
|
|
179
|
+
}
|
|
180
|
+
originalCodeMap.clear();
|
|
181
|
+
}
|
|
182
|
+
process.on('uncaughtException', async (error) => {
|
|
183
|
+
console.error('Uncaught Exception:', error);
|
|
184
|
+
await restoreAllOriginals();
|
|
185
|
+
process.exit(1);
|
|
186
|
+
});
|
|
187
|
+
process.on('unhandledRejection', async (reason, promise) => {
|
|
188
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
189
|
+
await restoreAllOriginals();
|
|
190
|
+
process.exit(1);
|
|
191
|
+
});
|
|
192
|
+
module.exports = {
|
|
193
|
+
extractAndInjectStyleProps,
|
|
194
|
+
restoreAllOriginals,
|
|
195
|
+
extractVueAndSvelte,
|
|
196
|
+
originalCodeMap,
|
|
197
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
3
|
const path = require('path');
|
|
3
|
-
const { unlinkSync, existsSync, readFileSync } = require('fs');
|
|
4
|
+
const { unlinkSync, existsSync, readFileSync, statSync } = require('fs');
|
|
4
5
|
const { readFile, writeFile } = require('fs/promises');
|
|
5
6
|
const { glob } = require('@rust-gear/glob');
|
|
6
7
|
const postcss = require('postcss');
|
|
@@ -10,6 +11,7 @@ const { execute } = require('rscute/execute');
|
|
|
10
11
|
const { transform } = require('lightningcss');
|
|
11
12
|
const { parseSync } = require('@swc/core');
|
|
12
13
|
const { buildGlobal, buildCreate } = require('@plumeria/core/processors');
|
|
14
|
+
const { extractAndInjectStyleProps, restoreAllOriginals, extractVueAndSvelte, } = require('./extract');
|
|
13
15
|
const projectRoot = process.cwd().split('node_modules')[0];
|
|
14
16
|
const directPath = path.join(projectRoot, 'node_modules/@plumeria/core');
|
|
15
17
|
const coreFilePath = path.join(directPath, 'stylesheet.css');
|
|
@@ -25,7 +27,10 @@ const cleanUp = async () => {
|
|
|
25
27
|
console.error('An error occurred:', err);
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
|
-
function isCSS(filePath) {
|
|
30
|
+
function isCSS(filePath, target) {
|
|
31
|
+
if (statSync(filePath).isDirectory()) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
29
34
|
const code = readFileSync(filePath, 'utf8');
|
|
30
35
|
const ast = parseSync(code, {
|
|
31
36
|
syntax: 'typescript',
|
|
@@ -37,7 +42,12 @@ function isCSS(filePath) {
|
|
|
37
42
|
function visit(node) {
|
|
38
43
|
if (node.type === 'MemberExpression' && node.property?.value) {
|
|
39
44
|
if (node.object?.type === 'Identifier' && node.object.value === 'css') {
|
|
40
|
-
if (
|
|
45
|
+
if (target === 'props') {
|
|
46
|
+
if (node.property.value === 'props') {
|
|
47
|
+
found = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (node.property.value === 'props' ||
|
|
41
51
|
node.property.value === 'global') {
|
|
42
52
|
found = true;
|
|
43
53
|
}
|
|
@@ -85,7 +95,7 @@ async function optimizeCSS() {
|
|
|
85
95
|
}
|
|
86
96
|
(async () => {
|
|
87
97
|
await cleanUp();
|
|
88
|
-
const files = await glob(path.join(projectRoot, '**/*.{js,jsx,ts,tsx}'), {
|
|
98
|
+
const files = await glob(path.join(projectRoot, '**/*.{js,jsx,ts,tsx,vue,svelte}'), {
|
|
89
99
|
exclude: [
|
|
90
100
|
'**/node_modules/**',
|
|
91
101
|
'**/dist/**',
|
|
@@ -94,11 +104,17 @@ async function optimizeCSS() {
|
|
|
94
104
|
],
|
|
95
105
|
cwd: projectRoot,
|
|
96
106
|
});
|
|
97
|
-
const
|
|
107
|
+
const projectName = path.basename(projectRoot);
|
|
108
|
+
const filesSupportExtensions = files.map((file) => extractVueAndSvelte(file));
|
|
109
|
+
const styleFiles = filesSupportExtensions.filter(isCSS).sort();
|
|
110
|
+
const cssPropsFiles = styleFiles.filter((file) => isCSS(file, 'props'));
|
|
111
|
+
for (let i = 0; i < cssPropsFiles.length; i++) {
|
|
112
|
+
await extractAndInjectStyleProps(path.resolve(cssPropsFiles[i]));
|
|
113
|
+
}
|
|
98
114
|
for (let i = 0; i < styleFiles.length; i++) {
|
|
99
115
|
await execute(path.resolve(styleFiles[i]));
|
|
100
116
|
if (process.argv.includes('--paths'))
|
|
101
|
-
console.log(path.relative(projectRoot, styleFiles[i]));
|
|
117
|
+
console.log(`✅: ${projectName}/${path.relative(projectRoot, styleFiles[i])}`);
|
|
102
118
|
}
|
|
103
119
|
for (let i = 0; i < styleFiles.length; i++) {
|
|
104
120
|
await buildGlobal(coreFilePath);
|
|
@@ -107,4 +123,5 @@ async function optimizeCSS() {
|
|
|
107
123
|
await buildCreate(coreFilePath);
|
|
108
124
|
}
|
|
109
125
|
await optimizeCSS();
|
|
126
|
+
await restoreAllOriginals();
|
|
110
127
|
})();
|