@mulanjs/mulanjs 1.0.1-dev.20260219221500 → 1.0.1-dev.20260220121828
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/README.md +4 -2
- package/dist/compiler/compiler.js +81 -4
- package/dist/compiler/script-compiler.js +158 -21
- package/dist/compiler/style-compiler.js +61 -4
- package/dist/compiler/template-compiler.js +44 -4
- package/dist/core/quantum.js +74 -9
- package/dist/core/query.js +12 -2
- package/dist/core/surge.js +92 -0
- package/dist/core/vault.js +6 -25
- package/dist/index.js +4 -2
- package/dist/mulan.esm.js +225 -43
- package/dist/mulan.js +14 -4
- package/dist/types/compiler/compiler.d.ts +2 -1
- package/dist/types/compiler/script-compiler.d.ts +4 -1
- package/dist/types/compiler/style-compiler.d.ts +2 -1
- package/dist/types/compiler/template-compiler.d.ts +1 -0
- package/dist/types/compiler.d.ts +2 -1
- package/dist/types/core/quantum.d.ts +28 -0
- package/dist/types/core/query.d.ts +6 -6
- package/dist/types/core/surge.d.ts +21 -0
- package/dist/types/core/vault.d.ts +0 -1
- package/dist/types/index.d.ts +16 -6
- package/dist/types/script-compiler.d.ts +4 -1
- package/dist/types/style-compiler.d.ts +2 -1
- package/dist/types/template-compiler.d.ts +1 -0
- package/package.json +1 -1
- package/src/compiler/compiler.ts +90 -5
- package/src/compiler/script-compiler.ts +189 -21
- package/src/compiler/style-compiler.ts +28 -4
- package/src/compiler/template-compiler.ts +52 -4
- package/src/loader/index.js +16 -41
package/README.md
CHANGED
|
@@ -16,7 +16,6 @@ MulanJS is a high-performance, next-generation web framework designed to bridge
|
|
|
16
16
|
> Coming soon!
|
|
17
17
|
|
|
18
18
|
### 🚧 Development Release (Bleeding Edge)
|
|
19
|
-
**Current Version**: `1.0.1-dev.20260219221500`
|
|
20
19
|
|
|
21
20
|
Want to try the latest features before they are stable? Use the development build.
|
|
22
21
|
|
|
@@ -33,7 +32,7 @@ npm install @mulanjs/mulanjs@dev
|
|
|
33
32
|
## ⚡ Core Features
|
|
34
33
|
|
|
35
34
|
* **Signal Reactivity Engine** ⚡: Fine-grained reactivity that tracks exact dependencies, eliminating the need for a Virtual DOM.
|
|
36
|
-
* **ASTR-Q+ Engine** 🌌: Simulated quantum registers
|
|
35
|
+
* **ASTR-Q+ Engine** 🌌: Simulated quantum registers with **Quantum Loops** (`muParallel`, `muSwitch`) for complex probabilistic branching.
|
|
37
36
|
* **Iron Fortress Security** 🛡️: Built-in "Iron Fortress" security module that auto-sanitizes inputs and generates CSP headers.
|
|
38
37
|
* **Mulan Cycle** 🔄: A redefined component lifecycle (Init, Mount, Destroy) for predictable state management.
|
|
39
38
|
* **TypeScript First** 🟦: Built from the ground up with TypeScript for world-class type safety.
|
|
@@ -57,6 +56,9 @@ State that survives refreshes using `muVault`. Your data, secured in the Iron Fo
|
|
|
57
56
|
### Mulan Router (Time Travel) 🧭
|
|
58
57
|
Zero-config hash routing with `<mu-link>` for instant, single-page navigation.
|
|
59
58
|
|
|
59
|
+
### Mulan Surge (High Performance) 🚀
|
|
60
|
+
Adaptive non-blocking loops (`muBurst`) and true multicore parallelism (`muSurge`) to handle billions of records at 60fps.
|
|
61
|
+
|
|
60
62
|
### Native SCSS Support 🎨
|
|
61
63
|
Built-in support for `<style lang="scss">`. No config required. Just design.
|
|
62
64
|
## 🚀 Quick Start Example
|
|
@@ -5,11 +5,12 @@ const sfc_parser_1 = require("./sfc-parser");
|
|
|
5
5
|
const script_compiler_1 = require("./script-compiler");
|
|
6
6
|
const template_compiler_1 = require("./template-compiler");
|
|
7
7
|
const style_compiler_1 = require("./style-compiler");
|
|
8
|
-
|
|
8
|
+
const source_map_1 = require("source-map");
|
|
9
|
+
async function compileSFC(source, filename, options) {
|
|
9
10
|
// 1. Parse
|
|
10
11
|
const descriptor = (0, sfc_parser_1.parseMUJS)(source, filename);
|
|
11
12
|
// 2. Script
|
|
12
|
-
const scriptResult = await (0, script_compiler_1.compileScript)(descriptor);
|
|
13
|
+
const scriptResult = await (0, script_compiler_1.compileScript)(descriptor, options);
|
|
13
14
|
// Replace export default to capture the component
|
|
14
15
|
// If the script already has 'export default', we intercept it.
|
|
15
16
|
let scriptCode = scriptResult.code.replace('export default', 'const __component__ =');
|
|
@@ -17,9 +18,85 @@ async function compileSFC(source, filename) {
|
|
|
17
18
|
scriptCode = scriptCode.replace(/export\s+default/, 'const __component__ =');
|
|
18
19
|
}
|
|
19
20
|
// 3. Style
|
|
20
|
-
const styleResult = (0, style_compiler_1.compileStyle)(descriptor, filename);
|
|
21
|
+
const styleResult = (0, style_compiler_1.compileStyle)(descriptor, filename, options);
|
|
21
22
|
// 4. Template
|
|
22
23
|
const templateResult = (0, template_compiler_1.compileTemplate)(descriptor, scriptResult, styleResult.scopedId);
|
|
24
|
+
// Calculate offsets for source map merging
|
|
25
|
+
// 1. Script Code
|
|
26
|
+
// 2. Padding (newlines)
|
|
27
|
+
// 3. Template Code
|
|
28
|
+
// We need to count lines in scriptCode to know where template code starts in the final file
|
|
29
|
+
const scriptLineCount = scriptCode.split(/\r?\n/).length;
|
|
30
|
+
const paddingLines = 2; // Two newlines between script and template
|
|
31
|
+
const templateOffset = scriptLineCount + paddingLines;
|
|
32
|
+
let mergedMap;
|
|
33
|
+
// Merge Maps
|
|
34
|
+
if (filename) {
|
|
35
|
+
const generator = new source_map_1.SourceMapGenerator({
|
|
36
|
+
file: filename + '.js',
|
|
37
|
+
});
|
|
38
|
+
// 1. Apply Script Map
|
|
39
|
+
if (scriptResult.map) {
|
|
40
|
+
const scriptConsumer = await new source_map_1.SourceMapConsumer(JSON.parse(scriptResult.map));
|
|
41
|
+
scriptConsumer.eachMapping(mapping => {
|
|
42
|
+
if (mapping.source) {
|
|
43
|
+
generator.addMapping({
|
|
44
|
+
generated: {
|
|
45
|
+
line: mapping.generatedLine, // Script is at the top, so no offset needed
|
|
46
|
+
column: mapping.generatedColumn
|
|
47
|
+
},
|
|
48
|
+
original: {
|
|
49
|
+
line: mapping.originalLine,
|
|
50
|
+
column: mapping.originalColumn
|
|
51
|
+
},
|
|
52
|
+
source: mapping.source,
|
|
53
|
+
name: mapping.name
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Copy source content from script map
|
|
58
|
+
if (scriptConsumer.sources) {
|
|
59
|
+
scriptConsumer.sources.forEach(sourceFile => {
|
|
60
|
+
const content = scriptConsumer.sourceContentFor(sourceFile);
|
|
61
|
+
if (content) {
|
|
62
|
+
generator.setSourceContent(sourceFile, content);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
scriptConsumer.destroy();
|
|
67
|
+
}
|
|
68
|
+
// 2. Apply Template Map
|
|
69
|
+
if (templateResult.map) {
|
|
70
|
+
const templateConsumer = await new source_map_1.SourceMapConsumer(JSON.parse(templateResult.map));
|
|
71
|
+
templateConsumer.eachMapping(mapping => {
|
|
72
|
+
if (mapping.source) {
|
|
73
|
+
generator.addMapping({
|
|
74
|
+
generated: {
|
|
75
|
+
line: mapping.generatedLine + templateOffset, // Shift by script length
|
|
76
|
+
column: mapping.generatedColumn
|
|
77
|
+
},
|
|
78
|
+
original: {
|
|
79
|
+
line: mapping.originalLine, // Original line in .mujs
|
|
80
|
+
column: mapping.originalColumn
|
|
81
|
+
},
|
|
82
|
+
source: mapping.source, // This should be the .mujs file
|
|
83
|
+
name: mapping.name
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// Copy source content from template map
|
|
88
|
+
if (templateConsumer.sources) {
|
|
89
|
+
templateConsumer.sources.forEach(sourceFile => {
|
|
90
|
+
const content = templateConsumer.sourceContentFor(sourceFile);
|
|
91
|
+
if (content) {
|
|
92
|
+
generator.setSourceContent(sourceFile, content);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
templateConsumer.destroy();
|
|
97
|
+
}
|
|
98
|
+
mergedMap = generator.toString();
|
|
99
|
+
}
|
|
23
100
|
// 5. Assembly
|
|
24
101
|
const cssInjection = styleResult.css ? `
|
|
25
102
|
if (typeof document !== 'undefined') {
|
|
@@ -86,6 +163,6 @@ export default __component__;
|
|
|
86
163
|
code: finalCode,
|
|
87
164
|
css: styleResult.css,
|
|
88
165
|
errors: [...scriptResult.errors, ...templateResult.errors],
|
|
89
|
-
map: scriptResult.map //
|
|
166
|
+
map: mergedMap || scriptResult.map // Fallback to script map if merge fails
|
|
90
167
|
};
|
|
91
168
|
}
|
|
@@ -36,27 +36,55 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.compileScript = compileScript;
|
|
37
37
|
const ts = __importStar(require("typescript"));
|
|
38
38
|
const source_map_1 = require("source-map");
|
|
39
|
-
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
async function compileScript(descriptor, options) {
|
|
40
41
|
const script = descriptor.script;
|
|
41
42
|
if (!script)
|
|
42
43
|
return { code: 'export default {}', errors: [] };
|
|
44
|
+
let content = script.content;
|
|
45
|
+
let filename = descriptor.filename;
|
|
46
|
+
let isExternal = false;
|
|
47
|
+
let externalPath = '';
|
|
48
|
+
// Handle External Script
|
|
49
|
+
if (script.attrs.src) {
|
|
50
|
+
if (options && options.readFileSync) {
|
|
51
|
+
try {
|
|
52
|
+
// Resolve path relative to the SFC file
|
|
53
|
+
const sfcDir = path.dirname(descriptor.filename);
|
|
54
|
+
externalPath = path.resolve(sfcDir, script.attrs.src);
|
|
55
|
+
content = options.readFileSync(externalPath);
|
|
56
|
+
// Keep filename as .mujs for now, but we will use externalPath for source mapping of the content
|
|
57
|
+
// Actually, if we want the external file to show up as ITSELF in devtools, we should map to externalPath.
|
|
58
|
+
isExternal = true;
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
return { code: 'export default {}', errors: [`Failed to read external script: ${e.message}`] };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return { code: 'export default {}', errors: [`External script found but no readFileSync option provided.`] };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
43
68
|
const isSetup = !!script.attrs.setup;
|
|
44
|
-
const isTs = script.attrs.lang === 'ts' || script.attrs.lang === 'tsx';
|
|
69
|
+
const isTs = script.attrs.lang === 'ts' || script.attrs.lang === 'tsx' || externalPath.endsWith('.ts') || externalPath.endsWith('.tsx');
|
|
45
70
|
if (isSetup) {
|
|
46
|
-
return await compileSetupScript(script, isTs, descriptor);
|
|
71
|
+
return await compileSetupScript(script, isTs, descriptor, content, filename, isExternal, externalPath);
|
|
72
|
+
}
|
|
73
|
+
else if (isTs) {
|
|
74
|
+
return await compileStandardScript(script, descriptor, content, filename, isExternal, externalPath);
|
|
47
75
|
}
|
|
48
76
|
else {
|
|
49
77
|
// Standard Options API - just pass through, assuming it has export default
|
|
50
|
-
return { code:
|
|
78
|
+
return { code: content, errors: [] };
|
|
51
79
|
}
|
|
52
80
|
}
|
|
53
81
|
// Global list of Mulan hooks for auto-imports and reactivity exemption
|
|
54
82
|
const COMMON_HOOKS = ['muState', 'onMuMount', 'onMuInit', 'onMuDestroy', 'muEffect', 'muMemo', 'muQubit', 'muGate', 'muMeasure', 'muRegister', 'muEntangle', 'persistent'];
|
|
55
|
-
async function compileSetupScript(script, isTs, descriptor) {
|
|
83
|
+
async function compileSetupScript(script, isTs, descriptor, content, filename, isExternal, externalPath) {
|
|
56
84
|
var _a;
|
|
57
85
|
// 1. Pre-process: Natural Reactivity Transformation ($ syntax)
|
|
58
86
|
// We do this BEFORE extraction so that the rest of the compiler sees standard 'muState' code.
|
|
59
|
-
const transformedContent = transformNaturalReactivity(
|
|
87
|
+
const transformedContent = transformNaturalReactivity(content, isTs);
|
|
60
88
|
// 2. Parse the TRANSFORMED code
|
|
61
89
|
const sourceFile = ts.createSourceFile('script.' + (isTs ? 'ts' : 'js'), transformedContent, ts.ScriptTarget.Latest, true);
|
|
62
90
|
const imports = [];
|
|
@@ -129,7 +157,6 @@ async function compileSetupScript(script, isTs, descriptor) {
|
|
|
129
157
|
const autoImportStmt = autoImports.length > 0
|
|
130
158
|
? `import { ${autoImports.join(', ')} } from '@mulanjs/mulanjs';`
|
|
131
159
|
: '';
|
|
132
|
-
const filename = descriptor.filename;
|
|
133
160
|
const componentName = filename ? ((_a = filename.split(/[/\\]/).pop()) === null || _a === void 0 ? void 0 : _a.split('.')[0].replace(/\W/g, '')) || 'App' : 'App';
|
|
134
161
|
const bindingString = bindings.length > 0
|
|
135
162
|
? `
|
|
@@ -171,27 +198,53 @@ export default ${hasDefineComponent ? 'defineComponent' : '_defineComponent'}({
|
|
|
171
198
|
});
|
|
172
199
|
// Fix: Remove the //# sourceMappingURL= comment added by TS
|
|
173
200
|
const codeWithoutMapComment = result.outputText.replace(/\/\/# sourceMappingURL=.*$/gm, '');
|
|
174
|
-
// Enhance Source Map to show ORIGINAL .mujs content
|
|
201
|
+
// Enhance Source Map to show ORIGINAL .mujs content or EXTERNAL content
|
|
175
202
|
let finalMap = result.sourceMapText;
|
|
176
203
|
if (finalMap) {
|
|
177
204
|
try {
|
|
178
205
|
// Determine offsets
|
|
179
206
|
const preambleLines = preamble.split('\n').length - 1;
|
|
180
207
|
// scriptBody starts at line `preambleLines` (0-indexed) in finalCode.
|
|
181
|
-
// Determine where script starts
|
|
182
|
-
|
|
183
|
-
|
|
208
|
+
// Determine where script starts
|
|
209
|
+
// If External: Start at 0
|
|
210
|
+
// If Inline: Start at script.start line
|
|
211
|
+
let linesBeforeScript = 0;
|
|
212
|
+
let originalSource = content;
|
|
213
|
+
if (!isExternal) {
|
|
214
|
+
originalSource = descriptor.source;
|
|
215
|
+
linesBeforeScript = originalSource.substring(0, script.start).split('\n').length - 1;
|
|
216
|
+
}
|
|
184
217
|
const consumer = await new source_map_1.SourceMapConsumer(finalMap);
|
|
185
218
|
const generator = new source_map_1.SourceMapGenerator({
|
|
186
219
|
file: filename,
|
|
187
220
|
sourceRoot: ''
|
|
188
221
|
});
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
222
|
+
// Determine relative path for source
|
|
223
|
+
let relativePath = filename.split(/[/\\]/).pop() || 'unknown.mujs'; // Default to basename
|
|
224
|
+
if (isExternal) {
|
|
225
|
+
// For external files, we want Source Map to point to the actual TS file
|
|
226
|
+
// externalPath is absolute. Make it relative to project root or something reasonable?
|
|
227
|
+
// Webpack often likes 'webpack:///[resource-path]'
|
|
228
|
+
// We'll try to map it so it looks like a separate file
|
|
229
|
+
const normalized = externalPath.replace(/\\/g, '/');
|
|
230
|
+
const srcIdx = normalized.indexOf('/src/');
|
|
231
|
+
if (srcIdx !== -1) {
|
|
232
|
+
relativePath = 'webpack:///' + normalized.substring(srcIdx + 1); // e.g. webpack:///src/logic.ts
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
relativePath = 'webpack:///' + path.basename(externalPath);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Inline: Point to .mujs file
|
|
240
|
+
const normalized = filename.replace(/\\/g, '/');
|
|
241
|
+
const srcIdx = normalized.indexOf('/src/');
|
|
242
|
+
if (srcIdx !== -1) {
|
|
243
|
+
relativePath = 'webpack:///' + normalized.substring(srcIdx + 1); // e.g. webpack:///src/App.mujs
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// If inline, we set source content of .mujs (the whole file)
|
|
247
|
+
// If external, we set source content of the .ts file
|
|
195
248
|
generator.setSourceContent(relativePath, originalSource);
|
|
196
249
|
consumer.eachMapping(m => {
|
|
197
250
|
if (m.originalLine === null)
|
|
@@ -205,9 +258,10 @@ export default ${hasDefineComponent ? 'defineComponent' : '_defineComponent'}({
|
|
|
205
258
|
if (lineInFinalCode > preambleLines) {
|
|
206
259
|
// Calculate offset inside scriptBody
|
|
207
260
|
const lineOffsetInBody = lineInFinalCode - preambleLines; // 1-based offset (1st line of body is 1)
|
|
208
|
-
// Calculate original line
|
|
209
|
-
// If lineOffsetInBody is
|
|
210
|
-
|
|
261
|
+
// Calculate original line
|
|
262
|
+
// If External: lineOffsetInBody is the line number
|
|
263
|
+
// If Inline: linesBeforeScript + lineOffsetInBody
|
|
264
|
+
const originalLine = linesBeforeScript + lineOffsetInBody;
|
|
211
265
|
// Add mapping
|
|
212
266
|
generator.addMapping({
|
|
213
267
|
generated: {
|
|
@@ -215,7 +269,7 @@ export default ${hasDefineComponent ? 'defineComponent' : '_defineComponent'}({
|
|
|
215
269
|
column: m.generatedColumn
|
|
216
270
|
},
|
|
217
271
|
original: {
|
|
218
|
-
line:
|
|
272
|
+
line: originalLine,
|
|
219
273
|
column: m.originalColumn // Column should be preserved if we didn't change indentation
|
|
220
274
|
},
|
|
221
275
|
source: relativePath,
|
|
@@ -244,6 +298,89 @@ export default ${hasDefineComponent ? 'defineComponent' : '_defineComponent'}({
|
|
|
244
298
|
map: undefined
|
|
245
299
|
};
|
|
246
300
|
}
|
|
301
|
+
async function compileStandardScript(script, descriptor, content, filename, isExternal, externalPath) {
|
|
302
|
+
// For standard script, we also might need source map if we transpiled it (e.g. from TS)
|
|
303
|
+
// and/or just to map it back to .mujs
|
|
304
|
+
let finalMap;
|
|
305
|
+
let code = content;
|
|
306
|
+
// Transpile if TS
|
|
307
|
+
if (externalPath.endsWith('.ts') || script.attrs.lang === 'ts') {
|
|
308
|
+
const result = ts.transpileModule(content, {
|
|
309
|
+
compilerOptions: {
|
|
310
|
+
module: ts.ModuleKind.ESNext,
|
|
311
|
+
target: ts.ScriptTarget.ES2019,
|
|
312
|
+
sourceMap: true,
|
|
313
|
+
inlineSources: true,
|
|
314
|
+
},
|
|
315
|
+
fileName: filename
|
|
316
|
+
});
|
|
317
|
+
code = result.outputText.replace(/\/\/# sourceMappingURL=.*$/gm, '');
|
|
318
|
+
finalMap = result.sourceMapText;
|
|
319
|
+
}
|
|
320
|
+
// Adjust Source Map
|
|
321
|
+
if (finalMap) {
|
|
322
|
+
try {
|
|
323
|
+
// Standard script content is usually 1:1 with source lines if we ignore transpilation shifts (which TS handles)
|
|
324
|
+
// But if it's inline, TS thinks it starts at line 0. We need to shift it by `linesBeforeScript`.
|
|
325
|
+
let linesBeforeScript = 0;
|
|
326
|
+
let originalSource = content;
|
|
327
|
+
if (!isExternal) {
|
|
328
|
+
originalSource = descriptor.source;
|
|
329
|
+
linesBeforeScript = descriptor.source.substring(0, script.start).split('\n').length - 1;
|
|
330
|
+
}
|
|
331
|
+
const consumer = await new source_map_1.SourceMapConsumer(finalMap);
|
|
332
|
+
const generator = new source_map_1.SourceMapGenerator({
|
|
333
|
+
file: filename,
|
|
334
|
+
sourceRoot: ''
|
|
335
|
+
});
|
|
336
|
+
// Determine relative path for source (same logic as Setup)
|
|
337
|
+
let relativePath = filename.split(/[/\\]/).pop() || 'unknown.mujs';
|
|
338
|
+
if (isExternal) {
|
|
339
|
+
const normalized = externalPath.replace(/\\/g, '/');
|
|
340
|
+
const srcIdx = normalized.indexOf('/src/');
|
|
341
|
+
if (srcIdx !== -1) {
|
|
342
|
+
relativePath = 'webpack:///' + normalized.substring(srcIdx + 1);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
relativePath = 'webpack:///' + path.basename(externalPath);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
const normalized = filename.replace(/\\/g, '/');
|
|
350
|
+
const srcIdx = normalized.indexOf('/src/');
|
|
351
|
+
if (srcIdx !== -1) {
|
|
352
|
+
relativePath = 'webpack:///' + normalized.substring(srcIdx + 1);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
generator.setSourceContent(relativePath, originalSource);
|
|
356
|
+
consumer.eachMapping(m => {
|
|
357
|
+
if (m.originalLine === null)
|
|
358
|
+
return;
|
|
359
|
+
const originalLine = m.originalLine + linesBeforeScript;
|
|
360
|
+
generator.addMapping({
|
|
361
|
+
generated: {
|
|
362
|
+
line: m.generatedLine,
|
|
363
|
+
column: m.generatedColumn
|
|
364
|
+
},
|
|
365
|
+
original: {
|
|
366
|
+
line: originalLine,
|
|
367
|
+
column: m.originalColumn
|
|
368
|
+
},
|
|
369
|
+
source: relativePath,
|
|
370
|
+
name: m.name
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
finalMap = generator.toString();
|
|
374
|
+
consumer.destroy();
|
|
375
|
+
}
|
|
376
|
+
catch (e) { /* ignore */ }
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
code: code,
|
|
380
|
+
errors: [],
|
|
381
|
+
map: finalMap
|
|
382
|
+
};
|
|
383
|
+
}
|
|
247
384
|
// --- Natural Reactivity Transformer ---
|
|
248
385
|
function transformNaturalReactivity(code, isTs) {
|
|
249
386
|
// If no '$(' or '$q(' or '$qr(' usage, return original code for safety/speed
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.compileStyle = compileStyle;
|
|
4
|
-
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
function compileStyle(descriptor, filename, options) {
|
|
5
39
|
const styles = descriptor.styles;
|
|
6
40
|
if (!styles || styles.length === 0)
|
|
7
41
|
return { css: '', errors: [] };
|
|
@@ -9,18 +43,41 @@ function compileStyle(descriptor, filename) {
|
|
|
9
43
|
const scopedId = 'data-v-' + hash(filename);
|
|
10
44
|
styles.forEach(style => {
|
|
11
45
|
let content = style.content;
|
|
46
|
+
// Handle External Style
|
|
47
|
+
if (style.attrs.src) {
|
|
48
|
+
if (options && options.readFileSync) {
|
|
49
|
+
try {
|
|
50
|
+
const sfcDir = path.dirname(filename);
|
|
51
|
+
const externalPath = path.resolve(sfcDir, style.attrs.src);
|
|
52
|
+
content = options.readFileSync(externalPath);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
// Start error with "Style Compilation Error" to be consistent? Or just add to errors list.
|
|
56
|
+
// But we are inside forEach, so we can't return easily. We'll add a comment in CSS or log.
|
|
57
|
+
// Better to collect errors.
|
|
58
|
+
// But function signature returns { errors: string[] }.
|
|
59
|
+
// We'll just append to errors? But we need to change forEach loop or use functional approach.
|
|
60
|
+
// For now, let's just ignore/log in CSS content?
|
|
61
|
+
content = `/* Failed to read external style: ${e.message} */`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
content = `/* External style found but no readFileSync option provided */`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
12
68
|
if (style.attrs.scoped) {
|
|
13
69
|
// SCSS Compilation
|
|
14
|
-
if (style.attrs.lang === 'scss' || style.attrs.lang === 'sass') {
|
|
70
|
+
if (style.attrs.lang === 'scss' || style.attrs.lang === 'sass' || (style.attrs.src && (style.attrs.src.endsWith('.scss') || style.attrs.src.endsWith('.sass')))) {
|
|
15
71
|
try {
|
|
16
72
|
const sass = require('sass');
|
|
17
73
|
const result = sass.compileString(content, {
|
|
18
|
-
syntax: style.attrs.lang === 'sass' ? 'indented' : 'scss'
|
|
74
|
+
syntax: (style.attrs.lang === 'sass' || (style.attrs.src && style.attrs.src.endsWith('.sass'))) ? 'indented' : 'scss'
|
|
19
75
|
});
|
|
20
76
|
content = result.css;
|
|
21
77
|
}
|
|
22
78
|
catch (e) {
|
|
23
|
-
return { css: '', errors: [`SCSS Compilation Error: ${e.message}`] };
|
|
79
|
+
// return { css: '', errors: [`SCSS Compilation Error: ${e.message}`] };
|
|
80
|
+
content = `/* SCSS Compilation Error: ${e.message} */`;
|
|
24
81
|
}
|
|
25
82
|
}
|
|
26
83
|
// Rewrite selectors
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.compileTemplate = compileTemplate;
|
|
4
|
+
// --- Compile Function ---
|
|
5
|
+
const source_map_1 = require("source-map");
|
|
4
6
|
function compileTemplate(descriptor, scriptResult, scopedId) {
|
|
5
7
|
console.log(`[MulanJS Compiler v1.0.1-dev.2] Compiling template for: ${descriptor.filename || 'anonymous'}`);
|
|
6
8
|
const template = descriptor.template;
|
|
@@ -14,8 +16,7 @@ function compileTemplate(descriptor, scriptResult, scopedId) {
|
|
|
14
16
|
transform(ast, scriptResult, scopedId, [], descriptor.filename);
|
|
15
17
|
// 3. Codegen Phase (AST -> JS Function)
|
|
16
18
|
const code = generate(ast, scriptResult.bindings || []);
|
|
17
|
-
|
|
18
|
-
code: `function render() {
|
|
19
|
+
const renderFn = `function render() {
|
|
19
20
|
const _s = (v) => (v && typeof v === 'object' && 'value' in v) ? v.value : v;
|
|
20
21
|
const _h = (v, raw) => {
|
|
21
22
|
const val = _s(v);
|
|
@@ -27,8 +28,47 @@ function compileTemplate(descriptor, scriptResult, scopedId) {
|
|
|
27
28
|
return val.replace(/</g, '<').replace(/>/g, '>');
|
|
28
29
|
};
|
|
29
30
|
return ${code};
|
|
30
|
-
}
|
|
31
|
-
|
|
31
|
+
}`;
|
|
32
|
+
// 4. Source Map Generation
|
|
33
|
+
// We map the entire render function to the starting line of the template in the source file
|
|
34
|
+
let map = undefined;
|
|
35
|
+
if (descriptor.filename) {
|
|
36
|
+
const generator = new source_map_1.SourceMapGenerator({
|
|
37
|
+
file: descriptor.filename + '.template.js', // Virtual file name
|
|
38
|
+
});
|
|
39
|
+
// Find start line of template in original source
|
|
40
|
+
// descriptor.template.start is the index of content start
|
|
41
|
+
const sourceBefore = descriptor.source.substring(0, template.start);
|
|
42
|
+
const startLine = sourceBefore.split(/\r?\n/).length;
|
|
43
|
+
// Simple mapping: One-to-one mapping isn't easy without AST location tracking
|
|
44
|
+
// But we can map the 'return' statement to the template start
|
|
45
|
+
// The render function has about 12 lines of preamble.
|
|
46
|
+
// Let's just mapping the whole block to the start line for now.
|
|
47
|
+
// This ensures the file shows up in devtools.
|
|
48
|
+
generator.addMapping({
|
|
49
|
+
generated: { line: 1, column: 0 },
|
|
50
|
+
source: descriptor.filename, // This should be the .mujs file path
|
|
51
|
+
original: { line: startLine, column: 0 }
|
|
52
|
+
});
|
|
53
|
+
// Also map the return line (approx line 12)
|
|
54
|
+
generator.addMapping({
|
|
55
|
+
generated: { line: 12, column: 0 },
|
|
56
|
+
source: descriptor.filename,
|
|
57
|
+
original: { line: startLine, column: 0 }
|
|
58
|
+
});
|
|
59
|
+
// We must include the "source content" so DevTools can display it!
|
|
60
|
+
// IMPORTANT: We want the FULL .mujs content here, so it matches what Webpack sees?
|
|
61
|
+
// Actually, if we use the same filename as script-compiler, they might conflict or merge.
|
|
62
|
+
// Script compiler uses 'webpack:///...'
|
|
63
|
+
// Let's use the same convention.
|
|
64
|
+
// But we just use the filename here, compiler.ts will handle the final path adjustment if needed.
|
|
65
|
+
generator.setSourceContent(descriptor.filename, descriptor.source);
|
|
66
|
+
map = generator.toString();
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
code: renderFn,
|
|
70
|
+
errors,
|
|
71
|
+
map
|
|
32
72
|
};
|
|
33
73
|
}
|
|
34
74
|
// --- Parser (Recursive Descent) ---
|