Skip to content

Commit

Permalink
Merge branch 'pillsilly-pr-filter-paths'
Browse files Browse the repository at this point in the history
Fixes #279
  • Loading branch information
Luis Fernando Planella Gonzalez committed Sep 6, 2024
2 parents 833811f + 24eb453 commit 0075218
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 0 deletions.
44 changes: 44 additions & 0 deletions lib/ng-openapi-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,54 @@ export async function runNgOpenApiGen() {
}
}
}) as OpenAPIObject;

const {excludeTags = [], excludePaths = [], includeTags = []} = options;
openApi.paths = filterPaths(openApi.paths, excludeTags, excludePaths, includeTags);

const gen = new NgOpenApiGen(openApi, options);

gen.generate();
} catch (err) {
console.log(`Error on API generation from ${input}: ${err}`);
process.exit(1);
}
}

export function filterPaths(paths: OpenAPIObject['paths'], excludeTags: Options['excludeTags'] = [], excludePaths: Options['excludePaths'] = [], includeTags: Options['includeTags'] = []) {
paths = JSON.parse(JSON.stringify(paths));
const filteredPaths: OpenAPIObject['paths'] = {};
for (const key in paths) {
if (!paths.hasOwnProperty(key)) continue ;

if (excludePaths?.includes(key)) {
console.log(`Path ${key} is excluded by excludePaths`);
continue;
}

let shouldRemovePath = false;
for (const method of Object.keys(paths[key])) {
const tags: string[] = paths[key]?.[method]?.tags || [];
// if tag on method in includeTags then continue
if (tags.some(tag => includeTags.includes(tag))) {
continue;
}
// if tag on method in excludeTags then remove the method
if (tags.some(tag => excludeTags.includes(tag)) || !!includeTags?.length) {
console.log(`Path ${key} is excluded by excludeTags`);
delete paths[key]?.[method];

// if path has no method left then "should remove"
if (Object.keys(paths[key]).length === 0 ) {
shouldRemovePath = true;
break;
}
}
}
if (shouldRemovePath) {
continue;
}
filteredPaths[key] = paths[key];
}
return filteredPaths;
}

3 changes: 3 additions & 0 deletions lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,7 @@ export interface Options {

/** When true (default) models names will be camelized, besides having the first letter capitalized. Setting to false will prevent camelizing. */
camelizeModelNames?: boolean;

/** List of paths to early exclude from the processing */
excludePaths?: string[];
}
190 changes: 190 additions & 0 deletions test/filterPaths.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { filterPaths } from '../lib/ng-openapi-gen';

describe('filterPaths', () => {

it('should include all paths if nothing is set', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
'/path3': { PUT: { tags: ['tag3'] } },
};
const result = filterPaths(paths, [], [], []);
expect(result).toEqual(paths);
});


it('should exclude paths based on excludePaths', () => {
const paths = {
'/path1': {},
'/path2': {},
'/path3': {},
};

const excludePaths = ['/path2'];

const result = filterPaths(paths, [], excludePaths, []);

expect(result).toEqual({
'/path1': {},
'/path3': {},
});
});

it('should exclude paths based on excludeTags', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
'/path3': { PUT: { tags: ['tag3'] } },
};

const excludeTags = ['tag2'];

const result = filterPaths(paths, excludeTags, [], []);

expect(result).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
'/path3': { PUT: { tags: ['tag3'] } },
});
});

it('should include paths based on includeTags', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
'/path3': { PUT: { tags: ['tag3'] } },
};

const includeTags = ['tag1', 'tag3'];

const result = filterPaths(paths, [], [], includeTags);

expect(result).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
'/path3': { PUT: { tags: ['tag3'] } },
});
});

it('should handle empty paths', () => {
const paths = {};

const result = filterPaths(paths, ['tag1'], ['/path1'], []);

expect(result).toEqual({});
});

it('should include all paths when no filters are provided', () => {
const paths = {
'/path1': {},
'/path2': {},
};

const result = filterPaths(paths);

expect(result).toEqual({
'/path1': {},
'/path2': {},
});
});

it('should handle multiple filters simultaneously', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
'/path3': { PUT: { tags: ['tag3'] } },
'/path4': { DELETE: { tags: ['tag4'] } },
};

const excludeTags = ['tag2', 'tag4'];
const excludePaths = ['/path2'];
const includeTags = ['tag1', 'tag3'];

const result = filterPaths(paths, excludeTags, excludePaths, includeTags);

expect(result).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
'/path3': { PUT: { tags: ['tag3'] } },
});
});

it('should handle paths with no tags', () => {
const paths = {
'/path1': { GET: {} },
'/path2': { POST: {} },
};

const result = filterPaths(paths, ['tag1'], [], []);

expect(result).toEqual({
'/path1': { GET: {} },
'/path2': { POST: {} },
});
});

it('should handle paths with multiple methods', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] }, POST: { tags: ['tag2'] } },
'/path2': { PUT: { tags: ['tag3'] }, DELETE: { tags: ['tag4'] } },
};

const excludeTags = ['tag2', 'tag4'];
const includeTags = ['tag1', 'tag3'];

const result = filterPaths(paths, excludeTags, [], includeTags);

expect(result).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { PUT: { tags: ['tag3'] } },
});
});

it('should be case-insensitive when matching tag', () => {
const paths = {
'/path1': { GET: { tags: ['Tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
};

const excludeTags = ['tag1'];
const includeTags = ['TAG2'];

const result = filterPaths(paths, excludeTags, [], includeTags);

console.log(result);
expect(result).toEqual({});
});

it('should exclude paths with no remaining methods', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
};

const excludeTags = ['tag1', 'tag2'];

const result = filterPaths(paths, excludeTags, [], []);

expect(result).toEqual({});
});

it('should not modify the original paths object', () => {
const paths = {
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
};

const excludeTags = ['tag2'];

const result = filterPaths(paths, excludeTags, [], []);

// Ensure the original object is not modified
expect(paths).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
'/path2': { POST: { tags: ['tag2'] } },
});

// Ensure the result is correct
expect(result).toEqual({
'/path1': { GET: { tags: ['tag1'] } },
});
});
});

0 comments on commit 0075218

Please sign in to comment.