all files / src/ source-modifier.js

100% Statements 25/25
100% Branches 2/2
100% Functions 0/0
100% Lines 23/23
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   10×               40×     10×   10×                           14×                    
import ES6GlobalParser from 'es6-global-parser'
import EscapeStringRegexp from 'escape-string-regexp'
 
const ReplaceAt = (original, replacement, start, end) => {
    return original.slice(0, start) + replacement + original.slice(end)
}
 
const SourceModifier = (source, filename) => {
    const shortFileName = filename.replace(process.cwd(), '')
    const invocations = []
    const substitutions = []
    const suffixID = '__NUTRA_MOCK__'
 
    // Get all the global names that would need to be mocked
    const globals = ES6GlobalParser(source)
 
    // Go through all the names to in reverse as to not distort the positions of
    // the static replacements
    globals.reverse().forEach(({ type, name, start, end }) => {
        // Add suffix to all global names to make it easier to do a global
        // replacement of all relevant names in the deep execution contexts
        source = ReplaceAt(source, name + suffixID, start, end)
        // While we are at it
        if (type !== 'export') {
            // Create all the invocations that will set the original values for
            // all the global names in the file
            invocations.push(
                `NutraMock.setEntry("${shortFileName}", "${name}", ${name})`
            )
            // Create all the substitutions that will deliver the correct values
            // whenever these global names are requested
            substitutions.push({
                name,
                alias: `NutraMock.store["${shortFileName}"]["${name}"]`
            })
        }
    })
 
    // Replace all deep execution contexts names with their substitutes
    substitutions.forEach(({ name, alias }) => {
        const escapedRegex = EscapeStringRegexp(name)
        const pattern = new RegExp(`\\b${name}\\b`, 'g')
        source = source.replace(pattern, alias)
    })
 
    // Restore all global names to their original value
    const pattern = new RegExp(`${suffixID}`, 'g')
    source = source.replace(pattern, '')
 
    // Inject the invocations that will set the original values
    source = source + ';\n' + invocations.join(';\n')
 
    return source
}
 
export default SourceModifier