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

93.33% Statements 70/75
76.92% Branches 20/26
100% Functions 6/6
97.22% Lines 70/72

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

    37x
    37x
    37x
    37x

    354x
    354x

    12x
    12x
    12x
    12x

    342x

    342x

    14x
    14x
    14x
    14x
    14x

    328x
    328x
    318x

    6x
    2x

    4x
    4x
    4x
    4x
    4x

    312x
    7x

    17x
    17x
    17x

    17x
    17x
    17x
    15x

    17x
    34x

    32x

    32x
    32x

    17x
    17x

    305x

    147x
    147x
    147x
    147x
    147x

    11x
    11x
    11x
    11x
    11x

    147x
    147x
    147x
    147x
    147x

    305x

    9x
    9x
    9x
    9x
    4x
    4x
    4x
    4x

    301x

    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;
                })
            Eif (result.length) {
                return result;
            } else {
                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) {
                //
            }
        }
        return selector;
    }

    module.exports = getSelector;