all files / src/ es6-global-parser.js

11.54% Statements 6/52
0% Branches 0/31
100% Functions 0/0
13.33% Lines 6/45
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                                                                                                                                                                                                                                                      
import Fs from 'fs'
import Espree from 'espree'
 
const EspreeConfig = {
    // attach range information to each node
    range: true,
    // attach line/column location information to each node
    loc: true,
    // create a top-level comments array containing all comments
    comment: true,
    // attach comments to the closest relevant node as leadingComments and
    // trailingComments
    attachComment: true,
    // create a top-level tokens array containing all tokens
    tokens: true,
    // specify the language version (3, 5, 6, or 7, default is 5)
    ecmaVersion: 5,
    // specify which type of script you're parsing (script or module, default is script)
    sourceType: 'module',
    // specify additional language features
    ecmaFeatures: {
        // enable JSX parsing
        jsx: true,
        // enable return in global scope
        globalReturn: true,
        // enable implied strict mode (if ecmaVersion >= 5)
        impliedStrict: true,
        // allow experimental object rest/spread
        experimentalObjectRestSpread: true,
        // allow let and const declarations
        blockBindings: true
    }
}
 
// Leaving this code here in case support for assignment variables are needed.
// Since we are only supporting "const" for now, this isn't needed.
const ExtractAssignmentConstants = (node, store) => {
    if (!node) {
        throw new Error('Something went wrong!')
    }
    if (node.type !== 'AssignmentExpression') {
        return node.end
    }
    const { name, start, end } = node.left
    store.push({ name, start, end })
    ExtractAssignmentConstants(node.right, store)
}
 
const ExtractGlobals = (astBody) => {
    const globals = {
        imports: {
            start: null,
            end: null,
            nodes: []
        },
        constants: {
            start: null,
            end: null,
            nodes: []
        },
        exports: {
            start: null,
            end: null,
            nodes: []
        }
    }
 
    astBody.forEach(node => {
        if (node.type === 'ImportDeclaration') { // handle imports
            const { start, end, specifiers } = node
            if (globals.imports.start === null) {
                globals.imports.start = start
            }
            globals.imports.end = end
            specifiers.forEach(node => {
                const { name, start, end } = node.local
                globals.imports.nodes.push({ name, start, end })
            })
        } else if (node.type === 'ExportAllDeclaration' || // handle exports
            node.type === 'ExportDefaultDeclaration' ||
            node.type === 'ExportNamedDeclaration') {
            if (globals.exports.start === null) {
                globals.exports.start = node.start
            }
            if (node.type === 'ExportDefaultDeclaration') {
                const { name, start, end } = node.declaration
                globals.exports.nodes.push({ name, start, end })
            } else if (node.type === 'ExportNamedDeclaration') {
                if (node.declaration && node.declaration.declarations[0]) {
                    const { id, init } = node.declaration.declarations[0]
                    const { name, start, end } = id
                    globals.exports.nodes.push({ name, start, end })
                    ExtractAssignmentConstants(init, globals.exports.nodes)
                } else {
                    node.specifiers.forEach(node => {
                        const { name, start, end } = node.local
                        globals.exports.nodes.push({ name, start, end })
                    })
                }
            }
            globals.exports.end = node.end
        } else if (node.type === 'VariableDeclaration' && // handle constants
                   node.kind === 'const') {
            if (globals.constants.start === null) {
                globals.constants.start = node.start
            }
            node.declarations.forEach(node => {
                const { id, init } = node
                const { name, start, end } = id
                const constantNodes = globals.constants.nodes
                const terminal = ExtractAssignmentConstants(init, constantNodes)
                constantNodes.push({ name, start, end, terminal })
            })
            globals.constants.end = node.end
        }
    })
    return globals
}
 
const Parse = (code) => {
    if (typeof code !== 'string') {
        throw new Error('Please pass in a valid code string!')
    }
    const ast = Espree.parse(code, EspreeConfig)
    return ExtractGlobals(ast.body)
}
 
export default Parse