fork of hey-api/openapi-ts because I need some additional things
1import path from 'node:path';
2
3import type { IProjectRenderMeta } from '../extensions';
4import { FileRegistry } from '../files/registry';
5import { defaultExtensions } from '../languages/extensions';
6import { defaultNameConflictResolvers } from '../languages/resolvers';
7import type { Extensions, NameConflictResolvers } from '../languages/types';
8import type { AstContext } from '../nodes/context';
9import { NodeRegistry } from '../nodes/registry';
10import type { IOutput } from '../output';
11import { Planner } from '../planner/planner';
12import { simpleNameConflictResolver } from '../planner/resolvers';
13import type { NameConflictResolver } from '../planner/types';
14import type { Renderer } from '../renderer';
15import { SymbolRegistry } from '../symbols/registry';
16import type { IProject } from './types';
17
18export class Project implements IProject {
19 readonly files: FileRegistry;
20 readonly nodes = new NodeRegistry();
21 readonly symbols = new SymbolRegistry();
22
23 readonly defaultFileName: string;
24 readonly defaultNameConflictResolver: NameConflictResolver;
25 readonly extensions: Extensions;
26 readonly fileName?: (name: string) => string;
27 readonly nameConflictResolvers: NameConflictResolvers;
28 readonly renderers: ReadonlyArray<Renderer>;
29 readonly root: string;
30
31 constructor(
32 args: Pick<
33 Partial<IProject>,
34 | 'defaultFileName'
35 | 'defaultNameConflictResolver'
36 | 'extensions'
37 | 'fileName'
38 | 'nameConflictResolvers'
39 | 'renderers'
40 > &
41 Pick<IProject, 'root'>,
42 ) {
43 const fileName = args.fileName;
44 this.defaultFileName = args.defaultFileName ?? 'main';
45 this.defaultNameConflictResolver =
46 args.defaultNameConflictResolver ?? simpleNameConflictResolver;
47 this.extensions = {
48 ...defaultExtensions,
49 ...args.extensions,
50 };
51 this.fileName = typeof fileName === 'string' ? () => fileName : fileName;
52 this.files = new FileRegistry(this);
53 this.nameConflictResolvers = {
54 ...defaultNameConflictResolvers,
55 ...args.nameConflictResolvers,
56 };
57 this.renderers = args.renderers ?? [];
58 this.root = path.resolve(args.root).replace(/[/\\]+$/, '');
59 }
60
61 render(meta?: IProjectRenderMeta): ReadonlyArray<IOutput> {
62 new Planner(this).plan(meta);
63 const files: Array<IOutput> = [];
64 const astContext: AstContext = {
65 getAccess(node) {
66 return node;
67 },
68 };
69 for (const file of this.files.registered()) {
70 if (file.finalPath && file.renderer) {
71 const content = file.renderer.render({
72 astContext,
73 file,
74 meta,
75 project: this,
76 });
77 files.push({ content, path: file.finalPath });
78 }
79 }
80 return files;
81 }
82}