@mulanjs/mulanjs 1.0.1-dev.20260227135307 → 1.0.1-dev.20260227173253

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.
Files changed (52) hide show
  1. package/dist/compiler/ast-parser.d.ts +48 -0
  2. package/dist/compiler/ast-parser.js +54 -9
  3. package/dist/compiler/compiler.d.ts +9 -0
  4. package/dist/compiler/compiler.js +45 -2
  5. package/dist/compiler/dom-compiler.d.ts +7 -0
  6. package/dist/compiler/dom-compiler.js +90 -33
  7. package/dist/compiler/script-compiler.d.ts +11 -0
  8. package/dist/compiler/script-compiler.js +108 -116
  9. package/dist/compiler/sfc-parser.d.ts +21 -0
  10. package/dist/compiler/ssr-compiler.d.ts +7 -0
  11. package/dist/compiler/ssr-compiler.js +142 -0
  12. package/dist/compiler/style-compiler.d.ts +8 -0
  13. package/dist/compiler/template-compiler.d.ts +8 -0
  14. package/dist/components/bloch-sphere.js +9 -3
  15. package/dist/components/infinity-list.js +7 -1
  16. package/dist/core/component.js +66 -15
  17. package/dist/core/hooks.js +53 -29
  18. package/dist/core/quantum.js +30 -17
  19. package/dist/core/query.js +11 -6
  20. package/dist/core/reactive.js +88 -7
  21. package/dist/core/renderer.js +9 -8
  22. package/dist/core/ssr.js +50 -0
  23. package/dist/core/surge.js +7 -2
  24. package/dist/core/vault.js +9 -5
  25. package/dist/index.js +63 -27
  26. package/dist/mulan.esm.js +187 -19
  27. package/dist/mulan.esm.js.map +1 -1
  28. package/dist/mulan.js +1890 -1590
  29. package/dist/mulan.js.map +1 -1
  30. package/dist/router/index.js +17 -10
  31. package/dist/security/sanitizer.js +5 -1
  32. package/dist/store/index.js +9 -5
  33. package/dist/types/ast-parser.d.ts +2 -0
  34. package/dist/types/compiler/ast-parser.d.ts +2 -0
  35. package/dist/types/compiler/compiler.d.ts +1 -0
  36. package/dist/types/compiler/ssr-compiler.d.ts +7 -0
  37. package/dist/types/compiler.d.ts +1 -0
  38. package/dist/types/components/bloch-sphere.d.ts +3 -1
  39. package/dist/types/components/infinity-list.d.ts +3 -1
  40. package/dist/types/core/component.d.ts +14 -0
  41. package/dist/types/core/reactive.d.ts +5 -1
  42. package/dist/types/core/renderer.d.ts +0 -1
  43. package/dist/types/core/ssr.d.ts +9 -0
  44. package/dist/types/index.d.ts +1 -0
  45. package/dist/types/ssr-compiler.d.ts +7 -0
  46. package/package.json +1 -1
  47. package/src/compiler/ast-parser.ts +62 -10
  48. package/src/compiler/compiler.ts +46 -1
  49. package/src/compiler/dom-compiler.ts +100 -34
  50. package/src/compiler/script-compiler.ts +117 -126
  51. package/src/compiler/ssr-compiler.ts +157 -0
  52. package/src/loader/index.js +12 -19
@@ -0,0 +1,157 @@
1
+ import { SFCDescriptor } from './sfc-parser';
2
+ import { ScriptCompileResult } from './script-compiler';
3
+ import { parse, Node, ElementNode, TextNode, InterpolationNode } from './ast-parser';
4
+
5
+ export interface SSRCompileResult {
6
+ code: string;
7
+ errors: string[];
8
+ }
9
+
10
+ export function compileToSSR(descriptor: SFCDescriptor, scriptResult: ScriptCompileResult, scopedId?: string): SSRCompileResult {
11
+ const template = descriptor.template;
12
+ if (!template) return { code: 'function render() { return ""; }', errors: [] };
13
+
14
+ const errors: string[] = [];
15
+ const ast = parse(template.content, errors);
16
+
17
+ // Simplistic Transformer (Options API bindings mapping)
18
+ const bindings = scriptResult.bindings || [];
19
+ const localScope: string[] = [];
20
+
21
+ let uidRef = { current: 0 };
22
+ const getUid = () => uidRef.current++;
23
+
24
+ let codeChunks: string[] = [];
25
+ ast.children.forEach(child => {
26
+ const chunk = generateSSRInstruction(child, bindings, localScope, getUid);
27
+ if (chunk) codeChunks.push(chunk);
28
+ });
29
+
30
+ // The render function generates a giant template literal
31
+ const bodyFn = `return \`${codeChunks.join('')}\`;`;
32
+
33
+ const renderFn = `function render() {
34
+ const _s = (v) => (v && typeof v === 'object' && 'value' in v) ? v.value : (v === null || v === undefined ? '' : v);
35
+ const _h = (v) => {
36
+ const val = _s(v);
37
+ if (val === null || val === undefined) return '';
38
+ if (typeof val !== 'string') return val;
39
+ if (typeof Mulan !== 'undefined' && Mulan.Security) {
40
+ return Mulan.Security.sanitize(val);
41
+ }
42
+ return val.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
43
+ };
44
+
45
+ ${bodyFn}
46
+ }`;
47
+
48
+ return {
49
+ code: renderFn,
50
+ errors
51
+ };
52
+ }
53
+
54
+ function processBindings(exp: string, bindings: string[], localScope: string[]) {
55
+ const isOptionsAPI = !bindings || bindings.length === 0;
56
+ const bindingSet = new Set(bindings || []);
57
+ return exp.replace(/\b([a-zA-Z_$][\w$]*)\b/g, (match, id, offset, str) => {
58
+ if (offset > 0 && str[offset - 1] === '.') return match;
59
+ // simplistic keyword check
60
+ if (['true', 'false', 'null', 'undefined', 'this', 'Math'].includes(id) || localScope.includes(id)) return match;
61
+ if (isOptionsAPI) return `this.${id}`;
62
+ if (bindingSet.has(id)) return `this.${id}`;
63
+ return match;
64
+ });
65
+ }
66
+
67
+ function generateSSRInstruction(node: Node, bindings: string[], localScope: string[], getUid: () => number): string {
68
+ if (node.type === 'Text') {
69
+ const text = node as TextNode;
70
+ // we can preserve interpolation \${ } because the outer string is also a template literal
71
+ // but we need to ensure the variables map to 'this'
72
+ if (text.content.includes('${')) {
73
+ let processed = text.content.replace(/\$\{(.*?)\}/g, (_: any, expr: string) => {
74
+ return `\${_h(${processBindings(expr, bindings, localScope)})}`;
75
+ });
76
+ return processed;
77
+ }
78
+ return text.content;
79
+ }
80
+
81
+ if (node.type === 'Interpolation') {
82
+ const interp = node as InterpolationNode;
83
+ return `\${_h(${processBindings(interp.content, bindings, localScope)})}`;
84
+ }
85
+
86
+ if (node.type === 'Element') {
87
+ const el = node as ElementNode;
88
+ const uid = getUid();
89
+ let html = `<${el.tag} data-mu-node-id="${uid}"`;
90
+
91
+ let vIfCondition = '';
92
+ let vForDirective: any = null;
93
+
94
+ for (const key in el.props) {
95
+ if (key === 'v-if' || key === 'mu-if') {
96
+ vIfCondition = processBindings(el.props[key], bindings, localScope);
97
+ continue;
98
+ }
99
+ if (key === 'v-for' || key === 'mu-for') {
100
+ const parts = el.props[key].split(' in ');
101
+ if (parts.length >= 2) {
102
+ vForDirective = { item: parts[0].trim(), list: processBindings(parts.slice(1).join(' in ').trim(), bindings, localScope) };
103
+ }
104
+ continue;
105
+ }
106
+
107
+ // Client side events are ignored in SSR HTML output
108
+ if (key.startsWith('@') || key.startsWith('v-on:') || key.startsWith('on')) {
109
+ // To support Resumability, we'd inject a serialize marker here
110
+ // html += ` mu-event="${key}"`;
111
+ continue;
112
+ }
113
+
114
+ let value = el.props[key];
115
+ if (key.startsWith(':') || key.startsWith('.')) {
116
+ let attrName = key.slice(1);
117
+ let expr = processBindings(value, bindings, localScope);
118
+ html += ` ${attrName}="\${_h(${expr})}"`;
119
+ } else {
120
+ if (value.includes('${')) {
121
+ value = value.replace(/\$\{(.*?)\}/g, (_: any, expr: string) => {
122
+ return `\${_h(${processBindings(expr, bindings, localScope)})}`;
123
+ });
124
+ html += ` ${key}="${value}"`;
125
+ } else {
126
+ html += ` ${key}="${value.replace(/"/g, '&quot;')}"`;
127
+ }
128
+ }
129
+ }
130
+
131
+ const isSelfClosing = ['img', 'br', 'input', 'hr', 'link', 'meta'].includes(el.tag.toLowerCase());
132
+ if (isSelfClosing) {
133
+ html += '/>';
134
+ } else {
135
+ html += '>';
136
+ for (const child of el.children) {
137
+ html += generateSSRInstruction(child, bindings, localScope, getUid);
138
+ }
139
+ html += `</${el.tag}>`;
140
+ }
141
+
142
+ // Apply wrappers for Control Flow (v-if / v-for)
143
+ if (vIfCondition) {
144
+ html = `\${(${vIfCondition}) ? \`${html}\` : '<!--mu-if-->'}`;
145
+ }
146
+
147
+ if (vForDirective) {
148
+ const { item, list } = vForDirective;
149
+ // The mapping function returns strings which we join
150
+ html = `\${(${list}).map((${item}, _index) => \`${html}\`).join('')}`;
151
+ }
152
+
153
+ return html;
154
+ }
155
+
156
+ return '';
157
+ }
@@ -25,34 +25,27 @@ module.exports = function (content) {
25
25
  }
26
26
  }
27
27
 
28
- // Resolve path to the compiled compiler module (ESM)
29
- // Assuming structure: dist/loader/index.js and dist/compiler/compiler.js
30
- // OR src/loader/index.js and dist/compiler/compiler.js
31
- // We'll target the dist folder for the compiler.
28
+ // Resolve path to the compiled compiler module (CJS)
32
29
  const compilerRef = path.resolve(__dirname, '../../dist/compiler/compiler.js');
33
- const compilerUrl = pathToFileURL(compilerRef).href;
34
-
35
- // Use dynamic import to load ESM compiler from CommonJS loader
36
- import(compilerUrl).then(async compiler => {
37
- try {
38
- const result = await compiler.compileSFC(content, filePath, {
39
- readFileSync: (file) => fs.readFileSync(file, 'utf-8')
40
- });
41
30
 
31
+ try {
32
+ const compiler = require(compilerRef);
33
+ compiler.compileSFC(content, filePath, {
34
+ readFileSync: (file) => fs.readFileSync(file, 'utf-8')
35
+ }).then(result => {
42
36
  if (result.errors && result.errors.length > 0) {
43
37
  this.emitError(new Error(result.errors.join('\n')));
44
38
  }
45
39
 
46
40
  // Pass source map to Webpack if available
47
- const map = result.map ? JSON.parse(result.map) : null;
41
+ const map = result.map ? (typeof result.map === 'string' ? JSON.parse(result.map) : result.map) : null;
48
42
  callback(null, result.code, map);
49
- } catch (e) {
43
+ }).catch(e => {
50
44
  callback(e);
51
- }
52
- }).catch(err => {
53
- // Fallback or helpful error
54
- console.error(`[MulanJS Loader] Failed to load compiler from ${compilerUrl}`);
45
+ });
46
+ } catch (err) {
47
+ console.error(`[MulanJS Loader] Failed to load compiler from ${compilerRef}`);
55
48
  console.error(`Make sure to run 'npm run build' to generate the compiler.`);
56
49
  callback(err);
57
- });
50
+ }
58
51
  };