@darkchest/wck 0.0.1

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.
@@ -0,0 +1,34 @@
1
+ import parser from '@babel/parser';
2
+ import t from '@babel/types';
3
+ import { Logger } from './utils/index.js';
4
+
5
+ import compileStyles from './compilers/compileStyles.js'
6
+ import compileScriptDefault from './compilers/compileScriptDefault.js'
7
+ import compileScriptSetup from './compilers/compileScriptSetup.js'
8
+ import compileTemplate from './compilers/compileTemplate.js'
9
+
10
+ export const compileSFCStyles = (styles) => compileStyles(styles);
11
+
12
+ export const compileSFCScripts = (script) => {
13
+ const ast = parser.parse(script?.content ?? '', { sourceType: 'module'});
14
+
15
+ if(ast.program.body.some(node => t.isExportDefaultDeclaration(node))){
16
+ // 检测到顶层export default, 认为这是vue2的组件脚本风格.
17
+ return compileScriptDefault(ast);
18
+ }
19
+
20
+ return compileScriptSetup(ast);
21
+ };
22
+ export const compileSFCTempalte = (template) => {
23
+ const compiled = compileTemplate(template?.ast);
24
+
25
+ compiled?.warnings?.forEach?.(str => Logger.warn(str));
26
+
27
+ return compiled?.template ?? '';
28
+ };
29
+
30
+ export default{
31
+ compileSFCStyles,
32
+ compileSFCScripts,
33
+ compileSFCTempalte,
34
+ }
@@ -0,0 +1,199 @@
1
+ import { reactive, createApp } from './libs/petite-vue.es.js';
2
+ import { isComp, Logger } from "./utils/index.js";
3
+
4
+ export default class extends HTMLElement {
5
+ static observedAttributes = [/** <!-- Attributes --> */];
6
+ constructor() {
7
+ super();
8
+ this._isDarkchest = true;
9
+ this._componentId = Math.random().toString(36).substring(2);
10
+ this._types = {/** <!-- Types --> */};
11
+ this._watchers = {};
12
+ this._listeners = [];
13
+ this._el = null;
14
+ this._parent = null;
15
+ this._children = [];
16
+ this._eventPrefix = '@';
17
+
18
+ this.attachShadow({ mode: "open" });
19
+
20
+ const style = document.createElement("style");
21
+ style.textContent = `
22
+ *, *::before, *::after {
23
+ padding: 0;
24
+ margin: 0;
25
+ box-sizing: border-box;
26
+ }
27
+ /** <!-- Styles --> */
28
+ `;
29
+
30
+ const container = document.createElement("div");
31
+ container.innerHTML = `<div /** <!-- Watcher --> */>/** <!-- Template --> */</div>`;
32
+ this._el = container.firstElementChild;
33
+
34
+ this.shadowRoot.appendChild(style);
35
+ this.shadowRoot.appendChild(this._el);
36
+
37
+ this.app = null;
38
+ }
39
+
40
+ connectedCallback() {
41
+ const that = this;
42
+ this.app = reactive({
43
+ /** <!-- Config --> */
44
+ get $el(){
45
+ return that.$el;
46
+ },
47
+ get $parent(){
48
+ return that.$parent;
49
+ },
50
+
51
+ get $children(){
52
+ return that.$children;
53
+ },
54
+
55
+ get $root(){
56
+ return that.$root;
57
+ },
58
+ $emit(name, data){
59
+ that.dispatchEvent(new CustomEvent(that._eventPrefix + name, { detail: data }));
60
+ },
61
+ });
62
+ this.$app = createApp(this.app).mount(this._el);
63
+
64
+ let parent = this.parentElement;
65
+ while(parent && !isComp(parent)){
66
+ parent = parent.parentElement;
67
+ }
68
+ if(parent){
69
+ this._parent = parent;
70
+ parent._children.push(this);
71
+ }
72
+
73
+ this.dispatchEvent(new CustomEvent('mounted'));
74
+ this.app?.$lifecycle_mounted?.();
75
+
76
+ /** <!-- initializeAttribute --> */
77
+
78
+ /** <!-- initializeData --> */
79
+ }
80
+
81
+ attributeChangedCallback(name, oldValue, newValue){
82
+ if(!this.app){
83
+ var that = this;
84
+ setTimeout(function(){
85
+ that.attributeChangedCallback(name, oldValue, newValue);
86
+ }, 10);
87
+ return;
88
+ }
89
+ if((this?.constructor?.observedAttributes ?? []).indexOf?.(name) >= 0){
90
+ const prop = this._types[name];
91
+ if(prop){
92
+ this.app[prop.attr] = this._typeChcker(newValue, prop.type);
93
+ }
94
+ }
95
+ }
96
+
97
+ disconnectedCallback() {
98
+ if(this._children){
99
+ this._children.forEach(child => child.disconnectedCallback());
100
+ this._children = [];
101
+ }
102
+ if(this._parent){
103
+ this._parent._children = this._parent._children.filter(child => child !== this);
104
+ this._parent = null;
105
+ }
106
+
107
+ Object.keys(this._listeners).forEach(name => this.off(name));
108
+ this._listeners = {};
109
+
110
+ this.dispatchEvent(new CustomEvent('unmounted'));
111
+ this.app?.$lifecycle_unmounted?.();
112
+ this.app = null;
113
+ this.$app.unmount();
114
+ this.$app = null;
115
+
116
+ this._el = null;
117
+ }
118
+
119
+ get __isDarkchest(){
120
+ return this._isDarkchest;
121
+ }
122
+
123
+ get __componentId(){
124
+ return this._componentId;
125
+ }
126
+
127
+ get $el(){
128
+ return this._el || null;
129
+ }
130
+
131
+ get $parent(){
132
+ return this._parent || null;
133
+ }
134
+
135
+ get $children(){
136
+ return this._children || [];
137
+ }
138
+
139
+ get $root(){
140
+ let root = this;
141
+ while(root.$parent && isComp(root.$parent)){
142
+ root = root.$parent;
143
+ }
144
+ return root;
145
+ }
146
+
147
+ _typeChcker(val, type){
148
+ console.log('_typeChcker: ', type)
149
+ return val;
150
+ }
151
+
152
+ prop(name, value){
153
+ if((this?.constructor?.observedAttributes ?? []).indexOf?.(name) >= 0){
154
+ if(value === undefined) return this.getAttribute(name);
155
+ this.setAttribute(name, value);
156
+ }else{
157
+ Logger.info(`未定义的prop [${name}]`);
158
+ }
159
+ }
160
+
161
+ /** <!-- Props --> */
162
+
163
+ on(name, handler, options){
164
+ const eventName = this._eventPrefix + name;
165
+ this._listeners[eventName] = handler;
166
+ this.addEventListener(eventName, handler, options);
167
+ return this;
168
+ }
169
+
170
+ off(name, handler){
171
+ if(name){
172
+ const eventName = this._eventPrefix + name;
173
+ if(handler){
174
+ // 尝试删除特定的事件监听
175
+ this.removeEventListener(eventName, handler);
176
+ delete this._listeners[eventName];
177
+ }else{
178
+ const eventHandler = this._listeners[eventName];
179
+ if(eventHandler){
180
+ this.removeEventListener(eventName, eventHandler);
181
+ delete this._listeners[eventName];
182
+ }
183
+ }
184
+ }
185
+ return this;
186
+ }
187
+
188
+ once(name, handler, options){
189
+ const eventName = this._eventPrefix + name;
190
+ const eventHandler = (...args) => {
191
+ this.removeEventListener(eventName, eventHandler);
192
+ handler(...args);
193
+ };
194
+ this.addEventListener(eventName, eventHandler, options);
195
+ return this;
196
+ }
197
+
198
+ /** <!-- Methods --> */
199
+ }
@@ -0,0 +1,333 @@
1
+ import parser from '@babel/parser';
2
+ import traverse from '@babel/traverse';
3
+ import { generate } from "@babel/generator";
4
+ import t from '@babel/types';
5
+ import { LogSig } from '../utils/index.js';
6
+
7
+ export const compileExportDefault = (ast) => {
8
+ const scriptData = {
9
+ config: [], // petite使用的配置项
10
+ attributes: [], // web组件暴露给html标签的属性名称列表
11
+ types: [], // web组件暴露给html标签的属性类型索引
12
+ props: [], // web组件属性名称列表, 用于间接设置petite的attrivutes属性
13
+ watcher: [], // 用于模拟watch效果的变量收集
14
+ methods: [], // web组件方法名称, 用于间接调用petite方法.
15
+ initializeAttribute: [], // 初始化this.app.props的属性
16
+ initializeData: [], // 初始化this.app.data的数据
17
+ };
18
+ let exportedDeclaration = null;
19
+
20
+ const isSimpleType = (node) => t.isIdentifier(node) && ['String', 'Number', 'Boolean'].includes(node.name);
21
+
22
+ const getFunctionAst = (node) => parser.parse('const fn = ' + generate(node)?.code, { sourceType: 'module' });
23
+
24
+ const getFunctionReturnValue = (node) => {
25
+ const returnStatements = [];
26
+ const ast = getFunctionAst(node);
27
+ traverse.default(ast, {
28
+ ReturnStatement(path) {
29
+ returnStatements.push(path.node.argument);
30
+ }
31
+ });
32
+ const returnNode = returnStatements?.[0];
33
+ if (returnNode && t.isArrayExpression(returnNode)) {
34
+ return eval(generate(returnNode)?.code);
35
+ }
36
+ if (returnNode && t.isObjectExpression(returnNode)) {
37
+ return eval(`(${generate(returnNode)?.code})`);
38
+ }
39
+ return undefined;
40
+ };
41
+
42
+ const getFunctionCode = (node) => {
43
+ let async = false;
44
+ let paramsNode = [];
45
+ let bodyNode = { body: [] };
46
+ if(t.isObjectProperty(node) && t.isArrowFunctionExpression(node.value)){
47
+ async = node.value.async;
48
+ if(t.isBlockStatement(node.value.body)){
49
+ bodyNode = node.value.body;
50
+ }else{
51
+ const ast = parser.parse(`function anonymous(){
52
+ return ${generate(node.value.body)?.code};
53
+ }`, { sourceType: 'module' });
54
+ bodyNode = ast.program.body[0].body;
55
+ }
56
+ paramsNode = node.value.params;
57
+ }
58
+ if(t.isObjectProperty(node) && t.isFunctionExpression(node.value)){
59
+ async = node.value.async;
60
+ if(t.isBlockStatement(node.value.body)){
61
+ bodyNode = node.value.body;
62
+ paramsNode = node.value.params;
63
+ }
64
+ }
65
+ if(t.isObjectMethod(node)){
66
+ async = node.async;
67
+ if(t.isBlockStatement(node.body)){
68
+ bodyNode = node.body;
69
+ paramsNode = node.params;
70
+ }
71
+ }
72
+ return {
73
+ async,
74
+ name: node.key.name,
75
+ params: paramsNode?.map?.(node => generate(node).code)?.join?.(', ') ?? '',
76
+ body: bodyNode?.body?.map?.(node => generate(node).code)?.join?.('\n') ?? '',
77
+ }
78
+ }
79
+
80
+ const getNodePropData = (node) => {
81
+ const name = node.key.name;
82
+ if(t.isObjectProperty(node) || t.isObjectMethod(node)){
83
+ const valueNode = node.value;
84
+ if(isSimpleType(valueNode) && t.isIdentifier(valueNode)){
85
+ return {
86
+ name,
87
+ type: [`"${valueNode.name}"`],
88
+ default: null,
89
+ }
90
+ }
91
+ if(t.isStringLiteral(valueNode)){
92
+ return {
93
+ name,
94
+ type: ["String"],
95
+ default: generate(valueNode).code,
96
+ }
97
+ }
98
+ if(t.isNumericLiteral(valueNode)){
99
+ return {
100
+ name,
101
+ type: ["Number"],
102
+ default: generate(valueNode).code,
103
+ }
104
+ }
105
+ if(t.isBooleanLiteral(valueNode)){
106
+ return {
107
+ name,
108
+ type: ["Boolean"],
109
+ default: !!(valueNode.value),
110
+ }
111
+ }
112
+ if(t.isArrayExpression(valueNode)){
113
+ return {
114
+ name,
115
+ type: valueNode.elements.map(item => t.isIdentifier(item) ? "${item.name}" : null).filter(item => !!item),
116
+ default: null,
117
+ }
118
+ }
119
+
120
+ if(t.isArrowFunctionExpression(valueNode) || t.isFunctionExpression(valueNode) || t.isObjectMethod(node)){
121
+ return{
122
+ name,
123
+ type: ["Object"],
124
+ default: `function(){
125
+ ${getFunctionCode(node).body}
126
+ }`,
127
+ }
128
+ }
129
+ }
130
+ if(t.isObjectProperty(node) && t.isObjectExpression(node.value)){
131
+ const typeNode = node.value.properties.find(item => item.key.name === 'type');
132
+ const defaultNode = node.value.properties.find(item => item.key.name === 'default');
133
+ const defaultValue = getNodePropData(defaultNode);
134
+
135
+ let type = [].concat(defaultValue?.type);
136
+ if(typeNode){
137
+ if(t.isArrayExpression(typeNode.value)){
138
+ type = typeNode.value.elements.map(item => `"${generate?.(item)?.code}"`);
139
+ }
140
+ if(t.isIdentifier(typeNode.value)){
141
+ type = [`"${typeNode.value.name}"`];
142
+ }
143
+ }
144
+ return {
145
+ name,
146
+ type,
147
+ default: defaultValue?.default ?? null,
148
+ }
149
+ }
150
+ return { name, type: ["Object"], default: null };
151
+ }
152
+
153
+ traverse.default(ast, {
154
+ ExportDefaultDeclaration(path) {
155
+ // 存储 declaration,用于后续执行
156
+ exportedDeclaration = path.node.declaration;
157
+
158
+ // 映射 Options 属性到 AST 节点
159
+ if (t.isObjectExpression(exportedDeclaration)) {
160
+ exportedDeclaration.properties.forEach(propNode => {
161
+ if (t.isObjectProperty(propNode) || t.isObjectMethod(propNode)) {
162
+ const name = propNode.key.name;
163
+ switch(name){
164
+ case 'props':
165
+ if (t.isObjectProperty(propNode)){
166
+ const toLowerCase = (str) => str.toLowerCase();
167
+ const toSnakeCase = (str) => str.replace(/([A-Z])/g, '-$1').toLowerCase();
168
+ scriptData.attributes = propNode.value.properties?.map?.(item => `"${toLowerCase(item.key.name)}"`).concat(propNode.value.properties?.map?.(item => `"${toSnakeCase(item.key.name)}"`));
169
+ propNode.value.properties?.forEach?.(node => {
170
+ const ret = getNodePropData(node);
171
+ if(ret){
172
+ const type = `[${ret.type.join(', ')}]`
173
+ scriptData.types.push(`"${ret.name}": { type: ${type}, attr: "${ret.name}" }`);
174
+ scriptData.types.push(`"${toLowerCase(ret.name)}": { type: ${type}, attr: "${ret.name}" }`);
175
+ scriptData.types.push(`"${toSnakeCase(ret.name)}": { type: ${type}, attr: "${ret.name}" }`);
176
+ if(ret.type?.indexOf?.('Object') >= 0 || ret.type?.indexOf?.('Array') >= 0 || ret.type?.indexOf?.('Function') >= 0){
177
+ // 只要类型中存在复合类型, 则需要通过initializeAttribute函数去赋值.
178
+ scriptData.config.push(`${ret.name}: null`);
179
+ if(ret?.default?.indexOf?.('function(){') === 0){
180
+ // 如果默认值类型是函数, 则放在initializeAttribute中执行.
181
+ scriptData.initializeAttribute.push(`this.setAttribute("${ret.name}", (${ret.default})());`);
182
+ }
183
+ }else{
184
+ scriptData.config.push(`${ret.name}: ${ret.default}`);
185
+ }
186
+ scriptData.props.push(`
187
+ get ${ret.name}() { return this?.app?.${ret.name}; }
188
+ set ${ret.name}(value) {
189
+ this.app.${ret.name} = this?._typeChcker?.(value, ${ret?.type ?? []});
190
+ }
191
+ `);
192
+ }
193
+ });
194
+ }
195
+ break;
196
+ case 'data':
197
+ if(t.isObjectProperty(propNode) && t.isObjectExpression(propNode.value)){
198
+ propNode.value.properties?.forEach?.(node => {
199
+ const name = node.key.name;
200
+ scriptData.config.push(`${name}: ${generate(node.value)?.code ?? null}`);
201
+ });
202
+ }else{
203
+ const ast = parser.parse(`function anonymous(){
204
+ ${getFunctionCode(propNode).body};
205
+ }`, { sourceType: 'module' });
206
+ const returnNode = ast.program.body[0].body.body.find(item => t.isReturnStatement(item));
207
+ returnNode.argument.properties.forEach(node => {
208
+ const name = node.key.name;
209
+ scriptData.config.push(`${name}: ${generate(node.value)?.code ?? null}`);
210
+ });
211
+ scriptData.initializeData.push(`(function(){
212
+ const data = (function anonymous(){
213
+ ${getFunctionCode(propNode).body};
214
+ })();
215
+ Object.keys(data).forEach(name => {
216
+ if((that?.constructor?.observedAttributes ?? []).indexOf?.(name) >= 0){
217
+ Logger.info('当前属性 '+ name +' 已定义为 prop 属性, 无法初始化.')
218
+ }else{
219
+ that.app[name] = data[name];
220
+ }
221
+ });
222
+ })();`);
223
+ }
224
+ break;
225
+ case 'methods':
226
+ if(t.isObjectProperty(propNode)){
227
+ propNode.value.properties?.forEach(node => {
228
+ const { name, async, params, body } = getFunctionCode(node);
229
+ scriptData.config.push(`${async ? 'async':''} ${name}(${params}){
230
+ ${body}
231
+ }`);
232
+ scriptData.methods.push(`${async ? 'async':''} ${name}(${params}){
233
+ return this.app["${name}"](${params});
234
+ }`)
235
+ })
236
+ }
237
+ break;
238
+ case 'computed':
239
+ if(t.isObjectProperty(propNode)){
240
+ propNode.value.properties?.map(node => {
241
+ if(t.isObjectMethod(node)){
242
+ scriptData.config.push(`get ${node.key.name}(){
243
+ ${getFunctionCode(node).body}
244
+ }`);
245
+ }
246
+ if(t.isObjectProperty(node)){
247
+ const getNode = node.value.properties.find(item => item.key.name === 'get');
248
+ if(getNode){
249
+ scriptData.config.push(`get ${node.key.name}(){
250
+ ${getFunctionCode(getNode).body}
251
+ }`);
252
+ }
253
+ }
254
+ })
255
+ }
256
+ break;
257
+ case 'watch':
258
+ if(t.isObjectProperty(propNode)){
259
+ const toSnakeCase = (str) => str.replace(/([A-Z])/g, '_$1').replace(/[.\s]+/g, '_').toLowerCase();
260
+ propNode.value.properties?.map(node => {
261
+ const name = t.isStringLiteral(node.key) ? node.key.value : node.key.name;
262
+ const snaked = toSnakeCase(name);
263
+ scriptData.watcher.push(`:data-watch-${name}="$${snaked}"`);
264
+ if(t.isObjectMethod(node)){
265
+ const code = getFunctionCode(node);
266
+ const params = !!code.params?.trim?.() ? code.params : 'newVal, oldVal';
267
+ scriptData.config.push(`$$${snaked}_handler(${params}){
268
+ that._watchers['$$${snaked}'] = ${params}?.split?.(',')?.shift?.()?.trim?.();
269
+ ${code.body}
270
+ },
271
+ get $$${snaked}(){
272
+ const watchedVal = this.${name};
273
+ if(that._watchers['$$${snaked}'] !== watchedVal){
274
+ this.$$${snaked}_handler(watchedVal, that._watchers['$$${snaked}']);
275
+ }
276
+ return watchedVal;
277
+ }`);
278
+ }
279
+ if(t.isObjectProperty(node)){
280
+ const handlerNode = node.value.properties.find(item => item.key.name === 'handler');
281
+ const immediateNode = node.value.properties.find(item => item.key.name === 'immediate');
282
+ if(handlerNode){
283
+ const immediate = immediateNode?.value?.value === true;
284
+ const code = getFunctionCode(handlerNode);
285
+ const params = !!code.params?.trim?.() ? code.params : 'newVal, oldVal';
286
+ scriptData.config.push(`$$${snaked}_handler(${params}){
287
+ that._watchers['$$${snaked}'] = ${params}?.split?.(',')?.shift?.()?.trim?.();
288
+ ${code.body}
289
+ },
290
+ get $$${snaked}(){
291
+ const watchedVal = this.${name};
292
+ if(that._watchers['$$${snaked}'] !== watchedVal){
293
+ this.$$${snaked}_handler(watchedVal, that._watchers['$$${snaked}']);
294
+ }
295
+ return watchedVal;
296
+ }`);
297
+
298
+ if(immediate){
299
+ scriptData.initializeData.push(`this.app.$$${snaked}_handler(this.${name}, this._watchers['$$${snaked}']);`);
300
+ }
301
+ }
302
+ }
303
+ })
304
+ }
305
+ break;
306
+ case 'mounted':
307
+ case 'onMounted':
308
+ scriptData.config.push(`$lifecycle_mounted(){
309
+ ${getFunctionCode(propNode).body}
310
+ }`);
311
+ break;
312
+ case 'destroyed':
313
+ case 'unmounted':
314
+ case 'onUnmounted':
315
+ scriptData.config.push(`$lifecycle_unmounted(){
316
+ ${getFunctionCode(propNode).body}
317
+ }`);
318
+ break;
319
+ }
320
+ }
321
+ })
322
+ }
323
+ }
324
+ });
325
+
326
+ if (!exportedDeclaration) {
327
+ throw new Error(`${LogSig} 在组件script中没有找到 'export default {}' 模块.`);
328
+ }
329
+
330
+ return scriptData;
331
+ };
332
+
333
+ export default compileExportDefault;
@@ -0,0 +1,5 @@
1
+ export const compileScriptSetup = (ast) => {
2
+ // todo: 支持vue3的script setup语法转换.
3
+ }
4
+
5
+ export default compileScriptSetup;
@@ -0,0 +1,29 @@
1
+ import * as sass from 'sass';
2
+ import { Logger } from '../utils/index.js';
3
+
4
+ export const compileStyles = (styles) => {
5
+ if (!styles || styles.length === 0) {
6
+ return '';
7
+ }
8
+
9
+ const compiledCss = styles?.map?.(s => {
10
+ let content = s.content;
11
+ try {
12
+ if (s.lang === 'scss') {
13
+ const result = sass.compileString(content, { charset: false });
14
+ content = result.css.toString().replace(/\:+\s*root\s*\{/gi, ':host {');
15
+ }
16
+ if (s.scoped) {
17
+ // Logger.warn(`忽略scoped标识.`);
18
+ }
19
+ return content;
20
+ } catch (e) {
21
+ Logger.error(`解析CSS(${s.lang})失败:`, e);
22
+ return `/* Compilation Error */`;
23
+ }
24
+ }).join('\n');
25
+
26
+ return compiledCss;
27
+ };
28
+
29
+ export default compileStyles;
@@ -0,0 +1,62 @@
1
+ export const compileTemplate = (ast) => {
2
+ const warnings = new Set();
3
+
4
+ // 完整的 Vue AST 节点类型(从 @vue/compiler-core 源码)
5
+ const NodeTypes = {
6
+ ROOT: 0, // 根节点
7
+ ELEMENT: 1, // 元素节点
8
+ TEXT: 2, // 文本节点
9
+ COMMENT: 3, // 注释节点
10
+ SIMPLE_EXPRESSION: 4, // 简单表达式
11
+ INTERPOLATION: 5, // 插值表达式 {{ }}
12
+ ATTRIBUTE: 6, // 普通属性
13
+ DIRECTIVE: 7, // 指令
14
+ // containers
15
+ COMPOUND_EXPRESSION: 8, // 复合表达式
16
+ IF: 9, // v-if 节点
17
+ IF_BRANCH: 10, // v-if 分支
18
+ FOR: 11, // v-for 节点
19
+ TEXT_CALL: 12, // 文本调用
20
+ // codegen
21
+ VNODE_CALL: 13, // VNode 调用
22
+ JS_CALL_EXPRESSION: 14, // JS 函数调用
23
+ JS_OBJECT_EXPRESSION: 15, // JS 对象表达式
24
+ JS_PROPERTY: 16, // JS 对象属性
25
+ JS_ARRAY_EXPRESSION: 17, // JS 数组表达式
26
+ JS_FUNCTION_EXPRESSION: 18, // JS 函数表达式
27
+ JS_CONDITIONAL_EXPRESSION: 19, // JS 条件表达式
28
+ JS_CACHE_EXPRESSION: 20, // JS 缓存表达式
29
+ // ssr
30
+ JS_BLOCK_STATEMENT: 21, // JS 块语句
31
+ JS_TEMPLATE_LITERAL: 22, // JS 模板字符串
32
+ JS_IF_STATEMENT: 23, // JS if 语句
33
+ JS_ASSIGNMENT_EXPRESSION: 24, // JS 赋值表达式
34
+ JS_SEQUENCE_EXPRESSION: 25, // JS 序列表达式
35
+ JS_RETURN_STATEMENT: 26, // JS return 语句
36
+ };
37
+
38
+ // 执行转换
39
+ try {
40
+ let rootProps = `@vue:mounted="console.log('mounted on: ', $el)" @vue:unmounted="console.log('unmounted: ', $el)"`;
41
+ let html = ast.source.slice(ast.source.indexOf('<template>'), ast.source.lastIndexOf('</template>')).replace('<template>', '');
42
+ if(ast?.children?.length > 1 || ast?.children?.[0]?.type !== NodeTypes.ELEMENT){
43
+ html = `<div ${rootProps}>${html}</div>`;
44
+ }else{
45
+ const tag = ast.children?.[0]?.tag;
46
+ html = html.replace(`<${tag}`, `<${tag} ${rootProps}`);
47
+ }
48
+
49
+ return {
50
+ template: html.trim(),
51
+ warnings: Array.from(warnings)
52
+ };
53
+ } catch (error) {
54
+ return {
55
+ template: '',
56
+ warnings: [`转换错误: ${error.message}`],
57
+ error: error.message
58
+ };
59
+ }
60
+ }
61
+
62
+ export default compileTemplate;
@@ -0,0 +1,2 @@
1
+ export * from "./petite-vue/petite-vue.es.js";
2
+ export * from "./utils/index.js";