pulse-js-framework 1.7.32 → 1.7.33
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/cli/index.js +0 -0
- package/cli/release.js +159 -22
- package/compiler/parser.js +93 -9
- package/compiler/transformer/expressions.js +26 -6
- package/loader/README.md +509 -0
- package/loader/esbuild-plugin.js +251 -0
- package/loader/parcel-plugin.js +216 -0
- package/loader/rollup-plugin.js +259 -0
- package/loader/swc-plugin.js +286 -0
- package/loader/webpack-loader.js +228 -0
- package/package.json +12 -2
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Rollup Plugin
|
|
3
|
+
*
|
|
4
|
+
* Enables .pulse file support in Rollup projects
|
|
5
|
+
* Extracts CSS and compiles to JavaScript with source maps
|
|
6
|
+
*
|
|
7
|
+
* CSS Preprocessor Support:
|
|
8
|
+
* - If `sass`, `less`, or `stylus` is installed in the user's project,
|
|
9
|
+
* preprocessor syntax in style blocks is automatically compiled
|
|
10
|
+
* - No configuration needed - just install the preprocessor package
|
|
11
|
+
*
|
|
12
|
+
* Usage in rollup.config.js:
|
|
13
|
+
* ```js
|
|
14
|
+
* import pulsePlugin from 'pulse-js-framework/rollup';
|
|
15
|
+
*
|
|
16
|
+
* export default {
|
|
17
|
+
* input: 'src/main.js',
|
|
18
|
+
* output: { file: 'dist/bundle.js', format: 'es' },
|
|
19
|
+
* plugins: [
|
|
20
|
+
* pulsePlugin({
|
|
21
|
+
* sourceMap: true,
|
|
22
|
+
* extractCss: 'dist/bundle.css',
|
|
23
|
+
* sass: { loadPaths: ['src/styles'] }
|
|
24
|
+
* })
|
|
25
|
+
* ]
|
|
26
|
+
* };
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { compile } from '../compiler/index.js';
|
|
31
|
+
import {
|
|
32
|
+
preprocessStylesSync,
|
|
33
|
+
isSassAvailable,
|
|
34
|
+
isLessAvailable,
|
|
35
|
+
isStylusAvailable,
|
|
36
|
+
getSassVersion,
|
|
37
|
+
getLessVersion,
|
|
38
|
+
getStylusVersion,
|
|
39
|
+
detectPreprocessor
|
|
40
|
+
} from '../compiler/preprocessor.js';
|
|
41
|
+
import { dirname } from 'path';
|
|
42
|
+
|
|
43
|
+
// Cache for preprocessor availability checks
|
|
44
|
+
let preprocessorCache = null;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check available preprocessors once
|
|
48
|
+
*/
|
|
49
|
+
function checkPreprocessors() {
|
|
50
|
+
if (preprocessorCache) return preprocessorCache;
|
|
51
|
+
|
|
52
|
+
preprocessorCache = {
|
|
53
|
+
sass: isSassAvailable(),
|
|
54
|
+
less: isLessAvailable(),
|
|
55
|
+
stylus: isStylusAvailable()
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return preprocessorCache;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create Pulse Rollup plugin
|
|
63
|
+
*/
|
|
64
|
+
export default function pulsePlugin(options = {}) {
|
|
65
|
+
const {
|
|
66
|
+
include = /\.pulse$/,
|
|
67
|
+
exclude = /node_modules/,
|
|
68
|
+
sourceMap = true,
|
|
69
|
+
extractCss = null, // Path to output CSS file, or null for inline
|
|
70
|
+
sass: sassOptions = {},
|
|
71
|
+
less: lessOptions = {},
|
|
72
|
+
stylus: stylusOptions = {}
|
|
73
|
+
} = options;
|
|
74
|
+
|
|
75
|
+
const filter = createFilter(include, exclude);
|
|
76
|
+
|
|
77
|
+
// Accumulated CSS from all .pulse files
|
|
78
|
+
let accumulatedCss = '';
|
|
79
|
+
let cssEmitted = false;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
name: 'pulse',
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Log preprocessor availability on build start
|
|
86
|
+
*/
|
|
87
|
+
buildStart() {
|
|
88
|
+
// Reset accumulated CSS
|
|
89
|
+
accumulatedCss = '';
|
|
90
|
+
cssEmitted = false;
|
|
91
|
+
|
|
92
|
+
// Check preprocessor availability
|
|
93
|
+
const available = checkPreprocessors();
|
|
94
|
+
const preprocessors = [];
|
|
95
|
+
|
|
96
|
+
if (available.sass) {
|
|
97
|
+
preprocessors.push(`SASS ${getSassVersion() || 'unknown'}`);
|
|
98
|
+
}
|
|
99
|
+
if (available.less) {
|
|
100
|
+
preprocessors.push(`LESS ${getLessVersion() || 'unknown'}`);
|
|
101
|
+
}
|
|
102
|
+
if (available.stylus) {
|
|
103
|
+
preprocessors.push(`Stylus ${getStylusVersion() || 'unknown'}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (preprocessors.length > 0) {
|
|
107
|
+
console.log(`[Pulse Rollup] Preprocessor support: ${preprocessors.join(', ')}`);
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Resolve .pulse files
|
|
113
|
+
*/
|
|
114
|
+
resolveId(id, importer) {
|
|
115
|
+
// Handle .pulse imports
|
|
116
|
+
if (id.endsWith('.pulse')) {
|
|
117
|
+
return null; // Let Rollup handle it
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check if a .js import has a corresponding .pulse file
|
|
121
|
+
if (id.endsWith('.js') && importer) {
|
|
122
|
+
const pulseId = id.replace(/\.js$/, '.pulse');
|
|
123
|
+
// Let Rollup's resolution handle this
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return null;
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Transform .pulse files to JavaScript
|
|
132
|
+
*/
|
|
133
|
+
transform(source, id) {
|
|
134
|
+
if (!filter(id)) return null;
|
|
135
|
+
if (!id.endsWith('.pulse')) return null;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Compile .pulse to JavaScript
|
|
139
|
+
const result = compile(source, {
|
|
140
|
+
runtime: 'pulse-js-framework/runtime',
|
|
141
|
+
sourceMap,
|
|
142
|
+
filename: id
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (!result.success) {
|
|
146
|
+
const errors = result.errors.map(e =>
|
|
147
|
+
`${e.message}${e.line ? ` at line ${e.line}` : ''}`
|
|
148
|
+
).join('\n');
|
|
149
|
+
|
|
150
|
+
this.error(`Pulse compilation failed:\n${errors}`);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let outputCode = result.code;
|
|
155
|
+
let outputMap = result.map;
|
|
156
|
+
|
|
157
|
+
// Extract CSS from compiled output
|
|
158
|
+
const stylesMatch = outputCode.match(/const styles = `([\s\S]*?)`;/);
|
|
159
|
+
|
|
160
|
+
if (stylesMatch) {
|
|
161
|
+
let css = stylesMatch[1];
|
|
162
|
+
|
|
163
|
+
// Check available preprocessors
|
|
164
|
+
const available = checkPreprocessors();
|
|
165
|
+
const preprocessor = detectPreprocessor(css);
|
|
166
|
+
|
|
167
|
+
// Preprocess if preprocessor detected and available
|
|
168
|
+
if (preprocessor !== 'none' && available[preprocessor]) {
|
|
169
|
+
try {
|
|
170
|
+
const preprocessorOptions = {
|
|
171
|
+
sass: sassOptions,
|
|
172
|
+
less: lessOptions,
|
|
173
|
+
stylus: stylusOptions
|
|
174
|
+
}[preprocessor];
|
|
175
|
+
|
|
176
|
+
const preprocessed = preprocessStylesSync(css, {
|
|
177
|
+
filename: id,
|
|
178
|
+
loadPaths: [dirname(id), ...(preprocessorOptions.loadPaths || [])],
|
|
179
|
+
compressed: preprocessorOptions.compressed || false,
|
|
180
|
+
preprocessor // Force detected preprocessor
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
css = preprocessed.css;
|
|
184
|
+
|
|
185
|
+
// Log preprocessor usage in verbose mode
|
|
186
|
+
if (preprocessorOptions.verbose) {
|
|
187
|
+
console.log(`[Pulse] Compiled ${preprocessor.toUpperCase()} in ${id}`);
|
|
188
|
+
}
|
|
189
|
+
} catch (preprocessorError) {
|
|
190
|
+
// Emit warning but continue with original CSS
|
|
191
|
+
this.warn(`${preprocessor.toUpperCase()} compilation warning: ${preprocessorError.message}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (extractCss) {
|
|
196
|
+
// Accumulate CSS for later emission
|
|
197
|
+
accumulatedCss += `/* ${id} */\n${css}\n\n`;
|
|
198
|
+
|
|
199
|
+
// Remove inline CSS injection from output
|
|
200
|
+
outputCode = outputCode.replace(
|
|
201
|
+
/\/\/ Styles\nconst styles = `[\s\S]*?`;\n\/\/ Inject styles\nconst styleEl = document\.createElement\("style"\);\nstyleEl\.textContent = styles;\ndocument\.head\.appendChild\(styleEl\);/,
|
|
202
|
+
'// Styles extracted to CSS file'
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
// else: keep inline CSS injection
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
code: outputCode,
|
|
210
|
+
map: sourceMap ? outputMap : null
|
|
211
|
+
};
|
|
212
|
+
} catch (error) {
|
|
213
|
+
this.error(`Pulse plugin error: ${error.message}`);
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Emit accumulated CSS as asset
|
|
220
|
+
*/
|
|
221
|
+
generateBundle() {
|
|
222
|
+
if (extractCss && accumulatedCss && !cssEmitted) {
|
|
223
|
+
this.emitFile({
|
|
224
|
+
type: 'asset',
|
|
225
|
+
fileName: extractCss,
|
|
226
|
+
source: accumulatedCss
|
|
227
|
+
});
|
|
228
|
+
cssEmitted = true;
|
|
229
|
+
console.log(`[Pulse] Emitted CSS to ${extractCss}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Create filter function for include/exclude patterns
|
|
237
|
+
* Simple implementation to avoid dependency on @rollup/pluginutils
|
|
238
|
+
*/
|
|
239
|
+
function createFilter(include, exclude) {
|
|
240
|
+
return (id) => {
|
|
241
|
+
// Check exclude first
|
|
242
|
+
if (exclude) {
|
|
243
|
+
if (exclude instanceof RegExp && exclude.test(id)) return false;
|
|
244
|
+
if (Array.isArray(exclude) && exclude.some(pattern =>
|
|
245
|
+
pattern instanceof RegExp ? pattern.test(id) : id.includes(pattern)
|
|
246
|
+
)) return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Check include
|
|
250
|
+
if (include) {
|
|
251
|
+
if (include instanceof RegExp) return include.test(id);
|
|
252
|
+
if (Array.isArray(include)) return include.some(pattern =>
|
|
253
|
+
pattern instanceof RegExp ? pattern.test(id) : id.includes(pattern)
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return true;
|
|
258
|
+
};
|
|
259
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse SWC Plugin
|
|
3
|
+
*
|
|
4
|
+
* Enables .pulse file support in SWC-based build pipelines
|
|
5
|
+
* Provides transform functions and a plugin interface for custom build scripts
|
|
6
|
+
*
|
|
7
|
+
* CSS Preprocessor Support:
|
|
8
|
+
* - If `sass`, `less`, or `stylus` is installed in the user's project,
|
|
9
|
+
* preprocessor syntax in style blocks is automatically compiled
|
|
10
|
+
* - No configuration needed - just install the preprocessor package
|
|
11
|
+
*
|
|
12
|
+
* Usage with direct transform API:
|
|
13
|
+
* ```js
|
|
14
|
+
* import { transformPulseFile } from 'pulse-js-framework/swc';
|
|
15
|
+
*
|
|
16
|
+
* const result = transformPulseFile('src/App.pulse', {
|
|
17
|
+
* sourceMap: true,
|
|
18
|
+
* sass: { loadPaths: ['src/styles'] }
|
|
19
|
+
* });
|
|
20
|
+
* console.log(result.code); // Compiled JavaScript
|
|
21
|
+
* console.log(result.css); // Extracted CSS (or null)
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Usage with plugin interface:
|
|
25
|
+
* ```js
|
|
26
|
+
* import pulsePlugin from 'pulse-js-framework/swc';
|
|
27
|
+
*
|
|
28
|
+
* const plugin = pulsePlugin({ extractCss: 'dist/bundle.css' });
|
|
29
|
+
* plugin.buildStart();
|
|
30
|
+
* const result = plugin.transform(source, 'src/App.pulse');
|
|
31
|
+
* plugin.buildEnd(); // Writes accumulated CSS
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Batch processing:
|
|
35
|
+
* ```js
|
|
36
|
+
* import { buildPulseFiles } from 'pulse-js-framework/swc';
|
|
37
|
+
*
|
|
38
|
+
* const results = buildPulseFiles(['src/App.pulse', 'src/Home.pulse'], {
|
|
39
|
+
* extractCss: 'dist/bundle.css'
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { compile } from '../compiler/index.js';
|
|
45
|
+
import {
|
|
46
|
+
preprocessStylesSync,
|
|
47
|
+
isSassAvailable,
|
|
48
|
+
isLessAvailable,
|
|
49
|
+
isStylusAvailable,
|
|
50
|
+
getSassVersion,
|
|
51
|
+
getLessVersion,
|
|
52
|
+
getStylusVersion,
|
|
53
|
+
detectPreprocessor
|
|
54
|
+
} from '../compiler/preprocessor.js';
|
|
55
|
+
import { dirname, resolve } from 'path';
|
|
56
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
57
|
+
|
|
58
|
+
// Cache for preprocessor availability checks
|
|
59
|
+
let preprocessorCache = null;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check available preprocessors once
|
|
63
|
+
*/
|
|
64
|
+
function checkPreprocessors() {
|
|
65
|
+
if (preprocessorCache) return preprocessorCache;
|
|
66
|
+
|
|
67
|
+
preprocessorCache = {
|
|
68
|
+
sass: isSassAvailable(),
|
|
69
|
+
less: isLessAvailable(),
|
|
70
|
+
stylus: isStylusAvailable()
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return preprocessorCache;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create Pulse SWC plugin
|
|
78
|
+
*/
|
|
79
|
+
export default function pulsePlugin(options = {}) {
|
|
80
|
+
const {
|
|
81
|
+
sourceMap = true,
|
|
82
|
+
extractCss = null, // Path to output CSS file, or null for inline
|
|
83
|
+
sass: sassOptions = {},
|
|
84
|
+
less: lessOptions = {},
|
|
85
|
+
stylus: stylusOptions = {}
|
|
86
|
+
} = options;
|
|
87
|
+
|
|
88
|
+
// Accumulated CSS from all .pulse files
|
|
89
|
+
let accumulatedCss = '';
|
|
90
|
+
let buildStarted = false;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
name: 'pulse',
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Reset accumulated CSS and log preprocessor availability
|
|
97
|
+
*/
|
|
98
|
+
buildStart() {
|
|
99
|
+
accumulatedCss = '';
|
|
100
|
+
|
|
101
|
+
if (!buildStarted) {
|
|
102
|
+
const available = checkPreprocessors();
|
|
103
|
+
const preprocessors = [];
|
|
104
|
+
|
|
105
|
+
if (available.sass) {
|
|
106
|
+
preprocessors.push(`SASS ${getSassVersion() || 'unknown'}`);
|
|
107
|
+
}
|
|
108
|
+
if (available.less) {
|
|
109
|
+
preprocessors.push(`LESS ${getLessVersion() || 'unknown'}`);
|
|
110
|
+
}
|
|
111
|
+
if (available.stylus) {
|
|
112
|
+
preprocessors.push(`Stylus ${getStylusVersion() || 'unknown'}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (preprocessors.length > 0) {
|
|
116
|
+
console.log(`[Pulse SWC] Preprocessor support: ${preprocessors.join(', ')}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
buildStarted = true;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Transform a .pulse file source to JavaScript
|
|
125
|
+
* @param {string} source - The .pulse file source code
|
|
126
|
+
* @param {string} filePath - The file path for error reporting and preprocessor resolution
|
|
127
|
+
* @returns {{ code: string|null, map: object|null, css: string|null, error: string|null }}
|
|
128
|
+
*/
|
|
129
|
+
transform(source, filePath) {
|
|
130
|
+
try {
|
|
131
|
+
// Compile .pulse to JavaScript
|
|
132
|
+
const result = compile(source, {
|
|
133
|
+
runtime: 'pulse-js-framework/runtime',
|
|
134
|
+
sourceMap,
|
|
135
|
+
filename: filePath
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (!result.success) {
|
|
139
|
+
const errors = result.errors.map(e =>
|
|
140
|
+
`${e.message}${e.line ? ` at line ${e.line}` : ''}`
|
|
141
|
+
).join('\n');
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
code: null,
|
|
145
|
+
map: null,
|
|
146
|
+
css: null,
|
|
147
|
+
error: `Pulse compilation failed:\n${errors}`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let outputCode = result.code;
|
|
152
|
+
let extractedCss = null;
|
|
153
|
+
|
|
154
|
+
// Extract CSS from compiled output
|
|
155
|
+
const stylesMatch = outputCode.match(/const styles = `([\s\S]*?)`;/);
|
|
156
|
+
|
|
157
|
+
if (stylesMatch) {
|
|
158
|
+
let css = stylesMatch[1];
|
|
159
|
+
|
|
160
|
+
// Check available preprocessors
|
|
161
|
+
const available = checkPreprocessors();
|
|
162
|
+
const preprocessor = detectPreprocessor(css);
|
|
163
|
+
|
|
164
|
+
// Preprocess if preprocessor detected and available
|
|
165
|
+
if (preprocessor !== 'none' && available[preprocessor]) {
|
|
166
|
+
try {
|
|
167
|
+
const preprocessorOptions = {
|
|
168
|
+
sass: sassOptions,
|
|
169
|
+
less: lessOptions,
|
|
170
|
+
stylus: stylusOptions
|
|
171
|
+
}[preprocessor];
|
|
172
|
+
|
|
173
|
+
const preprocessed = preprocessStylesSync(css, {
|
|
174
|
+
filename: filePath,
|
|
175
|
+
loadPaths: [dirname(filePath), ...(preprocessorOptions.loadPaths || [])],
|
|
176
|
+
compressed: preprocessorOptions.compressed || false,
|
|
177
|
+
preprocessor // Force detected preprocessor
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
css = preprocessed.css;
|
|
181
|
+
|
|
182
|
+
// Log preprocessor usage in verbose mode
|
|
183
|
+
if (preprocessorOptions.verbose) {
|
|
184
|
+
console.log(`[Pulse] Compiled ${preprocessor.toUpperCase()} in ${filePath}`);
|
|
185
|
+
}
|
|
186
|
+
} catch (preprocessorError) {
|
|
187
|
+
// Emit warning but continue with original CSS
|
|
188
|
+
console.warn(`[Pulse SWC] ${preprocessor.toUpperCase()} compilation warning: ${preprocessorError.message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
extractedCss = css;
|
|
193
|
+
|
|
194
|
+
if (extractCss) {
|
|
195
|
+
// Accumulate CSS for later emission
|
|
196
|
+
accumulatedCss += `/* ${filePath} */\n${css}\n\n`;
|
|
197
|
+
|
|
198
|
+
// Remove inline CSS injection from output
|
|
199
|
+
outputCode = outputCode.replace(
|
|
200
|
+
/\/\/ Styles\nconst styles = `[\s\S]*?`;\n\/\/ Inject styles\nconst styleEl = document\.createElement\("style"\);\nstyleEl\.textContent = styles;\ndocument\.head\.appendChild\(styleEl\);/,
|
|
201
|
+
'// Styles extracted to CSS file'
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
// else: keep inline CSS injection
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
code: outputCode,
|
|
209
|
+
map: result.sourceMap || null,
|
|
210
|
+
css: extractedCss,
|
|
211
|
+
error: null
|
|
212
|
+
};
|
|
213
|
+
} catch (error) {
|
|
214
|
+
return {
|
|
215
|
+
code: null,
|
|
216
|
+
map: null,
|
|
217
|
+
css: null,
|
|
218
|
+
error: `Pulse plugin error: ${error.message}`
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Write accumulated CSS to disk
|
|
225
|
+
* Call after all transforms are complete
|
|
226
|
+
*/
|
|
227
|
+
buildEnd() {
|
|
228
|
+
if (extractCss && accumulatedCss) {
|
|
229
|
+
try {
|
|
230
|
+
const cssPath = resolve(typeof extractCss === 'string' ? extractCss : 'dist/bundle.css');
|
|
231
|
+
const cssDir = dirname(cssPath);
|
|
232
|
+
mkdirSync(cssDir, { recursive: true });
|
|
233
|
+
writeFileSync(cssPath, accumulatedCss, 'utf8');
|
|
234
|
+
console.log(`[Pulse] Emitted CSS to ${extractCss}`);
|
|
235
|
+
} catch (writeError) {
|
|
236
|
+
console.error(`[Pulse] Failed to write CSS file: ${writeError.message}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Transform a .pulse file to JavaScript (standalone function)
|
|
245
|
+
* @param {string} filePath - Path to the .pulse file
|
|
246
|
+
* @param {object} options - Plugin options
|
|
247
|
+
* @returns {{ code: string|null, map: object|null, css: string|null, error: string|null }}
|
|
248
|
+
*/
|
|
249
|
+
export function transformPulseFile(filePath, options = {}) {
|
|
250
|
+
const resolvedPath = resolve(filePath);
|
|
251
|
+
const source = readFileSync(resolvedPath, 'utf8');
|
|
252
|
+
return transformPulseCode(source, { ...options, filename: resolvedPath });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Transform .pulse source code to JavaScript (standalone function)
|
|
257
|
+
* @param {string} source - The .pulse source code
|
|
258
|
+
* @param {object} options - Plugin options (plus optional `filename`)
|
|
259
|
+
* @returns {{ code: string|null, map: object|null, css: string|null, error: string|null }}
|
|
260
|
+
*/
|
|
261
|
+
export function transformPulseCode(source, options = {}) {
|
|
262
|
+
const { filename = 'unknown.pulse', ...pluginOptions } = options;
|
|
263
|
+
const plugin = pulsePlugin({ ...pluginOptions, extractCss: null });
|
|
264
|
+
return plugin.transform(source, filename);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Batch process multiple .pulse files
|
|
269
|
+
* @param {string[]} files - Array of .pulse file paths
|
|
270
|
+
* @param {object} options - Plugin options
|
|
271
|
+
* @returns {Array<{ file: string, code: string|null, map: object|null, css: string|null, error: string|null }>}
|
|
272
|
+
*/
|
|
273
|
+
export function buildPulseFiles(files, options = {}) {
|
|
274
|
+
const plugin = pulsePlugin(options);
|
|
275
|
+
plugin.buildStart();
|
|
276
|
+
|
|
277
|
+
const results = files.map(filePath => {
|
|
278
|
+
const resolvedPath = resolve(filePath);
|
|
279
|
+
const source = readFileSync(resolvedPath, 'utf8');
|
|
280
|
+
const result = plugin.transform(source, resolvedPath);
|
|
281
|
+
return { file: filePath, ...result };
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
plugin.buildEnd();
|
|
285
|
+
return results;
|
|
286
|
+
}
|