Skip to content

Commit

Permalink
feat: optimize templates
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael M committed May 10, 2022
1 parent 2126a92 commit e1eafae
Show file tree
Hide file tree
Showing 27 changed files with 203 additions and 256 deletions.
2 changes: 0 additions & 2 deletions packages/ng-openapi-gen/src/lib/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ export class Generator {

// Generate the general files
this.write('configuration', general, this.globals.configurationFile);
this.write('response', general, this.globals.responseFile);
this.write('requestBuilder', general, this.globals.requestBuilderFile);
this.write('baseService', general, this.globals.baseServiceFile);
if (this.globals.moduleClass && this.globals.moduleFile) {
this.write('module', general, this.globals.moduleFile);
}
Expand Down
28 changes: 16 additions & 12 deletions packages/ng-openapi-gen/src/lib/globals.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
import { defaultOptions, Options } from './options.js';
import { fileName } from './utils/string.js';
import { fileName, tsComments } from './utils/string.js';

export class Globals {
public configurationClass: string;
public configurationFile: string;
public configurationParams: string;
public baseServiceClass: string;
public baseServiceFile: string;
public rootUrlToken: string;
public requestBuilderClass: string;
public requestBuilderFile: string;
public responseClass: string;
public responseFile: string;
public pathToModelsDir: string;
public pathToServicesDir: string;
public autoGenerationNotice: string;
public moduleClass?: string;
public moduleFile?: string;
public modelIndexFile?: string;
public serviceIndexFile?: string;
public rootUrl?: string;

constructor(options: Options) {
this.configurationClass = options.configuration;
this.configurationFile = fileName(this.configurationClass);
this.configurationParams = `${this.configurationClass}Params`;
this.baseServiceClass = options.baseService;
this.baseServiceFile = fileName(this.baseServiceClass);
this.configurationFile = options.configurationFile;
this.rootUrlToken = options.rootUrlToken;
this.requestBuilderClass = options.requestBuilder;
this.requestBuilderFile = fileName(this.requestBuilderClass);
this.responseClass = options.response;
this.responseFile = fileName(this.responseClass);
this.pathToModelsDir = `./${options.modelsDir}/`;
this.pathToServicesDir = `./${options.servicesDir}/`;

if (options.module !== false && options.module !== '') {
this.moduleClass = typeof options.module === 'string' ? options.module : (defaultOptions.module as string);
Expand All @@ -46,5 +41,14 @@ export class Globals {
this.modelIndexFile =
typeof options.modelIndex === 'string' ? options.modelIndex : (defaultOptions.modelIndex as string);
}

this.autoGenerationNotice = tsComments(
[
'This file was generated automatically from API specification.',
'Manual changes to this file may cause incorrect behavior and will be lost when the code is regenerated.',
'To update this file run the generation tool.',
].join('\n'),
0,
);
}
}
28 changes: 20 additions & 8 deletions packages/ng-openapi-gen/src/lib/hb-provider.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import { existsSync, realpathSync } from 'node:fs';
import { join } from 'node:path';
import { realpathSync } from 'node:fs';

import Handlebars from 'handlebars';

import { joinIfExists } from './utils/file-system.js';

export class HbProvider {
public instance: typeof Handlebars = Handlebars;

constructor() {
this.instance.registerHelper('reIndent', function (input: string, baseIndent: number): string {
if (!input?.includes('\n')) {
return input;
}

const allLines = input.split('\n');
const middleLines = allLines.slice(1, -1);
return [
allLines[0],
...middleLines.map((line) => ' '.repeat(baseIndent + 1) + line),
' '.repeat(baseIndent) + allLines[allLines.length - 1],
].join('\n');
});
}

public async loadCustomHelpers(templatesDir: string | undefined): Promise<void> {
if (!templatesDir) {
return;
}

const loadPath =
ifFileExists(join(templatesDir, 'handlebars.mjs')) || ifFileExists(join(templatesDir, 'handlebars.js'));
const loadPath = joinIfExists(templatesDir, 'handlebars.mjs') || joinIfExists(templatesDir, 'handlebars.js');
if (!loadPath) {
return;
}
Expand All @@ -23,7 +39,3 @@ export class HbProvider {
}
}
}

function ifFileExists(filePath: string): string | null {
return existsSync(filePath) ? filePath : null;
}
12 changes: 0 additions & 12 deletions packages/ng-openapi-gen/src/lib/oa-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ export class OaImport {
fileName(unqualifiedName(model.refName, model.options)),
];
this.setRelativePath();

if (model.refName.includes('Enums.Audit')) {
console.info(this);
}
return this;
}

Expand All @@ -37,10 +33,6 @@ export class OaImport {
this.useAlias = this.typeName !== this.qualifiedName;
[this.namespace, this.fileName] = [namespace(refName), fileName(unqualifiedName(refName, options))];
this.setRelativePath();

if (refName.includes('Enums.Audit')) {
console.info(this);
}
return this;
}

Expand All @@ -53,10 +45,6 @@ export class OaImport {
// this.useAlias = this.typeName !== this.qualifiedName;
[this.namespace, this.fileName] = [source.namespace, source.fileName];
this.setRelativePath();

if (source.refName.includes('Enums.Audit')) {
console.info(this);
}
return this;
}

Expand Down
10 changes: 0 additions & 10 deletions packages/ng-openapi-gen/src/lib/oa-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ export class OaModel extends OaBase {
const description = schema.description || '';
this.tsComments = tsComments(description, 0, schema.deprecated);
this.pathToModels = '';

if (openApi.info.title === 'EDS Partial') {
console.info({
name: this.name,
typeName: this.typeName,
namespace: this.namespace,
fileName: this.fileName,
qualifiedName: this.qualifiedName,
});
}
}

public collectImports(imports: Map<string, OaImport>): void {
Expand Down
30 changes: 20 additions & 10 deletions packages/ng-openapi-gen/src/lib/oa-operation-variant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class OaOperationVariant {

public isVoid: boolean;
public isNumber: boolean;
public isString: boolean;
public isBoolean: boolean;
public isOther: boolean;

Expand Down Expand Up @@ -45,8 +46,9 @@ export class OaOperationVariant {

this.isVoid = this.resultType === 'void';
this.isNumber = this.resultType === 'number';
this.isString = this.resultType === 'string';
this.isBoolean = this.resultType === 'boolean';
this.isOther = !this.isVoid && !this.isNumber && !this.isBoolean;
this.isOther = !this.isVoid && !this.isNumber && !this.isString && !this.isBoolean;

this.responseMethodTsComments = tsComments(this.responseMethodDescription(), 1, operation.deprecated);
this.bodyMethodTsComments = tsComments(this.bodyMethodDescription(), 1, operation.deprecated);
Expand Down Expand Up @@ -83,33 +85,41 @@ export class OaOperationVariant {
}

private responseMethodDescription(): string {
return `${this.descriptionPrefix()}This method provides access to the full \`HttpResponse\`, allowing access to response headers.
To access only the response body, use \`${this.methodName}()\` instead.${this.descriptionSuffix()}`;
return this.options.responseMethodDescription.replace(
/{{([\da-z]+)}}/gi,
function (_, key: string) {
return this[key];
}.bind(this),
);
}

private bodyMethodDescription(): string {
return `${this.descriptionPrefix()}This method provides access to only to the response body.
To access the full response (for headers, for example), \`${
this.responseMethodName
}()\` instead.${this.descriptionSuffix()}`;
return this.options.bodyMethodDescription.replace(
/{{([\da-z]+)}}/gi,
function (_, key: string) {
return this[key];
}.bind(this),
);
}

private descriptionPrefix(): string {
// noinspection JSUnusedLocalSymbols
private get descriptionPrefix(): string {
let description = (this.operation.spec.description || '').trim();
let summary = this.operation.spec.summary;
if (summary) {
if (!summary.endsWith('.')) {
summary += '.';
}
description = summary + '\n\n' + description;
description = summary + (description === '' ? '' : '\n\n') + description;
}
if (description !== '') {
description += '\n\n';
}
return description;
}

private descriptionSuffix(): string {
// noinspection JSUnusedLocalSymbols
private get descriptionSuffix(): string {
const sends = this.requestBody ? 'sends `' + this.requestBody.mediaType + '` and ' : '';
const handles = this.requestBody
? `handles request body of type \`${this.requestBody.mediaType}\``
Expand Down
26 changes: 18 additions & 8 deletions packages/ng-openapi-gen/src/lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ interface OptionsInput {
modelSuffix?: string;
/** Name for the module class that provides all services. Set "false" to skip. Defaults to 'ApiModule'. */
module?: string | boolean;
/** Name for the configuration class to generate. Defaults to 'ApiConfiguration'. */
configuration?: string;
/** Name for the base service class to generate. Defaults to 'BaseService'. */
baseService?: string;
/** Name for the configuration file to generate. Defaults to 'api-configuration'. */
configurationFile?: string;
/** Name for the "root URL" DI token to generate. Defaults to 'API_ROOT_URL_TOKEN'. */
rootUrlToken?: string;
/** Name for the request builder class to generate. Defaults to 'RequestBuilder'. */
requestBuilder?: string;
/** Name for the response class to generate. Defaults to 'StrictHttpResponse'. */
Expand All @@ -53,6 +53,10 @@ interface OptionsInput {
toUse: 'arraybuffer' | 'blob' | 'json' | 'document';
};
};
/** Description template for generated $response method. Defaults to '{{descriptionPrefix}}This method provides access to the full `HttpResponse`, allowing access to response headers.\nTo access only the response body, use `{{methodName}}()` instead.{{descriptionSuffix}}'. */
responseMethodDescription?: string;
/** Description template for generated $body method. Defaults to '{{descriptionPrefix}}This method provides access only to the response body.\nTo access the full response (for headers, for example), use `{{responseMethodName}}()` instead.{{descriptionSuffix}}'. */
bodyMethodDescription?: string;
/** Fallback property type when type can not be determined for any reason. Defaults to 'any'. */
fallbackPropertyType?: string;
modelsDir?: string;
Expand All @@ -75,12 +79,14 @@ type DefaultedOptions =
| 'modelPrefix'
| 'modelSuffix'
| 'module'
| 'configuration'
| 'baseService'
| 'configurationFile'
| 'rootUrlToken'
| 'requestBuilder'
| 'response'
| 'enumStyle'
| 'skipJsonSuffix'
| 'responseMethodDescription'
| 'bodyMethodDescription'
| 'fallbackPropertyType'
| 'modelsDir'
| 'servicesDir';
Expand All @@ -103,12 +109,16 @@ export const defaultOptions: Required<Pick<OptionsInput, DefaultedOptions>> = {
modelPrefix: '',
modelSuffix: '',
module: 'ApiModule',
configuration: 'ApiConfiguration',
baseService: 'BaseService',
configurationFile: 'api-configuration',
rootUrlToken: 'API_ROOT_URL_TOKEN',
requestBuilder: 'RequestBuilder',
response: 'StrictHttpResponse',
enumStyle: 'pascal',
skipJsonSuffix: false,
responseMethodDescription:
'{{descriptionPrefix}}This method provides access to the full `HttpResponse`, allowing access to response headers.\nTo access only the response body, use `{{methodName}}()` instead.{{descriptionSuffix}}',
bodyMethodDescription:
'{{descriptionPrefix}}This method provides access only to the response body.\nTo access the full response (for headers, for example), use `{{responseMethodName}}()` instead.{{descriptionSuffix}}',
fallbackPropertyType: 'any',
modelsDir: 'models',
servicesDir: 'services',
Expand Down
5 changes: 5 additions & 0 deletions packages/ng-openapi-gen/src/lib/utils/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ export function syncDirs(srcDir: string, destDir: string, removeStale: boolean):
}
}
}

export function joinIfExists(...pathSegments: string[]): string | null {
const joined = join(...pathSegments);
return existsSync(joined) ? joined : null;
}
2 changes: 1 addition & 1 deletion packages/ng-openapi-gen/src/lib/utils/open-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { OaImport } from '../oa-import.js';
import { OaModel } from '../oa-model.js';
import { Options } from '../options.js';
import { camelCase, upperCase, upperFirst } from './lo/index.js';
import { fileName, namespace, refName, toBasicChars, tsComments, typeName } from './string.js';
import { namespace, refName, toBasicChars, tsComments, typeName } from './string.js';

/** Returns the unqualified model class name, that is, the last part after '.' */
export function unqualifiedName(name: string, options: Options): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/ng-openapi-gen/src/ng-openapi-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const parsedArgs = yargsParser(process.argv.slice(2), {
'serviceSuffix',
'modelPrefix',
'modelSuffix',
'configuration',
'baseService',
'configurationFile',
'rootUrlToken',
'requestBuilder',
'response',
'templates',
Expand Down
22 changes: 16 additions & 6 deletions packages/ng-openapi-gen/src/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@
],
"default": "ApiModule"
},
"configuration": {
"description": "Name for the configuration class to generate. Defaults to 'ApiConfiguration'.",
"configurationFile": {
"description": "Name for the configuration file to generate. Defaults to 'api-configuration'.",
"type": "string",
"default": "ApiConfiguration"
"default": "api-configuration"
},
"baseService": {
"description": "Name for the base service class to generate. Defaults to 'BaseService'.",
"rootUrlToken": {
"description": "Name for the \"root URL\" DI token to generate. Defaults to 'API_ROOT_URL_TOKEN'.",
"type": "string",
"default": "BaseService"
"default": "API_ROOT_URL_TOKEN"
},
"requestBuilder": {
"description": "Name for the request builder class to generate. Defaults to 'RequestBuilder'.",
Expand Down Expand Up @@ -169,6 +169,16 @@
}
}
},
"responseMethodDescription": {
"description": "Description template for generated $response method. Defaults to '{{descriptionPrefix}}This method provides access to the full `HttpResponse`, allowing access to response headers.\nTo access only the response body, use `{{methodName}}()` instead.{{descriptionSuffix}}'.",
"type": "string",
"default": "{{descriptionPrefix}}This method provides access to the full `HttpResponse`, allowing access to response headers.\nTo access only the response body, use `{{methodName}}()` instead.{{descriptionSuffix}}"
},
"bodyMethodDescription": {
"description": "Description template for generated $body method. Defaults to '{{descriptionPrefix}}This method provides access only to the response body.\nTo access the full response (for headers, for example), use `{{responseMethodName}}()` instead.{{descriptionSuffix}}'.",
"type": "string",
"default": "{{descriptionPrefix}}This method provides access only to the response body.\nTo access the full response (for headers, for example), use `{{responseMethodName}}()` instead.{{descriptionSuffix}}"
},
"fallbackPropertyType": {
"description": "Fallback property type when type can not be determined for any reason. Defaults to 'any'.",
"type": "string",
Expand Down
34 changes: 0 additions & 34 deletions packages/ng-openapi-gen/src/templates/baseService.handlebars

This file was deleted.

Loading

0 comments on commit e1eafae

Please sign in to comment.