2020-03-17 19:02:06 +08:00

147 lines
3.6 KiB
TypeScript

import { COMMON_CHUNK_NAME } from '../../const/generator';
import {
BuilderComponentPlugin,
ChunkType,
CodeGeneratorError,
DependencyType,
FileType,
ICodeChunk,
ICodeStruct,
IDependency,
IExternalDependency,
IInternalDependency,
IWithDependency,
} from '../../types';
function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
const depMap: Record<string, IDependency[]> = {};
const addDep = (pkg: string, dep: IDependency) => {
if (!depMap[pkg]) {
depMap[pkg] = [];
}
depMap[pkg].push(dep);
};
deps.forEach(dep => {
if (dep.dependencyType === DependencyType.Internal) {
addDep(
`${(dep as IInternalDependency).moduleName}${dep.main || ''}`,
dep,
);
} else {
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep);
}
});
return depMap;
}
function buildPackageImport(
pkg: string,
deps: IDependency[],
isJSX: boolean,
): ICodeChunk[] {
const chunks: ICodeChunk[] = [];
let defaultImport: string = '';
let defaultImportAs: string = '';
const imports: Record<string, string> = {};
deps.forEach(dep => {
const srcName = dep.exportName;
let targetName = dep.importName || dep.exportName;
if (dep.subName) {
return;
}
if (dep.subName) {
chunks.push({
type: ChunkType.STRING,
fileType: isJSX ? FileType.JSX : FileType.JS,
name: COMMON_CHUNK_NAME.FileVarDefine,
content: `const ${targetName} = ${srcName}.${dep.subName};`,
linkAfter: [
COMMON_CHUNK_NAME.ExternalDepsImport,
COMMON_CHUNK_NAME.InternalDepsImport,
],
});
targetName = srcName;
}
if (dep.destructuring) {
imports[srcName] = targetName;
} else if (defaultImport) {
throw new CodeGeneratorError(
`[${pkg}] has more than one default export.`,
);
} else {
defaultImport = srcName;
defaultImportAs = targetName;
}
});
const items = Object.keys(imports).map(src =>
src === imports[src] ? src : `${src} as ${imports[src]}`,
);
const statementL = ['import'];
if (defaultImport) {
statementL.push(defaultImportAs);
if (items.length > 0) {
statementL.push(',');
}
}
if (items.length > 0) {
statementL.push(`{ ${items.join(', ')} }`);
}
statementL.push('from');
if (deps[0].dependencyType === DependencyType.Internal) {
// TODO: Internal Deps path use project slot setting
statementL.push(`'@/${(deps[0] as IInternalDependency).type}/${pkg}';`);
chunks.push({
type: ChunkType.STRING,
fileType: isJSX ? FileType.JSX : FileType.JS,
name: COMMON_CHUNK_NAME.InternalDepsImport,
content: statementL.join(' '),
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
});
} else {
statementL.push(`'${pkg}';`);
chunks.push({
type: ChunkType.STRING,
fileType: isJSX ? FileType.JSX : FileType.JS,
name: COMMON_CHUNK_NAME.ExternalDepsImport,
content: statementL.join(' '),
linkAfter: [],
});
}
return chunks;
}
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
const next: ICodeStruct = {
...pre,
};
const isJSX = next.chunks.some(chunk => chunk.fileType === FileType.JSX);
const ir = next.ir as IWithDependency;
if (ir && ir.deps && ir.deps.length > 0) {
const packs = groupDepsByPack(ir.deps);
Object.keys(packs).forEach(pkg => {
const chunks = buildPackageImport(pkg, packs[pkg], isJSX);
next.chunks.push.apply(next.chunks, chunks);
});
}
return next;
};
export default plugin;