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

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;