mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-02-22 09:33:45 +00:00
101 lines
3.0 KiB
TypeScript
101 lines
3.0 KiB
TypeScript
import {
|
|
ChunkContent,
|
|
ChunkType,
|
|
CodeGeneratorError,
|
|
CodeGeneratorFunction,
|
|
ICodeBuilder,
|
|
ICodeChunk,
|
|
} from '../types';
|
|
|
|
export default class Builder implements ICodeBuilder {
|
|
private chunkDefinitions: ICodeChunk[] = [];
|
|
|
|
private generators: { [key: string]: CodeGeneratorFunction<ChunkContent> } = {
|
|
[ChunkType.STRING]: (str: string) => str, // no-op for string chunks
|
|
[ChunkType.JSON]: (json: object) => JSON.stringify(json), // stringify json to string
|
|
};
|
|
|
|
constructor(chunkDefinitions: ICodeChunk[] = []) {
|
|
this.chunkDefinitions = chunkDefinitions;
|
|
}
|
|
|
|
/**
|
|
* Links all chunks together based on their requirements. Returns an array
|
|
* of ordered chunk names which need to be compiled and glued together.
|
|
*/
|
|
public link(chunkDefinitions: ICodeChunk[] = []): string {
|
|
const chunks = chunkDefinitions || this.chunkDefinitions;
|
|
if (chunks.length <= 0) {
|
|
return '';
|
|
}
|
|
|
|
const unprocessedChunks = chunks.map(chunk => {
|
|
return {
|
|
name: chunk.name,
|
|
type: chunk.type,
|
|
content: chunk.content,
|
|
linkAfter: this.cleanupInvalidChunks(chunk.linkAfter, chunks),
|
|
};
|
|
});
|
|
|
|
const resultingString: string[] = [];
|
|
|
|
while (unprocessedChunks.length > 0) {
|
|
let indexToRemove = 0;
|
|
for (let index = 0; index < unprocessedChunks.length; index++) {
|
|
if (unprocessedChunks[index].linkAfter.length <= 0) {
|
|
indexToRemove = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (unprocessedChunks[indexToRemove].linkAfter.length > 0) {
|
|
throw new CodeGeneratorError(
|
|
'Operation aborted. Reason: cyclic dependency between chunks.',
|
|
);
|
|
}
|
|
|
|
const { type, content, name } = unprocessedChunks[indexToRemove];
|
|
const compiledContent = this.generateByType(type, content);
|
|
if (compiledContent) {
|
|
resultingString.push(compiledContent + '\n');
|
|
}
|
|
|
|
unprocessedChunks.splice(indexToRemove, 1);
|
|
unprocessedChunks.forEach(
|
|
// remove the processed chunk from all the linkAfter arrays from the remaining chunks
|
|
ch => (ch.linkAfter = ch.linkAfter.filter(after => after !== name)),
|
|
);
|
|
}
|
|
|
|
return resultingString.join('\n');
|
|
}
|
|
|
|
public generateByType(type: string, content: unknown): string {
|
|
if (!content) {
|
|
return '';
|
|
}
|
|
if (Array.isArray(content)) {
|
|
return content
|
|
.map(contentItem => this.generateByType(type, contentItem))
|
|
.join('\n');
|
|
}
|
|
|
|
if (!this.generators[type]) {
|
|
throw new Error(
|
|
`Attempted to generate unknown type ${type}. Please register a generator for this type in builder/index.ts`,
|
|
);
|
|
}
|
|
|
|
return this.generators[type](content);
|
|
}
|
|
|
|
// remove invalid chunks (which did not end up being created) from the linkAfter fields
|
|
// one use-case is when you want to remove the import plugin
|
|
private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) {
|
|
return linkAfter.filter(chunkName =>
|
|
chunks.some(chunk => chunk.name === chunkName),
|
|
);
|
|
}
|
|
}
|