xwjie/VueStudyNote

02 生成语法树

xwjie opened this issue · 1 comments

xwjie commented

采用了 jQuery 作者 John Resig 的 HTML Parser ,(VUE也是用了这个),然后生成语法树,非常少的代码,语法树的结构参考了VUE的,目前只用了几个字段,不够后面再加。

生成语法树就是生成一颗树,比较麻烦的是父节点的处理,这里用一个栈来存放(就是一个数组,采用push和pop方法),代码非常简单,自己写的话10行左右就生成了语法树。

type1 表示dom节点,2表示表达式(未实现)3表示文本/注释,

/* @flow */
import { log } from '../util'
import { HTMLParser, HTMLtoXML, HTMLtoDOM } from './htmlparser'

//D:\OutPut\VUE\vue\src\compiler\parser\index.js
function html2ast(templte: string, data: Object): ?ASTElement {
    let root: ?ASTElement;
    let parent: ASTElement;
    let parentStack = [];

    HTMLParser(templte, {
        start: function (tag, attrs, unary) {
            //
            if (false === unary && parent) {
                parentStack.push(parent);
            }

            let e = createASTElement(tag, attrs, parent);

            if (!root) {
                root = e;
            }

            if(false === unary){
                parent = e;
            }
        },
        end: function (tag) {
            parent = parentStack.pop();
        },
        chars: function (text) {
            createTextlement(text, parent);
        },
        comment: function (text) {
            createCommentlement(text, parent);
        }
    });

    log('htmlparser ast', root);
    log('htmlparser parentStack', parentStack);
    return root;
}

function createASTElement(
    tag: string,
    attrs: Array<Attr>,
    parent: ?ASTElement
): ASTElement {
    let e = {
        type: 1,
        tag,
        //attrsList: attrs,
        attrsMap: makeAttrsMap(attrs),
        //parent,
        children: []
    }

    if (parent) {
        parent.children.push(e);
    }

    return e;
}

function createTextlement(
    text: string,
    parent: ASTElement
): ASTText {
    let e = {
        type: 3,
        text,
        //parent
    }

    parent.children.push(e);

    return e;
}

function createCommentlement(
    text: string,
    parent: ASTElement
): ASTText {
    let e = {
        type: 3,
        text,
        isComment: true,
        //parent
    }

    parent.children.push(e);

    return e;
}

function makeAttrsMap(attrs: Array<Object>): Object {
    const map = {}
    for (let i = 0, l = attrs.length; i < l; i++) {
        map[attrs[i].name] = attrs[i].value
    }
    return map
}

export { html2ast }

image

换行和空格的处理,有什么思路吗