Skip to content

Commit

Permalink
Merge 901ac2b into 18496a5
Browse files Browse the repository at this point in the history
  • Loading branch information
eight04 committed Jun 13, 2019
2 parents 18496a5 + 901ac2b commit 9498fd0
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 502 deletions.
255 changes: 151 additions & 104 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,13 @@ function factory({
exportType = null,
_fs = fs
} = {}) {
const cjsEsCache = new Set;
const exportTypeCache = {};
const exportTable = {};
const exportCache = {};
const filter = createFilter(include, exclude);

if (exportType && typeof exportType === "object") {
const newMap = {};
for (const key of Object.keys(exportType)) {
const newKey = path.resolve(key);
newMap[newKey] = exportType[key];
}
exportType = newMap;
resolveRelPathInExportType();
}

if (cache) {
Expand All @@ -45,6 +40,15 @@ function factory({
buildEnd
};

function resolveRelPathInExportType() {
const newMap = {};
for (const key of Object.keys(exportType)) {
const newKey = path.resolve(key);
newMap[newKey] = exportType[key];
}
exportType = newMap;
}

function loadCjsEsCache() {
let data;
try {
Expand All @@ -53,45 +57,45 @@ function factory({
return;
}
data = JSON.parse(data);
for (const [id, expectBy] of Object.entries(data)) {
exportCache[id[0] === "~" ? id.slice(1) : path.resolve(id)] =
expectBy ? path.resolve(expectBy) : null;
for (const id of data) {
const absId = id[0] === "~" ? id.slice(1) : path.resolve(id);
cjsEsCache.add(absId);
}
}

function writeCjsEsCache() {
const data = Object.entries(exportTable)
.map(([id, info]) => {
if (info.loaded && info.trusted) {
if (info.default && !info.named) {
return {
id,
expectBy: null
};
.filter(([, info]) => {
// is ES module
if (info.trusted) {
if (info.default && !info.named.length) {
return true;
}
return;
return false;
}
if (info.expects) {
const trustedExpect = info.expects.find(e => e.trusted);
// FIXME: is it possible that someone imports named/default at the same time?
if (trustedExpect && trustedExpect.default) {
return {
id,
expectBy: trustedExpect.id
};
return true;
}
// importer and exporter are both untrustable (cjs module)
// find missing names
if (info.loaded) {
const expect = info.expects.find(e =>
e.importedProps && e.importedProps.some(n => !info.exportedProps.includes(n))
);
if (expect) {
return true;
}
}
}
return false;
})
.filter(Boolean)
.sort((a, b) => a.id.localeCompare(b.id))
.reduce((output, {id, expectBy}) => {
if (expectBy) {
expectBy = path.relative(".", expectBy).replace(/\\/g, "/");
}
id = path.isAbsolute(id) ? path.relative(".", id).replace(/\\/g, "/") : `~${id}`;
output[id] = expectBy;
return output;
}, {});
.map(([id]) =>
path.isAbsolute(id) ? path.relative(".", id).replace(/\\/g, "/") : `~${id}`
)
.sort((a, b) => a.localeCompare(b));
_fs.writeFileSync(cache, JSON.stringify(data, null, 2), "utf8");
}

Expand All @@ -117,111 +121,154 @@ function factory({
});
}

function getExportType(id, importer = null) {
async function getExportType(id) {
// get export type from options
return Promise.resolve(getExportTypeFromOptions(id))
.then(result => {
if (result) {
return result;
}
// get export type from loaded table
if (exportTable[id] && exportTable[id].loaded) {
return exportTable[id].named ? "named" : "default";
}
if (exportTable[id] && exportTable[id].expects) {
const trustedExpect = exportTable[id].expects.find(e => e.trusted);
if (trustedExpect) {
return trustedExpect.named ? "named" : "default";
}
}
// check if id is in preferDefault cache
if (exportCache.hasOwnProperty(id) && exportCache[id] !== importer) {
let result;
result = await getExportTypeFromOptions(id);
if (result) {
return result;
}
// get export type from loaded table
if (exportTable[id] && exportTable[id].loaded) {
return exportTable[id].named.length ? "named" : "default";
}
if (exportTable[id] && exportTable[id].expects) {
for (const expect of exportTable[id].expects) {
if (expect.default) {
return "default";
}
});
if (expect.named.length || expect.all) {
return "named";
}
}
}
// check if id is in preferDefault cache
if (cjsEsCache.has(id)) {
return "default";
}
}

function updateExportTable({id, code, context, info, guessExportType}) {
if (!info) {
info = esInfoAnalyze(context.parse(code));
async function updateEsExportTable({id, context, info}) {
if (!exportTable[id]) {
exportTable[id] = {id};
}
Object.assign(exportTable[id], info.export);
exportTable[id].trusted = true;
exportTable[id].loaded = true;

await Promise.all(Object.entries(info.import).map(async ([name, importInfo]) => {
if (!importInfo.default && !importInfo.named.length && !importInfo.all) {
return;
}
importInfo.id = id;
importInfo.trusted = true;
let importee = await context.resolveId(name, id);
let external = false;
if (!importee) {
importee = name;
external = true;
}
if (!exportTable[importee]) {
exportTable[importee] = {id: importee};
}
if (!exportTable[importee].expects) {
exportTable[importee].expects = [];
}
importInfo.external = external;
exportTable[importee].expects.push(importInfo);
}));
}

async function updateCjsExportTable({
id,
context,
transformContext: {
importedProperties,
namedExports,
objectExports,
finalExportType,
finalImportType
},
guessedIds
}) {
if (!exportTable[id]) {
exportTable[id] = {id};
}
const exportInfo = info.export;
const props = new Set([...namedExports.keys(), ...objectExports.keys()]);
exportTable[id].default = finalExportType === "default";
exportTable[id].named = finalExportType === "named" ? [...props] : [];
exportTable[id].exportedProps = [...props];
exportTable[id].loaded = true;
exportTable[id].default = exportInfo.default;
exportTable[id].named = exportInfo.named.length > 0 || exportInfo.all;
exportTable[id].trusted = !guessExportType.has(id);
exportTable[id].trusted = !guessedIds.has(id);

return Promise.all(Object.entries(info.import).map(([name, importInfo]) => {
const expect = {
await Promise.all(Object.entries(finalImportType).map(async ([name, type]) => {
const props = importedProperties.get(name) || [];
const importInfo = {
id,
default: importInfo.default,
named: importInfo.named.length || importInfo.all
named: type === "named" ? [...props] : [],
default: type === "default",
all: type === "named" && !props.length,
importedProps: [...props]
};
if (!expect.default && !expect.named) {
return;
let importee = await context.resolveId(name, id);
let external = false;
if (!importee) {
importee = name;
external = true;
}
return context.resolveId(name, id)
.then(importee => {
let external = false;
if (!importee) {
importee = name;
external = true;
}
if (!exportTable[importee]) {
exportTable[importee] = {id: importee};
}
if (!exportTable[importee].expects) {
exportTable[importee].expects = [];
}
expect.trusted = !guessExportType.has(importee);
expect.external = external;
exportTable[importee].expects.push(expect);
});
if (!exportTable[importee]) {
exportTable[importee] = {id: importee};
}
if (!exportTable[importee].expects) {
exportTable[importee].expects = [];
}
importInfo.external = external;
importInfo.trusted = !guessedIds.has(importee);
exportTable[importee].expects.push(importInfo);
}));
}

function transform(code, id) {
async function transform(code, id) {
if (!filter(id)) {
return;
}
const ast = this.parse(code);
const guessExportType = new Set;
const info = esInfoAnalyze(ast);
const info = esInfoAnalyze({ast});
if (isEsModule(info)) {
return updateExportTable({context: this, info, id, guessExportType})
.then(() => undefined);
await updateEsExportTable({context: this, info, id});
return;
}
return cjsEs({
const guessedIds = new Set;
const result = await cjsEs({
code,
ast,
sourceMap,
importStyle: requireId =>
this.resolveId(requireId, id)
.then(newId => {
guessExportType.add(newId || requireId);
return getExportType(newId || requireId, id);
}),
importStyle: async requireId => {
const absId = await this.resolveId(requireId, id);
guessedIds.add(absId);
return getExportType(absId || requireId, id);
},
exportStyle: () => {
guessExportType.add(id);
guessedIds.add(id);
return getExportType(id);
},
nested,
warn: (message, pos) => {
this.warn(message, pos);
}
})
.then(({code, map, isTouched}) => {
if (isTouched) {
return updateExportTable({context: this, code, id, guessExportType})
.then(() => ({
code,
map
}));
}
});
if (result.isTouched) {
await updateCjsExportTable({
context: this,
id,
transformContext: result.context,
guessedIds
});
return {
code: result.code,
map: result.map
};
}
}

function buildEnd() {
Expand Down Expand Up @@ -257,7 +304,7 @@ function factory({
if (expect.default && !exportInfo.default) {
return missingExportWarning(expect.id, "default", exportInfo.id);
}
if (expect.named && !exportInfo.named) {
if ((expect.named.length || expect.all) && !exportInfo.named.length && !exportInfo.all) {
return missingExportWarning(expect.id, "names", exportInfo.id);
}
}
Expand Down

0 comments on commit 9498fd0

Please sign in to comment.