@markandrus/effect-derive
Version:
Derive Covariant (Functor), Foldable, and Traversable instances, as well as base functors, for algebraic data types (ADTs)
138 lines (137 loc) • 6.45 kB
JavaScript
export class OutFile {
packages = new Set();
packageAsteriskImports = new Map;
packageDefaultImports = new Map;
packageImports = new Map;
locals = new Set();
localDefaultImports = new Map;
localImports = new Map;
declarations = '';
addPackageAsteriskImport(module, alias, isTypeImport = false) {
this.packages.add(module);
const imports = this.packageAsteriskImports.get(module) ?? new Map();
this.packageAsteriskImports.set(module, imports);
const existingAlias = imports.get(alias) ?? isTypeImport;
imports.set(alias, isTypeImport ? existingAlias : false);
return this;
}
addPackageDefaultImport(module, alias, isTypeImport = false) {
this.packages.add(module);
const imports = this.packageDefaultImports.get(module) ?? new Map();
this.packageDefaultImports.set(module, imports);
const existingAlias = imports.get(alias) ?? isTypeImport;
imports.set(alias, isTypeImport ? existingAlias : false);
return this;
}
addPackageImport(module, imported, aliasOrIsTypeImport, isTypeImport) {
const alias = typeof aliasOrIsTypeImport === 'string' ? aliasOrIsTypeImport : undefined;
isTypeImport = typeof aliasOrIsTypeImport === 'boolean' ? aliasOrIsTypeImport : isTypeImport ?? false;
this.packages.add(module);
const imports = this.packageImports.get(module) ?? new Map();
this.packageImports.set(module, imports);
const existingImport = imports.get(imported) ?? [alias, isTypeImport];
if (existingImport[0] !== alias) {
throw new Error('Multiple import aliases are not supported');
}
imports.set(imported, isTypeImport ? existingImport : [alias, false]);
return this;
}
addLocalDefaultImport(module, alias, isTypeImport = false) {
this.locals.add(module);
const imports = this.localDefaultImports.get(module) ?? new Map();
this.localDefaultImports.set(module, imports);
const existingAlias = imports.get(alias) ?? isTypeImport;
imports.set(alias, isTypeImport ? existingAlias : false);
return this;
}
addLocalImport(module, imported, aliasOrIsTypeImport, isTypeImport) {
const alias = typeof aliasOrIsTypeImport === 'string' ? aliasOrIsTypeImport : undefined;
isTypeImport = typeof aliasOrIsTypeImport === 'boolean' ? aliasOrIsTypeImport : isTypeImport ?? false;
this.locals.add(module);
const imports = this.localImports.get(module) ?? new Map();
this.localImports.set(module, imports);
const existingImport = imports.get(imported) ?? [alias, isTypeImport];
if (existingImport[0] !== alias) {
throw new Error('Multiple import aliases are not supported');
}
imports.set(imported, isTypeImport ? existingImport : [alias, false]);
return this;
}
addDeclarations(declarations) {
this.declarations += declarations;
return this;
}
merge(other) {
for (const [module, imports] of other.packageAsteriskImports) {
for (const [alias, isTypeImport] of imports) {
this.addPackageAsteriskImport(module, alias, isTypeImport);
}
}
for (const [module, imports] of other.packageDefaultImports) {
for (const [alias, isTypeImport] of imports) {
this.addPackageDefaultImport(module, alias, isTypeImport);
}
}
for (const [module, imports] of other.packageImports) {
for (const [imported, [alias, isTypeImport]] of imports) {
this.addPackageImport(module, imported, alias, isTypeImport);
}
}
for (const [module, imports] of other.localDefaultImports) {
for (const [imported, isTypeImport] of imports) {
this.addLocalDefaultImport(module, imported, isTypeImport);
}
}
for (const [module, imports] of other.localImports) {
for (const [imported, [alias, isTypeImport]] of imports) {
this.addLocalImport(module, imported, alias, isTypeImport);
}
}
this.declarations += other.declarations;
return this;
}
toString() {
let out = '';
const packages = Array.from(this.packages).sort();
for (const module of packages) {
const asteriskImports = this.packageAsteriskImports.get(module) ?? new Map();
for (const [alias, isTypeImport] of asteriskImports) {
out += `import ${isTypeImport ? 'type ' : ''}* as ${alias} from "${module}"\n`;
}
const defaultImports = this.packageDefaultImports.get(module) ?? new Map();
for (const [alias, isTypeImport] of defaultImports) {
out += `import ${isTypeImport ? 'type ' : ''} ${alias} from "${module}"\n`;
}
const imports = this.packageImports.get(module);
if (imports != null && imports.size > 0) {
out += 'import { ';
let i = 0;
for (const [imported, [alias, isTypeImport]] of imports) {
out += `${i++ === 0 ? '' : ', '}${isTypeImport ? 'type ' : ''}${imported}${alias == null ? '' : ` as ${alias}`}`;
}
out += ` } from "${module}"\n`;
}
}
if (this.packageImports.size > 0)
out += '\n';
const locals = Array.from(this.locals).sort();
for (const module of locals) {
const defaultImports = this.localDefaultImports.get(module) ?? new Map();
for (const [alias, isTypeImport] of defaultImports) {
out += `import ${isTypeImport ? 'type ' : ''} ${alias} from "${module}"\n`;
}
const imports = this.localImports.get(module);
if (imports != null && imports.size > 0) {
out += 'import { ';
let i = 0;
for (const [imported, [alias, isTypeImport]] of imports) {
out += `${i++ === 0 ? '' : ', '}${isTypeImport ? 'type ' : ''}${imported}${alias == null ? '' : ` as ${alias}`}`;
}
out += ` } from "${module}"\n`;
}
}
if (this.localImports.size > 0)
out += '\n';
return out + this.declarations;
}
}