@plumeria/compiler 0.13.0 → 0.14.7
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 +262 -0
- package/dist/index.js +42 -8
- package/package.json +1 -1
package/dist/extract.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
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 isInString(code, position) {
|
|
33
|
+
let inSingleQuote = false;
|
|
34
|
+
let inDoubleQuote = false;
|
|
35
|
+
let inBacktick = false;
|
|
36
|
+
let escape = false;
|
|
37
|
+
for (let i = 0; i < position; i++) {
|
|
38
|
+
const char = code[i];
|
|
39
|
+
if (escape) {
|
|
40
|
+
escape = false;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (char === '\\') {
|
|
44
|
+
escape = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!inSingleQuote && !inDoubleQuote && !inBacktick) {
|
|
48
|
+
if (char === "'") {
|
|
49
|
+
inSingleQuote = true;
|
|
50
|
+
}
|
|
51
|
+
else if (char === '"') {
|
|
52
|
+
inDoubleQuote = true;
|
|
53
|
+
}
|
|
54
|
+
else if (char === '`') {
|
|
55
|
+
inBacktick = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
if (inSingleQuote && char === "'") {
|
|
60
|
+
inSingleQuote = false;
|
|
61
|
+
}
|
|
62
|
+
else if (inDoubleQuote && char === '"') {
|
|
63
|
+
inDoubleQuote = false;
|
|
64
|
+
}
|
|
65
|
+
else if (inBacktick && char === '`') {
|
|
66
|
+
inBacktick = false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return inSingleQuote || inDoubleQuote || inBacktick;
|
|
71
|
+
}
|
|
72
|
+
function isInHtmlText(code, position) {
|
|
73
|
+
let lastOpenTag = -1;
|
|
74
|
+
let lastCloseTag = -1;
|
|
75
|
+
for (let i = position - 1; i >= 0; i--) {
|
|
76
|
+
if (code[i] === '>' && lastCloseTag === -1) {
|
|
77
|
+
lastCloseTag = i;
|
|
78
|
+
}
|
|
79
|
+
if (code[i] === '<') {
|
|
80
|
+
lastOpenTag = i;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let nextOpenTag = -1;
|
|
85
|
+
for (let i = position; i < code.length; i++) {
|
|
86
|
+
if (code[i] === '<') {
|
|
87
|
+
nextOpenTag = i;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return lastCloseTag > lastOpenTag && nextOpenTag > position;
|
|
92
|
+
}
|
|
93
|
+
function extractCssProps(code) {
|
|
94
|
+
const propsMatches = [];
|
|
95
|
+
const regex = /css\.props\s*\(/g;
|
|
96
|
+
let match;
|
|
97
|
+
while ((match = regex.exec(code))) {
|
|
98
|
+
if (isInComment(code, match.index) ||
|
|
99
|
+
isInString(code, match.index) ||
|
|
100
|
+
isInHtmlText(code, match.index)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const startIndex = match.index + match[0].length;
|
|
104
|
+
let parenCount = 1;
|
|
105
|
+
let currentIndex = startIndex;
|
|
106
|
+
let args = '';
|
|
107
|
+
while (parenCount > 0 && currentIndex < code.length) {
|
|
108
|
+
const char = code[currentIndex];
|
|
109
|
+
if (char === '(') {
|
|
110
|
+
parenCount++;
|
|
111
|
+
}
|
|
112
|
+
else if (char === ')') {
|
|
113
|
+
parenCount--;
|
|
114
|
+
}
|
|
115
|
+
if (parenCount > 0 || char !== ')') {
|
|
116
|
+
args += char;
|
|
117
|
+
}
|
|
118
|
+
currentIndex++;
|
|
119
|
+
}
|
|
120
|
+
if (parenCount === 0) {
|
|
121
|
+
const normalizedArgs = args.replace(/\s+/g, ' ').trim();
|
|
122
|
+
const cleanArgs = parseCssPropsArguments(normalizedArgs);
|
|
123
|
+
if (cleanArgs.length > 0) {
|
|
124
|
+
propsMatches.push(`css.props(${cleanArgs.join(', ')})`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return propsMatches;
|
|
129
|
+
}
|
|
130
|
+
function extractCssCreate(code) {
|
|
131
|
+
const cssCreateMatches = [];
|
|
132
|
+
const regex = /(?:(?:\s*const\s+[a-zA-Z0-9_$]+\s*=\s*css\.create\([\s\S]*?\);\s*))/g;
|
|
133
|
+
let match;
|
|
134
|
+
while ((match = regex.exec(code))) {
|
|
135
|
+
if (isInComment(code, match.index) ||
|
|
136
|
+
isInString(code, match.index) ||
|
|
137
|
+
isInHtmlText(code, match.index)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
cssCreateMatches.push(match[0]);
|
|
141
|
+
}
|
|
142
|
+
return cssCreateMatches.join('\n');
|
|
143
|
+
}
|
|
144
|
+
function parseCssPropsArguments(args) {
|
|
145
|
+
const results = [];
|
|
146
|
+
const splitArgs = args.split(/\s*,\s*(?![^(]*\))/);
|
|
147
|
+
for (const arg of splitArgs) {
|
|
148
|
+
if (arg.includes('&&')) {
|
|
149
|
+
const match = arg.match(/&&\s*([^\s,]+)/);
|
|
150
|
+
if (match) {
|
|
151
|
+
results.push(match[1]);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (arg.includes('?')) {
|
|
156
|
+
const match = arg.match(/([^?]+)\?([^:]+):(.+)$/);
|
|
157
|
+
if (match) {
|
|
158
|
+
results.push(match[2].trim());
|
|
159
|
+
results.push(match[3].trim());
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
results.push(arg.trim());
|
|
164
|
+
}
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
async function extractVueAndSvelte(filePath) {
|
|
168
|
+
const ext = path.extname(filePath);
|
|
169
|
+
if (!(ext === '.svelte' || ext === '.vue'))
|
|
170
|
+
return filePath;
|
|
171
|
+
const code = fs.readFileSync(filePath, 'utf8');
|
|
172
|
+
originalCodeMap.set(filePath, code);
|
|
173
|
+
const lines = code.split(/\r?\n/);
|
|
174
|
+
let inScript = false;
|
|
175
|
+
const contentLines = [];
|
|
176
|
+
for (const line of lines) {
|
|
177
|
+
const trimmed = line.trim();
|
|
178
|
+
if (!inScript && /^<script\b/.test(trimmed)) {
|
|
179
|
+
inScript = true;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (inScript && /^<\/script>/.test(trimmed)) {
|
|
183
|
+
inScript = false;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (inScript) {
|
|
187
|
+
contentLines.push(line);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const tsCode = contentLines.join('\n');
|
|
191
|
+
const propsMatches = [...extractCssProps(tsCode), ...extractCssProps(code)];
|
|
192
|
+
const calls = propsMatches
|
|
193
|
+
.filter(Boolean)
|
|
194
|
+
.map((call) => `${call};`)
|
|
195
|
+
.join('\n');
|
|
196
|
+
const importRegex = /^(\s*import\s[^;]+;\s*)+/m;
|
|
197
|
+
const importMatch = tsCode.match(importRegex);
|
|
198
|
+
const importSection = importMatch ? importMatch[0] : '';
|
|
199
|
+
const stylesSection = extractCssCreate(tsCode);
|
|
200
|
+
let finalCode = '';
|
|
201
|
+
if (importSection) {
|
|
202
|
+
finalCode += importSection + '\n';
|
|
203
|
+
}
|
|
204
|
+
if (stylesSection) {
|
|
205
|
+
finalCode += stylesSection + '\n';
|
|
206
|
+
}
|
|
207
|
+
if (calls) {
|
|
208
|
+
finalCode += calls + '\n';
|
|
209
|
+
}
|
|
210
|
+
const tsPath = filePath.replace(ext, '.ts');
|
|
211
|
+
fs.writeFileSync(tsPath, finalCode, 'utf8');
|
|
212
|
+
generatedTsMap.set(filePath, tsPath);
|
|
213
|
+
return tsPath;
|
|
214
|
+
}
|
|
215
|
+
async function extractAndInjectStyleProps(filePath) {
|
|
216
|
+
const original = fs.readFileSync(filePath, 'utf8');
|
|
217
|
+
originalCodeMap.set(filePath, original);
|
|
218
|
+
const importRegex = /^(?:\s*import\s[^;]+;\s*)+/m;
|
|
219
|
+
const importMatch = original.match(importRegex);
|
|
220
|
+
const importSection = importMatch ? importMatch[0] : '';
|
|
221
|
+
const cssCreateSection = extractCssCreate(original);
|
|
222
|
+
const propsMatches = extractCssProps(original);
|
|
223
|
+
const calls = propsMatches
|
|
224
|
+
.filter(Boolean)
|
|
225
|
+
.map((call) => `${call};`)
|
|
226
|
+
.join('\n');
|
|
227
|
+
let finalCode = '';
|
|
228
|
+
if (importSection)
|
|
229
|
+
finalCode += importSection + '\n';
|
|
230
|
+
if (cssCreateSection)
|
|
231
|
+
finalCode += cssCreateSection + '\n';
|
|
232
|
+
finalCode += calls;
|
|
233
|
+
fs.writeFileSync(filePath, finalCode, 'utf8');
|
|
234
|
+
}
|
|
235
|
+
async function restoreAllOriginals() {
|
|
236
|
+
for (const [originalPath, genPath] of generatedTsMap.entries()) {
|
|
237
|
+
if (genPath !== originalPath && fs.existsSync(genPath)) {
|
|
238
|
+
fs.unlinkSync(genPath);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
generatedTsMap.clear();
|
|
242
|
+
for (const [filePath, backup] of originalCodeMap.entries()) {
|
|
243
|
+
fs.writeFileSync(filePath, backup, 'utf8');
|
|
244
|
+
}
|
|
245
|
+
originalCodeMap.clear();
|
|
246
|
+
}
|
|
247
|
+
process.on('uncaughtException', async (error) => {
|
|
248
|
+
console.error('Uncaught Exception:', error);
|
|
249
|
+
await restoreAllOriginals();
|
|
250
|
+
process.exit(1);
|
|
251
|
+
});
|
|
252
|
+
process.on('unhandledRejection', async (reason, promise) => {
|
|
253
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
254
|
+
await restoreAllOriginals();
|
|
255
|
+
process.exit(1);
|
|
256
|
+
});
|
|
257
|
+
module.exports = {
|
|
258
|
+
extractAndInjectStyleProps,
|
|
259
|
+
restoreAllOriginals,
|
|
260
|
+
extractVueAndSvelte,
|
|
261
|
+
originalCodeMap,
|
|
262
|
+
};
|
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');
|
|
@@ -9,7 +10,8 @@ const combineMediaQuery = require('postcss-combine-media-query');
|
|
|
9
10
|
const { execute } = require('rscute/execute');
|
|
10
11
|
const { transform } = require('lightningcss');
|
|
11
12
|
const { parseSync } = require('@swc/core');
|
|
12
|
-
const { buildGlobal,
|
|
13
|
+
const { buildGlobal, buildProps } = 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,17 +104,41 @@ async function optimizeCSS() {
|
|
|
94
104
|
],
|
|
95
105
|
cwd: projectRoot,
|
|
96
106
|
});
|
|
97
|
-
const
|
|
107
|
+
const projectName = path.basename(projectRoot);
|
|
108
|
+
const filesSupportExtensions = [];
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
const tsFile = await extractVueAndSvelte(file);
|
|
111
|
+
filesSupportExtensions.push(tsFile);
|
|
112
|
+
}
|
|
113
|
+
const styleFiles = filesSupportExtensions
|
|
114
|
+
.filter((file) => isCSS(file, ''))
|
|
115
|
+
.sort();
|
|
116
|
+
const cssPropsFiles = styleFiles.filter((file) => {
|
|
117
|
+
if (file.endsWith('.ts')) {
|
|
118
|
+
const vueFile = file.replace('.ts', '.vue');
|
|
119
|
+
const svelteFile = file.replace('.ts', '.svelte');
|
|
120
|
+
const isGeneratedFromVue = existsSync(vueFile);
|
|
121
|
+
const isGeneratedFromSvelte = existsSync(svelteFile);
|
|
122
|
+
if (isGeneratedFromVue || isGeneratedFromSvelte) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return isCSS(file, 'props');
|
|
127
|
+
});
|
|
128
|
+
for (let i = 0; i < cssPropsFiles.length; i++) {
|
|
129
|
+
await extractAndInjectStyleProps(path.resolve(cssPropsFiles[i]));
|
|
130
|
+
}
|
|
98
131
|
for (let i = 0; i < styleFiles.length; i++) {
|
|
99
132
|
await execute(path.resolve(styleFiles[i]));
|
|
100
133
|
if (process.argv.includes('--paths'))
|
|
101
|
-
console.log(path.relative(projectRoot, styleFiles[i]));
|
|
134
|
+
console.log(`✅: ${projectName}/${path.relative(projectRoot, styleFiles[i])}`);
|
|
102
135
|
}
|
|
103
136
|
for (let i = 0; i < styleFiles.length; i++) {
|
|
104
137
|
await buildGlobal(coreFilePath);
|
|
105
138
|
}
|
|
106
139
|
for (let i = 0; i < styleFiles.length; i++) {
|
|
107
|
-
await
|
|
140
|
+
await buildProps(coreFilePath);
|
|
108
141
|
}
|
|
109
142
|
await optimizeCSS();
|
|
143
|
+
await restoreAllOriginals();
|
|
110
144
|
})();
|