All files / gogocode-core/src/js-core get-selector.js

94.04% Statements 79/84
78.57% Branches 22/28
100% Functions 6/6
97.53% Lines 79/81

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141    37x 37x 37x 37x     376x 376x   12x 12x 12x 12x   364x           364x   15x 15x 15x 15x 15x     349x 349x 338x   6x 2x           4x 4x 4x 4x 4x     332x 7x       18x 18x 18x           18x 18x 18x 16x         18x 36x   34x       34x 34x   18x 18x         325x   154x 154x 154x 154x 154x     11x 11x 11x 11x 11x     160x 160x 160x 160x 160x     325x   9x 9x 9x 9x 4x 4x 4x 4x       316x 10x 10x 10x 10x 9x 9x 9x 9x           312x       37x
// 把简单的api转换成ast
// todo await 
const recast = require('recast-yx');
const parse = require('./parse');
const visit = recast.types.visit;
const filterProps = require('./filter-prop.js');
 
function getSelector(selectorCode, parseOptions, expando) {
    const selector = { nodeType: '', structure: {} };
    if (typeof selectorCode != 'string') {
        // 如果是通过builders造出来的ast结构,比如return语句
        selector.nodeType = selectorCode.type;
        filterProps(selectorCode, selector.structure, '', expando);
        selector.type = selectorCode.type; // 兼容只用type匹配的选择器
        return selector;
    } else {
        selectorCode = selectorCode
            .replace(/\$_\$/g, expando)
            .replace(/\$\$\$/g, expando.slice(0, -1) + '$3')
            .replace(/\/\$_\/\$/g, '$_$')
            .replace(/\/\$\/\$\/\$/g, '$$$$$$')
    }
    if (selectorCode.match(/^{((.|\s)+(:|\(\))(.|\s)+)+}$/)) {
        // 如果是对象字面量
        let ast = parse(`var o = ${selectorCode}`);
        ast = ast.program.body[0].declarations[0].init;
        selector.nodeType = 'ObjectExpression';
        filterProps(ast, selector.structure);
        return selector;
    }
    let seletorAst;
    try {
        seletorAst = parse(selectorCode, parseOptions);
        if (seletorAst.program.body.length == 0) {
            // 开头的字符串会被解析成directive
            if (seletorAst.program.directives.length) {
                return {
                    nodeType: 'StringLiteral',
                    structure: {
                        value: selectorCode ? selectorCode.slice(1, -1) : ''
                    }
                }
            } else Eif (seletorAst.program.comments.length) {
                let ast = seletorAst.program.comments[0]
                selector.nodeType = ast.type;
                filterProps(ast, selector.structure);
                return selector;
            }
            
        } else if (seletorAst.program.body[0] && seletorAst.program.body[0].type == 'LabeledStatement') {
            throw new Error('Missing semicolon')
        }
    } catch(e) {
        // 可能是对象属性
        try {
            seletorAst = parse(`({${selectorCode}})`, parseOptions);
            seletorAst = seletorAst.program.body[0].expression.properties[0]
        } catch(e) {
            seletorAst = null;
        }
        
        // 可能是类属性
        let clsSelectorAst = null;
        try {
            clsSelectorAst = parse(`class a$_$ { ${selectorCode} }`, parseOptions)
            clsSelectorAst = clsSelectorAst.program.body[0].body.body[0]
        } catch(e) {
            //
        }
        
        const result = [seletorAst, clsSelectorAst]
            .filter(s => !!s)
            .map(sel => {
                const selector = {
                    nodeType: sel.type,
                    structure: {}
                }
                filterProps(sel, selector.structure)
                return selector;
            })
        if (result.length) {
            return result;
        } else E{
            throw new Error('parse error!' + e.message);
        }
    }
    visit(seletorAst, {
        visitExpressionStatement(path) {
            const expression = path.value.expression;
            Iif (!expression) return;
            selector.nodeType = expression.type;
            filterProps(expression, selector.structure);
            this.abort();
        },
        visitStatement(path) {
            const expression = path.value;
            Iif (!expression) return;
            selector.nodeType = expression.type;
            filterProps(expression, selector.structure);
            this.abort();
        },
        visitDeclaration(path) {
            const declaration = path.value;
            Iif (!declaration) return;
            selector.nodeType = declaration.type;
            filterProps(declaration, selector.structure);
            this.abort();
        }
    });
    if (selector.nodeType == 'AssignmentExpression') {
        // class中的属性
        try {
            const selectorAstList = [selector]
            const classPropSelector = { nodeType: '', structure: {} };
            const classPropSelectorAst = parse(`class A { ${selectorCode } }`, parseOptions).program.body[0].body.body[0]
            classPropSelector.nodeType = classPropSelectorAst.type;
            filterProps(classPropSelectorAst, classPropSelector.structure);
            selectorAstList.push(classPropSelector);
            return selectorAstList;
        } catch(e) {
            //
        }
    } else if (selector.nodeType == 'MemberExpression') {
        try {
            const selectorAstList = [selector]
            const classPropSelector = { nodeType: '', structure: {} };
            const classPropSelectorAst = parse(`type a = ${selectorCode}`, parseOptions).program.body[0].typeAnnotation.typeName
            classPropSelector.nodeType = classPropSelectorAst.type;
            filterProps(classPropSelectorAst, classPropSelector.structure);
            selectorAstList.push(classPropSelector);
            return selectorAstList;
        } catch(e) {
            // maybe selectorCode = this.xxx
        }
        
    }
    return selector;
}
 
 
module.exports = getSelector;