Skip to content

Commit

Permalink
Merge pull request #284 from hey-api/chore/improve-typescript-file-class
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanshatford authored Apr 8, 2024
2 parents 759e4a4 + 955856f commit ae5c3f3
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 42 deletions.
22 changes: 18 additions & 4 deletions packages/openapi-ts/src/compiler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,29 @@ import * as module from './module';
import * as types from './types';
import { tsNodeToString } from './utils';

export class TypeScriptFile extends Array<ts.Node> {
public override toString(seperator: string = '\n') {
return this.map(v => tsNodeToString(v)).join(seperator);
export class TypeScriptFile {
private _imports: Array<ts.Node> = [];
private _items: Array<ts.Node> = [];

public addNamedImport(...params: Parameters<typeof module.createNamedImportDeclarations>): void {
this._imports.push(compiler.import.named(...params));
}

public add(...nodes: Array<ts.Node>): void {
this._items.push(...nodes);
}

public toString(seperator: string = '\n') {
const importsString = this._imports.map(v => tsNodeToString(v)).join('\n');
return [importsString, ...this._items.map(v => tsNodeToString(v))].join(seperator);
}

public write(file: PathOrFileDescriptor, seperator: string = '\n') {
writeFileSync(file, this.toString(seperator));
}
}

export default {
export const compiler = {
export: {
all: module.createExportAllDeclaration,
asConst: module.createExportVariableAsConst,
Expand All @@ -30,3 +42,5 @@ export default {
object: types.createObjectType,
},
};

export default compiler;
18 changes: 9 additions & 9 deletions packages/openapi-ts/src/utils/write/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ import type { Config } from '../../types/config';
export const writeClientIndex = async (client: Client, outputPath: string, config: Config): Promise<void> => {
const file = new TypeScriptFile();
if (config.name) {
file.push(compiler.export.named([config.name], `./${config.name}`));
file.add(compiler.export.named([config.name], `./${config.name}`));
}
if (config.exportCore) {
file.push(compiler.export.named('ApiError', './core/ApiError'));
file.add(compiler.export.named('ApiError', './core/ApiError'));
if (config.serviceResponse === 'response') {
file.push(compiler.export.named({ isTypeOnly: true, name: 'ApiResult' }, './core/ApiResult'));
file.add(compiler.export.named({ isTypeOnly: true, name: 'ApiResult' }, './core/ApiResult'));
}
if (config.name) {
file.push(compiler.export.named('BaseHttpRequest', './core/BaseHttpRequest'));
file.add(compiler.export.named('BaseHttpRequest', './core/BaseHttpRequest'));
}
if (config.client !== 'angular') {
file.push(compiler.export.named(['CancelablePromise', 'CancelError'], './core/CancelablePromise'));
file.add(compiler.export.named(['CancelablePromise', 'CancelError'], './core/CancelablePromise'));
}
file.push(compiler.export.named(['OpenAPI', { isTypeOnly: true, name: 'OpenAPIConfig' }], './core/OpenAPI'));
file.add(compiler.export.named(['OpenAPI', { isTypeOnly: true, name: 'OpenAPIConfig' }], './core/OpenAPI'));
}
if (client.models.length) {
if (config.exportModels) {
file.push(compiler.export.all('./models'));
file.add(compiler.export.all('./models'));
}
if (config.exportSchemas) {
file.push(compiler.export.all('./schemas'));
file.add(compiler.export.all('./schemas'));
}
}
if (client.services.length && config.exportServices) {
file.push(compiler.export.all('./services'));
file.add(compiler.export.all('./services'));
}
file.write(path.resolve(outputPath, 'index.ts'));
};
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/utils/write/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export const writeClientModels = async (
const file = new TypeScriptFile();
for (const model of client.models) {
const nodes = processModel(config, client, model);
file.push(...nodes);
file.add(...nodes);
}
file.write(path.resolve(outputPath, 'models.ts'), '\n\n');
};
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/utils/write/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export const writeClientSchemas = async (
const file = new TypeScriptFile();
for (const model of client.models) {
const result = exportSchema(config, model);
file.push(result);
file.add(result);
}
file.write(path.resolve(outputPath, 'schemas.ts'), '\n\n');
};
50 changes: 23 additions & 27 deletions packages/openapi-ts/src/utils/write/services.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { writeFileSync } from 'node:fs';
import path from 'node:path';

import compiler, { TypeScriptFile } from '../../compiler';
import { TypeScriptFile } from '../../compiler';
import type { Client } from '../../types/client';
import type { Config } from '../../types/config';
import { operationDataType, type Templates } from '../handlebars';
Expand Down Expand Up @@ -42,52 +42,48 @@ export const writeClientServices = async (

// Import required packages and core files.
if (config.client === 'angular') {
file.push(compiler.import.named('Injectable', '@angular/core'));
file.addNamedImport('Injectable', '@angular/core');
if (config.name === undefined) {
file.push(compiler.import.named('HttpClient', '@angular/common/http'));
file.addNamedImport('HttpClient', '@angular/common/http');
}
file.push(compiler.import.named({ isTypeOnly: true, name: 'Observable' }, 'rxjs'));
file.addNamedImport({ isTypeOnly: true, name: 'Observable' }, 'rxjs');
} else {
file.push(compiler.import.named({ isTypeOnly: true, name: 'CancelablePromise' }, './core/CancelablePromise'));
file.addNamedImport({ isTypeOnly: true, name: 'CancelablePromise' }, './core/CancelablePromise');
}
if (config.serviceResponse === 'response') {
file.push(compiler.import.named({ isTypeOnly: true, name: 'ApiResult' }, './core/ApiResult'));
file.addNamedImport({ isTypeOnly: true, name: 'ApiResult' }, './core/ApiResult');
}
if (config.name) {
file.push(
compiler.import.named(
{ isTypeOnly: config.client !== 'angular', name: 'BaseHttpRequest' },
'./core/BaseHttpRequest'
)
file.addNamedImport(
{ isTypeOnly: config.client !== 'angular', name: 'BaseHttpRequest' },
'./core/BaseHttpRequest'
);
} else {
if (config.useOptions) {
if (config.serviceResponse === 'generics') {
file.push(compiler.import.named(['mergeOpenApiConfig', 'OpenAPI'], './core/OpenAPI'));
file.push(compiler.import.named({ alias: '__request', name: 'request' }, './core/request'));
file.push(
compiler.import.named(
[
{ isTypeOnly: true, name: 'TApiResponse' },
{ isTypeOnly: true, name: 'TConfig' },
{ isTypeOnly: true, name: 'TResult' },
],
'./core/types'
)
file.addNamedImport(['mergeOpenApiConfig', 'OpenAPI'], './core/OpenAPI');
file.addNamedImport({ alias: '__request', name: 'request' }, './core/request');
file.addNamedImport(
[
{ isTypeOnly: true, name: 'TApiResponse' },
{ isTypeOnly: true, name: 'TConfig' },
{ isTypeOnly: true, name: 'TResult' },
],
'./core/types'
);
} else {
file.push(compiler.import.named('OpenAPI', './core/OpenAPI'));
file.push(compiler.import.named({ alias: '__request', name: 'request' }, './core/request'));
file.addNamedImport('OpenAPI', './core/OpenAPI');
file.addNamedImport({ alias: '__request', name: 'request' }, './core/request');
}
} else {
file.push(compiler.import.named('OpenAPI', './core/OpenAPI'));
file.push(compiler.import.named({ alias: '__request', name: 'request' }, './core/request'));
file.addNamedImport('OpenAPI', './core/OpenAPI');
file.addNamedImport({ alias: '__request', name: 'request' }, './core/request');
}
}

// Import all models required by the services.
const models = imports.filter(unique).map(imp => ({ isTypeOnly: true, name: imp }));
file.push(compiler.import.named(models, './models'));
file.addNamedImport(models, './models');

const data = [file.toString(), ...operationTypes, ...results].join('\n\n');

Expand Down

0 comments on commit ae5c3f3

Please sign in to comment.