Skip to content

Commit

Permalink
feat: remove 'sway' dependency from sdk generator (#1701)
Browse files Browse the repository at this point in the history
## Proposed change

<!-- Please include a summary of the changes and the related issue.
Please also include relevant motivation and context. List any
dependencies that is required for this change. -->

## Related issues

- 🐛 Fixes #(issue)
- 🚀 Feature #(issue)

<!-- Please make sure to follow the contributing guidelines on
https://github.com/amadeus-digital/Otter/blob/main/CONTRIBUTING.md -->

cherry-pick from #1578
  • Loading branch information
mrednic-1A authored Apr 24, 2024
2 parents 3a19e4c + bd3cd79 commit df8f53e
Show file tree
Hide file tree
Showing 11 changed files with 379 additions and 325 deletions.
2 changes: 1 addition & 1 deletion apps/github-cascading-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"nock": "^13.0.5",
"nx": "~16.10.0",
"rxjs": "^7.8.1",
"smee-client": "^1.2.2",
"smee-client": "^2.0.0",
"ts-jest": "~29.1.1",
"tslib": "^2.5.3",
"typescript": "~5.1.6",
Expand Down
5 changes: 4 additions & 1 deletion packages/@ama-sdk/generator-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
"dependencies": {
"@ama-sdk/core": "workspace:^",
"@o3r/dev-tools": "workspace:^",
"js-yaml": "^4.1.0",
"rimraf": "^5.0.1",
"sway": "^2.0.6",
"tslib": "^2.5.3",
"yeoman-generator": "^5.0.0"
},
Expand All @@ -60,6 +60,7 @@
"@o3r/test-helpers": "workspace:^",
"@schematics/angular": "~16.2.0",
"@types/jest": "~29.5.2",
"@types/js-yaml": "^4.0.5",
"@types/node": "^18.0.0",
"@types/yeoman-environment": "^2.10.7",
"@types/yeoman-generator": "^5.2.10",
Expand All @@ -82,8 +83,10 @@
"minimist": "^1.2.6",
"npm-run-all": "^4.1.5",
"onchange": "^7.0.2",
"openapi-types": "^12.0.0",
"rimraf": "^5.0.1",
"ts-jest": "~29.1.1",
"type-fest": "^3.12.0",
"typescript": "~5.1.6",
"yeoman-assert": "^3.1.1",
"yeoman-environment": "^3.10.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { OpenAPIV3 } from 'openapi-types';
import { generateOperationFinderFromSingleFile } from './path-extractor';

describe('generateOperationFinderFromSingleFile', () => {

it('should parse a full path object', () => {
const spec: OpenAPIV3.Document = {
openapi: '3.0.0',
info: {
title: 'test',
version: '0.0.0'
},
paths: {
'/pet': {
post: {
description: 'Add a new pet to the store',
operationId: 'addPet',
responses: {
200: {
$ref: ''
},
405: {
$ref: ''
}
}
},
put: {
description: 'Update an existing pet by Id',
operationId: 'updatePet',
responses: {
200: {
$ref: ''
},
405: {
$ref: ''
}
}
}
},
// eslint-disable-next-line @typescript-eslint/naming-convention
'/pet/{petId}': {
get: {
description: 'Returns a single pet',
operationId: 'getPetById',
responses: {
200: {
$ref: ''
},
405: {
$ref: ''
}
}
}
}
}
};

const result = generateOperationFinderFromSingleFile(spec);
expect(result).toEqual([
{
path: '/pet', regexp: new RegExp('^/pet(?:/(?=$))?$'), operations: [{ 'method': 'post', 'operationId': 'addPet' }, { 'method': 'put', 'operationId': 'updatePet' }]
},
{
path: '/pet/{petId}', regexp: new RegExp('^/pet/((?:[^/]+?))(?:/(?=$))?$'), operations: [{ 'method': 'get', 'operationId': 'getPetById' }]
}
]);
});

it('should parse a path object with reference', () => {
const spec: OpenAPIV3.Document = {
openapi: '3.0.0',
info: {
title: 'test',
version: '0.0.0'
},
paths: {
'/pet': {
$ref: '#/components/schemas'
}
},
components: {
schemas: {
post: {
description: 'Add a new pet to the store',
operationId: 'addPet',
responses: {
200: {
$ref: ''
},
405: {
$ref: ''
}
}
} as any
}
}
};

const result = generateOperationFinderFromSingleFile(spec);
expect(result).toEqual([
{
path: '/pet', regexp: new RegExp('^/pet(?:/(?=$))?$'), operations: [{ 'method': 'post', 'operationId': 'addPet' }]
}
]);
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// File copied from @ama-sdk/schematics generator in order to fix an issue
import type { PathObject } from '@ama-sdk/core';
// eslint-disable-next-line camelcase
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';

/**
* Parse a single specification to retrieve the Operation Finder information
* This function is properly working to a specification that does not include external references in the Paths object
* @param specification Specification single object to parse
*/
// eslint-disable-next-line camelcase
export const generateOperationFinderFromSingleFile = (specification: OpenAPIV2.Document | OpenAPIV3.Document | OpenAPIV3_1.Document): PathObject[] => {
if (!specification.paths) {
return [];
}

return Object.entries(specification.paths)
.filter(([, pathObject]) => !!pathObject)
.map(([path, pathObjectOrRef]) => {
// eslint-disable-next-line camelcase
const pathObject: Record<OpenAPIV2.HttpMethods, OpenAPIV2.OperationObject | OpenAPIV3.OperationObject | OpenAPIV3_1.OperationObject> = pathObjectOrRef.$ref
? (pathObjectOrRef.$ref as string).replace(/^#\/?/, '').split('/').reduce((acc: any, ref) => acc[ref], specification)
: pathObjectOrRef;
return {
path,
regexp: new RegExp(`^${path.replace(/\{[^}]+}/g, '((?:[^/]+?))')}(?:/(?=$))?$`),
operations: Object.entries(pathObject)
.map(([method, reqObject]) => ({
method,
operationId: reqObject.operationId
}))
};
});
};
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './properties';
export * from './helpers/path-extractor';
52 changes: 23 additions & 29 deletions packages/@ama-sdk/generator-sdk/src/generators/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import * as path from 'node:path';
import * as rimraf from 'rimraf';
import * as sway from 'sway';
import { type } from 'node:os';
import type {Operation, PathObject} from '@ama-sdk/core';
import type { PathObject } from '@ama-sdk/core';

import Generator from 'yeoman-generator';

import { SdkGenerator } from '../sdk-generator';
import { Properties } from './core';
import { generateOperationFinderFromSingleFile, Properties } from './core';
import { readFileSync } from 'node:fs';
import { JsonObject } from 'type-fest';

export default class extends SdkGenerator {

Expand All @@ -32,33 +33,27 @@ export default class extends SdkGenerator {
/**
* Generates the operation id finder from spec
*/
private async _generateOperationFinder(): Promise<PathObject[]> {
const swayOptions = {
definition: path.resolve(this.properties.swaggerSpecPath!)
};
const swayApi = await sway.create(swayOptions);
const extraction = swayApi.getPaths().map((obj) => ({
path: `${obj.path as string}`,
regexp: obj.regexp as RegExp,
operations: obj.getOperations().map((op: any) => {
const operation: Operation = {
method: `${op.method as string}`,
operationId: `${op.operationId as string}`
};
return operation;
}) as Operation[]
}));
return extraction;
}
private _generateOperationFinder = async (): Promise<PathObject[]> => {
const specPath = path.resolve(process.cwd(), this.getSwaggerSpecPath(this.properties.swaggerSpecPath!));
const specContent = readFileSync(specPath).toString();
// eslint-disable-next-line no-undef-init
let jsonSpecContent: JsonObject | undefined = undefined;
try {
jsonSpecContent = JSON.parse(specContent) as JsonObject;
} catch (e) {
}
const specification: any = jsonSpecContent || (await import('js-yaml')).load(specContent);
const extraction = generateOperationFinderFromSingleFile(specification);
return extraction || [];
};

private _getRegexpTemplate(regexp: RegExp) {
return `new RegExp('${regexp.toString().replace(/\/(.*)\//, '$1').replace(/\\\//g, '/')}')`;
}

private _getPathObjectTemplate(pathObj: PathObject) {
return `{
${
(Object.keys(pathObj) as (keyof PathObject)[]).map((propName) => {
${(Object.keys(pathObj) as (keyof PathObject)[]).map((propName) => {
const value = (propName) === 'regexp' ? this._getRegexpTemplate(pathObj[propName]) : JSON.stringify(pathObj[propName]);
return `${propName as string}: ${value}`;
}).join(',')
Expand Down Expand Up @@ -99,15 +94,14 @@ export default class extends SdkGenerator {
}

public async writing() {
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'api', '**', '*.ts'), {glob: true});
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'models', 'base', '**', '!(index).ts'), {glob: true});
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'spec', '!(operation-adapter|index).ts'), {glob: true});
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'api', '**', '*.ts'), { glob: true });
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'models', 'base', '**', '!(index).ts'), { glob: true });
rimraf.sync(path.resolve(this.destinationPath(), 'src', 'spec', '!(operation-adapter|index).ts'), { glob: true });
this.log('Removed previously generated sources');

const pathObjects = await this._generateOperationFinder() || [];

this.properties.swayOperationAdapter = `[${
pathObjects.map((pathObj) => this._getPathObjectTemplate(pathObj)).join(',')
this.properties.swayOperationAdapter = `[${pathObjects.map((pathObj) => this._getPathObjectTemplate(pathObj)).join(',')
}]`;

this.fs.copyTpl(
Expand Down Expand Up @@ -153,7 +147,7 @@ export default class extends SdkGenerator {
}

public end() {
rimraf.sync(path.resolve(this.destinationPath(), 'swagger-codegen-typescript', '**'), {glob: true});
rimraf.sync(path.resolve(this.destinationPath(), 'swagger-codegen-typescript', '**'), { glob: true });
try {
const packageManagerCommand = process.env && process.env.npm_execpath && process.env.npm_execpath.indexOf('yarn') === -1 ? 'npx' : 'yarn';
this.spawnCommandSync(packageManagerCommand, ['eslint', path.join('src', 'spec', 'operation-adapter.ts'), '--quiet', '--fix'], { cwd: this.destinationPath() });
Expand Down
2 changes: 1 addition & 1 deletion packages/@ama-sdk/schematics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"minimatch": "~9.0.3",
"rxjs": "^7.8.1",
"semver": "^7.5.2",
"sway": "^2.0.6",
"tslib": "^2.5.3"
},
"devDependencies": {
Expand Down Expand Up @@ -90,6 +89,7 @@
"npm-run-all": "^4.1.5",
"nx": "~16.10.0",
"onchange": "^7.0.2",
"openapi-types": "^12.0.0",
"pid-from-port": "^1.1.3",
"semver": "^7.5.2",
"ts-jest": "~29.1.1",
Expand Down
Loading

0 comments on commit df8f53e

Please sign in to comment.