aboutsummaryrefslogtreecommitdiff
path: root/node_modules/istanbul-lib-instrument/src/read-coverage.js
blob: 5b76dbb1d57328b1494ec6dad5f5618d91ef1e2e (plain)
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
const { parseSync, traverse } = require('@babel/core');
const { defaults } = require('@istanbuljs/schema');
const { MAGIC_KEY, MAGIC_VALUE } = require('./constants');

function getAst(code) {
    if (typeof code === 'object' && typeof code.type === 'string') {
        // Assume code is already a babel ast.
        return code;
    }

    if (typeof code !== 'string') {
        throw new Error('Code must be a string');
    }

    // Parse as leniently as possible
    return parseSync(code, {
        babelrc: false,
        configFile: false,
        parserOpts: {
            allowAwaitOutsideFunction: true,
            allowImportExportEverywhere: true,
            allowReturnOutsideFunction: true,
            allowSuperOutsideMethod: true,
            sourceType: 'script',
            plugins: defaults.instrumenter.parserPlugins
        }
    });
}

module.exports = function readInitialCoverage(code) {
    const ast = getAst(code);

    let covScope;
    traverse(ast, {
        ObjectProperty(path) {
            const { node } = path;
            if (
                !node.computed &&
                path.get('key').isIdentifier() &&
                node.key.name === MAGIC_KEY
            ) {
                const magicValue = path.get('value').evaluate();
                if (!magicValue.confident || magicValue.value !== MAGIC_VALUE) {
                    return;
                }
                covScope =
                    path.scope.getFunctionParent() ||
                    path.scope.getProgramParent();
                path.stop();
            }
        }
    });

    if (!covScope) {
        return null;
    }

    const result = {};

    for (const key of ['path', 'hash', 'gcv', 'coverageData']) {
        const binding = covScope.getOwnBinding(key);
        if (!binding) {
            return null;
        }
        const valuePath = binding.path.get('init');
        const value = valuePath.evaluate();
        if (!value.confident) {
            return null;
        }
        result[key] = value.value;
    }

    delete result.coverageData[MAGIC_KEY];
    delete result.coverageData.hash;

    return result;
};