You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.2 KiB
182 lines
5.2 KiB
const stackTrace = require('./stackTrace'); |
|
const splitPath = require('./splitPath'); |
|
const startWith = require('./startWith'); |
|
const defineProp = require('./defineProp'); |
|
const isStr = require('./isStr'); |
|
const has = require('./has'); |
|
const objToStr = require('./objToStr'); |
|
const unique = require('./unique'); |
|
const concat = require('./concat'); |
|
const keys = require('./keys'); |
|
const isArr = require('./isArr'); |
|
const toBool = require('./toBool'); |
|
|
|
const path = require('path'); |
|
|
|
exports = function(importFn, dirname) { |
|
return function(moduleId) { |
|
if (isRelative(moduleId)) { |
|
if (!dirname) { |
|
dirname = findDirName(); |
|
} |
|
moduleId = path.join(dirname, moduleId); |
|
} |
|
return proxyExports(importFn, moduleId); |
|
}; |
|
}; |
|
|
|
function proxyExports(importFn, moduleId) { |
|
const fakeExports = function() {}; |
|
let cache; |
|
|
|
function doImport() { |
|
if (cache) { |
|
return; |
|
} |
|
const module = importFn(moduleId); |
|
cache = Object(module); |
|
|
|
const valueOfDescriptor = createDescriptor(0, 0, 1); |
|
if (isStr(module)) { |
|
valueOfDescriptor.value = () => String(module.valueOf()); |
|
} else { |
|
valueOfDescriptor.value = () => Number(module.valueOf()); |
|
} |
|
defineProp(cache, 'valueOf', valueOfDescriptor); |
|
|
|
defineProp( |
|
cache, |
|
'toString', |
|
createDescriptor(0, 0, 1, () => String(module.toString())) |
|
); |
|
|
|
if (!has(cache, Symbol.toStringTag)) { |
|
const realType = objToStr(module).slice(8, -1); |
|
Object.defineProperty(cache, Symbol.toStringTag, { |
|
configurable: true, |
|
get() { |
|
return realType; |
|
} |
|
}); |
|
} |
|
} |
|
|
|
return new Proxy(fakeExports, { |
|
get(target, property) { |
|
doImport(); |
|
return cache[property]; |
|
}, |
|
set(target, property, value) { |
|
doImport(); |
|
cache[property] = value; |
|
return true; |
|
}, |
|
|
|
has(target, prop) { |
|
doImport(); |
|
return prop in cache; |
|
}, |
|
|
|
construct(target, argumentsList) { |
|
doImport(); |
|
|
|
return new cache(...argumentsList); |
|
}, |
|
|
|
apply(target, thisArg, argumentsList) { |
|
doImport(); |
|
return cache.apply(thisArg, argumentsList); |
|
}, |
|
|
|
ownKeys() { |
|
doImport(); |
|
|
|
const descriptors = Object.getOwnPropertyDescriptors(cache); |
|
delete descriptors.valueOf; |
|
delete descriptors.toString; |
|
|
|
return unique( |
|
concat( |
|
[ |
|
'arguments', |
|
'caller', |
|
'prototype', |
|
'name', |
|
'length', |
|
Symbol.toStringTag |
|
], |
|
keys(descriptors) |
|
) |
|
); |
|
}, |
|
getOwnPropertyDescriptor(target, prop) { |
|
if (has(cache, prop)) { |
|
if (isArr(cache) && prop === 'length') { |
|
return { |
|
configurable: true, |
|
enumerable: false, |
|
writable: true |
|
}; |
|
} else { |
|
const descriptor = Object.getOwnPropertyDescriptor( |
|
cache, |
|
prop |
|
); |
|
if (descriptor.configurable) { |
|
return descriptor; |
|
} |
|
if (!fakeExports.prop) { |
|
defineProp(fakeExports, prop, descriptor); |
|
} |
|
return descriptor; |
|
} |
|
} else { |
|
switch (prop) { |
|
case 'arguments': |
|
return createDescriptor(0, 0, 0, null); |
|
case 'caller': |
|
return createDescriptor(0, 0, 0, null); |
|
case 'prototype': |
|
return createDescriptor(0, 0, 1, null); |
|
case 'length': |
|
return createDescriptor(1, 0, 0, 0); |
|
case 'name': |
|
return createDescriptor(1, 0, 0, ''); |
|
default: |
|
return { |
|
configurable: true, |
|
enumerable: true, |
|
writable: true |
|
}; |
|
} |
|
} |
|
} |
|
}); |
|
} |
|
|
|
function createDescriptor(configurable, enumerable, writable, value) { |
|
return { |
|
configurable: toBool(configurable), |
|
enumerable: toBool(enumerable), |
|
writable: toBool(writable), |
|
value |
|
}; |
|
} |
|
|
|
function findDirName() { |
|
const stack = stackTrace(); |
|
for (const item of stack) { |
|
const fileName = item.getFileName(); |
|
if (fileName !== module.filename) { |
|
return splitPath(fileName).dir; |
|
} |
|
} |
|
|
|
return ''; |
|
} |
|
|
|
function isRelative(moduleId) { |
|
return startWith(moduleId, './') || startWith(moduleId, '../'); |
|
} |
|
|
|
module.exports = exports;
|
|
|