手写AST(抽象语法树)

 1 // 将字符串的属性转换为key:value类型
 2         const convert = (attr) => {
 3             if (attr == undefined) {
 4                 return [];
 5             } else {
 6                 let point = 0;
 7                 let flag = false;
 8                 let result = [];
 9                 for (let i = 0; i < attr.length; i++) {
10                     if (attr[i] == '"') {
11                         flag = !flag;
12                     } else if (!flag && attr[i] == ' ') {
13                         if (!/^\s*$/.test(attr.slice(point, i))) {
14                             result.push(attr.slice(point, i).trim());
15                             point = i;
16                         }
17                     }
18                 }
19                 result.push(attr.slice(point, attr.length).trim());
20                 result = result.map((item) => {
21                     let res = item.match(/^(.+)="(.+)"$/);
22                     return {
23                         name: res[1],
24                         value: res[2]
25                     }
26                 })
27                 return result;
28             }
29         }
30         // 将模板dom转换为对象的形式,以AST的形式实现
31         function prase(template) {
32             let startStark = [];
33             let endStark = [{ children: [] }];
34             let startReg = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/;   //开始标签的正则
35             let endReg = /^\<\/([a-z]+[1-6]?)+\>/;   //结束标签的正则
36             let innerReg = /^([^\<]+)\<\/[a-z]+[1-6]?\>/;
37             let attrReg = /^\"(a-z)+\"/;
38             let i = 0;
39             let rest = template;
40             while (i < template.length - 1) {
41                 rest = template.substring(i);
42                 // 匹配开始标签
43                 if (startReg.test(rest)) {
44                     // 把开始的标签提取出来
45                     let tag = rest.match(startReg)[1];
46                     let attr = rest.match(startReg)[2];
47                     let attrs = convert(attr);
48                     let attrLen = attr != undefined ? attr.length : 0;
49                     // push到startStark栈中
50                     startStark.push(tag);
51                     // 结束标签push一个空栈顶用来存放,内容
52                     endStark.push({ tag: tag, children: [], attrs: attrs });
53                     // 加2是因为<>
54                     i += tag.length + 2 + attrLen;
55                     // 匹配结束标签
56                 } else if (endReg.test(rest)) {
57                     // 把结束的标签提取出来
58                     let tag = rest.match(endReg)[1];
59                     // 判断是否是封闭标签,如果是,就去除栈顶
60                     if (startStark[startStark.length - 1] === tag) {
61                         // 去除开始标签
62                         startStark.pop();
63                         // 在下面检查到内容字符之后,检测到闭标签时弹栈,弹出的数组包含了内容字符
64                         let pop_arr = endStark.pop();
65                         // 把弹出栈的元素push给新的栈顶元素
66                         endStark[endStark.length - 1].children.push(pop_arr);
67                     } else {
68                         new Error(startStark[startStark.length - 1] + '没有封闭');
69                     }
70                     // 加3是因为</>
71                     i += tag.length + 3;
72                     // 匹配是否是内容字符且不为空内容
73                 } else if (innerReg.test(rest)) {
74                     // 把文本节点的内容提取出来
75                     let inner = rest.match(innerReg)[1];
76                     // 判断是否为空
77                     if (!/^\s+$/.test(inner)) {
78                         // 栈顶的元素push进去该文本节点
79                         endStark[endStark.length - 1].children.push({ text: inner, type: 3 });
80                     }
81                     i += inner.length;
82                 }
83                 else {
84                     i++;
85                 }
86             }
87             return endStark[0].children[0];
88         }
89         prase(`<div>
90             <h3 class="box" id="box2">你好</h3>
91             <ul>
92                 <li>A</li>
93                 <li>B</li>
94                 <li>C</li>
95             </ul>
96         </div>`);

 

posted @ 2023-09-04 17:44  Null&boy  阅读(68)  评论(0)    收藏  举报