electron-link/test/unit/file-require-transform.test.js

485 lines
11 KiB
JavaScript

'use strict'
const assert = require('assert')
const dedent = require('dedent')
const path = require('path')
const recast = require('recast')
const FileRequireTransform = require('../../lib/file-require-transform')
suite('FileRequireTransform', () => {
test('simple require', () => {
const source = dedent`
const a = require('a')
const b = require('b')
function main () {
const c = {a: b, b: a}
return a + b
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'a'}).apply(),
dedent`
let a;
function get_a() {
return a = a || require('a');
}
const b = require('b')
function main () {
const c = {a: b, b: get_a()}
return get_a() + b;
}
`
)
})
test('conditional requires', () => {
const source = dedent`
let a, b;
if (condition) {
a = require('a')
b = require('b')
} else {
a = require('c')
b = require('d')
}
function main () {
return a + b
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'a' || mod === 'c'}).apply(),
dedent`
let a, b;
let get_a;
if (condition) {
get_a = function() {
return a = a || require('a');
}
b = require('b')
} else {
get_a = function() {
return a = a || require('c');
}
b = require('d')
}
function main () {
return get_a() + b;
}
`
)
})
test('top-level variables assignments that depend on previous requires', () => {
const source = dedent`
const a = require('a')
const b = require('b')
const c = require('c').foo.bar
const d = c.X | c.Y | c.Z
var e
e = c.e
const f = b.f
function main () {
c.qux()
console.log(d)
e()
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => ['a', 'c'].indexOf(mod) >= 0}).apply(),
dedent`
let a;
function get_a() {
return a = a || require('a');
}
const b = require('b')
let c;
function get_c() {
return c = c || require('c').foo.bar;
}
let d;
function get_d() {
return d = d || get_c().X | get_c().Y | get_c().Z;
}
var e
function get_e() {
return e = e || get_c().e;
};
const f = b.f
function main () {
get_c().qux()
get_console().log(get_d())
get_e()()
}
`)
})
test('requires that appear in a closure wrapper defined in the top-level scope (e.g. CoffeeScript)', () => {
const source = dedent`
(function () {
const a = require('a')
const b = require('b')
function main () {
return a + b
}
}).call(this)
(function () {
const a = require('a')
const b = require('b')
function main () {
return a + b
}
})()
foo(function () {
const b = require('b')
const c = require('c')
function main () {
return b + c
}
})
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'a' || mod === 'c'}).apply(),
dedent`
(function () {
let a;
function get_a() {
return a = a || require('a');
}
const b = require('b')
function main () {
return get_a() + b;
}
}).call(this)
(function () {
let a;
function get_a() {
return a = a || require('a');
}
const b = require('b')
function main () {
return get_a() + b;
}
})()
foo(function () {
const b = require('b')
const c = require('c')
function main () {
return b + c
}
})
`
)
})
test('references to shadowed variables', () => {
const source = dedent`
const a = require('a')
function outer () {
console.log(a)
function inner () {
console.log(a)
}
let a = []
}
function other () {
console.log(a)
function inner () {
let a = []
console.log(a)
}
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'a'}).apply(),
dedent`
let a;
function get_a() {
return a = a || require('a');
}
function outer () {
get_console().log(a)
function inner () {
get_console().log(a)
}
let a = []
}
function other () {
get_console().log(get_a())
function inner () {
let a = []
get_console().log(a)
}
}
`
)
})
test('references to globals', () => {
const source = dedent`
global.a = 1
process.b = 2
window.c = 3
document.d = 4
function inner () {
const window = {}
global.e = 4
process.f = 5
window.g = 6
document.h = 7
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'a'}).apply(),
dedent`
get_global().a = 1
get_process().b = 2
get_window().c = 3
get_document().d = 4
function inner () {
const window = {}
get_global().e = 4
get_process().f = 5
window.g = 6
get_document().h = 7
}
`
)
})
test('multiple assignments separated by commas referencing deferred modules', () => {
const source = dedent`
let a, b, c, d, e, f;
a = 1, b = 2, c = 3;
d = require("d"), e = d.e, f = e.f;
`
assert.equal(
new FileRequireTransform({source, didFindRequire: () => true}).apply(),
dedent`
let a, b, c, d, e, f;
a = 1, b = 2, c = 3;
function get_d() {
return d = d || require("d");
}
function get_e() {
return e = e || get_d().e;
}
function get_f() {
return f = f || get_e().f;
}
`
)
})
test('require with destructuring assignment', () => {
const source = dedent`
const {a, b, c} = require('module').foo
function main() {
a.bar()
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: () => true}).apply(),
dedent`
let {a, b, c} = {};
function get_a() {
return a = a || require('module').foo.a;
}
function get_b() {
return b = b || require('module').foo.b;
}
function get_c() {
return c = c || require('module').foo.c;
}
function main() {
get_a().bar()
}
`
)
})
test('JSON source', () => {
const filePath = 'something.json'
const source = '{"a": 1, "b": 2}'
assert.equal(
new FileRequireTransform({filePath, source, didFindRequire: () => false}).apply(),
dedent`
module.exports = {"a": 1, "b": 2}
`
)
})
test('Object spread properties', () => {
const source = 'let {a, b, ...rest} = {a: 1, b: 2, c: 3}'
assert.equal(
new FileRequireTransform({source, didFindRequire: () => false}).apply(),
dedent`
let {a, b, ...rest} = {a: 1, b: 2, c: 3}
`
)
})
test('path resolution', () => {
const baseDirPath = path.resolve(__dirname, '..', 'fixtures', 'module-1')
const filePath = path.join(baseDirPath, 'dir', 'entry.js')
const source = dedent`
const a = require('a')
const b = require('./subdir/b')
const c = require('c')
const fs = require('fs')
function inner () {
require('./subdir/b')
require.resolve('a')
require.resolve('d')
require('d')
}
`
const requiredModules = []
assert.equal(
new FileRequireTransform({baseDirPath, filePath, source, didFindRequire: (unresolvedPath, resolvedPath) => {
requiredModules.push({unresolvedPath, resolvedPath})
return true
}}).apply(),
dedent`
let a;
function get_a() {
return a = a || require("./node_modules/a/index.js");
}
let b;
function get_b() {
return b = b || require("./dir/subdir/b.js");
}
let c;
function get_c() {
return c = c || require('c');
}
let fs;
function get_fs() {
return fs = fs || require('fs');
}
function inner () {
require("./dir/subdir/b.js")
require.resolve("./node_modules/a/index.js")
require.resolve('d')
require('d')
}
`
)
assert.deepEqual(requiredModules, [
{unresolvedPath: 'a' , resolvedPath: path.join(baseDirPath, 'node_modules', 'a', 'index.js')},
{unresolvedPath: './subdir/b' , resolvedPath: path.join(baseDirPath, 'dir', 'subdir', 'b.js')},
{unresolvedPath: 'c' , resolvedPath: 'c'},
{unresolvedPath: './subdir/b' , resolvedPath: path.join(baseDirPath, 'dir', 'subdir', 'b.js')},
{unresolvedPath: 'd' , resolvedPath: 'd'},
])
})
test('use reference directly', () => {
const source = dedent`
var pack = require('pack')
const x = console.log(pack);
if (condition) {
pack
} else {
Object.keys(pack).forEach(function (prop) {
exports[prop] = pack[prop]
})
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'pack'}).apply(),
dedent`
var pack
function get_pack() {
return pack = pack || require('pack');
}
let x;
function get_x() {
return x = x || get_console().log(get_pack());
}
if (condition) {
get_pack()
} else {
Object.keys(get_pack()).forEach(function (prop) {
exports[prop] = get_pack()[prop]
})
}
`
)
})
test('assign to `module` or `exports`', () => {
const source = dedent`
var pack = require('pack')
if (condition) {
module.exports.pack = pack
module.exports = pack
exports.pack = pack
exports = pack
}
`
assert.equal(
new FileRequireTransform({source, didFindRequire: (mod) => mod === 'pack'}).apply(),
dedent`
var pack
function get_pack() {
return pack = pack || require('pack');
}
if (condition) {
module.exports.pack = get_pack()
module.exports = get_pack()
exports.pack = get_pack()
exports = get_pack()
}
`
)
})
})