@compas/code-gen
Version:
Generate various boring parts of your server
109 lines (92 loc) • 2.61 kB
JavaScript
import { AppError, isNil } from "@compas/stdlib";
/**
* Collect and format JS imports. We only support ES module style imports for now.
*/
export class JavascriptImportCollector {
/**
* Resolve and type the import collector for JS files.
*
* @param {import("../file/context.js").GenerateFile}file
* @returns {JavascriptImportCollector}
*/
static getImportCollector(file, typeImports = false) {
if (typeImports) {
if (
isNil(file.typeImportCollector) ||
!(file.typeImportCollector instanceof JavascriptImportCollector)
) {
throw AppError.serverError({
message: `File is created without a type import collector.`,
});
}
return file.typeImportCollector;
}
if (
isNil(file.importCollector) ||
!(file.importCollector instanceof JavascriptImportCollector)
) {
throw AppError.serverError({
message: `File is created without an import collector.`,
});
}
return file.importCollector;
}
constructor(isTypeImports = false) {
/**
* @private
*/
this.isTypeImports = isTypeImports;
/**
* @private
* @type {Map<string, Set<string>>}
*/
this.destructuredImports = new Map();
/**
* @private
* @type {Set<string>}
*/
this.rawImports = new Set();
}
/**
* Use a destructure import
*
* @param {string} path
* @param {string} symbol
*/
destructure(path, symbol) {
if (!this.destructuredImports.has(path)) {
this.destructuredImports.set(path, new Set());
}
this.destructuredImports.get(path)?.add(symbol);
}
/**
* Add a raw import. These are deduplicated, before writing.
*
* @param {string} importString
*/
raw(importString) {
this.rawImports.add(importString);
}
toString() {
const result = [...this.rawImports];
// Sort the destructure imports, so even without any post formatting it looks pretty
// good.
const destructureKeys = [...this.destructuredImports.keys()].sort();
for (const key of destructureKeys) {
const symbols = [
...(this.destructuredImports.get(key)?.values() ?? []),
].sort();
const isMultiline = symbols.length > 3;
if (isMultiline) {
result.push(
`import${this.isTypeImports ? " type" : ""} {\n ${symbols.join(",\n ")},\n} from "${key}";`,
);
} else {
result.push(
`import${this.isTypeImports ? " type" : ""} { ${symbols.join(", ")} } from "${key}";`,
);
}
}
return result.join("\n");
}
}