@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.
@@ -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, buildCreate } = require('@plumeria/core/processors');
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 (node.property.value === 'create' ||
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 styleFiles = files.filter(isCSS).sort();
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 buildCreate(coreFilePath);
140
+ await buildProps(coreFilePath);
108
141
  }
109
142
  await optimizeCSS();
143
+ await restoreAllOriginals();
110
144
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/compiler",
3
- "version": "0.13.0",
3
+ "version": "0.14.7",
4
4
  "description": "A faster compiler for Plumeria",
5
5
  "keywords": [
6
6
  "css",