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

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.
@@ -25,10 +25,21 @@ function parse(template, errors) {
25
25
  tag: 'fragment',
26
26
  props: {},
27
27
  children: [],
28
- directives: {}
28
+ directives: {},
29
+ startLine: 1,
30
+ startColumn: 0,
31
+ endLine: 1,
32
+ endColumn: 0
29
33
  };
30
34
  const stack = [root];
31
35
  let cursor = 0;
36
+ const getPos = (idx) => {
37
+ const lines = template.slice(0, idx).split('\n');
38
+ return {
39
+ startLine: lines.length,
40
+ startColumn: lines[lines.length - 1].length
41
+ };
42
+ };
32
43
  while (cursor < template.length) {
33
44
  const char = template[cursor];
34
45
  // 1. Comments
@@ -69,7 +80,18 @@ function parse(template, errors) {
69
80
  const tagContent = template.slice(cursor + 1, end);
70
81
  const { tag, props, directives } = parseTag(tagContent);
71
82
  const isSelfClosing = tagContent.endsWith('/') || ['img', 'br', 'input', 'hr', 'link', 'meta'].includes(tag.toLowerCase());
72
- const element = { type: 'Element', tag, props, children: [], directives };
83
+ const startPos = getPos(cursor);
84
+ const endPos = getPos(end + 1);
85
+ const element = {
86
+ type: 'Element',
87
+ tag,
88
+ props,
89
+ children: [],
90
+ directives,
91
+ ...startPos,
92
+ endLine: endPos.startLine,
93
+ endColumn: endPos.startColumn
94
+ };
73
95
  stack[stack.length - 1].children.push(element);
74
96
  if (!isSelfClosing) {
75
97
  stack.push(element);
@@ -85,7 +107,15 @@ function parse(template, errors) {
85
107
  break;
86
108
  }
87
109
  const content = template.slice(cursor + 2, end).trim();
88
- stack[stack.length - 1].children.push({ type: 'Interpolation', content });
110
+ const startPos = getPos(cursor);
111
+ const endPos = getPos(end + 2);
112
+ stack[stack.length - 1].children.push({
113
+ type: 'Interpolation',
114
+ content,
115
+ ...startPos,
116
+ endLine: endPos.startLine,
117
+ endColumn: endPos.startColumn
118
+ });
89
119
  cursor = end + 2;
90
120
  }
91
121
  // 4. Native Template Literals ${ } (Protection)
@@ -105,9 +135,20 @@ function parse(template, errors) {
105
135
  const lastChild = stack[stack.length - 1].children[stack[stack.length - 1].children.length - 1];
106
136
  if (lastChild && lastChild.type === 'Text') {
107
137
  lastChild.content += content;
138
+ const endPos = getPos(innerCursor);
139
+ lastChild.endLine = endPos.startLine;
140
+ lastChild.endColumn = endPos.startColumn;
108
141
  }
109
142
  else {
110
- stack[stack.length - 1].children.push({ type: 'Text', content });
143
+ const startPos = getPos(cursor);
144
+ const endPos = getPos(innerCursor);
145
+ stack[stack.length - 1].children.push({
146
+ type: 'Text',
147
+ content,
148
+ ...startPos,
149
+ endLine: endPos.startLine,
150
+ endColumn: endPos.startColumn
151
+ });
111
152
  }
112
153
  cursor = innerCursor;
113
154
  }
@@ -136,9 +177,20 @@ function parse(template, errors) {
136
177
  const lastChild = stack[stack.length - 1].children[stack[stack.length - 1].children.length - 1];
137
178
  if (lastChild && lastChild.type === 'Text') {
138
179
  lastChild.content += content;
180
+ const endPos = getPos(end);
181
+ lastChild.endLine = endPos.startLine;
182
+ lastChild.endColumn = endPos.startColumn;
139
183
  }
140
184
  else {
141
- stack[stack.length - 1].children.push({ type: 'Text', content });
185
+ const startPos = getPos(cursor);
186
+ const endPos = getPos(end);
187
+ stack[stack.length - 1].children.push({
188
+ type: 'Text',
189
+ content,
190
+ ...startPos,
191
+ endLine: endPos.startLine,
192
+ endColumn: endPos.startColumn
193
+ });
142
194
  }
143
195
  }
144
196
  cursor = end;
@@ -13,14 +13,21 @@ async function compileSFC(source, filename, options) {
13
13
  // 2. Script
14
14
  const scriptResult = await (0, script_compiler_1.compileScript)(descriptor, options);
15
15
  // Replace export default to capture the component
16
- // If the script already has 'export default', we intercept it.
17
- let scriptCode = scriptResult.code.replace('export default', 'const __component__ =');
18
- if (!scriptCode.includes('const __component__ =')) {
19
- scriptCode = scriptCode.replace(/export\s+default/, 'const __component__ =');
16
+ let scriptCode = scriptResult.code;
17
+ // Improved export capture
18
+ if (scriptCode.includes('export default')) {
19
+ scriptCode = scriptCode.replace('export default', 'const __component__ =');
20
20
  }
21
- if (!scriptCode.includes('const __component__ =')) {
21
+ else if (scriptCode.includes('exports.default =')) {
22
22
  scriptCode = scriptCode.replace('exports.default =', 'const __component__ =');
23
23
  }
24
+ else if (scriptCode.includes('module.exports =')) {
25
+ scriptCode = scriptCode.replace('module.exports =', 'const __component__ =');
26
+ }
27
+ else {
28
+ // Fallback for simple assignment
29
+ scriptCode += '\nconst __component__ = exports.default || module.exports || {};';
30
+ }
24
31
  // 3. Style
25
32
  const styleResult = (0, style_compiler_1.compileStyle)(descriptor, filename, options);
26
33
  // 4. Template (Use the new unified No-VDOM compiler!)
@@ -167,7 +174,7 @@ module.exports = __component__;
167
174
  code: finalCode,
168
175
  css: styleResult.css,
169
176
  errors: [...scriptResult.errors, ...templateResult.errors],
170
- map: mergedMap || scriptResult.map // Fallback to script map if merge fails
177
+ map: mergedMap || scriptResult.map || templateResult.map
171
178
  };
172
179
  }
173
180
  exports.compileSFC = compileSFC;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compileToDOM = void 0;
4
4
  const ast_parser_1 = require("./ast-parser");
5
+ const source_map_1 = require("source-map");
5
6
  function compileToDOM(descriptor, scriptResult, scopedId) {
6
7
  console.log(`[MulanJS DOM Compiler v2.0] Compiling template for: ${descriptor.filename || 'anonymous'}`);
7
8
  const template = descriptor.template;
@@ -21,9 +22,12 @@ function compileToDOM(descriptor, scriptResult, scopedId) {
21
22
  // We generate a DocumentFragment at the root
22
23
  let codeChunks = [];
23
24
  codeChunks.push(`const _frag = this._recoveryMode ? null : document.createDocumentFragment();`);
25
+ const generator = descriptor.filename ? new source_map_1.SourceMapGenerator({
26
+ file: descriptor.filename + '.template.js'
27
+ }) : null;
24
28
  // Generate code for all top-level children and append them to the fragment
25
29
  ast.children.forEach(child => {
26
- const rootId = generateDOMInstruction(child, codeChunks, getUid, getHoistId, hoists, uidRef, scriptResult.bindings || [], []);
30
+ const rootId = generateDOMInstruction(child, codeChunks, getUid, getHoistId, hoists, uidRef, scriptResult.bindings || [], [], generator, descriptor.filename);
27
31
  if (rootId) {
28
32
  codeChunks.push(`if (_frag) _frag.appendChild(${rootId});`);
29
33
  }
@@ -50,7 +54,8 @@ function compileToDOM(descriptor, scriptResult, scopedId) {
50
54
  }`;
51
55
  return {
52
56
  code: renderFn,
53
- errors
57
+ errors,
58
+ map: generator ? generator.toString() : undefined
54
59
  };
55
60
  }
56
61
  exports.compileToDOM = compileToDOM;
@@ -88,7 +93,22 @@ function htmlEscape(str) {
88
93
  .replace(/"/g, '&quot;')
89
94
  .replace(/'/g, '&#039;');
90
95
  }
91
- function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef, bindings, localScope) {
96
+ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef, bindings, localScope, generator, filename) {
97
+ const addMapping = (generatedLine) => {
98
+ if (generator && filename) {
99
+ generator.addMapping({
100
+ generated: {
101
+ line: generatedLine,
102
+ column: 0
103
+ },
104
+ original: {
105
+ line: node.startLine,
106
+ column: node.startColumn
107
+ },
108
+ source: filename
109
+ });
110
+ }
111
+ };
92
112
  // --- STATIC NODE HOISTING (THE COMPILER INTELLIGENCE) ---
93
113
  // If the node and ALL its children contain ZERO reactivity, we hoist it.
94
114
  if (node.type === 'Element' && node.isStatic) {
@@ -116,11 +136,13 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
116
136
  const numericId = uidRef.current - 1; // Not used for text nodes in SSR but kept for parity if needed
117
137
  // Native template literal interpolation
118
138
  if (text.content.includes('${')) {
139
+ addMapping(chunks.length + 1);
119
140
  chunks.push(`const ${id} = this._recoveryMode ? null : document.createTextNode("");`);
120
141
  // Wrap in effect for reactivity
121
142
  chunks.push(`this._bindEffect(() => { if (!${id}) return; ${id}.textContent = \`${text.content}\`; }, ${id});`);
122
143
  }
123
144
  else {
145
+ addMapping(chunks.length + 1);
124
146
  chunks.push(`const ${id} = this._recoveryMode ? null : document.createTextNode(${JSON.stringify(text.content)});`);
125
147
  }
126
148
  return id;
@@ -128,6 +150,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
128
150
  if (node.type === 'Interpolation') {
129
151
  const interp = node;
130
152
  const id = getUid();
153
+ addMapping(chunks.length + 1);
131
154
  chunks.push(`const ${id} = document.createTextNode("");`);
132
155
  // Fine-grained reactivity!
133
156
  chunks.push(`this._bindEffect(() => { ${id}.textContent = _h(${interp.content}, false); }, ${id});`);
@@ -151,7 +174,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
151
174
  let originalLength = blockChunks.length;
152
175
  // 2b. Generate the actual block
153
176
  const elementWithoutIf = { ...element, directives: { ...element.directives, vIf: undefined } };
154
- const clonedChildId = generateDOMInstruction(elementWithoutIf, blockChunks, getUid, getHoistId, hoists, uidRef, bindings, localScope);
177
+ const clonedChildId = generateDOMInstruction(elementWithoutIf, blockChunks, getUid, getHoistId, hoists, uidRef, bindings, localScope, generator, filename);
155
178
  if (clonedChildId) {
156
179
  blockChunks.push(`if (${blockId}_frag && ${clonedChildId} && !this._recoveryMode) ${blockId}_frag.appendChild(${clonedChildId});`);
157
180
  }
@@ -184,7 +207,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
184
207
  // 2b. Generate the actual repeating element (the template root of the mu-for)
185
208
  // We strip the vFor directive so it doesn't recurse infinitely
186
209
  const elementWithoutFor = { ...element, directives: { ...element.directives, vFor: undefined } };
187
- const clonedChildId = generateDOMInstruction(elementWithoutFor, rowChunks, getUid, getHoistId, hoists, uidRef, bindings, rowChildScope);
210
+ const clonedChildId = generateDOMInstruction(elementWithoutFor, rowChunks, getUid, getHoistId, hoists, uidRef, bindings, rowChildScope, generator, filename);
188
211
  if (clonedChildId) {
189
212
  rowChunks.push(`if (${rowId}_frag && ${clonedChildId} && !this._recoveryMode) ${rowId}_frag.appendChild(${clonedChildId});`);
190
213
  }
@@ -205,6 +228,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
205
228
  }
206
229
  const numericId = uidRef.current;
207
230
  const id = getUid();
231
+ addMapping(chunks.length + 1);
208
232
  chunks.push(`const ${id} = this._recoveryMode ? (this.container.getAttribute('data-mu-node-id') === "${numericId}" ? this.container : this.container.querySelector('[data-mu-node-id="${numericId}"]')) : document.createElement("${element.tag}");`);
209
233
  // Handle standard properties and classes
210
234
  for (const [key, value] of Object.entries(element.props)) {
@@ -252,7 +276,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
252
276
  // Recursively generate children
253
277
  const childScope = [...localScope];
254
278
  element.children.forEach(child => {
255
- const childId = generateDOMInstruction(child, chunks, getUid, getHoistId, hoists, uidRef, bindings, childScope);
279
+ const childId = generateDOMInstruction(child, chunks, getUid, getHoistId, hoists, uidRef, bindings, childScope, generator, filename);
256
280
  if (childId) {
257
281
  chunks.push(`if (${id} && ${childId} && !this._recoveryMode) ${id}.appendChild(${childId});`);
258
282
  }
@@ -29,8 +29,28 @@ const source_map_1 = require("source-map");
29
29
  const path = __importStar(require("path"));
30
30
  async function compileScript(descriptor, options) {
31
31
  const script = descriptor.script;
32
- if (!script)
33
- return { code: 'export default {}', errors: [] };
32
+ if (!script) {
33
+ let finalMap;
34
+ if (descriptor.filename) {
35
+ const generator = new source_map_1.SourceMapGenerator({
36
+ file: descriptor.filename
37
+ });
38
+ let relativePath = descriptor.filename.split(/[/\\]/).pop() || 'unknown.mujs';
39
+ const normalized = descriptor.filename.replace(/\\/g, '/');
40
+ const srcIdx = normalized.indexOf('/src/');
41
+ if (srcIdx !== -1) {
42
+ relativePath = 'webpack:///' + normalized.substring(srcIdx + 1);
43
+ }
44
+ generator.setSourceContent(relativePath, descriptor.source);
45
+ generator.addMapping({
46
+ generated: { line: 1, column: 0 },
47
+ original: { line: 1, column: 0 },
48
+ source: relativePath
49
+ });
50
+ finalMap = generator.toString();
51
+ }
52
+ return { code: 'export default {}', errors: [], map: finalMap };
53
+ }
34
54
  let content = script.content;
35
55
  let filename = descriptor.filename;
36
56
  let isExternal = false;
@@ -66,7 +66,7 @@ function parseMUJS(source, filename) {
66
66
  const content = source.slice(contentStart, contentEnd);
67
67
  const block = {
68
68
  type: tagName,
69
- content: content.trim(), // Trim content for cleanliness
69
+ content: content,
70
70
  attrs,
71
71
  start: start,
72
72
  end: contentEnd + closeTag.length
@@ -253,6 +253,6 @@ class MuBlochSphereElement extends MuBlochBase {
253
253
  }
254
254
  exports.MuBlochSphereElement = MuBlochSphereElement;
255
255
  // Register the custom element
256
- if (typeof customElements !== 'undefined') {
256
+ if (typeof customElements !== 'undefined' && !customElements.get('mu-bloch-sphere')) {
257
257
  customElements.define('mu-bloch-sphere', MuBlochSphereElement);
258
258
  }
package/dist/mulan.esm.js CHANGED
@@ -2318,7 +2318,7 @@ class MuBlochSphereElement extends MuBlochBase {
2318
2318
  }
2319
2319
  }
2320
2320
  // Register the custom element
2321
- if (typeof customElements !== 'undefined') {
2321
+ if (typeof customElements !== 'undefined' && !customElements.get('mu-bloch-sphere')) {
2322
2322
  customElements.define('mu-bloch-sphere', MuBlochSphereElement);
2323
2323
  }
2324
2324