@plumeria/compiler 2.4.2 → 3.0.0

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/bin/css.js CHANGED
@@ -1,25 +1,4 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  const path = require('path');
4
- const { styleText } = require('util');
5
- const { enableCompileCache } = require('node:module');
6
-
7
- enableCompileCache();
8
-
9
- const { register } = require('rscute/register');
10
-
11
- register();
12
-
13
- try {
14
- const stats = process.argv.includes('--stats');
15
- const view = process.argv.includes('--view');
16
- const paths = process.argv.includes('--paths');
17
-
18
- require(path.resolve(__dirname, '../dist/index.js'));
19
-
20
- if (!stats && !view && !paths)
21
- console.log(styleText(['green', 'bold'], 'āœ“ extract...'));
22
- } catch (error) {
23
- console.error('Compilation failed:', error.message);
24
- process.exit(1);
25
- }
3
+ require('rscute/register').register();
4
+ require(path.resolve(__dirname, '../dist/index.js'));
package/dist/index.js CHANGED
@@ -3,231 +3,178 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const path_1 = __importDefault(require("path"));
7
- const promises_1 = require("fs/promises");
8
- const postcss_1 = __importDefault(require("postcss"));
9
- const postcss_combine_media_query_1 = __importDefault(require("postcss-combine-media-query"));
10
- const execute_1 = require("rscute/execute");
11
- const glob_1 = require("@rust-gear/glob");
12
- const lightningcss_1 = require("lightningcss");
13
6
  const core_1 = require("@swc/core");
14
- const find_up_1 = require("find-up");
15
- const processors_1 = require("@plumeria/core/processors");
16
- const extract_1 = require("./extract");
17
- async function generateStats(buildTime, coreFilePath) {
18
- const cssCode = await (0, promises_1.readFile)(coreFilePath, 'utf8');
19
- const cssSize = Buffer.byteLength(cssCode, 'utf8');
20
- let rules = 0;
21
- const topProperties = new Map();
22
- (0, lightningcss_1.transform)({
23
- filename: coreFilePath,
24
- code: Buffer.from(cssCode),
25
- visitor: {
26
- Rule(rule) {
27
- if (rule.type === 'style') {
28
- rules++;
29
- rule.value.declarations.declarations.forEach((decl) => {
30
- if ('property' in decl) {
31
- topProperties.set(decl.property, (topProperties.get(decl.property) || 0) + 1);
32
- }
33
- });
34
- }
35
- },
36
- },
37
- });
38
- const sortedTopProperties = [...topProperties.entries()].sort((a, b) => b[1] - a[1]);
39
- console.log('\nšŸ“¦ Plumeria CSS Stats');
40
- console.log('────────────────────────────');
41
- console.log(`Total CSS size: ${(cssSize / 1024).toFixed(3)} KB`);
42
- console.log(`Rules: ${rules}`);
43
- console.log('Top properties:');
44
- for (let i = 0; i < Math.min(5, sortedTopProperties.length); i++) {
45
- const [prop, count] = sortedTopProperties[i];
46
- console.log(` - ${prop}: ${count}`);
47
- }
48
- console.log(`Build time: ${buildTime.toFixed(2)}s`);
49
- console.log('────────────────────────────\n');
50
- }
51
- async function main() {
52
- let projectRoot;
53
- const workspaceRootFile = await (0, find_up_1.findUp)(async (directory) => {
54
- const pnpmWsPath = path_1.default.join(directory, 'pnpm-workspace.yaml');
55
- try {
56
- await (0, promises_1.access)(pnpmWsPath);
57
- return pnpmWsPath;
58
- }
59
- catch {
60
- }
61
- const pkgJsonPath = path_1.default.join(directory, 'package.json');
62
- try {
63
- await (0, promises_1.access)(pkgJsonPath);
64
- const pkgJson = JSON.parse(await (0, promises_1.readFile)(pkgJsonPath, 'utf-8'));
65
- if (pkgJson.workspaces) {
66
- return pkgJsonPath;
67
- }
68
- }
69
- catch {
70
- }
71
- return undefined;
72
- });
73
- if (workspaceRootFile) {
74
- projectRoot = path_1.default.dirname(workspaceRootFile);
75
- }
76
- else {
77
- const singleProjectRootFile = await (0, find_up_1.findUp)('package.json');
78
- if (singleProjectRootFile) {
79
- projectRoot = path_1.default.dirname(singleProjectRootFile);
80
- }
81
- else {
82
- projectRoot = process.cwd();
83
- }
84
- }
85
- let coreFilePath;
86
- const coreSourcePackageJsonPath = path_1.default.join(process.cwd(), 'package.json');
87
- const coreSourcePackageJson = JSON.parse(await (0, promises_1.readFile)(coreSourcePackageJsonPath, 'utf-8'));
88
- const dependencies = {
89
- ...coreSourcePackageJson.dependencies,
90
- ...coreSourcePackageJson.devDependencies,
91
- };
92
- const coreVersion = dependencies['@plumeria/core'];
93
- const resolvedCorePackageJsonPath = require.resolve('@plumeria/core/package.json', {
94
- paths: [projectRoot, process.cwd()],
95
- });
96
- if (workspaceRootFile) {
97
- if (coreVersion.includes('workspace')) {
98
- coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
99
- }
100
- else {
101
- const corePackageJson = JSON.parse(await (0, promises_1.readFile)(resolvedCorePackageJsonPath, 'utf-8'));
102
- const exactCoreVersion = corePackageJson.version;
103
- coreFilePath = path_1.default.join(projectRoot, 'node_modules', '.pnpm', `@plumeria+core@${exactCoreVersion}`, 'node_modules', '@plumeria', 'core', 'stylesheet.css');
104
- }
105
- }
106
- else {
107
- coreFilePath = path_1.default.join(path_1.default.dirname(resolvedCorePackageJsonPath), 'stylesheet.css');
108
- }
109
- const cleanUp = async () => {
110
- if (process.env.CI) {
111
- try {
112
- await (0, promises_1.access)(coreFilePath);
113
- await (0, promises_1.unlink)(coreFilePath);
114
- console.log('File deleted successfully');
115
- }
116
- catch (error) {
117
- if (error.code !== 'ENOENT') {
118
- console.error(`Error deleting ${coreFilePath}:`, error);
119
- }
120
- }
121
- }
7
+ const zss_engine_1 = require("zss-engine");
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const utils_1 = require("@plumeria/utils");
11
+ const optimizer_1 = require("./optimizer");
12
+ async function compile(options) {
13
+ const { pattern, output, cwd = process.cwd() } = options;
14
+ let staticTable = null;
15
+ let keyframesData = null;
16
+ let viewTransitionData = null;
17
+ let themeData = null;
18
+ const allSheets = new Set();
19
+ const dependencies = new Set();
20
+ staticTable = (0, utils_1.scanForCreateStatic)((p) => dependencies.add(p));
21
+ utils_1.tables.staticTable = staticTable;
22
+ keyframesData = (0, utils_1.scanForKeyframes)((p) => dependencies.add(p));
23
+ utils_1.tables.keyframesHashTable = keyframesData.keyframesHashTableLocal;
24
+ utils_1.tables.keyframesObjectTable = keyframesData.keyframesObjectTableLocal;
25
+ viewTransitionData = (0, utils_1.scanForViewTransition)((p) => dependencies.add(p));
26
+ utils_1.tables.viewTransitionHashTable =
27
+ viewTransitionData.viewTransitionHashTableLocal;
28
+ utils_1.tables.viewTransitionObjectTable =
29
+ viewTransitionData.viewTransitionObjectTableLocal;
30
+ themeData = (0, utils_1.scanForCreateTheme)((p) => dependencies.add(p));
31
+ utils_1.tables.themeTable = themeData.themeTableLocal;
32
+ utils_1.tables.createThemeObjectTable = themeData.createThemeObjectTableLocal;
33
+ const processFile = (filePath) => {
34
+ const source = fs_1.default.readFileSync(filePath, 'utf-8');
35
+ const extractedSheets = [];
36
+ let ast;
122
37
  try {
123
- await (0, promises_1.writeFile)(coreFilePath, '', 'utf-8');
38
+ ast = (0, core_1.parseSync)(source, {
39
+ syntax: 'typescript',
40
+ tsx: true,
41
+ target: 'es2022',
42
+ });
124
43
  }
125
44
  catch (err) {
126
- console.error('An error occurred:', err);
127
- }
128
- };
129
- async function isCSS(code, filePath) {
130
- if (!code.includes('css.props')) {
131
- return false;
132
- }
133
- const ast = await (0, core_1.parse)(code, {
134
- syntax: 'typescript',
135
- tsx: filePath.endsWith('.tsx'),
136
- decorators: false,
137
- dynamicImport: true,
138
- });
139
- let found = false;
140
- function visit(node) {
141
- if (node.type === 'MemberExpression' && node.property?.value) {
142
- if (node.object?.type === 'Identifier' && node.object.value === 'css') {
143
- if (node.property.value === 'props') {
144
- found = true;
45
+ console.warn(`Failed to parse ${filePath}:`, err);
46
+ return [];
47
+ }
48
+ const localConsts = (0, utils_1.collectLocalConsts)(ast);
49
+ Object.assign(utils_1.tables.staticTable, localConsts);
50
+ const localCreateStyles = {};
51
+ (0, utils_1.traverse)(ast, {
52
+ VariableDeclarator({ node }) {
53
+ if (node.id.type === 'Identifier' &&
54
+ node.init &&
55
+ utils_1.t.isCallExpression(node.init) &&
56
+ utils_1.t.isMemberExpression(node.init.callee) &&
57
+ utils_1.t.isIdentifier(node.init.callee.object, { name: 'css' }) &&
58
+ utils_1.t.isIdentifier(node.init.callee.property, { name: 'create' }) &&
59
+ node.init.arguments.length === 1 &&
60
+ utils_1.t.isObjectExpression(node.init.arguments[0].expression)) {
61
+ const obj = (0, utils_1.objectExpressionToObject)(node.init.arguments[0].expression, utils_1.tables.staticTable, utils_1.tables.keyframesHashTable, utils_1.tables.viewTransitionHashTable, utils_1.tables.themeTable);
62
+ if (obj) {
63
+ localCreateStyles[node.id.value] = obj;
64
+ Object.entries(obj).forEach(([key, style]) => {
65
+ const records = (0, utils_1.getStyleRecords)(key, style, 1);
66
+ (0, utils_1.extractOndemandStyles)(style, extractedSheets);
67
+ records.forEach((r) => {
68
+ extractedSheets.push(r.sheet);
69
+ });
70
+ });
145
71
  }
146
72
  }
147
- }
148
- for (const key in node) {
149
- const value = node[key];
150
- if (value && typeof value === 'object') {
151
- if (Array.isArray(value)) {
152
- for (const item of value) {
153
- visit(item);
73
+ },
74
+ CallExpression({ node }) {
75
+ const callee = node.callee;
76
+ if (utils_1.t.isMemberExpression(callee) &&
77
+ utils_1.t.isIdentifier(callee.object, { name: 'css' }) &&
78
+ utils_1.t.isIdentifier(callee.property)) {
79
+ const args = node.arguments;
80
+ if (callee.property.value === 'props') {
81
+ const merged = {};
82
+ let allStatic = true;
83
+ args.forEach((arg) => {
84
+ const expr = arg.expression;
85
+ if (utils_1.t.isObjectExpression(expr)) {
86
+ const obj = (0, utils_1.objectExpressionToObject)(expr, utils_1.tables.staticTable, utils_1.tables.keyframesHashTable, utils_1.tables.viewTransitionHashTable, utils_1.tables.themeTable);
87
+ if (obj) {
88
+ Object.assign(merged, obj);
89
+ }
90
+ else {
91
+ allStatic = false;
92
+ }
93
+ }
94
+ else if (utils_1.t.isMemberExpression(expr)) {
95
+ if (utils_1.t.isIdentifier(expr.object) &&
96
+ utils_1.t.isIdentifier(expr.property)) {
97
+ const varName = expr.object.value;
98
+ const propName = expr.property.value;
99
+ const styleSet = localCreateStyles[varName];
100
+ if (styleSet && styleSet[propName]) {
101
+ Object.assign(merged, styleSet[propName]);
102
+ }
103
+ else {
104
+ allStatic = false;
105
+ }
106
+ }
107
+ else {
108
+ allStatic = false;
109
+ }
110
+ }
111
+ else if (utils_1.t.isIdentifier(expr)) {
112
+ const obj = localCreateStyles[expr.value];
113
+ if (obj) {
114
+ Object.assign(merged, obj);
115
+ }
116
+ else {
117
+ allStatic = false;
118
+ }
119
+ }
120
+ else {
121
+ allStatic = false;
122
+ }
123
+ });
124
+ if (allStatic && Object.keys(merged).length > 0) {
125
+ (0, utils_1.extractOndemandStyles)(merged, extractedSheets);
126
+ const hash = (0, zss_engine_1.genBase36Hash)(merged, 1, 8);
127
+ const records = (0, utils_1.getStyleRecords)(hash, merged, 1);
128
+ records.forEach((r) => extractedSheets.push(r.sheet));
154
129
  }
155
130
  }
156
- else {
157
- visit(value);
131
+ else if (callee.property.value === 'keyframes' &&
132
+ args.length > 0 &&
133
+ utils_1.t.isObjectExpression(args[0].expression)) {
134
+ const obj = (0, utils_1.objectExpressionToObject)(args[0].expression, utils_1.tables.staticTable, utils_1.tables.keyframesHashTable, utils_1.tables.viewTransitionHashTable, utils_1.tables.themeTable);
135
+ const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
136
+ utils_1.tables.keyframesObjectTable[hash] = obj;
137
+ }
138
+ else if (callee.property.value === 'viewTransition' &&
139
+ args.length > 0 &&
140
+ utils_1.t.isObjectExpression(args[0].expression)) {
141
+ const obj = (0, utils_1.objectExpressionToObject)(args[0].expression, utils_1.tables.staticTable, utils_1.tables.keyframesHashTable, utils_1.tables.viewTransitionHashTable, utils_1.tables.themeTable);
142
+ const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
143
+ utils_1.tables.viewTransitionObjectTable[hash] = obj;
144
+ }
145
+ else if (callee.property.value === 'createTheme' &&
146
+ args.length > 0 &&
147
+ utils_1.t.isObjectExpression(args[0].expression)) {
148
+ const obj = (0, utils_1.objectExpressionToObject)(args[0].expression, utils_1.tables.staticTable, utils_1.tables.keyframesHashTable, utils_1.tables.viewTransitionHashTable, utils_1.tables.themeTable);
149
+ const themeHash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
150
+ utils_1.tables.createThemeObjectTable[themeHash] = obj;
158
151
  }
159
152
  }
160
- }
161
- }
162
- visit(ast);
163
- return found;
164
- }
165
- async function optimizeCSS() {
166
- const cssCode = await (0, promises_1.readFile)(coreFilePath, 'utf8');
167
- const merged = (0, postcss_1.default)([(0, postcss_combine_media_query_1.default)()]).process(cssCode, {
168
- from: coreFilePath,
169
- to: coreFilePath,
170
- });
171
- const light = (0, lightningcss_1.transform)({
172
- filename: coreFilePath,
173
- code: Buffer.from(merged.css),
174
- minify: process.env.NODE_ENV === 'production',
175
- targets: {
176
- safari: 16,
177
- edge: 110,
178
- firefox: 110,
179
- chrome: 110,
180
153
  },
181
154
  });
182
- const optimizedCss = Buffer.from(light.code).toString('utf-8');
183
- await (0, promises_1.writeFile)(coreFilePath, optimizedCss, 'utf-8');
184
- }
185
- const startTime = performance.now();
186
- await cleanUp();
187
- const scanRoot = process.cwd();
188
- const files = (0, glob_1.globSync)('**/*.{js,jsx,ts,tsx,vue,svelte}', {
189
- cwd: scanRoot,
190
- exclude: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.next/**'],
155
+ return extractedSheets;
156
+ };
157
+ const files = fs_1.default.globSync(pattern, {
158
+ cwd,
159
+ exclude: ['**/node_modules/**', '**/dist/**', '**/.next/**'],
191
160
  });
192
- const projectName = path_1.default.basename(projectRoot);
193
- const filesSupportExtensions = await Promise.all(files.map(async (file) => {
194
- const ext = path_1.default.extname(file);
195
- if (ext === '.vue' || ext === '.svelte') {
196
- return await (0, extract_1.extractVueAndSvelte)(file);
197
- }
198
- else {
199
- return await (0, extract_1.extractTSFile)(file);
200
- }
201
- }));
202
- const styleFiles = await Promise.all(filesSupportExtensions.map(async (file) => {
203
- const code = extract_1.generatedTsMap.get(file);
204
- const isCssFile = code ? await isCSS(code, file) : false;
205
- return isCssFile ? file : null;
206
- }))
207
- .then((results) => results.filter(Boolean))
208
- .then((results) => results.sort());
209
- for (const file of styleFiles) {
210
- const code = extract_1.generatedTsMap.get(file);
211
- if (code) {
212
- const ext = path_1.default.extname(file);
213
- const tsPath = ext === '.vue' || ext === '.svelte' ? file.replace(ext, '.ts') : file;
214
- await (0, execute_1.executeCode)(code, { filePath: tsPath });
215
- if (process.argv.includes('--paths')) {
216
- console.log(`āœ…: ${projectName}/${path_1.default.relative(projectRoot, file)}`);
217
- }
218
- }
219
- }
220
- await processors_1.gQueue.build(coreFilePath);
221
- await processors_1.pQueue.build(coreFilePath);
222
- await optimizeCSS();
223
- extract_1.generatedTsMap.clear();
224
- if (process.argv.includes('--stats')) {
225
- const endTime = performance.now();
226
- const buildTime = (endTime - startTime) / 1000;
227
- await generateStats(buildTime, coreFilePath);
161
+ files.forEach((file) => {
162
+ const sheets = processFile(file);
163
+ sheets.forEach((sheet) => allSheets.add(sheet));
164
+ });
165
+ const outputPath = path_1.default.resolve(cwd, output);
166
+ const css = Array.from(allSheets).join('\n');
167
+ const outputDir = path_1.default.dirname(outputPath);
168
+ if (!fs_1.default.existsSync(outputDir)) {
169
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
228
170
  }
171
+ const optCSS = await (0, optimizer_1.optimizeCSS)(css);
172
+ fs_1.default.writeFileSync(outputPath, optCSS);
173
+ }
174
+ async function main() {
175
+ const coreFilePath = require.resolve('@plumeria/core/stylesheet.css');
176
+ await compile({ pattern: '**/*.{js,jsx,ts,tsx}', output: coreFilePath });
229
177
  }
230
- main().catch((error) => {
231
- console.error('Compilation failed:', error);
232
- process.exit(1);
178
+ main().catch((err) => {
179
+ console.error(err);
233
180
  });
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.optimizeCSS = optimizeCSS;
7
+ const postcss_1 = __importDefault(require("postcss"));
8
+ const postcss_combine_media_query_1 = __importDefault(require("postcss-combine-media-query"));
9
+ const lightningcss_1 = require("lightningcss");
10
+ async function optimizeCSS(cssCode) {
11
+ const merged = await (0, postcss_1.default)([(0, postcss_combine_media_query_1.default)()]).process(cssCode, {
12
+ from: undefined,
13
+ });
14
+ const light = (0, lightningcss_1.transform)({
15
+ filename: 'stylesheet.css',
16
+ code: Buffer.from(merged.css),
17
+ minify: process.env.NODE_ENV === 'production',
18
+ targets: {
19
+ safari: 16,
20
+ edge: 110,
21
+ firefox: 110,
22
+ chrome: 110,
23
+ },
24
+ });
25
+ return Buffer.from(light.code).toString('utf-8');
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/compiler",
3
- "version": "2.4.2",
3
+ "version": "3.0.0",
4
4
  "description": "Plumeria swc based compiler",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",
@@ -23,13 +23,16 @@
23
23
  "css": "./bin/css.js"
24
24
  },
25
25
  "dependencies": {
26
- "@rust-gear/glob": "^0.2.7",
27
- "@swc/core": "1.15.2",
28
- "find-up": "^8.0.0",
26
+ "rscute": "^1.1.5",
29
27
  "lightningcss": "^1.30.2",
30
28
  "postcss": "^8.5.6",
31
29
  "postcss-combine-media-query": "^2.1.0",
32
- "rscute": "^1.1.5"
30
+ "@plumeria/utils": "^3.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@swc/core": "1.15.2",
34
+ "zss-engine": "2.1.2",
35
+ "@plumeria/core": "^3.0.0"
33
36
  },
34
37
  "publishConfig": {
35
38
  "access": "public",
package/dist/extract.js DELETED
@@ -1,544 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generatedTsMap = void 0;
7
- exports.extractTSFile = extractTSFile;
8
- exports.extractVueAndSvelte = extractVueAndSvelte;
9
- const core_1 = require("@swc/core");
10
- const promises_1 = require("fs/promises");
11
- const path_1 = __importDefault(require("path"));
12
- const generatedTsMap = new Map();
13
- exports.generatedTsMap = generatedTsMap;
14
- function isInComment(code, position) {
15
- const beforePosition = code.substring(0, position);
16
- const lines = beforePosition.split('\n');
17
- const currentLine = lines[lines.length - 1];
18
- const singleLineCommentIndex = currentLine.indexOf('//');
19
- if (singleLineCommentIndex !== -1) {
20
- return true;
21
- }
22
- let inMultiLineComment = false;
23
- let i = 0;
24
- while (i < position) {
25
- if (code.substring(i, i + 2) === '/*') {
26
- inMultiLineComment = true;
27
- i += 2;
28
- }
29
- else if (code.substring(i, i + 2) === '*/') {
30
- inMultiLineComment = false;
31
- i += 2;
32
- }
33
- else {
34
- i++;
35
- }
36
- }
37
- return inMultiLineComment;
38
- }
39
- function isInVueAttribute(code, position) {
40
- let quotePosition = -1;
41
- for (let i = position - 1; i >= 0; i--) {
42
- const char = code[i];
43
- if (char === '"' || char === "'") {
44
- quotePosition = i;
45
- break;
46
- }
47
- }
48
- if (quotePosition === -1)
49
- return false;
50
- const beforeQuote = code.substring(Math.max(0, quotePosition - 30), quotePosition);
51
- const vueAttributePattern = /(:|v-bind:)(class|style)\s*=\s*$/;
52
- return vueAttributePattern.test(beforeQuote);
53
- }
54
- function isInString(code, position) {
55
- let inSingleQuote = false;
56
- let inDoubleQuote = false;
57
- let inBacktick = false;
58
- let escape = false;
59
- for (let i = 0; i < position; i++) {
60
- const char = code[i];
61
- if (escape) {
62
- escape = false;
63
- continue;
64
- }
65
- if (char === '\\') {
66
- escape = true;
67
- continue;
68
- }
69
- if (!inSingleQuote && !inDoubleQuote && !inBacktick) {
70
- if (char === "'") {
71
- inSingleQuote = true;
72
- }
73
- else if (char === '"') {
74
- inDoubleQuote = true;
75
- }
76
- else if (char === '`') {
77
- inBacktick = true;
78
- }
79
- }
80
- else {
81
- if (inSingleQuote && char === "'") {
82
- inSingleQuote = false;
83
- }
84
- else if (inDoubleQuote && char === '"') {
85
- inDoubleQuote = false;
86
- }
87
- else if (inBacktick && char === '`') {
88
- inBacktick = false;
89
- }
90
- }
91
- }
92
- const inStringLiteral = inSingleQuote || inDoubleQuote || inBacktick;
93
- if (inStringLiteral && isInVueAttribute(code, position))
94
- return false;
95
- return inStringLiteral;
96
- }
97
- function isInHtmlText(code, position) {
98
- let lastOpenTag = -1;
99
- let lastCloseTag = -1;
100
- for (let i = position - 1; i >= 0; i--) {
101
- if (code[i] === '>' && lastCloseTag === -1) {
102
- lastCloseTag = i;
103
- }
104
- if (code[i] === '<') {
105
- lastOpenTag = i;
106
- break;
107
- }
108
- }
109
- let nextOpenTag = -1;
110
- for (let i = position; i < code.length; i++) {
111
- if (code[i] === '<') {
112
- nextOpenTag = i;
113
- break;
114
- }
115
- }
116
- return lastCloseTag > lastOpenTag && nextOpenTag > position;
117
- }
118
- function expressionToString(expr) {
119
- switch (expr.type) {
120
- case 'Identifier':
121
- return expr.value;
122
- case 'MemberExpression': {
123
- const obj = expressionToString(expr.object);
124
- if (obj && expr.property.type === 'Identifier') {
125
- return `${obj}.${expr.property.value}`;
126
- }
127
- break;
128
- }
129
- case 'CallExpression': {
130
- if (expr.callee.type !== 'Super' && expr.callee.type !== 'Import') {
131
- const callee = expressionToString(expr.callee);
132
- if (callee) {
133
- const args = expr.arguments
134
- .map((arg) => expressionToString(arg.expression))
135
- .join(', ');
136
- return `${callee}(${args})`;
137
- }
138
- }
139
- break;
140
- }
141
- case 'ObjectExpression': {
142
- const properties = expr.properties
143
- .map((prop) => {
144
- if ('key' in prop && prop.key && prop.key.type === 'Identifier') {
145
- const key = prop.key.value;
146
- const value = expressionToString(prop.value);
147
- return `${key}: ${value}`;
148
- }
149
- return '[complex property]';
150
- })
151
- .join(', ');
152
- console.warn(`css.props: Argument unsupported ${expr.type}: { ${properties} } Use css.create instead.`);
153
- return '';
154
- }
155
- case 'StringLiteral':
156
- return String(expr.value);
157
- }
158
- console.warn(`css.props: Argument unsupported ${expr.type}: Use css.create instead.`);
159
- return '';
160
- }
161
- async function extractCreatedStyleKeys(ast) {
162
- const createdStylesMap = new Map();
163
- await visit(ast, {
164
- VariableDeclarator: (node) => {
165
- if (node.id.type === 'Identifier' &&
166
- node.init &&
167
- node.init.type === 'CallExpression' &&
168
- node.init.callee.type === 'MemberExpression' &&
169
- node.init.callee.object.type === 'Identifier' &&
170
- node.init.callee.object.value === 'css' &&
171
- node.init.callee.property.type === 'Identifier' &&
172
- node.init.callee.property.value === 'create' &&
173
- node.init.arguments.length > 0) {
174
- const variableName = node.id.value;
175
- const createArg = node.init.arguments[0].expression;
176
- if (createArg && createArg.type === 'ObjectExpression') {
177
- const keys = [];
178
- for (const prop of createArg.properties) {
179
- if (prop.type === 'KeyValueProperty' &&
180
- prop.key.type === 'Identifier') {
181
- keys.push(prop.key.value);
182
- }
183
- else if (prop.type === 'Identifier') {
184
- keys.push(prop.value);
185
- }
186
- }
187
- if (keys.length > 0) {
188
- createdStylesMap.set(variableName, keys);
189
- }
190
- }
191
- }
192
- },
193
- });
194
- return createdStylesMap;
195
- }
196
- async function extractCssProps(ast, code, createdStylesMap) {
197
- const propsMatches = [];
198
- if (code && !code.includes('css.props')) {
199
- return propsMatches;
200
- }
201
- try {
202
- await visit(ast, {
203
- CallExpression: async (node) => {
204
- if (node.callee.type === 'MemberExpression' &&
205
- node.callee.object.type === 'Identifier' &&
206
- node.callee.object.value === 'css' &&
207
- node.callee.property.type === 'Identifier' &&
208
- node.callee.property.value === 'props') {
209
- const staticArgs = [];
210
- const conditionalStyleObjects = [];
211
- for (const arg of node.arguments) {
212
- if (arg.expression) {
213
- if (arg.expression.type === 'ConditionalExpression' ||
214
- (arg.expression.type === 'BinaryExpression' &&
215
- arg.expression.operator === '&&')) {
216
- const styles = extractStyleObjectsFromExpression(arg.expression);
217
- conditionalStyleObjects.push(...styles);
218
- }
219
- else if (arg.expression.type === 'MemberExpression' &&
220
- arg.expression.property.type === 'Computed' &&
221
- arg.expression.object.type === 'Identifier') {
222
- const styleVarName = arg.expression.object.value;
223
- const styleKeys = createdStylesMap.get(styleVarName);
224
- if (styleKeys) {
225
- propsMatches.push(...styleKeys.map((key) => `css.props(${styleVarName}.${key})`));
226
- }
227
- }
228
- else {
229
- const argStr = expressionToString(arg.expression);
230
- if (argStr) {
231
- staticArgs.push(argStr);
232
- }
233
- }
234
- }
235
- }
236
- if (staticArgs.length > 0) {
237
- propsMatches.push(`css.props(${staticArgs.join(', ')})`);
238
- }
239
- for (const styleObj of conditionalStyleObjects) {
240
- if (styleObj &&
241
- styleObj !== 'false' &&
242
- styleObj !== 'null' &&
243
- styleObj !== 'undefined') {
244
- propsMatches.push(`css.props(${styleObj})`);
245
- }
246
- }
247
- }
248
- },
249
- });
250
- }
251
- catch (e) {
252
- console.error(`Failed to parse code to extract css.props: ${e}`);
253
- }
254
- return [...new Set(propsMatches)];
255
- }
256
- function extractStyleObjectsFromExpression(expression) {
257
- switch (expression.type) {
258
- case 'BinaryExpression':
259
- if (expression.operator === '&&') {
260
- return extractStyleObjectsFromExpression(expression.right);
261
- }
262
- break;
263
- case 'ConditionalExpression':
264
- return [
265
- ...extractStyleObjectsFromExpression(expression.consequent),
266
- ...extractStyleObjectsFromExpression(expression.alternate),
267
- ];
268
- case 'BooleanLiteral':
269
- case 'NullLiteral':
270
- return [];
271
- case 'Identifier':
272
- if (expression.value === 'undefined') {
273
- return [];
274
- }
275
- case 'ObjectExpression': {
276
- const str = expressionToString(expression);
277
- return str ? [str] : [];
278
- }
279
- }
280
- const str = expressionToString(expression);
281
- if (str) {
282
- return [str];
283
- }
284
- return [];
285
- }
286
- async function extractStaticStringLiteralVariable(ast) {
287
- const matches = [];
288
- try {
289
- for (const node of ast.body) {
290
- if (node.type === 'VariableDeclaration') {
291
- const allStringLiterals = node.declarations.length > 0 &&
292
- node.declarations.every((decl) => decl.init && decl.init.type === 'StringLiteral');
293
- if (allStringLiterals) {
294
- const { code: extractedCode } = await (0, core_1.print)({
295
- type: 'Module',
296
- body: [node],
297
- span: { start: 0, end: 0, ctxt: 0 },
298
- });
299
- matches.push(extractedCode.trim());
300
- }
301
- }
302
- }
303
- }
304
- catch (e) {
305
- console.error(`Failed to parse code to extract static string literal variables: ${e}`);
306
- }
307
- return matches.join('\n');
308
- }
309
- function extractCssPropsFromTemplate(code) {
310
- const matches = [];
311
- const regex = /css\.props\(([^)]*)\)/g;
312
- let match;
313
- while ((match = regex.exec(code)) !== null) {
314
- const matchStart = match.index;
315
- if (isInComment(code, matchStart) ||
316
- isInString(code, matchStart) ||
317
- isInHtmlText(code, matchStart)) {
318
- continue;
319
- }
320
- const scriptStartIndex = code.indexOf('<script');
321
- const scriptEndIndex = code.indexOf('</script>');
322
- if (scriptStartIndex !== -1 &&
323
- scriptEndIndex !== -1 &&
324
- match.index > scriptStartIndex &&
325
- match.index < scriptEndIndex) {
326
- continue;
327
- }
328
- const args = match[1];
329
- if (args && !args.includes('{') && !args.includes('(')) {
330
- matches.push(`css.props(${args})`);
331
- }
332
- }
333
- return matches;
334
- }
335
- async function visit(node, visitor) {
336
- if (!node)
337
- return;
338
- const visitorFunc = visitor[node.type];
339
- if (visitorFunc) {
340
- await visitorFunc(node);
341
- }
342
- for (const key in node) {
343
- if (typeof node[key] === 'object' && node[key] !== null) {
344
- if (Array.isArray(node[key])) {
345
- for (const child of node[key]) {
346
- await visit(child, visitor);
347
- }
348
- }
349
- else {
350
- await visit(node[key], visitor);
351
- }
352
- }
353
- }
354
- }
355
- function importDeclarationToString(node) {
356
- const source = node.source.value;
357
- const defaultImport = node.specifiers.find((s) => s.type === 'ImportDefaultSpecifier');
358
- const namespaceImport = node.specifiers.find((s) => s.type === 'ImportNamespaceSpecifier');
359
- const namedImports = node.specifiers.filter((s) => s.type === 'ImportSpecifier');
360
- let importClause = '';
361
- if (defaultImport) {
362
- importClause += defaultImport.local.value;
363
- }
364
- if (namespaceImport) {
365
- if (importClause)
366
- importClause += ', ';
367
- importClause += `* as ${namespaceImport.local.value}`;
368
- }
369
- if (namedImports.length > 0) {
370
- if (importClause)
371
- importClause += ', ';
372
- const namedParts = namedImports.map((spec) => {
373
- if (spec.imported && spec.imported.value !== spec.local.value) {
374
- return `${spec.imported.value} as ${spec.local.value}`;
375
- }
376
- return spec.local.value;
377
- });
378
- importClause += `{ ${namedParts.join(', ')} }`;
379
- }
380
- if (importClause) {
381
- return `import ${importClause} from '${source}';`;
382
- }
383
- return `import '${source}';`;
384
- }
385
- async function extractImportDeclarations(ast) {
386
- const importDeclarations = [];
387
- try {
388
- await visit(ast, {
389
- ImportDeclaration: (node) => {
390
- importDeclarations.push(importDeclarationToString(node));
391
- },
392
- });
393
- }
394
- catch (e) {
395
- console.error(`Failed to parse code to extract import declarations: ${e}`);
396
- }
397
- return importDeclarations.join('\n');
398
- }
399
- async function extractCssMethod(ast, methodName, code) {
400
- if (!code.includes(`css.${methodName}`)) {
401
- return '';
402
- }
403
- const matches = [];
404
- try {
405
- for (const node of ast.body) {
406
- if (node.type === 'VariableDeclaration') {
407
- const containsCssMethod = node.declarations.some((decl) => decl.init &&
408
- decl.init.type === 'CallExpression' &&
409
- decl.init.callee.type === 'MemberExpression' &&
410
- decl.init.callee.object.type === 'Identifier' &&
411
- decl.init.callee.object.value === 'css' &&
412
- decl.init.callee.property.type === 'Identifier' &&
413
- decl.init.callee.property.value === methodName);
414
- if (containsCssMethod && node.span) {
415
- const { code: extractedCode } = await (0, core_1.print)({
416
- type: 'Module',
417
- body: [node],
418
- span: { start: 0, end: 0, ctxt: 0 },
419
- });
420
- matches.push(extractedCode.trim());
421
- }
422
- }
423
- }
424
- }
425
- catch (e) {
426
- console.error(`Failed to parse code to extract css.${methodName}: ${e}`);
427
- }
428
- return matches.join('\n');
429
- }
430
- async function extractVueAndSvelte(filePath) {
431
- const ext = path_1.default.extname(filePath);
432
- if (!(ext === '.svelte' || ext === '.vue'))
433
- return filePath;
434
- const code = await (0, promises_1.readFile)(filePath, 'utf8');
435
- const lines = code.split(/\r?\n/);
436
- let inScript = false;
437
- const contentLines = [];
438
- for (const line of lines) {
439
- const trimmed = line.trim();
440
- if (!inScript && /^<script\b/.test(trimmed)) {
441
- inScript = true;
442
- continue;
443
- }
444
- if (inScript && /^<\/script>/.test(trimmed)) {
445
- inScript = false;
446
- continue;
447
- }
448
- if (inScript) {
449
- contentLines.push(line);
450
- }
451
- }
452
- const tsCode = contentLines.join('\n');
453
- const tsPath = filePath.replace(ext, '.ts');
454
- if (!tsCode.trim()) {
455
- generatedTsMap.set(filePath, '');
456
- return tsPath;
457
- }
458
- const ast = await (0, core_1.parse)(tsCode, {
459
- syntax: 'typescript',
460
- tsx: true,
461
- });
462
- const createdStylesMap = await extractCreatedStyleKeys(ast);
463
- const propsFromScript = await extractCssProps(ast, code, createdStylesMap);
464
- const propsFromTemplate = extractCssPropsFromTemplate(code);
465
- const propsMatches = [...new Set([...propsFromScript, ...propsFromTemplate])];
466
- const calls = propsMatches
467
- .filter(Boolean)
468
- .map((call) => `${call};`)
469
- .join('\n');
470
- const importSection = await extractImportDeclarations(ast);
471
- const staticVariableSection = await extractStaticStringLiteralVariable(ast);
472
- const cssCreateSection = await extractCssMethod(ast, 'create', code);
473
- const cssKeyframesSection = await extractCssMethod(ast, 'keyframes', code);
474
- const cssViewTransitionSection = await extractCssMethod(ast, 'viewTransition', code);
475
- const cssCreateStaticSection = await extractCssMethod(ast, 'createStatic', code);
476
- const cssCreateThemeSection = await extractCssMethod(ast, 'createTheme', code);
477
- let finalCode = '';
478
- if (importSection)
479
- finalCode += importSection + '\n';
480
- if (staticVariableSection)
481
- finalCode += staticVariableSection + '\n';
482
- if (cssKeyframesSection)
483
- finalCode += cssKeyframesSection + '\n';
484
- if (cssViewTransitionSection)
485
- finalCode += cssViewTransitionSection + '\n';
486
- if (cssCreateStaticSection)
487
- finalCode += cssCreateStaticSection + '\n';
488
- if (cssCreateThemeSection)
489
- finalCode += cssCreateThemeSection + '\n';
490
- if (cssCreateSection)
491
- finalCode += cssCreateSection + '\n';
492
- if (calls)
493
- finalCode += calls + '\n';
494
- generatedTsMap.set(filePath, finalCode);
495
- return filePath;
496
- }
497
- async function extractTSFile(filePath) {
498
- const code = await (0, promises_1.readFile)(filePath, 'utf8');
499
- const ast = await (0, core_1.parse)(code, {
500
- syntax: 'typescript',
501
- tsx: true,
502
- });
503
- const createdStylesMap = await extractCreatedStyleKeys(ast);
504
- const importSection = await extractImportDeclarations(ast);
505
- const staticVariableSection = await extractStaticStringLiteralVariable(ast);
506
- const cssCreateSection = await extractCssMethod(ast, 'create', code);
507
- const cssKeyframesSection = await extractCssMethod(ast, 'keyframes', code);
508
- const cssViewTransitionSection = await extractCssMethod(ast, 'viewTransition', code);
509
- const cssCreateStaticSection = await extractCssMethod(ast, 'createStatic', code);
510
- const cssCreateThemeSection = await extractCssMethod(ast, 'createTheme', code);
511
- const propsMatches = await extractCssProps(ast, code, createdStylesMap);
512
- const calls = propsMatches
513
- .filter(Boolean)
514
- .map((call) => `${call};`)
515
- .join('\n');
516
- let finalCode = '';
517
- if (importSection)
518
- finalCode += importSection + '\n';
519
- if (staticVariableSection)
520
- finalCode += staticVariableSection + '\n';
521
- if (cssKeyframesSection)
522
- finalCode += cssKeyframesSection + '\n';
523
- if (cssViewTransitionSection)
524
- finalCode += cssViewTransitionSection + '\n';
525
- if (cssCreateStaticSection)
526
- finalCode += cssCreateStaticSection + '\n';
527
- if (cssCreateThemeSection)
528
- finalCode += cssCreateThemeSection + '\n';
529
- if (cssCreateSection)
530
- finalCode += cssCreateSection + '\n';
531
- finalCode += calls;
532
- generatedTsMap.set(filePath, finalCode);
533
- return filePath;
534
- }
535
- process.on('uncaughtException', async (error) => {
536
- console.error('Uncaught Exception:', error);
537
- generatedTsMap.clear();
538
- process.exit(1);
539
- });
540
- process.on('unhandledRejection', async (reason, promise) => {
541
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
542
- generatedTsMap.clear();
543
- process.exit(1);
544
- });