-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathcodegen.ts
More file actions
118 lines (100 loc) · 2.94 KB
/
codegen.ts
File metadata and controls
118 lines (100 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import type {
ConfigFileFormat,
ImportDeclarationStructure,
PluginCodegenResult,
} from './types.js';
const CORE_CONFIG_IMPORT: ImportDeclarationStructure = {
moduleSpecifier: '@code-pushup/models',
namedImports: ['CoreConfig'],
isTypeOnly: true,
};
class CodeBuilder {
private lines: string[] = [];
addLine(text: string, depth = 0): void {
this.lines.push(`${' '.repeat(depth)}${text}`);
}
addLines(texts: string[], depth = 0): void {
texts.forEach(text => {
this.addLine(text, depth);
});
}
addEmptyLine(): void {
this.lines.push('');
}
toString(): string {
return `${this.lines.join('\n')}\n`;
}
}
function formatImport({
moduleSpecifier,
defaultImport,
namedImports,
isTypeOnly,
}: ImportDeclarationStructure): string {
const named = namedImports?.length ? `{ ${namedImports.join(', ')} }` : '';
const bindings = [defaultImport, named].filter(Boolean).join(', ');
const from = bindings ? `${bindings} from ` : '';
const type = isTypeOnly ? 'type ' : '';
return `import ${type}${from}'${moduleSpecifier}';`;
}
function collectTsImports(
plugins: PluginCodegenResult[],
): ImportDeclarationStructure[] {
return [
CORE_CONFIG_IMPORT,
...plugins.flatMap(({ imports }) => imports),
].toSorted((a, b) => a.moduleSpecifier.localeCompare(b.moduleSpecifier));
}
function collectJsImports(
plugins: PluginCodegenResult[],
): ImportDeclarationStructure[] {
return plugins
.flatMap(({ imports }) => imports)
.map(({ isTypeOnly: _, ...rest }) => rest)
.toSorted((a, b) => a.moduleSpecifier.localeCompare(b.moduleSpecifier));
}
function addPlugins(
builder: CodeBuilder,
plugins: PluginCodegenResult[],
): void {
if (plugins.length === 0) {
builder.addLine('plugins: [],', 1);
} else {
builder.addLine('plugins: [', 1);
builder.addLines(
plugins.map(({ pluginInit }) => `${pluginInit},`),
2,
);
builder.addLine('],', 1);
}
}
export function generateConfigSource(
plugins: PluginCodegenResult[],
format: ConfigFileFormat,
): string {
return format === 'ts'
? generateTsConfig(plugins)
: generateJsConfig(plugins);
}
function generateTsConfig(plugins: PluginCodegenResult[]): string {
const builder = new CodeBuilder();
builder.addLines(collectTsImports(plugins).map(formatImport));
builder.addEmptyLine();
builder.addLine('export default {');
addPlugins(builder, plugins);
builder.addLine('} satisfies CoreConfig;');
return builder.toString();
}
function generateJsConfig(plugins: PluginCodegenResult[]): string {
const builder = new CodeBuilder();
const pluginImports = collectJsImports(plugins);
if (pluginImports.length > 0) {
builder.addLines(pluginImports.map(formatImport));
builder.addEmptyLine();
}
builder.addLine("/** @type {import('@code-pushup/models').CoreConfig} */");
builder.addLine('export default {');
addPlugins(builder, plugins);
builder.addLine('};');
return builder.toString();
}