modules/code-generator/src/generator/ChunkBuilder.ts (98 lines of code) (raw):
import { BuilderComponentPlugin, IChunkBuilder, ICodeChunk, ICodeStruct, FileType } from '../types';
import { COMMON_SUB_MODULE_NAME } from '../const/generator';
import { FILE_TYPE_FAMILY } from '../const/file';
interface ChunkGroupInfo {
chunk: ICodeChunk;
familyIdx?: number;
}
function whichFamily(type: FileType): [number, FileType[]] | undefined {
const idx = FILE_TYPE_FAMILY.findIndex((family) => family.indexOf(type) >= 0);
if (idx < 0) {
return undefined;
}
return [idx, FILE_TYPE_FAMILY[idx]];
}
export const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => {
const tmp: Record<string, Record<number, number>> = {};
const col = chunks.reduce((chunksSet: Record<string, ChunkGroupInfo[]>, chunk) => {
const fileKey = chunk.subModule || COMMON_SUB_MODULE_NAME;
if (!chunksSet[fileKey]) {
// eslint-disable-next-line no-param-reassign
chunksSet[fileKey] = [];
}
const res = whichFamily(chunk.fileType as FileType);
const info: ChunkGroupInfo = {
chunk,
};
if (res) {
const [familyIdx, family] = res;
const rank = family.indexOf(chunk.fileType as FileType);
if (tmp[fileKey]) {
if (tmp[fileKey][familyIdx] !== undefined) {
if (tmp[fileKey][familyIdx] > rank) {
tmp[fileKey][familyIdx] = rank;
}
} else {
tmp[fileKey][familyIdx] = rank;
}
} else {
tmp[fileKey] = {};
tmp[fileKey][familyIdx] = rank;
}
info.familyIdx = familyIdx;
}
chunksSet[fileKey].push(info);
return chunksSet;
}, {});
const result: ICodeChunk[][] = [];
Object.keys(col).forEach((key) => {
const byType: Record<string, ICodeChunk[]> = {};
col[key].forEach((info) => {
let t: string = info.chunk.fileType;
if (info.familyIdx !== undefined) {
t = FILE_TYPE_FAMILY[info.familyIdx][tmp[key][info.familyIdx]];
// eslint-disable-next-line no-param-reassign
info.chunk.fileType = t;
}
if (!byType[t]) {
byType[t] = [];
}
byType[t].push(info.chunk);
});
result.push(...Object.keys(byType).map((t) => byType[t]));
});
return result;
};
/**
* 代码片段构建器
*
* @export
* @class ChunkBuilder
* @template T
*/
export class ChunkBuilder implements IChunkBuilder {
private plugins: BuilderComponentPlugin[];
constructor(plugins: BuilderComponentPlugin[] = []) {
this.plugins = plugins;
}
async run(
ir: unknown,
initialStructure: ICodeStruct = {
ir,
chunks: [],
depNames: [],
contextData: {},
},
) {
const structure = initialStructure;
const finalStructure: ICodeStruct = await this.plugins.reduce(
async (previousPluginOperation: Promise<ICodeStruct>, plugin) => {
const modifiedStructure = await previousPluginOperation;
return plugin(modifiedStructure);
},
Promise.resolve(structure),
);
const chunks = groupChunks(finalStructure.chunks);
return {
chunks,
};
}
getPlugins() {
return this.plugins;
}
addPlugin(plugin: BuilderComponentPlugin) {
this.plugins.push(plugin);
}
}
export default ChunkBuilder;