Skip to content

Commit

Permalink
Merge pull request #1178 from hey-api/feat/parser-plugin-tanstack-query
Browse files Browse the repository at this point in the history
feat: rewrite tanstack query plugin to new parser
  • Loading branch information
mrlubos authored Oct 21, 2024
2 parents 11480cc + 9885743 commit 2acbc80
Show file tree
Hide file tree
Showing 56 changed files with 7,875 additions and 7,210 deletions.
20 changes: 11 additions & 9 deletions packages/openapi-ts/src/generate/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export class TypeScriptFile {
type: {},
value: {},
};
/**
* Path relative to the client output root.
*/
// TODO: parser - add relative path property for quick access, currently
// everything is resolved into an absolute path with cwd
// public relativePath: string;

public constructor({
dir,
Expand All @@ -36,7 +42,7 @@ export class TypeScriptFile {
name: string;
}) {
this._name = this._setName(name);
this._path = path.resolve(dir, this.getName());
this._path = path.resolve(dir, this._name);

if (header) {
this._headers.push(
Expand Down Expand Up @@ -99,19 +105,15 @@ export class TypeScriptFile {
return importedItem;
}

public getName(withExtension = true) {
if (withExtension) {
return this._name;
}
public isEmpty() {
return !this._items.length;
}

public nameWithoutExtension() {
const { name } = splitNameAndExtension(this._name);
return name;
}

public isEmpty() {
return !this._items.length;
}

public remove(options?: Parameters<typeof rmSync>[1]) {
rmSync(this._path, options);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/generate/indexFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const generateIndexFile = ({ files }: { files: Files }): void => {

files.index.add(
compiler.exportAllDeclaration({
module: `./${file.getName(false)}`,
module: `./${file.nameWithoutExtension()}`,
}),
);
});
Expand Down
12 changes: 6 additions & 6 deletions packages/openapi-ts/src/generate/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ export const generateLegacyServices = async ({
files.services.import({
// this detection could be done safer, but it shouldn't cause any issues
asType: !imported.endsWith('Transformer'),
module: `./${files.types.getName(false)}`,
module: `./${files.types.nameWithoutExtension()}`,
name: imported,
});
},
Expand All @@ -981,8 +981,8 @@ const requestOptions = ({
path: string;
}) => {
const file = context.file({ id: servicesId })!;
const servicesOutput = file.getName(false);
// const typesModule = `./${context.file({ id: 'types' })!.getName(false)}`
const servicesOutput = file.nameWithoutExtension();
// const typesModule = `./${context.file({ id: 'types' })!.nameWithoutExtension()}`

// TODO: parser - add response transformers
// const operationName = operationResponseTypeName(operation.name);
Expand Down Expand Up @@ -1078,7 +1078,7 @@ const requestOptions = ({

const generateClassServices = ({ context }: { context: IRContext }) => {
const file = context.file({ id: servicesId })!;
const typesModule = `./${context.file({ id: 'types' })!.getName(false)}`;
const typesModule = `./${context.file({ id: 'types' })!.nameWithoutExtension()}`;

const services = new Map<string, Array<ts.MethodDeclaration>>();

Expand Down Expand Up @@ -1208,7 +1208,7 @@ const generateClassServices = ({ context }: { context: IRContext }) => {

const generateFlatServices = ({ context }: { context: IRContext }) => {
const file = context.file({ id: servicesId })!;
const typesModule = `./${context.file({ id: 'types' })!.getName(false)}`;
const typesModule = `./${context.file({ id: 'types' })!.nameWithoutExtension()}`;

for (const path in context.ir.paths) {
const pathItem = context.ir.paths[path as keyof IRPathsObject];
Expand Down Expand Up @@ -1324,7 +1324,7 @@ export const generateServices = ({ context }: { context: IRContext }) => {
id: servicesId,
path: 'services',
});
const servicesOutput = file.getName(false);
const servicesOutput = file.nameWithoutExtension();

// import required packages and core files
file.import({
Expand Down
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/generate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1539,7 +1539,7 @@ const operationToType = ({
});
};

const schemaToType = ({
export const schemaToType = ({
$ref,
context,
namespace = [],
Expand Down
10 changes: 10 additions & 0 deletions packages/openapi-ts/src/ir/ir.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export interface IROperationObject {

export interface IRBodyObject {
mediaType: string;
/**
* Does body control pagination? We handle only simple values
* for now, up to 1 nested field.
*/
pagination?: boolean | string;
required?: boolean;
schema: IRSchemaObject;
type?: IRMediaType;
Expand All @@ -60,6 +65,11 @@ export interface IRParameterObject {
*/
location: 'cookie' | 'header' | 'path' | 'query';
name: string;
/**
* Does this parameter control pagination? We handle only simple values
* for now, up to 1 nested field.
*/
pagination?: boolean | string;
required?: boolean;
schema: IRSchemaObject;
}
Expand Down
24 changes: 23 additions & 1 deletion packages/openapi-ts/src/ir/operation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { IROperationObject } from './ir';
import { hasParametersObjectRequired } from './parameter';
import type { Pagination } from './pagination';
import {
hasParametersObjectRequired,
parameterWithPagination,
} from './parameter';

export const hasOperationDataRequired = (
operation: IROperationObject,
Expand All @@ -14,3 +18,21 @@ export const hasOperationDataRequired = (

return false;
};

export const operationPagination = (
operation: IROperationObject,
): Pagination | undefined => {
if (operation.body?.pagination) {
return {
in: 'body',
name:
operation.body.pagination === true ? 'body' : operation.body.pagination,
schema:
operation.body.pagination === true
? operation.body.schema
: operation.body.schema.properties![operation.body.pagination],
};
}

return parameterWithPagination(operation.parameters);
};
9 changes: 9 additions & 0 deletions packages/openapi-ts/src/ir/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { IRSchemaObject } from './ir';

export const paginationKeywordsRegExp = /^(cursor|offset|page|start)/;

export interface Pagination {
in: string;
name: string;
schema: IRSchemaObject;
}
77 changes: 77 additions & 0 deletions packages/openapi-ts/src/ir/parameter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { IRParametersObject } from './ir';
import type { Pagination } from './pagination';

export const hasParametersObjectRequired = (
parameters: IRParametersObject | undefined,
Expand Down Expand Up @@ -33,3 +34,79 @@ export const hasParametersObjectRequired = (

return false;
};

export const parameterWithPagination = (
parameters: IRParametersObject | undefined,
): Pagination | undefined => {
if (!parameters) {
return;
}

for (const name in parameters.cookie) {
const parameter = parameters.cookie[name];
if (parameter.pagination) {
return {
in: parameter.location,
name:
parameter.pagination === true
? name
: `${name}.${parameter.pagination}`,
schema:
parameter.pagination === true
? parameter.schema
: parameter.schema.properties![parameter.pagination],
};
}
}

for (const name in parameters.header) {
const parameter = parameters.header[name];
if (parameter.pagination) {
return {
in: parameter.location,
name:
parameter.pagination === true
? name
: `${name}.${parameter.pagination}`,
schema:
parameter.pagination === true
? parameter.schema
: parameter.schema.properties![parameter.pagination],
};
}
}

for (const name in parameters.path) {
const parameter = parameters.path[name];
if (parameter.pagination) {
return {
in: parameter.location,
name:
parameter.pagination === true
? name
: `${name}.${parameter.pagination}`,
schema:
parameter.pagination === true
? parameter.schema
: parameter.schema.properties![parameter.pagination],
};
}
}

for (const name in parameters.query) {
const parameter = parameters.query[name];
if (parameter.pagination) {
return {
in: parameter.location,
name:
parameter.pagination === true
? name
: `${name}.${parameter.pagination}`,
schema:
parameter.pagination === true
? parameter.schema
: parameter.schema.properties![parameter.pagination],
};
}
}
};
22 changes: 18 additions & 4 deletions packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import type {
PathItemObject,
RequestBodyObject,
ResponseObject,
SchemaObject,
} from '../types/spec';
import { mediaTypeObject } from './mediaType';
import { paginationField } from './pagination';
import { schemaToIrSchema } from './schema';

interface Operation
Expand Down Expand Up @@ -76,17 +78,29 @@ const operationToIrOperation = ({
content: requestBodyObject.content,
});
if (content) {
const finalSchema: SchemaObject = {
description: requestBodyObject.description,
...content.schema,
};

const pagination = paginationField({
context,
name: '',
schema: finalSchema,
});

irOperation.body = {
mediaType: content.mediaType,
schema: schemaToIrSchema({
context,
schema: {
description: requestBodyObject.description,
...content.schema,
},
schema: finalSchema,
}),
};

if (pagination) {
irOperation.body.pagination = pagination;
}

if (requestBodyObject.required) {
irOperation.body.required = requestBodyObject.required;
}
Expand Down
83 changes: 83 additions & 0 deletions packages/openapi-ts/src/openApi/3.1.0/parser/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { IRContext } from '../../../ir/context';
import { paginationKeywordsRegExp } from '../../../ir/pagination';
import type { ParameterObject, RequestBodyObject } from '../types/spec';
import { type SchemaObject } from '../types/spec';
import { mediaTypeObject } from './mediaType';
import { getSchemaTypes } from './schema';

// We handle only simple values for now, up to 1 nested field
export const paginationField = ({
context,
name,
schema,
}: {
context: IRContext;
name: string;
schema: SchemaObject;
}): boolean | string => {
paginationKeywordsRegExp.lastIndex = 0;
if (paginationKeywordsRegExp.test(name)) {
return true;
}

if (schema.$ref) {
const ref = context.resolveRef<
ParameterObject | RequestBodyObject | SchemaObject
>(schema.$ref);

if ('content' in ref || 'in' in ref) {
let refSchema: SchemaObject | undefined;

if ('in' in ref) {
refSchema = ref.schema;
}

if (!refSchema) {
// parameter or body
const content = mediaTypeObject({ content: ref.content });
if (content?.schema) {
refSchema = content.schema;
}
}

if (!refSchema) {
return false;
}

return paginationField({
context,
name,
schema: refSchema,
});
}

return paginationField({
context,
name,
schema: ref,
});
}

for (const name in schema.properties) {
paginationKeywordsRegExp.lastIndex = 0;

if (paginationKeywordsRegExp.test(name)) {
const property = schema.properties[name];

if (typeof property !== 'boolean') {
const schemaTypes = getSchemaTypes({ schema: property });

if (
schemaTypes.includes('boolean') ||
schemaTypes.includes('integer') ||
schemaTypes.includes('number') ||
schemaTypes.includes('string')
) {
return name;
}
}
}
}

return false;
};
Loading

0 comments on commit 2acbc80

Please sign in to comment.