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.
183 lines
5.2 KiB
183 lines
5.2 KiB
2 years ago
|
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;
|