UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

148 lines (136 loc) 4.66 kB
import path from "path"; import { HashMap, HashSet, Pair } from "tstl"; import ts from "typescript"; import { FilePrinter } from "./FilePrinter"; export class ImportDictionary { private readonly components_: HashMap<Pair<string, boolean>, IComposition> = new HashMap(); public constructor(public readonly file: string) {} public empty(): boolean { return this.components_.empty(); } public external(props: ImportDictionary.IExternalProps): string { const composition: IComposition = this.components_.take( new Pair(`node_modules/${props.library}`, props.type), () => ({ location: `node_modules/${props.library}`, elements: new HashSet(), default: false, type: props.type, }), ); if (props.instance === null) composition.default = true; else composition.elements.insert(props.instance); return props.instance ?? props.library; } public internal(props: ImportDictionary.IInternalProps): string { const file: string = (() => { if (props.file.substring(props.file.length - 5) === ".d.ts") return props.file.substring(0, props.file.length - 5); else if (props.file.substring(props.file.length - 3) === ".ts") return props.file.substring(0, props.file.length - 3); return props.file; })(); const composition: IComposition = this.components_.take( new Pair(file, props.type), () => ({ location: file, elements: new HashSet(), default: false, type: props.type, }), ); if (props.instance === null) { composition.default = true; if (props.name) composition.name = props.name; } else composition.elements.insert(props.instance); return props.instance ?? file; } public toStatements(outDir: string): ts.Statement[] { const external: ts.ImportDeclaration[] = []; const internal: ts.ImportDeclaration[] = []; const locator = (str: string) => { const location: string = path.relative(outDir, str).split("\\").join("/"); const index: number = location.lastIndexOf(NODE_MODULES); return index === -1 ? location.startsWith("..") ? location : `./${location}` : location.substring(index + NODE_MODULES.length); }; const enroll = (filter: (str: string) => boolean) => (container: ts.ImportDeclaration[]) => { const compositions: IComposition[] = this.components_ .toJSON() .filter((c) => filter(c.second.location)) .map((e) => ({ ...e.second, location: locator(e.second.location), })) .sort((a, b) => a.location.localeCompare(b.location)); for (const c of compositions) { const brackets: string[] = []; if (c.default) brackets.push(c.name ?? c.location); if (c.elements.empty() === false) brackets.push( `{ ${c.elements .toJSON() .sort((a, b) => a.localeCompare(b)) .join(", ")} }`, ); container.push( ts.factory.createImportDeclaration( undefined, ts.factory.createImportClause( c.type, c.default ? ts.factory.createIdentifier(c.name ?? c.location) : undefined, c.elements.empty() === false ? ts.factory.createNamedImports( [...c.elements].map((elem) => ts.factory.createImportSpecifier( false, undefined, ts.factory.createIdentifier(elem), ), ), ) : undefined, ), ts.factory.createStringLiteral(c.location), ), ); } }; enroll((str) => str.indexOf(NODE_MODULES) !== -1)(external); enroll((str) => str.indexOf(NODE_MODULES) === -1)(internal); return [ ...external, ...(external.length && internal.length ? [FilePrinter.enter()] : []), ...internal, ]; } } export namespace ImportDictionary { export interface IExternalProps { type: boolean; library: string; instance: string | null; } export interface IInternalProps { type: boolean; file: string; instance: string | null; name?: string | null; } } interface IComposition { location: string; type: boolean; default: boolean; name?: string; elements: HashSet<string>; } const NODE_MODULES = "node_modules/";