@mbler/mcx-core 0.1.2-rc.9 → 0.1.3-rc.2

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/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import { n as __require, t as __exportAll } from "./chunk-DEq-mXcV.js";
1
+ import { n as __require, t as __exportAll } from "./chunk-D0rfrjR5.js";
2
2
  import * as Module from "node:module";
3
3
  import { createRequire } from "node:module";
4
+ import { NodeTypes, baseParse } from "@vue/compiler-core";
4
5
  import * as path from "node:path";
5
6
  import { extname } from "node:path";
6
7
  import * as t from "@babel/types";
@@ -16,295 +17,165 @@ import * as vm from "node:vm";
16
17
  import { Buffer } from "node:buffer";
17
18
  import { existsSync, readFileSync } from "node:fs";
18
19
  import { styleText } from "node:util";
19
- import { BlockComponent, BlockComponent as BlockComponent$1, EntityComponent, EntityComponent as EntityComponent$1, GIFImageComponent, GIFImageComponent as GIFImageComponent$1, ItemComponent, ItemComponent as ItemComponent$1, JPGImageComponent, JPGImageComponent as JPGImageComponent$1, PNGImageComponent, PNGImageComponent as PNGImageComponent$1, SVGImageComponent, SVGImageComponent as SVGImageComponent$1 } from "@mbler/mcx-component";
20
20
  import MagicString from "magic-string";
21
+
21
22
  //#region src/ast/tag.ts
22
- function createPos(line, column) {
23
+ function getExpressionContent(expr) {
24
+ return expr?.content ?? "true";
25
+ }
26
+ /** Convert absolute character offset in source to MCX position (line: 1-indexed, column: 0-indexed) */
27
+ function absOffsetToMCXPos(source, absOffset) {
28
+ let line = 1;
29
+ let col = 0;
30
+ const len = Math.min(absOffset, source.length);
31
+ for (let i = 0; i < len; i++) if (source.charCodeAt(i) === 10) {
32
+ line++;
33
+ col = 0;
34
+ } else col++;
23
35
  return {
24
36
  line,
25
- column
37
+ column: col
26
38
  };
27
39
  }
28
- var Tokenizer = class {
29
- text;
30
- constructor(text) {
31
- this.text = text;
32
- }
33
- *splitTokens() {
34
- const text = this.text;
35
- let i = 0;
36
- let line = 1;
37
- let column = 0;
38
- const len = text.length;
39
- while (i < len) if (text[i] === "<") {
40
- if (text.startsWith("!--", i + 1)) {
41
- const commentStart = i;
42
- const tokenStartLine = line;
43
- const tokenStartColumn = column;
44
- const endIdx = text.indexOf("-->", i + 4);
45
- const commentEnd = endIdx === -1 ? len - 1 : endIdx + 2;
46
- for (let j = i; j <= commentEnd; j++) if (text[j] === "\n") {
47
- line++;
48
- column = 0;
49
- } else column++;
50
- yield {
51
- data: text.slice(commentStart, commentEnd + 1),
52
- type: "Comment",
53
- start: createPos(tokenStartLine, tokenStartColumn),
54
- end: createPos(line, column)
55
- };
56
- i = commentEnd + 1;
57
- if (i < len && text[i] === ">") column++;
58
- continue;
59
- }
60
- const tokenStart = i;
61
- const tokenStartLine = line;
62
- const tokenStartColumn = column;
63
- let j = i + 1;
64
- let sawGt = false;
65
- for (; j < len; j++) {
66
- const c = text[j];
67
- if (c === ">") {
68
- sawGt = true;
69
- break;
70
- }
71
- if (c === "\n") {
72
- line++;
73
- column = 0;
74
- } else column++;
75
- }
76
- const buffer = text.slice(tokenStart, sawGt ? j + 1 : len);
77
- yield {
78
- data: buffer,
79
- type: buffer.startsWith("</") ? "TagEnd" : "Tag",
80
- start: createPos(tokenStartLine, tokenStartColumn),
81
- end: createPos(line, column)
82
- };
83
- i = sawGt ? j + 1 : len;
84
- if (sawGt) column++;
85
- } else {
86
- const contentStart = i;
87
- const contentStartLine = line;
88
- const contentStartColumn = column;
89
- let j = i;
90
- for (; j < len; j++) {
91
- const c = text[j];
92
- if (c === "<") break;
93
- if (c === "\n") {
94
- line++;
95
- column = 0;
96
- } else column++;
97
- }
98
- yield {
99
- data: text.slice(contentStart, j),
100
- type: "Content",
101
- start: createPos(contentStartLine, contentStartColumn),
102
- end: createPos(line, j > contentStart ? column - 1 : column)
103
- };
104
- i = j;
105
- }
106
- }
107
- };
108
- var Lexer$1 = class {
40
+ var McxAst = class McxAst {
109
41
  text;
110
42
  includeComments;
111
- booleanProxyCache;
112
43
  constructor(text, includeComments = false) {
113
44
  this.text = text;
114
45
  this.includeComments = includeComments;
115
- this.booleanProxyCache = /* @__PURE__ */ new WeakMap();
116
46
  }
117
- *tokenStream() {
118
- const tokenizer = new Tokenizer(this.text);
119
- for (const token of Array.from(tokenizer.splitTokens())) {
120
- if (!this.includeComments && token.type === "Comment") continue;
121
- yield token;
47
+ parseAST() {
48
+ const ast = baseParse(this.text, {
49
+ comments: true,
50
+ whitespace: "preserve"
51
+ });
52
+ const result = [];
53
+ for (const child of ast.children) {
54
+ const node = this.convertTemplateChild(child);
55
+ if (node && node.type === "TagNode") result.push(node);
122
56
  }
57
+ return result;
123
58
  }
124
- /**
125
- * 生成 Token 迭代器,用于遍历所有结构化 Token
126
- */
127
- *tokenIterator() {
128
- yield* this.tokenStream();
129
- }
130
- get tokens() {
131
- return { [Symbol.iterator]: () => this.tokenIterator() };
132
- }
133
- /**
134
- * 创建一个动态布尔属性访问的 Proxy(可选功能)
135
- */
136
- getBooleanCheckProxy() {
137
- if (!this.booleanProxyCache.has(this)) {
138
- const charMap = /* @__PURE__ */ new Map();
139
- const proxy = new Proxy({}, {
140
- get(_, prop) {
141
- if (typeof prop !== "string") return false;
142
- return charMap.get(prop) || false;
143
- },
144
- set(_, prop, value) {
145
- if (typeof prop !== "string") return false;
146
- charMap.set(prop, Boolean(value));
147
- return true;
59
+ convertTemplateChild(node) {
60
+ if (node.type === NodeTypes.ELEMENT) return this.convertVueElement(node);
61
+ if (node.type === NodeTypes.TEXT) {
62
+ const textNode = node;
63
+ if (textNode.content.trim()) return {
64
+ data: textNode.content,
65
+ type: "TagContent"
66
+ };
67
+ return null;
68
+ }
69
+ if (node.type === NodeTypes.INTERPOLATION) return {
70
+ data: `{{ ${getExpressionContent(node.content)} }}`,
71
+ type: "TagContent"
72
+ };
73
+ if (this.includeComments && node.type === NodeTypes.COMMENT) {
74
+ const commentNode = node;
75
+ return {
76
+ data: commentNode.content,
77
+ type: "Comment",
78
+ loc: {
79
+ start: {
80
+ line: commentNode.loc.start.line,
81
+ column: commentNode.loc.start.column
82
+ },
83
+ end: {
84
+ line: commentNode.loc.end.line,
85
+ column: commentNode.loc.end.column
86
+ }
148
87
  }
149
- });
150
- this.booleanProxyCache.set(this, proxy);
88
+ };
151
89
  }
152
- return this.booleanProxyCache.get(this);
153
- }
154
- };
155
- /** Parser - 负责将Token流解析为AST */
156
- var Parser$1 = class {
157
- lexer;
158
- constructor(lexer) {
159
- this.lexer = lexer;
90
+ return null;
160
91
  }
161
- /**
162
- * 解析标签属性,如:<div id="app" disabled />
163
- */
164
- parseAttributes(tagContent) {
165
- const attributes = {};
166
- let currentKey = "";
167
- let currentValue = "";
168
- let inKey = true;
169
- let name = "";
170
- let inValue = false;
171
- let quoteChar = null;
172
- let isTagName = true;
173
- for (let i = 0; i < tagContent.length; i++) {
174
- const char = tagContent[i];
175
- if (isTagName) {
176
- if (char === " " || char === ">") {
177
- name = currentKey.trim();
178
- currentKey = "";
179
- isTagName = false;
180
- if (char === ">") break;
181
- } else currentKey += char;
182
- continue;
92
+ convertVueElement(node) {
93
+ const attrs = {};
94
+ for (const prop of node.props) if (prop.type === NodeTypes.ATTRIBUTE) {
95
+ const attr = prop;
96
+ attrs[attr.name] = attr.value?.content ?? "true";
97
+ } else if (prop.type === NodeTypes.DIRECTIVE) {
98
+ const dir = prop;
99
+ if (dir.name === "bind") {
100
+ const key = `:${getExpressionContent(dir.arg)}`;
101
+ attrs[key] = getExpressionContent(dir.exp);
102
+ } else if (dir.name === "on") {
103
+ const key = `@${getExpressionContent(dir.arg)}`;
104
+ attrs[key] = "true";
183
105
  }
184
- if (inValue) if (char === quoteChar && (currentValue.length === 0 || currentValue[currentValue.length - 1] !== "\\")) {
185
- attributes[currentKey.trim()] = currentValue;
186
- currentKey = "";
187
- currentValue = "";
188
- inKey = true;
189
- inValue = false;
190
- quoteChar = null;
191
- } else currentValue += char;
192
- else if (char === "=" && inKey) {
193
- inKey = false;
194
- inValue = true;
195
- const nextIndex = i + 1;
196
- const nextChar = nextIndex < tagContent.length ? tagContent[nextIndex] : " ";
197
- if (nextChar === "\"" || nextChar === "'") {
198
- quoteChar = nextChar;
199
- i = nextIndex;
200
- } else quoteChar = " ";
201
- } else if (char === " " && inKey && currentKey) {
202
- attributes[currentKey.trim()] = "true";
203
- currentKey = "";
204
- } else if (inKey) currentKey += char;
205
106
  }
206
- if (isTagName) name = currentKey.trim();
207
- else if (currentKey) attributes[currentKey.trim()] = inValue ? currentValue.replace(/^["']/, "").replace(/["']$/, "") : "true";
208
- return {
209
- name,
210
- arr: attributes
211
- };
212
- }
213
- /**
214
- * 基于stack的解析以支持嵌套,并为ParsedTagNode添加loc: { start, end }
215
- * Content和Comment改为递归节点数组 (ParsedTagContentNode | ParsedCommentNode | ParsedTagNode)[]
216
- */
217
- *parseAST() {
218
- const rawTokens = Array.from(this.lexer.tokenStream());
219
- const root = [];
220
- const stack = [];
221
- for (let idx = 0; idx < rawTokens.length; idx++) {
222
- const token = rawTokens[idx];
223
- if (!token) continue;
224
- if (token.type === "Content") {
225
- const contentNode = {
226
- data: token.data,
227
- type: "TagContent"
228
- };
229
- if (stack.length > 0) stack[stack.length - 1].content.push(contentNode);
230
- else root.push(contentNode);
231
- } else if (token.type === "Comment") {
232
- const commentNode = {
233
- data: token.data,
234
- type: "Comment",
235
- loc: {
236
- start: { ...token.start },
237
- end: { ...token.end }
238
- }
239
- };
240
- if (stack.length > 0) stack[stack.length - 1].content.push(commentNode);
241
- else root.push(commentNode);
242
- } else if (token.type === "Tag") {
243
- const inner = token.data.slice(1, -1).trim();
244
- const isSelfClosing = inner.endsWith("/");
245
- const arr = this.parseAttributes(isSelfClosing ? inner.slice(0, -1).trim() : inner);
246
- const node = {
247
- start: token,
248
- name: arr.name,
249
- arr: arr.arr,
250
- content: [],
251
- end: null,
252
- type: "TagNode",
253
- loc: {
254
- start: { ...token.start },
255
- end: { ...token.end }
256
- }
257
- };
258
- if (isSelfClosing) if (stack.length > 0) stack[stack.length - 1].content.push(node);
259
- else yield node;
260
- else stack.push(node);
261
- } else if (token.type === "TagEnd") {
262
- const name = token.data.replace(/^<\/\s*/, "").replace(/\s*>$/, "").trim();
263
- for (let s = stack.length - 1; s >= 0; s--) {
264
- const candidate = stack[s];
265
- if (candidate && candidate.name === name) {
266
- candidate.end = token;
267
- candidate.loc.end = { ...token.end };
268
- stack.splice(s, 1);
269
- if (stack.length > 0) stack[stack.length - 1].content.push(candidate);
270
- else yield candidate;
271
- break;
272
- }
107
+ const children = this.convertVueChildren(node.children);
108
+ const fullSource = this.text;
109
+ const baseOffset = node.loc.start.offset;
110
+ const elementSource = node.loc.source;
111
+ let openEnd = elementSource.length;
112
+ let inQuote = null;
113
+ for (let i = 0; i < elementSource.length; i++) {
114
+ const c = elementSource[i];
115
+ if (inQuote) {
116
+ if (c === "\\") {
117
+ i++;
118
+ continue;
273
119
  }
120
+ if (c === inQuote) inQuote = null;
121
+ } else if (c === "\"" || c === "'") inQuote = c;
122
+ else if (c === ">") {
123
+ openEnd = i + 1;
124
+ break;
274
125
  }
275
126
  }
276
- while (stack.length > 0) {
277
- const node = stack.shift();
278
- if (stack.length > 0) stack[0].content.push(node);
279
- else yield node;
127
+ let closeStart = -1;
128
+ if (!node.isSelfClosing) {
129
+ for (let i = elementSource.length - 2; i >= 0; i--) if (elementSource[i] === "<" && elementSource[i + 1] === "/") {
130
+ closeStart = i;
131
+ break;
132
+ }
280
133
  }
134
+ const openTagStartAbs = baseOffset;
135
+ const openTagEndAbs = baseOffset + openEnd;
136
+ let endToken = null;
137
+ if (closeStart >= 0) {
138
+ const closeTagStartAbs = baseOffset + closeStart;
139
+ const closeTagEndAbs = baseOffset + elementSource.length;
140
+ endToken = {
141
+ data: elementSource.slice(closeStart),
142
+ type: "TagEnd",
143
+ start: absOffsetToMCXPos(fullSource, closeTagStartAbs),
144
+ end: absOffsetToMCXPos(fullSource, closeTagEndAbs)
145
+ };
146
+ }
147
+ return {
148
+ start: {
149
+ data: elementSource.slice(0, openEnd),
150
+ type: "Tag",
151
+ start: absOffsetToMCXPos(fullSource, openTagStartAbs),
152
+ end: absOffsetToMCXPos(fullSource, openTagEndAbs)
153
+ },
154
+ name: node.tag,
155
+ arr: attrs,
156
+ content: children,
157
+ end: endToken,
158
+ loc: {
159
+ start: {
160
+ line: node.loc.start.line,
161
+ column: node.loc.start.column
162
+ },
163
+ end: {
164
+ line: node.loc.end.line,
165
+ column: node.loc.end.column
166
+ }
167
+ },
168
+ type: "TagNode"
169
+ };
281
170
  }
282
- get ast() {
283
- return { [Symbol.iterator]: () => this.parseAST() };
284
- }
285
- };
286
- var McxAst = class McxAst {
287
- text;
288
- includeComments;
289
- constructor(text, includeComments = false) {
290
- this.text = text;
291
- this.includeComments = includeComments;
292
- }
293
- getAST() {
294
- const parser = new Parser$1(new Lexer$1(this.text, this.includeComments));
295
- return Array.from(parser.parseAST());
296
- }
297
- get data() {
298
- return this.getAST();
299
- }
300
- parseAST() {
301
- return this.getAST();
171
+ convertVueChildren(children) {
172
+ const result = [];
173
+ for (const child of children) {
174
+ const node = this.convertTemplateChild(child);
175
+ if (node) result.push(node);
176
+ }
177
+ return result;
302
178
  }
303
- /**
304
- * 生成代码字符串
305
- * @param node 代码的AST节点
306
- * @returns 代码字符串
307
- */
308
179
  static generateCode(node) {
309
180
  let code = `<${node.name}`;
310
181
  for (const [key, value] of Object.entries(node.arr || {})) if (value === "true") code += ` ${key}`;
@@ -312,6 +183,7 @@ var McxAst = class McxAst {
312
183
  code += ">";
313
184
  const contentArr = node.content;
314
185
  if (Array.isArray(contentArr)) for (const item of contentArr) if (item.type === "TagContent") code += item.data;
186
+ else if (item.type === "Comment") code += item.data;
315
187
  else code += McxAst.generateCode(item);
316
188
  code += `</${node.name}>`;
317
189
  return code;
@@ -330,31 +202,32 @@ var MCXUtils = class MCXUtils {
330
202
  static isAttributeMap(obj) {
331
203
  return !!obj && typeof obj === "object" && !Array.isArray(obj);
332
204
  }
333
- static isToken(obj) {
334
- return !!obj && typeof obj === "object" && "data" in obj && "type" in obj && "start" in obj && "end" in obj && (obj.type === "Tag" || obj.type === "TagEnd" || obj.type === "Content" || obj.type === "Comment");
205
+ static isParseNode(node) {
206
+ return Array.isArray(node) && node.every(MCXUtils.isTagNode);
335
207
  }
336
- static isTagToken(obj) {
337
- return MCXUtils.isToken(obj) && obj.type === "Tag";
208
+ static isToken(_obj) {
209
+ return false;
338
210
  }
339
- static isTagEndToken(obj) {
340
- return MCXUtils.isToken(obj) && obj.type === "TagEnd";
211
+ static isTagToken(_obj) {
212
+ return false;
341
213
  }
342
- static isContentToken(obj) {
343
- return MCXUtils.isToken(obj) && obj.type === "Content";
214
+ static isTagEndToken(_obj) {
215
+ return false;
344
216
  }
345
- static isCommentToken(obj) {
346
- return MCXUtils.isToken(obj) && obj.type === "Comment";
217
+ static isContentToken(_obj) {
218
+ return false;
347
219
  }
348
- static isBaseToken(obj) {
349
- return !!obj && typeof obj === "object" && "data" in obj && "type" in obj && "start" in obj && "end" in obj;
220
+ static isCommentToken(_obj) {
221
+ return false;
350
222
  }
351
- static isTokenType(value) {
352
- return value === "Tag" || value === "TagEnd" || value === "Content" || value === "Comment";
223
+ static isBaseToken(_obj) {
224
+ return false;
353
225
  }
354
- static isParseNode(node) {
355
- return Array.isArray(node) && node.every(MCXUtils.isTagNode);
226
+ static isTokenType(_value) {
227
+ return false;
356
228
  }
357
229
  };
230
+
358
231
  //#endregion
359
232
  //#region src/ast/prop.ts
360
233
  const STATUS = [0, 1];
@@ -404,12 +277,14 @@ function PropParser(code) {
404
277
  const lexer = new Lexer(code);
405
278
  return Array.from(lexer.tokenize());
406
279
  }
280
+
407
281
  //#endregion
408
282
  //#region src/ast/index.ts
409
283
  var ast_default = {
410
284
  tag: McxAst,
411
285
  prop: PropParser
412
286
  };
287
+
413
288
  //#endregion
414
289
  //#region src/compile-mcx/types.ts
415
290
  const _MCXstructureLocComponentTypes = {
@@ -417,6 +292,7 @@ const _MCXstructureLocComponentTypes = {
417
292
  blocks: "block",
418
293
  entities: "entity"
419
294
  };
295
+
420
296
  //#endregion
421
297
  //#region src/compile-mcx/compiler/compileData.ts
422
298
  var JsCompileData = class {
@@ -449,6 +325,7 @@ var MCXCompileData = class {
449
325
  this.File = dir;
450
326
  }
451
327
  };
328
+
452
329
  //#endregion
453
330
  //#region src/compile-mcx/compiler/utils.ts
454
331
  var Utils$1 = class Utils$1 {
@@ -525,6 +402,7 @@ var Utils$1 = class Utils$1 {
525
402
  };
526
403
  }
527
404
  };
405
+
528
406
  //#endregion
529
407
  //#region src/compile-mcx/compiler/index.ts
530
408
  var compiler_exports = /* @__PURE__ */ __exportAll({
@@ -724,7 +602,8 @@ var CompileMCX = class {
724
602
  isLoad: false
725
603
  },
726
604
  Component: {},
727
- UI: null
605
+ UI: null,
606
+ Form: null
728
607
  };
729
608
  getCompileData() {
730
609
  return this.CompileData;
@@ -756,6 +635,7 @@ var CompileMCX = class {
756
635
  script: "",
757
636
  Event: null,
758
637
  ui: null,
638
+ form: null,
759
639
  Component: {}
760
640
  };
761
641
  for (const node of this.mcxCode || []) {
@@ -781,6 +661,9 @@ var CompileMCX = class {
781
661
  } else if (node.name == "Ui") {
782
662
  if (component || temp.Event || temp.ui) throw makeError("[compile error]: UI node can't use with component or event or other ui node", node);
783
663
  temp.ui = node;
664
+ } else if (node.name == "Form") {
665
+ if (component || temp.Event || temp.form || temp.ui) throw makeError("[compile error]: Form node can't use with component, event, Ui, or other Form node", node);
666
+ temp.form = node;
784
667
  }
785
668
  }
786
669
  if (!temp.script) throw makeError("[compile error]: mcx must has a script");
@@ -803,6 +686,7 @@ var CompileMCX = class {
803
686
  this.handlerChildComponent(subNode);
804
687
  }
805
688
  if (temp.ui) this.tempLoc.UI = temp.ui;
689
+ if (temp.form) this.tempLoc.Form = temp.form;
806
690
  }
807
691
  handlerChildComponent(node) {
808
692
  const name = node.name;
@@ -868,6 +752,7 @@ const compileMCXFn = ((mcxCode) => {
868
752
  });
869
753
  compileJSFn.cache = {};
870
754
  compileMCXFn.cache = {};
755
+
871
756
  //#endregion
872
757
  //#region src/transforms/config.ts
873
758
  var config_default = {
@@ -877,6 +762,7 @@ var config_default = {
877
762
  eventExtendsName: "McxExtendsBy",
878
763
  paramCtx: "__mcx__ctx"
879
764
  };
765
+
880
766
  //#endregion
881
767
  //#region src/utils.ts
882
768
  var Utils = class Utils {
@@ -925,12 +811,14 @@ var Utils = class Utils {
925
811
  return path.isAbsolute(inputPath) ? inputPath : path.join(baseDir, inputPath);
926
812
  }
927
813
  };
814
+
928
815
  //#endregion
929
816
  //#region src/transforms/file_id.ts
930
817
  let fileIdCounter = 0;
931
818
  function generateFileId() {
932
819
  return `__file_import_${fileIdCounter++}__`;
933
820
  }
821
+
934
822
  //#endregion
935
823
  //#region src/transforms/utils.ts
936
824
  function extractVarDefIdList(express) {
@@ -1049,110 +937,328 @@ function _enableWithData() {
1049
937
  fn.prototype.enable = d;
1050
938
  return fn;
1051
939
  }
940
+ function processDefineProp(code, mode, impBody) {
941
+ const obsMap = {};
942
+ for (const stmt of code.node.body) if (t.isVariableDeclaration(stmt)) {
943
+ for (const decl of stmt.declarations) if (t.isCallExpression(decl.init) && t.isIdentifier(decl.init.callee) && decl.init.callee.name === "defineProp" && t.isIdentifier(decl.id)) {
944
+ const varName = decl.id.name;
945
+ const defaultVal = decl.init.arguments[1] || decl.init.arguments[0];
946
+ let defaultExpr = t.nullLiteral();
947
+ if (defaultVal && t.isExpression(defaultVal)) defaultExpr = defaultVal;
948
+ const propAccess = t.logicalExpression("??", t.memberExpression(t.memberExpression(t.identifier("__mcx__ctx"), t.identifier("$prop")), t.identifier(varName)), defaultExpr);
949
+ if (mode === "ui") {
950
+ const obsType = inferObservableType(defaultExpr);
951
+ if (obsType) {
952
+ obsMap[obsType] = obsType;
953
+ decl.init = t.newExpression(t.identifier(obsType), [propAccess]);
954
+ } else decl.init = propAccess;
955
+ } else decl.init = propAccess;
956
+ }
957
+ }
958
+ if (mode === "ui" && Object.keys(obsMap).length > 0) impBody.push(t.importDeclaration(Object.values(obsMap).map((name) => t.importSpecifier(t.identifier(name), t.identifier(name))), t.stringLiteral("@minecraft/server-ui")));
959
+ }
960
+ function inferObservableType(expr) {
961
+ if (t.isStringLiteral(expr)) return "ObservableString";
962
+ if (t.isBooleanLiteral(expr)) return "ObservableBoolean";
963
+ if (t.isNumericLiteral(expr)) return "ObservableNumber";
964
+ if (t.isNullLiteral(expr)) return "ObservableString";
965
+ if (t.isIdentifier(expr) && expr.name === "undefined") return "ObservableString";
966
+ return null;
967
+ }
968
+ function collectSetupDeclarations(code, existingReturnMembers) {
969
+ const result = [];
970
+ const seen = new Set(existingReturnMembers);
971
+ for (const stmt of code.node.body) {
972
+ if (!t.isDeclaration(stmt)) continue;
973
+ const ids = extractIdList(stmt);
974
+ for (const id of ids) if (id && !seen.has(id)) {
975
+ seen.add(id);
976
+ result.push(t.objectProperty(t.identifier(id), t.identifier(id)));
977
+ }
978
+ }
979
+ return result;
980
+ }
981
+ function processHooks(code) {
982
+ let startup = null;
983
+ let mounted = null;
984
+ const toRemove = [];
985
+ for (let i = 0; i < code.node.body.length; i++) {
986
+ const stmt = code.node.body[i];
987
+ if (!stmt) continue;
988
+ if (t.isExpressionStatement(stmt) && t.isCallExpression(stmt.expression)) {
989
+ const call = stmt.expression;
990
+ if (t.isIdentifier(call.callee)) {
991
+ const name = call.callee.name;
992
+ if (name === "onStartup" || name === "onMounted") {
993
+ if (call.arguments.length > 0) {
994
+ const cb = call.arguments[0];
995
+ if (t.isExpression(cb)) if (name === "onStartup") startup = cb;
996
+ else mounted = cb;
997
+ }
998
+ toRemove.push(i);
999
+ }
1000
+ }
1001
+ }
1002
+ }
1003
+ for (const idx of toRemove.reverse()) code.node.body.splice(idx, 1);
1004
+ const hookNames = new Set(["onStartup", "onMounted"]);
1005
+ for (const imp of code.BuildCache.import) if (imp.source === "@mbler/mcx") imp.imported = imp.imported.filter((item) => !hookNames.has(item.import || item.as));
1006
+ code.BuildCache.import = code.BuildCache.import.filter((imp) => imp.source !== "@mbler/mcx" || imp.imported.length > 0);
1007
+ return {
1008
+ startup,
1009
+ mounted
1010
+ };
1011
+ }
1012
+
1052
1013
  //#endregion
1053
- //#region src/transforms/transform/ui.ts
1054
- async function Comp$2(ctx) {
1014
+ //#region src/transforms/transform/layout.ts
1015
+ /**
1016
+ * Shared layout generation for both <Form> and <Ui>.
1017
+ * Generates layout config with (s) => expr functions for content and params.
1018
+ */
1019
+ function generateLayout(ctx, tagNode, tagName, mode) {
1055
1020
  const internalCtx = ctx.ctx;
1056
- ctx.impBody.push(t.importDeclaration([t.importSpecifier(t.identifier("__mcx__ui"), t.identifier("ui"))], t.stringLiteral("@mbler/mcx")), t.importDeclaration([t.importNamespaceSpecifier(t.identifier("__minecraft__ui"))], t.stringLiteral("@minecraft/server-ui")));
1057
- const uiTagNode = ctx.ctx.compiledCode.strLoc.UI;
1058
- if (!uiTagNode || uiTagNode?.name !== "Ui") throw new Error("[UI Component]: why didn't parent compeled verify?");
1059
- let MCXUIType = null;
1060
- const UITree = [];
1061
- for (const uiClientTag of uiTagNode.content) if (uiClientTag.type == "TagNode") {
1062
- if (uiClientTag.content.some((i) => i.type == "TagNode")) internalCtx.rollupContext.error("[UI]: can't support ui client element", uiClientTag.loc ? {
1063
- column: uiClientTag.loc.start.column,
1064
- line: uiClientTag.loc.start.line
1021
+ const parsedObj = [];
1022
+ const typeTags = [];
1023
+ const elements = [];
1024
+ for (const child of tagNode.content) {
1025
+ if (child.type !== "TagNode") continue;
1026
+ if (child.content.some((i) => i.type === "TagNode")) internalCtx.rollupContext.error(`[${tagName}]: can't support nested elements`, child.loc ? {
1027
+ column: child.loc.start.column,
1028
+ line: child.loc.start.line
1065
1029
  } : void 0);
1066
1030
  let _for;
1067
- if (typeof uiClientTag.arr.for === "string") {
1068
- const match = uiClientTag.arr.for.match(/^(\w+)\s+in\s+(\w+)$/);
1031
+ if (typeof child.arr.for === "string") {
1032
+ const match = child.arr.for.match(/^(\w+)\s+in\s+(\w+)$/);
1069
1033
  if (match) _for = {
1070
1034
  variable: match[1],
1071
- useProp: match[2]
1035
+ useSetup: match[2]
1072
1036
  };
1073
- else internalCtx.rollupContext.error("[UI]: invalid for syntax, expected 'variable in propName'", uiClientTag.loc ? {
1074
- column: uiClientTag.loc.start.column,
1075
- line: uiClientTag.loc.start.line
1037
+ else internalCtx.rollupContext.error(`[${tagName}]: invalid for syntax, expected 'variable in propName'`, child.loc ? {
1038
+ column: child.loc.start.column,
1039
+ line: child.loc.start.line
1076
1040
  } : void 0);
1077
1041
  }
1078
- UITree.push({
1079
- arr: uiClientTag.arr,
1080
- content: uiClientTag.content.map((i) => i.type == "TagContent" && i.data || "").join(""),
1081
- type: uiClientTag.name,
1082
- loc: uiClientTag.loc,
1083
- for: _for
1042
+ let _if;
1043
+ if (typeof child.arr.if === "string") _if = { useSetup: child.arr.if };
1044
+ elements.push({
1045
+ arr: child.arr,
1046
+ content: child.content.map((i) => i.type === "TagContent" && i.data || "").join(""),
1047
+ type: child.name,
1048
+ loc: child.loc,
1049
+ ..._for ? { for: _for } : {},
1050
+ ..._if ? { if: _if } : {}
1084
1051
  });
1085
1052
  }
1086
- const parsedObj = [];
1087
- function pushToTree(name, params, content, _for) {
1053
+ for (const el of elements) {
1054
+ const name = el.type;
1055
+ const cleanedArr = { ...el.arr };
1056
+ delete cleanedArr.for;
1057
+ delete cleanedArr.if;
1058
+ const formType = detectFormType(name);
1059
+ if (formType === "invalid") {
1060
+ internalCtx.rollupContext.error(`[${tagName}]: don't support tag: ${name}`, el.loc ? {
1061
+ line: el.loc.start.line,
1062
+ column: el.loc.start.column
1063
+ } : void 0);
1064
+ continue;
1065
+ }
1066
+ if (formType) typeTags.push(formType);
1067
+ const paramsObj = t.objectExpression(Object.entries(cleanedArr).filter(([key]) => key !== "for" && key !== "if").map(([key, value]) => {
1068
+ const isDynamic = key.startsWith(":");
1069
+ const paramName = isDynamic ? key.slice(1) : key;
1070
+ if (paramName === "click") return t.objectProperty(t.identifier(paramName), simpleFn(String(value)));
1071
+ return t.objectProperty(t.identifier(paramName), isDynamic ? simpleFn(String(value)) : typeof value === "boolean" ? t.booleanLiteral(value) : t.stringLiteral(value));
1072
+ }));
1073
+ const contentExpr = parseContent(el.content);
1088
1074
  const props = [
1089
1075
  t.objectProperty(t.identifier("type"), t.stringLiteral(name)),
1090
- t.objectProperty(t.identifier("params"), t.objectExpression(Object.entries(params).map(([key, value]) => {
1091
- const isDynamic = key.startsWith(":");
1092
- const paramName = isDynamic ? key.slice(1) : key;
1093
- return t.objectProperty(t.identifier(paramName), isDynamic ? t.objectExpression([t.objectProperty(t.identifier("useProp"), t.stringLiteral(String(value)))]) : typeof value == "boolean" ? t.booleanLiteral(value) : t.stringLiteral(value));
1094
- }))),
1095
- t.objectProperty(t.identifier("content"), content.startsWith("{{ ") && content.endsWith(" }}") ? t.objectExpression([t.objectProperty(t.identifier("useProp"), t.stringLiteral(content.slice(3, content.length - 3).trim()))]) : t.stringLiteral(content))
1076
+ t.objectProperty(t.identifier("params"), paramsObj),
1077
+ t.objectProperty(t.identifier("content"), contentExpr)
1096
1078
  ];
1097
- if (_for) props.push(t.objectProperty(t.identifier("for"), t.objectExpression([t.objectProperty(t.identifier("variable"), t.stringLiteral(_for.variable)), t.objectProperty(t.identifier("useProp"), t.stringLiteral(_for.useProp))])));
1079
+ if (el.for) props.push(t.objectProperty(t.identifier("for"), t.objectExpression([t.objectProperty(t.identifier("variable"), t.stringLiteral(el.for.variable)), t.objectProperty(t.identifier("useSetup"), t.stringLiteral(el.for.useSetup))])));
1080
+ if (el.if) props.push(t.objectProperty(t.identifier("if"), t.objectExpression([t.objectProperty(t.identifier("useSetup"), t.stringLiteral(el.if.useSetup))])));
1098
1081
  parsedObj.push(t.objectExpression(props));
1099
1082
  }
1100
- for (const tp of UITree) {
1101
- const name = tp.type;
1102
- const cleanedArr = { ...tp.arr };
1103
- delete cleanedArr.for;
1104
- if ([
1105
- "input",
1106
- "dropdown",
1107
- "submit",
1108
- "toggle",
1109
- "slider"
1110
- ].includes(name)) {
1111
- if (MCXUIType && MCXUIType !== "ModalFormData") internalCtx.rollupContext.error("[UI]: a mcx can't have a ModalFormData Node and other form tag", tp.loc ? {
1112
- line: tp.loc.start.line,
1113
- column: tp.loc.start.column
1114
- } : void 0);
1115
- MCXUIType = "ModalFormData";
1116
- pushToTree(name, cleanedArr, tp.content, tp.for);
1117
- } else if (["button-m"].includes(name)) {
1118
- if (MCXUIType && MCXUIType !== "MessageFormData") internalCtx.rollupContext.error("[UI]: ", tp.loc ? {
1119
- line: tp.loc.start.line,
1120
- column: tp.loc.start.column
1121
- } : void 0);
1122
- MCXUIType = "MessageFormData";
1123
- pushToTree(name, cleanedArr, tp.content, tp.for);
1124
- } else if ([
1125
- "body",
1126
- "divider",
1127
- "title",
1128
- "label"
1129
- ].includes(name)) pushToTree(name, cleanedArr, tp.content, tp.for);
1130
- else if (name == "button") {
1131
- if (MCXUIType !== "ActionFormData" && MCXUIType) internalCtx.rollupContext.error("[UI]: don't support use button for messageFormData", tp.loc ? {
1132
- line: tp.loc.start.line,
1133
- column: tp.loc.start.column
1134
- } : void 0);
1135
- pushToTree(name, cleanedArr, tp.content, tp.for);
1136
- MCXUIType = "ActionFormData";
1137
- } else internalCtx.rollupContext.error("[UI]: don't support tag: " + name, tp.loc ? {
1138
- line: tp.loc.start.line,
1139
- column: tp.loc.start.column
1140
- } : void 0);
1083
+ let formTypeStr = "ActionFormData";
1084
+ if (typeTags.some((t) => [
1085
+ "input",
1086
+ "dropdown",
1087
+ "submit",
1088
+ "toggle",
1089
+ "slider"
1090
+ ].includes(t))) formTypeStr = "ModalFormData";
1091
+ else if (typeTags.some((t) => t === "button-m")) formTypeStr = "MessageFormData";
1092
+ else if (typeTags.some((t) => t === "button")) formTypeStr = "ActionFormData";
1093
+ return {
1094
+ parsedObj,
1095
+ formTypeStr
1096
+ };
1097
+ }
1098
+ function detectFormType(tag) {
1099
+ if ([
1100
+ "input",
1101
+ "dropdown",
1102
+ "submit",
1103
+ "toggle",
1104
+ "slider"
1105
+ ].includes(tag)) return "modal";
1106
+ if (tag === "button-m") return "message";
1107
+ if (tag === "button") return "action";
1108
+ if ([
1109
+ "body",
1110
+ "divider",
1111
+ "title",
1112
+ "label",
1113
+ "header",
1114
+ "spacer",
1115
+ "close-button"
1116
+ ].includes(tag)) return "shared";
1117
+ return "invalid";
1118
+ }
1119
+ /** Simple arrow function for params (non-reactive): (ctx) => ctx[0].a.b.c */
1120
+ function simpleFn(expr) {
1121
+ const ctx = t.identifier("ctx");
1122
+ const body = dotAccess(expr, ctx);
1123
+ return t.arrowFunctionExpression([ctx], body);
1124
+ }
1125
+ /** Extract root identifiers from an expression for dependency tracking */
1126
+ function extractIdentifiers(expr) {
1127
+ const reserved = new Set([
1128
+ "true",
1129
+ "false",
1130
+ "null",
1131
+ "undefined",
1132
+ "this",
1133
+ "new",
1134
+ "typeof",
1135
+ "instanceof"
1136
+ ]);
1137
+ const ids = /* @__PURE__ */ new Set();
1138
+ const regex = /\b([a-zA-Z_$][\w$]*)\b/g;
1139
+ let m;
1140
+ while ((m = regex.exec(expr)) !== null) if (!reserved.has(m[1])) ids.add(m[1]);
1141
+ return [...ids];
1142
+ }
1143
+ /** Generate new Computation((ctx) => expr, [deps]) */
1144
+ function arrowFn(expr) {
1145
+ const ctx = t.identifier("ctx");
1146
+ const body = dotAccess(expr, ctx);
1147
+ const evalFn = t.arrowFunctionExpression([ctx], body);
1148
+ const deps = extractIdentifiers(expr).map((id) => {
1149
+ const c = t.identifier("ctx");
1150
+ return t.arrowFunctionExpression([c], dotAccess(id, c));
1151
+ });
1152
+ return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
1153
+ }
1154
+ /**
1155
+ * Parse content string, returns:
1156
+ * - t.stringLiteral for pure static text
1157
+ * - t.NewExpression (Computation) for content with {{ }} interpolation
1158
+ *
1159
+ * Supports:
1160
+ * - "Hello" → "Hello"
1161
+ * - "{{ a }}" → new Computation((ctx) => ctx[0].a, [ctx => ctx[0].a])
1162
+ * - "Hi {{ a }}" → new Computation((ctx) => `Hi ${ctx[0].a}`, [ctx => ctx[0].a])
1163
+ * - "{{ a.slice(1,2) }}" → new Computation((ctx) => ctx[0].a.slice(1,2), [ctx => ctx[0].a])
1164
+ */
1165
+ function parseContent(raw) {
1166
+ if (!raw.includes("{{ ")) return t.stringLiteral(raw);
1167
+ const parts = splitInterpolation(raw);
1168
+ if (parts.length === 1 && parts[0].type === "expr") return arrowFn(parts[0].value);
1169
+ const ctx = t.identifier("ctx");
1170
+ const quasis = [];
1171
+ const expressions = [];
1172
+ const allIds = /* @__PURE__ */ new Set();
1173
+ for (const part of parts) if (part.type === "text") quasis.push(t.templateElement({
1174
+ raw: part.value,
1175
+ cooked: part.value
1176
+ }));
1177
+ else {
1178
+ expressions.push(dotAccess(part.value, ctx));
1179
+ for (const id of extractIdentifiers(part.value)) allIds.add(id);
1180
+ }
1181
+ quasis.push(t.templateElement({
1182
+ raw: "",
1183
+ cooked: ""
1184
+ }, true));
1185
+ const tpl = t.templateLiteral(quasis, expressions);
1186
+ const evalFn = t.arrowFunctionExpression([ctx], tpl);
1187
+ const deps = [...allIds].map((id) => {
1188
+ const c = t.identifier("ctx");
1189
+ return t.arrowFunctionExpression([c], dotAccess(id, c));
1190
+ });
1191
+ return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
1192
+ }
1193
+ function splitInterpolation(raw) {
1194
+ const result = [];
1195
+ const regex = /\{\{\s*(.*?)\s*\}\}/g;
1196
+ let lastIndex = 0;
1197
+ let match;
1198
+ while ((match = regex.exec(raw)) !== null) {
1199
+ if (match.index > lastIndex) result.push({
1200
+ type: "text",
1201
+ value: raw.slice(lastIndex, match.index)
1202
+ });
1203
+ result.push({
1204
+ type: "expr",
1205
+ value: match[1]
1206
+ });
1207
+ lastIndex = regex.lastIndex;
1141
1208
  }
1142
- if (!MCXUIType) MCXUIType = "ActionFormData";
1143
- const finallyData = t.objectExpression([
1209
+ if (lastIndex < raw.length) result.push({
1210
+ type: "text",
1211
+ value: raw.slice(lastIndex)
1212
+ });
1213
+ return result;
1214
+ }
1215
+ /** "a.b.c" → __ctx[0].a.b.c */
1216
+ function dotAccess(expr, root) {
1217
+ const parts = expr.split(".");
1218
+ let node = t.memberExpression(root, t.numericLiteral(0), true);
1219
+ for (const part of parts) node = t.memberExpression(node, t.identifier(part));
1220
+ return node;
1221
+ }
1222
+
1223
+ //#endregion
1224
+ //#region src/transforms/transform/ui.ts
1225
+ async function Comp$3(ctx) {
1226
+ ctx.impBody.push(t.importDeclaration([t.importSpecifier(t.identifier("__mcx__ui"), t.identifier("ui"))], t.stringLiteral("@mbler/mcx")), t.importDeclaration([t.importNamespaceSpecifier(t.identifier("__minecraft__ui"))], t.stringLiteral("@minecraft/server-ui")));
1227
+ const tagNode = ctx.ctx.compiledCode.strLoc.UI;
1228
+ if (!tagNode || tagNode.name !== "Ui") throw new Error("[UI Component]: why did parent not verify?");
1229
+ const { parsedObj, formTypeStr } = generateLayout(ctx, tagNode, "Ui", "ui");
1230
+ const configObj = t.objectExpression([
1231
+ t.objectProperty(t.identifier("mode"), t.stringLiteral("ui")),
1232
+ t.objectProperty(t.identifier("layout"), t.arrayExpression(parsedObj)),
1233
+ t.objectProperty(t.identifier("use"), t.memberExpression(t.identifier("__minecraft__ui"), t.identifier(formTypeStr))),
1234
+ t.objectProperty(t.identifier("UI"), t.identifier("__minecraft__ui"))
1235
+ ]);
1236
+ ctx.app([t.objectProperty(t.identifier("ui"), t.newExpression(t.identifier("__mcx__ui"), [configObj, t.identifier(config_default.scriptCompileFn)]))]);
1237
+ }
1238
+
1239
+ //#endregion
1240
+ //#region src/transforms/transform/form.ts
1241
+ async function Comp$2(ctx) {
1242
+ ctx.impBody.push(t.importDeclaration([t.importSpecifier(t.identifier("__mcx__ui"), t.identifier("ui"))], t.stringLiteral("@mbler/mcx")), t.importDeclaration([t.importNamespaceSpecifier(t.identifier("__minecraft__ui"))], t.stringLiteral("@minecraft/server-ui")));
1243
+ const tagNode = ctx.ctx.compiledCode.strLoc.Form;
1244
+ if (!tagNode || tagNode.name !== "Form") throw new Error("[Form Component]: why did parent not verify?");
1245
+ const { parsedObj, formTypeStr } = generateLayout(ctx, tagNode, "Form", "form");
1246
+ const configObj = t.objectExpression([
1247
+ t.objectProperty(t.identifier("mode"), t.stringLiteral("form")),
1144
1248
  t.objectProperty(t.identifier("layout"), t.arrayExpression(parsedObj)),
1145
- t.objectProperty(t.identifier("use"), t.memberExpression(t.identifier("__minecraft__ui"), t.identifier(MCXUIType))),
1249
+ t.objectProperty(t.identifier("use"), t.memberExpression(t.identifier("__minecraft__ui"), t.identifier(formTypeStr))),
1146
1250
  t.objectProperty(t.identifier("UI"), t.identifier("__minecraft__ui"))
1147
1251
  ]);
1148
- ctx.app([t.objectProperty(t.identifier("ui"), t.newExpression(t.identifier("__mcx__ui"), [finallyData, t.identifier(config_default.scriptCompileFn)]))]);
1252
+ ctx.app([t.objectProperty(t.identifier("ui"), t.newExpression(t.identifier("__mcx__ui"), [configObj, t.identifier(config_default.scriptCompileFn)]))]);
1149
1253
  }
1254
+
1150
1255
  //#endregion
1151
1256
  //#region src/transforms/transform/event.ts
1152
1257
  async function Comp$1(ctx) {
1153
1258
  const appData = [t.objectProperty(t.identifier("event"), await generateEventConfig(ctx.ctx.compiledCode.raw.find((node) => node.name === "Event"), ctx.ctx, ctx.impBody))];
1154
1259
  ctx.app(appData);
1155
1260
  }
1261
+
1156
1262
  //#endregion
1157
1263
  //#region src/transforms/transform/app.ts
1158
1264
  async function Comp(ctx) {
@@ -1194,6 +1300,7 @@ async function Comp(ctx) {
1194
1300
  ctx.app(appData);
1195
1301
  }
1196
1302
  }
1303
+
1197
1304
  //#endregion
1198
1305
  //#region src/mcx-component/cjsTransform.ts
1199
1306
  /**
@@ -1283,6 +1390,7 @@ function transformImportIRtoRequire(importIR) {
1283
1390
  }
1284
1391
  return define;
1285
1392
  }
1393
+
1286
1394
  //#endregion
1287
1395
  //#region src/mcx-component/vm.ts
1288
1396
  const BLOCKED_MODULES = new Set([
@@ -1394,17 +1502,11 @@ var RunScript = class {
1394
1502
  }
1395
1503
  static isCanUseEsmRunVm = typeof vm.SourceTextModule == "function";
1396
1504
  };
1505
+
1397
1506
  //#endregion
1398
1507
  //#region src/mcx-component/index.ts
1399
1508
  var mcx_component_exports = /* @__PURE__ */ __exportAll({
1400
- BlockComponent: () => BlockComponent$1,
1401
- EntityComponent: () => EntityComponent$1,
1402
- GIFImageComponent: () => GIFImageComponent$1,
1403
- ItemComponent: () => ItemComponent$1,
1404
- JPGImageComponent: () => JPGImageComponent$1,
1405
- PNGImageComponent: () => PNGImageComponent$1,
1406
1509
  RunScript: () => RunScript,
1407
- SVGImageComponent: () => SVGImageComponent$1,
1408
1510
  clearCachedOptions: () => clearCachedOptions,
1409
1511
  compileComponent: () => compileComponent,
1410
1512
  execESMMethod: () => execESMMethod,
@@ -1650,9 +1752,14 @@ async function compileComponent(compiledCode, ctx) {
1650
1752
  await writeFile(filePoint, JSON.stringify(json, null, 2));
1651
1753
  }
1652
1754
  }
1755
+
1653
1756
  //#endregion
1654
1757
  //#region src/transforms/main.ts
1655
1758
  async function _transform(ctx) {
1759
+ const formTag = ctx.compiledCode.strLoc.Form;
1760
+ const uiTag = ctx.compiledCode.strLoc.UI;
1761
+ const isSetupMode = formTag && formTag.arr.setup !== void 0 || uiTag && uiTag.arr.setup !== void 0;
1762
+ const modeType = formTag && formTag.arr.setup !== void 0 ? "form" : uiTag && uiTag.arr.setup !== void 0 ? "ui" : null;
1656
1763
  const _temp_main = generateMain(ctx.compiledCode.JSIR);
1657
1764
  const mainFn = ctx.mainFn.body = _temp_main[0];
1658
1765
  const prop = [];
@@ -1666,16 +1773,22 @@ async function _transform(ctx) {
1666
1773
  app
1667
1774
  };
1668
1775
  let type = "app";
1776
+ if (isSetupMode && modeType) processDefineProp(ctx.compiledCode.JSIR, modeType, parseCtx.impBody);
1669
1777
  const enableSetup = _enable();
1670
1778
  if (ctx.compiledCode.strLoc.Event.isLoad) {
1671
1779
  type = "event";
1672
1780
  enableSetup();
1673
1781
  await Comp$1(parseCtx);
1674
1782
  }
1783
+ if (ctx.compiledCode.strLoc.Form) {
1784
+ type = "form";
1785
+ enableSetup();
1786
+ await Comp$2(parseCtx);
1787
+ }
1675
1788
  if (ctx.compiledCode.strLoc.UI) {
1676
1789
  type = "ui";
1677
1790
  enableSetup();
1678
- await Comp$2(parseCtx);
1791
+ await Comp$3(parseCtx);
1679
1792
  }
1680
1793
  if (Object.getOwnPropertyNames(ctx.compiledCode.strLoc.Component).length >= 1) {
1681
1794
  type = "component";
@@ -1686,6 +1799,22 @@ async function _transform(ctx) {
1686
1799
  enableSetup();
1687
1800
  await Comp(parseCtx);
1688
1801
  }
1802
+ if (isSetupMode) {
1803
+ const existingExportNames = /* @__PURE__ */ new Set();
1804
+ for (const exp of ctx.compiledCode.JSIR.BuildCache.export) if (t.isExportNamedDeclaration(exp) && exp.declaration) {
1805
+ const ids = extractIdList(exp.declaration);
1806
+ for (const id of ids) existingExportNames.add(id);
1807
+ }
1808
+ for (const p of parseCtx.prop) if (t.isObjectProperty(p) && t.isIdentifier(p.key)) existingExportNames.add(p.key.name);
1809
+ const setupDecls = collectSetupDeclarations(ctx.compiledCode.JSIR, existingExportNames);
1810
+ const hooks = processHooks(ctx.compiledCode.JSIR);
1811
+ const returnStmt = mainFn[mainFn.length - 1];
1812
+ if (t.isReturnStatement(returnStmt) && t.isObjectExpression(returnStmt.argument)) {
1813
+ returnStmt.argument.properties.push(...setupDecls);
1814
+ if (hooks.startup) returnStmt.argument.properties.push(t.objectProperty(t.identifier("__mcx_startup"), hooks.startup));
1815
+ if (hooks.mounted) returnStmt.argument.properties.push(t.objectProperty(t.identifier("__mcx_mounted"), hooks.mounted));
1816
+ }
1817
+ }
1689
1818
  prop.push(t.objectProperty(t.identifier("type"), t.stringLiteral(type)));
1690
1819
  if (enableSetup.prototype.enable) prop.push(t.objectProperty(t.identifier("setup"), t.identifier(config_default.scriptCompileFn)));
1691
1820
  if (app.prototype.enable) prop.push(t.objectProperty(t.identifier("app"), t.objectExpression(app.prototype.enable)));
@@ -1695,6 +1824,7 @@ async function _transform(ctx) {
1695
1824
  t.exportDefaultDeclaration(t.objectExpression(prop))
1696
1825
  ])).code;
1697
1826
  }
1827
+
1698
1828
  //#endregion
1699
1829
  //#region src/transforms/index.ts
1700
1830
  function createErrorProxy(err, id) {
@@ -1727,8 +1857,10 @@ async function transform(code, cache, id, context, opt, output) {
1727
1857
  });
1728
1858
  } catch (err) {
1729
1859
  context.error(createErrorProxy(err, id));
1860
+ return "";
1730
1861
  }
1731
1862
  }
1863
+
1732
1864
  //#endregion
1733
1865
  //#region src/compile-mcx/compiler/main.ts
1734
1866
  function createMcxPlugin(opt, output) {
@@ -1859,14 +1991,11 @@ function createMcxPlugin(opt, output) {
1859
1991
  compileData = cache.has(id) ? cache.get(id) : compileMCXFn(code);
1860
1992
  cache.set(id, compileData);
1861
1993
  } catch (err) {
1862
- if (err instanceof CompileError) {
1863
- const error = err;
1864
- this.error(error.message, {
1865
- column: error.loc.column,
1866
- line: error.loc.line
1867
- });
1868
- }
1869
- this.error(err instanceof Error ? `${err.message} : ${err.stack}` : String(err));
1994
+ if (err instanceof CompileError) this.error(err.message, {
1995
+ column: err.loc.column,
1996
+ line: err.loc.line
1997
+ });
1998
+ else this.error(err instanceof Error ? `${err.message} : ${err.stack}` : String(err));
1870
1999
  return;
1871
2000
  }
1872
2001
  compileData.setFilePath(id);
@@ -1905,16 +2034,18 @@ function rollupPlugin(opt, output) {
1905
2034
  function rolldownPlugin(opt, output) {
1906
2035
  return createMcxPlugin(opt, output);
1907
2036
  }
2037
+
1908
2038
  //#endregion
1909
2039
  //#region src/types.ts
1910
2040
  var types_exports$1 = /* @__PURE__ */ __exportAll({});
2041
+
1911
2042
  //#endregion
1912
2043
  //#region src/mcx-component/types.ts
1913
2044
  var types_exports = /* @__PURE__ */ __exportAll({ createFileEdit: () => createFileEdit });
1914
2045
  function createFileEdit(expression) {
1915
2046
  return expression;
1916
2047
  }
1917
- //#endregion
1918
- export { ast_default as AST, BlockComponent, types_exports as ComponentType, EntityComponent, GIFImageComponent, ItemComponent, JPGImageComponent, PNGImageComponent, types_exports$1 as PubType, SVGImageComponent, mcx_component_exports as compile_component, compiler_exports as compiler, rolldownPlugin, rollupPlugin, transform, Utils as utils };
1919
2048
 
2049
+ //#endregion
2050
+ export { ast_default as AST, types_exports as ComponentType, types_exports$1 as PubType, mcx_component_exports as compile_component, compiler_exports as compiler, rolldownPlugin, rollupPlugin, transform, Utils as utils };
1920
2051
  //# sourceMappingURL=index.js.map