@zhin.js/core 1.0.1 → 1.0.3

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 (69) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/app.d.ts +10 -2
  3. package/lib/app.d.ts.map +1 -1
  4. package/lib/app.js +27 -2
  5. package/lib/app.js.map +1 -1
  6. package/lib/bot.d.ts +4 -2
  7. package/lib/bot.d.ts.map +1 -1
  8. package/lib/command.d.ts +2 -1
  9. package/lib/command.d.ts.map +1 -1
  10. package/lib/command.js.map +1 -1
  11. package/lib/component.d.ts +22 -102
  12. package/lib/component.d.ts.map +1 -1
  13. package/lib/component.js +438 -242
  14. package/lib/component.js.map +1 -1
  15. package/lib/jsx-dev-runtime.d.ts +3 -0
  16. package/lib/jsx-dev-runtime.d.ts.map +1 -0
  17. package/lib/jsx-dev-runtime.js +3 -0
  18. package/lib/jsx-dev-runtime.js.map +1 -0
  19. package/lib/jsx-runtime.d.ts +12 -0
  20. package/lib/jsx-runtime.d.ts.map +1 -0
  21. package/lib/jsx-runtime.js +11 -0
  22. package/lib/jsx-runtime.js.map +1 -0
  23. package/lib/jsx.d.ts +32 -0
  24. package/lib/jsx.d.ts.map +1 -0
  25. package/lib/jsx.js +57 -0
  26. package/lib/jsx.js.map +1 -0
  27. package/lib/log-transport.d.ts +37 -0
  28. package/lib/log-transport.d.ts.map +1 -0
  29. package/lib/log-transport.js +136 -0
  30. package/lib/log-transport.js.map +1 -0
  31. package/lib/message.d.ts +10 -7
  32. package/lib/message.d.ts.map +1 -1
  33. package/lib/message.js.map +1 -1
  34. package/lib/models/system-log.d.ts +11 -0
  35. package/lib/models/system-log.d.ts.map +1 -0
  36. package/lib/models/system-log.js +9 -0
  37. package/lib/models/system-log.js.map +1 -0
  38. package/lib/plugin.d.ts +4 -3
  39. package/lib/plugin.d.ts.map +1 -1
  40. package/lib/plugin.js +12 -2
  41. package/lib/plugin.js.map +1 -1
  42. package/lib/prompt.d.ts.map +1 -1
  43. package/lib/prompt.js +3 -2
  44. package/lib/prompt.js.map +1 -1
  45. package/lib/types.d.ts +13 -15
  46. package/lib/types.d.ts.map +1 -1
  47. package/lib/utils.d.ts.map +1 -1
  48. package/lib/utils.js +3 -1
  49. package/lib/utils.js.map +1 -1
  50. package/package.json +16 -4
  51. package/src/app.ts +37 -4
  52. package/src/bot.ts +5 -3
  53. package/src/command.ts +2 -1
  54. package/src/component.ts +523 -280
  55. package/src/jsx-dev-runtime.ts +2 -0
  56. package/src/jsx-runtime.ts +12 -0
  57. package/src/jsx.d.ts +52 -0
  58. package/src/jsx.ts +92 -0
  59. package/src/log-transport.ts +163 -0
  60. package/src/message.ts +8 -5
  61. package/src/models/system-log.ts +20 -0
  62. package/src/plugin.ts +19 -5
  63. package/src/prompt.ts +3 -2
  64. package/src/types.ts +13 -13
  65. package/src/utils.ts +6 -5
  66. package/tests/component-new.test.ts +348 -0
  67. package/tests/expression-evaluation.test.ts +258 -0
  68. package/tests/plugin.test.ts +26 -17
  69. package/tests/component.test.ts +0 -656
package/lib/component.js CHANGED
@@ -1,273 +1,469 @@
1
1
  import { getValueWithRuntime, compiler, segment } from './utils.js';
2
+ // 组件匹配符号
2
3
  export const CapWithChild = Symbol('CapWithChild');
3
4
  export const CapWithClose = Symbol('CapWithClose');
5
+ // 组件定义函数 - 简化版,只支持函数式组件
6
+ export function defineComponent(component, name = component.name) {
7
+ if (name) {
8
+ // 创建一个新的函数来避免修改只读属性
9
+ const namedComponent = component;
10
+ Object.defineProperty(namedComponent, 'name', {
11
+ value: name,
12
+ writable: false,
13
+ enumerable: false,
14
+ configurable: true
15
+ });
16
+ return namedComponent;
17
+ }
18
+ return component;
19
+ }
20
+ // 组件匹配函数
21
+ export function matchComponent(comp, template) {
22
+ // 使用更复杂的正则表达式来正确处理大括号内的内容
23
+ const selfClosingRegex = new RegExp(`<${comp.name}((?:[^>]|{[^}]*})*)?/>`);
24
+ const closingRegex = new RegExp(`<${comp.name}((?:[^>]|{[^}]*})*)?>([^<]*?)</${comp.name}>`);
25
+ let match = template.match(selfClosingRegex);
26
+ if (!match) {
27
+ match = template.match(closingRegex);
28
+ }
29
+ return match ? match[0] : '';
30
+ }
31
+ // 属性解析函数 - 支持 children
32
+ export function getProps(comp, template, context) {
33
+ // 1. 首先匹配组件标签,支持自闭合和闭合标签
34
+ const selfClosingRegex = new RegExp(`<${comp.name}((?:[^>]|{[^}]*})*)?/>`);
35
+ const closingRegex = new RegExp(`<${comp.name}((?:[^>]|{[^}]*})*)?>([^<]*?)</${comp.name}>`);
36
+ let match = template.match(selfClosingRegex);
37
+ let isSelfClosing = true;
38
+ let children = '';
39
+ if (!match) {
40
+ match = template.match(closingRegex);
41
+ isSelfClosing = false;
42
+ if (match) {
43
+ children = match[2] || '';
44
+ }
45
+ }
46
+ if (!match) {
47
+ return {};
48
+ }
49
+ const attributesString = match[1] || '';
50
+ // 2. 解析属性,支持多种格式
51
+ const props = {};
52
+ // 如果有属性字符串,解析属性
53
+ if (attributesString.trim()) {
54
+ // 使用手动解析来处理复杂的嵌套结构
55
+ let i = 0;
56
+ while (i < attributesString.length) {
57
+ // 跳过空白字符
58
+ while (i < attributesString.length && /\s/.test(attributesString[i])) {
59
+ i++;
60
+ }
61
+ if (i >= attributesString.length)
62
+ break;
63
+ // 解析属性名
64
+ let key = '';
65
+ while (i < attributesString.length && /[a-zA-Z0-9_$\-]/.test(attributesString[i])) {
66
+ key += attributesString[i];
67
+ i++;
68
+ }
69
+ if (!key) {
70
+ i++;
71
+ continue;
72
+ }
73
+ // 跳过空白字符
74
+ while (i < attributesString.length && /\s/.test(attributesString[i])) {
75
+ i++;
76
+ }
77
+ // 检查是否有等号
78
+ if (i < attributesString.length && attributesString[i] === '=') {
79
+ i++; // 跳过等号
80
+ // 跳过空白字符
81
+ while (i < attributesString.length && /\s/.test(attributesString[i])) {
82
+ i++;
83
+ }
84
+ if (i >= attributesString.length) {
85
+ props[key] = true;
86
+ break;
87
+ }
88
+ // 解析属性值
89
+ const value = parseAttributeValue(attributesString, i, context);
90
+ props[key] = value.value;
91
+ i = value.nextIndex;
92
+ }
93
+ else {
94
+ // 没有等号,是布尔属性
95
+ props[key] = true;
96
+ }
97
+ }
98
+ }
99
+ // 3. 处理 children(如果不是自闭合标签)
100
+ if (!isSelfClosing && children.trim()) {
101
+ props.children = children;
102
+ }
103
+ // 4. 处理 kebab-case 到 camelCase 的转换
104
+ const camelCaseProps = {};
105
+ for (const [key, value] of Object.entries(props)) {
106
+ const camelKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
107
+ camelCaseProps[camelKey] = value;
108
+ }
109
+ return camelCaseProps;
110
+ }
4
111
  /**
5
- * Component类:消息组件系统核心,支持模板渲染、属性解析、循环等。
6
- * 用于自定义消息结构和复用UI片段。
7
- * @template T 组件props类型
8
- * @template D 组件data类型
9
- * @template P 组件props配置类型
112
+ * 解析属性值
10
113
  */
11
- export class Component {
12
- $options;
13
- [CapWithClose];
14
- [CapWithChild];
15
- $props = [];
16
- get name() {
17
- return this.$options.name;
114
+ function parseAttributeValue(str, startIndex, context) {
115
+ let i = startIndex;
116
+ // 处理引号包围的字符串
117
+ if (str[i] === '"' || str[i] === "'") {
118
+ const quote = str[i];
119
+ i++; // 跳过开始引号
120
+ let value = '';
121
+ while (i < str.length && str[i] !== quote) {
122
+ if (str[i] === '\\' && i + 1 < str.length) {
123
+ // 处理转义字符
124
+ i++;
125
+ value += str[i];
126
+ }
127
+ else {
128
+ value += str[i];
129
+ }
130
+ i++;
131
+ }
132
+ if (i < str.length) {
133
+ i++; // 跳过结束引号
134
+ }
135
+ // 检查引号内是否包含表达式(大括号)
136
+ if (value.includes('{') && value.includes('}')) {
137
+ // 包含表达式,进行求值
138
+ const evaluatedValue = evaluateQuotedExpression(value, context);
139
+ return { value: evaluatedValue, nextIndex: i };
140
+ }
141
+ return { value, nextIndex: i };
18
142
  }
19
- set name(value) {
20
- this.$options.name = value;
143
+ // 处理大括号包围的表达式
144
+ if (str[i] === '{') {
145
+ let braceCount = 0;
146
+ let value = '';
147
+ i++; // 跳过开始大括号
148
+ while (i < str.length) {
149
+ if (str[i] === '{') {
150
+ braceCount++;
151
+ }
152
+ else if (str[i] === '}') {
153
+ if (braceCount === 0) {
154
+ i++; // 跳过结束大括号
155
+ break;
156
+ }
157
+ braceCount--;
158
+ }
159
+ value += str[i];
160
+ i++;
161
+ }
162
+ return { value: parseExpressionValue(value, context), nextIndex: i };
21
163
  }
22
- /**
23
- * 构造函数:初始化组件,生成属性正则
24
- * @param $options 组件配置项
25
- */
26
- constructor($options) {
27
- this.$options = $options;
28
- this.formatProps();
29
- this[CapWithChild] = new RegExp(`<${$options.name}([^>]*)?>([^<])*?</${$options.name}>`);
30
- this[CapWithClose] = new RegExp(`<${$options.name}([^>]*)?/>`);
164
+ // 处理无引号的值
165
+ let value = '';
166
+ while (i < str.length && !/\s/.test(str[i]) && str[i] !== '>') {
167
+ value += str[i];
168
+ i++;
31
169
  }
32
- /**
33
- * 判断模板是否为自闭合标签
34
- * @param template 模板字符串
35
- */
36
- isClosing(template) {
37
- return this[CapWithClose].test(template);
170
+ return { value: parseUnquotedValue(value, context), nextIndex: i };
171
+ }
172
+ /**
173
+ * 求值引号内的表达式
174
+ */
175
+ function evaluateQuotedExpression(quotedValue, context) {
176
+ if (!context)
177
+ return quotedValue;
178
+ // 处理引号内的表达式,将 {expr} 格式转换为 ${expr} 格式
179
+ let result = quotedValue;
180
+ const expressionRegex = /\{([^}]+)\}/g;
181
+ let match;
182
+ while ((match = expressionRegex.exec(quotedValue)) !== null) {
183
+ const expr = match[1];
184
+ try {
185
+ const value = context.getValue(expr);
186
+ if (value !== undefined && value !== expr) {
187
+ const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
188
+ result = result.replace(match[0], stringValue);
189
+ }
190
+ }
191
+ catch (error) {
192
+ // 如果求值失败,保持原始表达式
193
+ }
194
+ }
195
+ return result;
196
+ }
197
+ /**
198
+ * 解析表达式值
199
+ */
200
+ function parseExpressionValue(expr, context) {
201
+ expr = expr.trim();
202
+ // 处理字符串字面量
203
+ if ((expr.startsWith('"') && expr.endsWith('"')) ||
204
+ (expr.startsWith("'") && expr.endsWith("'"))) {
205
+ return expr.slice(1, -1);
38
206
  }
39
- /**
40
- * 匹配组件标签
41
- * @param template 模板字符串
42
- * @returns 匹配到的标签内容
43
- */
44
- match(template) {
45
- let [match] = this[CapWithChild].exec(template) || [];
46
- if (match)
47
- return match;
48
- [match] = this[CapWithClose].exec(template) || [];
49
- return match;
207
+ // 处理数字
208
+ if (/^-?\d+(\.\d+)?$/.test(expr)) {
209
+ return parseFloat(expr);
50
210
  }
51
- /**
52
- * 格式化props配置,生成props数组
53
- */
54
- formatProps() {
55
- for (const [key, value] of Object.entries(this.$options.props || {})) {
56
- this.formatProp(key, value);
211
+ // 处理布尔值
212
+ if (expr === 'true')
213
+ return true;
214
+ if (expr === 'false')
215
+ return false;
216
+ if (expr === 'null')
217
+ return null;
218
+ if (expr === 'undefined')
219
+ return undefined;
220
+ // 处理数组
221
+ if (expr.startsWith('[') && expr.endsWith(']')) {
222
+ try {
223
+ return JSON.parse(expr);
224
+ }
225
+ catch {
226
+ // 如果JSON解析失败,尝试手动解析简单数组
227
+ const items = expr.slice(1, -1).split(',').map(item => parseExpressionValue(item.trim(), context));
228
+ return items;
57
229
  }
58
230
  }
59
- /**
60
- * 格式化单个prop配置
61
- * @param name 属性名
62
- * @param value 类型或配置
63
- */
64
- formatProp(name, value) {
65
- if (typeof value === 'function') {
66
- return this.$props.push({
67
- name,
68
- type: value,
69
- default: undefined,
70
- });
231
+ // 处理对象 - 改进的嵌套大括号处理
232
+ if (expr.startsWith('{') && expr.endsWith('}')) {
233
+ try {
234
+ return JSON.parse(expr);
235
+ }
236
+ catch {
237
+ // 如果JSON解析失败,尝试手动解析简单对象
238
+ try {
239
+ return parseSimpleObject(expr);
240
+ }
241
+ catch {
242
+ // 如果都失败,返回原始字符串
243
+ return expr;
244
+ }
71
245
  }
72
- return this.$props.push({
73
- name,
74
- type: value.type,
75
- default: value.default,
76
- });
77
246
  }
78
- parseProps(template) {
79
- const result = Object.fromEntries(this.$props.map(prop => {
80
- const generateDefault = typeof prop.default === 'function' ? prop.default : () => prop.default;
81
- return [prop.name, generateDefault()];
82
- }));
83
- const matchedArr = [...template.matchAll(/([a-zA-Z\-:]+)\s*=\s*(['"])(.*?)\2/g)].filter(Boolean);
84
- if (!matchedArr.length)
247
+ // 处理表达式 - 在沙盒中执行
248
+ if (context) {
249
+ try {
250
+ const result = context.getValue(expr);
251
+ // 如果结果是 undefined,说明表达式被阻止或求值失败,返回原始表达式
252
+ if (result === undefined) {
253
+ return expr;
254
+ }
85
255
  return result;
86
- for (const [_, key, __, value] of matchedArr) {
87
- Object.defineProperty(result, key, {
88
- enumerable: true,
89
- writable: false,
90
- value,
91
- });
92
256
  }
93
- return result;
94
- }
95
- parseChildren(template) {
96
- if (this.isClosing(template))
97
- return '';
98
- const matched = template.match(/<[^>]+>([^<]*?)<\/[^?]+>/);
99
- if (!matched)
100
- return '';
101
- return matched[1];
257
+ catch (error) {
258
+ // 如果执行失败,返回原始表达式
259
+ return expr;
260
+ }
102
261
  }
103
- async render(template, context) {
104
- const props = this.parseProps(template);
105
- const assignValue = () => {
106
- for (const key of keys) {
107
- if (!key.startsWith(':'))
108
- continue;
109
- Object.defineProperty(props, key.slice(1), {
110
- value: getValueWithRuntime(Reflect.get(props, key), context.parent),
111
- });
112
- Reflect.deleteProperty(props, key);
262
+ // 如果没有上下文,返回原始表达式
263
+ return expr;
264
+ }
265
+ /**
266
+ * 解析简单对象(处理嵌套大括号和方括号)
267
+ */
268
+ function parseSimpleObject(objStr) {
269
+ const result = {};
270
+ let i = 1; // 跳过开始的 {
271
+ let depth = 0;
272
+ let bracketDepth = 0;
273
+ let key = '';
274
+ let value = '';
275
+ let inKey = true;
276
+ let inString = false;
277
+ let stringChar = '';
278
+ while (i < objStr.length - 1) { // 跳过结束的 }
279
+ const char = objStr[i];
280
+ if (!inString) {
281
+ if (char === '{') {
282
+ depth++;
283
+ value += char;
113
284
  }
114
- };
115
- const keys = Object.keys(props).map(key => {
116
- const newKey = key.replace(/(\w)+-(\w)/g, function (_, char, later) {
117
- return `${char}${later.toUpperCase()}`;
118
- });
119
- if (key !== newKey) {
120
- Object.defineProperty(props, newKey, {
121
- value: Reflect.get(props, key),
122
- enumerable: true,
123
- });
124
- Reflect.deleteProperty(props, key);
285
+ else if (char === '}') {
286
+ depth--;
287
+ value += char;
125
288
  }
126
- return newKey;
127
- });
128
- assignValue();
129
- const data = this.$options.data ? this.$options.data.apply(props) : {};
130
- for (const key of keys) {
131
- if (key === 'vFor') {
132
- const { 'vFor': expression, 'v-for': _, ...rest } = props;
133
- const { name, value, ...other } = Component.fixLoop(expression);
134
- const list = value === '__loop__' ? other[value] : getValueWithRuntime(value, context);
135
- const fnStr = `
136
- const result=[];\n
137
- for(const ${name} of list){\n
138
- result.push(render(props,{\n
139
- ...context,\n
140
- children:'',\n
141
- $origin:'${template.replace(/'/g, "'")}',
142
- parent:{\n
143
- ...context.parent,\n
144
- ${name}:list[${name}]
145
- }\n
146
- }))\n
289
+ else if (char === '[') {
290
+ bracketDepth++;
291
+ value += char;
292
+ }
293
+ else if (char === ']') {
294
+ bracketDepth--;
295
+ value += char;
296
+ }
297
+ else if (char === ':' && depth === 0 && bracketDepth === 0) {
298
+ inKey = false;
299
+ i++;
300
+ continue;
301
+ }
302
+ else if (char === ',' && depth === 0 && bracketDepth === 0) {
303
+ // 处理键值对
304
+ if (key.trim() && value.trim()) {
305
+ const parsedValue = parseExpressionValue(value.trim());
306
+ result[key.trim()] = parsedValue;
147
307
  }
148
- return result;`;
149
- const fn = new Function('render,list,props,context', fnStr);
150
- const newTpl = template
151
- .replace(`v-for="${expression}"`, '')
152
- .replace(`v-for='${expression}'`, '')
153
- .replace(`vFor="${expression}"`, '')
154
- .replace(`vFor='${expression}'`, '');
155
- return (await Promise.all(fn(this.render.bind(this), list, newTpl, context))).join('');
308
+ key = '';
309
+ value = '';
310
+ inKey = true;
311
+ i++;
312
+ continue;
156
313
  }
157
- if (key === 'vIf') {
158
- const needRender = getValueWithRuntime(Reflect.get(props, 'vIf'), context);
159
- if (!needRender)
160
- return '';
314
+ else if (char === '"' || char === "'") {
315
+ inString = true;
316
+ stringChar = char;
317
+ if (inKey) {
318
+ key += char;
319
+ }
320
+ else {
321
+ value += char;
322
+ }
323
+ }
324
+ else {
325
+ if (inKey) {
326
+ key += char;
327
+ }
328
+ else {
329
+ value += char;
330
+ }
161
331
  }
162
332
  }
163
- context.children = this.parseChildren(template) || context.children;
164
- const ctx = {
165
- $slots: context.$slots || {},
166
- ...props,
167
- ...data,
168
- $message: context.$message,
169
- render: context.render,
170
- parent: context,
171
- children: context.children,
172
- };
173
- const result = segment.toString(await this.$options.render(props, ctx));
174
- context.$root = context.$root.replace(context.$origin || template, result.includes('<') ? segment.escape(result) : result);
175
- return context.render(context.$root, context);
333
+ else {
334
+ if (char === stringChar) {
335
+ inString = false;
336
+ }
337
+ if (inKey) {
338
+ key += char;
339
+ }
340
+ else {
341
+ value += char;
342
+ }
343
+ }
344
+ i++;
345
+ }
346
+ // 处理最后一个键值对
347
+ if (key.trim() && value.trim()) {
348
+ const parsedValue = parseExpressionValue(value.trim());
349
+ result[key.trim()] = parsedValue;
176
350
  }
351
+ return result;
177
352
  }
178
- export function defineComponent(options, name = options.name) {
179
- if (typeof options === 'function')
180
- options = {
181
- name,
182
- render: options,
183
- };
184
- return new Component(options);
353
+ /**
354
+ * 解析无引号的值
355
+ */
356
+ function parseUnquotedValue(value, context) {
357
+ // 检查是否是大括号表达式
358
+ if (value.startsWith('{') && value.endsWith('}')) {
359
+ const expr = value.slice(1, -1); // 移除大括号
360
+ return parseExpressionValue(expr, context);
361
+ }
362
+ // 处理布尔值
363
+ if (value === 'true')
364
+ return true;
365
+ if (value === 'false')
366
+ return false;
367
+ // 处理数字
368
+ if (/^-?\d+(\.\d+)?$/.test(value)) {
369
+ return parseFloat(value);
370
+ }
371
+ // 处理 null/undefined
372
+ if (value === 'null')
373
+ return null;
374
+ if (value === 'undefined')
375
+ return undefined;
376
+ // 其他情况作为字符串处理
377
+ return value;
185
378
  }
186
- (function (Component) {
187
- Component.fixLoop = (loop) => {
188
- let [_, name, value] = /(\S+)\sin\s(\S+)/.exec(loop) || [];
189
- if (/\d+/.test(value))
190
- value = `[${new Array(+value)
191
- .fill(0)
192
- .map((_, i) => i)
193
- .join(',')}]`;
194
- if (/^\[.+]$/.test(value)) {
195
- return { name, value: '__loop__', __loop__: JSON.parse(value) };
196
- }
197
- return { name, value };
379
+ // 创建组件上下文的工厂函数
380
+ export function createComponentContext(props = {}, parent, root = '') {
381
+ return {
382
+ // 基础渲染能力
383
+ render: async (template, context) => {
384
+ // 这里需要实现渲染逻辑
385
+ return template;
386
+ },
387
+ // 数据访问(只读)
388
+ props: Object.freeze({ ...props }),
389
+ // 父组件上下文(只读)
390
+ parent: parent ? Object.freeze(parent) : undefined,
391
+ // 根模板(只读)
392
+ root,
393
+ // 子组件内容(React 概念)
394
+ children: undefined,
395
+ getValue: (template) => getValueWithRuntime(template, props),
396
+ compile: (template) => compiler(template, props),
198
397
  };
199
- async function render(componentMap, options) {
200
- if (!componentMap.size)
201
- return options;
202
- const components = [
203
- ...componentMap.values(),
204
- Component.Template,
205
- Component.Slot,
206
- ];
207
- const createContext = (runtime = {}, parent, $root) => {
208
- return {
209
- $slots: {},
210
- ...runtime,
211
- $message: parent.$message,
212
- $root,
213
- parent,
214
- render: (template, context) => {
215
- return renderWithRuntime(template, context, context.$root);
216
- },
217
- };
218
- };
219
- const renderWithRuntime = async (template, runtime, $root) => {
220
- const ctx = createContext(runtime, runtime, $root);
221
- template = compiler(template, runtime);
398
+ }
399
+ export async function renderComponent(component, template, context) {
400
+ const props = getProps(component, template, context);
401
+ return component(props, context);
402
+ }
403
+ // 渲染函数 - 支持新的组件系统
404
+ export async function renderComponents(componentMap, options, customContext) {
405
+ if (!componentMap.size)
406
+ return options;
407
+ const components = [...Array.from(componentMap.values()), Fetch, Fragment];
408
+ // 创建根上下文
409
+ const rootContext = customContext || createComponentContext(options, undefined, typeof options.content === 'string' ? options.content : segment.toString(options.content));
410
+ // 实现渲染逻辑
411
+ const renderWithContext = async (template, context) => {
412
+ let result = template;
413
+ let hasChanges = true;
414
+ let iterations = 0;
415
+ const maxIterations = 10; // 防止无限循环
416
+ // 编译模板
417
+ result = context.compile(result);
418
+ // 递归处理所有组件,直到没有更多组件需要渲染
419
+ while (hasChanges && iterations < maxIterations) {
420
+ hasChanges = false;
421
+ iterations++;
222
422
  for (const comp of components) {
223
- const match = comp.match(template);
224
- if (!match)
225
- continue;
226
- return await comp.render(match, ctx);
227
- }
228
- return template;
229
- };
230
- const template = segment.toString(options.content);
231
- const output = await renderWithRuntime(template, options, template);
232
- const content = segment.from(output);
233
- return {
234
- ...options,
235
- content
236
- };
237
- }
238
- Component.render = render;
239
- Component.Template = defineComponent({
240
- name: 'template',
241
- render(props, context) {
242
- const keys = Object.keys(props);
243
- if (!keys.length)
244
- keys.push('#default');
245
- for (const key of Object.keys(props)) {
246
- if (key.startsWith('#')) {
247
- context.parent.$slots[key.slice(1)] = (async (p) => {
248
- return await context.render(context.children || '', { ...context, ...p });
249
- });
423
+ const match = matchComponent(comp, result);
424
+ if (match) {
425
+ // 创建组件特定的上下文
426
+ const componentContext = createComponentContext(context.props, context, result);
427
+ const rendered = await renderComponent(comp, match, componentContext);
428
+ const renderedString = typeof rendered === 'string' ? rendered : segment.toString(rendered);
429
+ result = result.replace(match, renderedString);
430
+ hasChanges = true;
431
+ break; // 处理一个组件后重新开始循环
250
432
  }
251
433
  }
252
- return '';
253
- },
254
- });
255
- Component.Slot = defineComponent({
256
- name: 'slot',
257
- props: {
258
- name: String,
259
- },
260
- render({ name, ...props }, context) {
261
- name = name || 'default';
262
- if (!context.parent)
263
- return '';
264
- if (context.parent.$slots[name])
265
- return context.parent.$slots[name](props, context);
266
- return context.children || '';
267
- },
268
- });
269
- })(Component || (Component = {}));
270
- process.on('unhandledRejection', e => {
271
- // console.error 已替换为注释
272
- });
434
+ }
435
+ return result;
436
+ };
437
+ // 更新根上下文的渲染函数
438
+ rootContext.render = async (template, context) => {
439
+ return await renderWithContext(template, rootContext);
440
+ };
441
+ // 渲染模板
442
+ const output = await renderWithContext(rootContext.root, rootContext);
443
+ const content = typeof output === 'string' ? segment.from(output) : output;
444
+ return {
445
+ ...options,
446
+ content
447
+ };
448
+ }
449
+ // 内置组件
450
+ export const Fragment = defineComponent(async (props, context) => {
451
+ let children = props.children || '';
452
+ if (Array.isArray(children)) {
453
+ return children.join('');
454
+ }
455
+ if (typeof children === 'string') {
456
+ try {
457
+ const parsed = JSON.parse(segment.unescape(children));
458
+ return context.render(parsed || '', context);
459
+ }
460
+ catch {
461
+ return context.render(children || '', context);
462
+ }
463
+ }
464
+ return String(children);
465
+ }, 'Fragment');
466
+ export const Fetch = defineComponent(async ({ url }) => {
467
+ return await fetch(url).then((r) => r.text());
468
+ }, 'fetch');
273
469
  //# sourceMappingURL=component.js.map