feat(misskey-js): multipart/form-dataのリクエストに対応 (#14147)

* feat(misskey-js): multipart/form-dataのリクエストに対応

* lint

* add test

* Update Changelog

* テストを厳しくする

* lint

* multipart/form-dataではnullのプロパティを弾くように
This commit is contained in:
かっこかり 2024-07-07 14:08:18 +09:00 committed by GitHub
parent 984d582796
commit f119f8c2cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 537 additions and 14 deletions

View file

@ -20,7 +20,14 @@ async function generateBaseTypes(
}
lines.push('');
const generatedTypes = await openapiTS(openApiJsonPath, { exportType: true });
const generatedTypes = await openapiTS(openApiJsonPath, {
exportType: true,
transform(schemaObject) {
if ('format' in schemaObject && schemaObject.format === 'binary') {
return schemaObject.nullable ? 'Blob | null' : 'Blob';
}
},
});
lines.push(generatedTypes);
lines.push('');
@ -56,6 +63,8 @@ async function generateEndpoints(
endpointOutputPath: string,
) {
const endpoints: Endpoint[] = [];
const endpointReqMediaTypes: EndpointReqMediaType[] = [];
const endpointReqMediaTypesSet = new Set<string>();
// misskey-jsはPOST固定で送っているので、こちらも決め打ちする。別メソッドに対応することがあればこちらも直す必要あり
const paths = openApiDocs.paths ?? {};
@ -78,13 +87,24 @@ async function generateEndpoints(
const supportMediaTypes = Object.keys(reqContent);
if (supportMediaTypes.length > 0) {
// いまのところ複数のメディアタイプをとるエンドポイントは無いので決め打ちする
endpoint.request = new OperationTypeAlias(
const req = new OperationTypeAlias(
operationId,
path,
supportMediaTypes[0],
OperationsAliasType.REQUEST,
);
endpoint.request = req;
const reqType = new EndpointReqMediaType(path, req);
endpointReqMediaTypesSet.add(reqType.getMediaType());
endpointReqMediaTypes.push(reqType);
} else {
endpointReqMediaTypesSet.add('application/json');
endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json'));
}
} else {
endpointReqMediaTypesSet.add('application/json');
endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json'));
}
if (operation.responses && isResponseObject(operation.responses['200']) && operation.responses['200'].content) {
@ -137,6 +157,19 @@ async function generateEndpoints(
endpointOutputLine.push('}');
endpointOutputLine.push('');
function generateEndpointReqMediaTypesType() {
return `Record<keyof Endpoints, ${[...endpointReqMediaTypesSet].map((t) => `'${t}'`).join(' | ')}>`;
}
endpointOutputLine.push(`export const endpointReqTypes: ${generateEndpointReqMediaTypesType()} = {`);
endpointOutputLine.push(
...endpointReqMediaTypes.map(it => '\t' + it.toLine()),
);
endpointOutputLine.push('};');
endpointOutputLine.push('');
await writeFile(endpointOutputPath, endpointOutputLine.join('\n'));
}
@ -314,6 +347,26 @@ class Endpoint {
}
}
class EndpointReqMediaType {
public readonly path: string;
public readonly mediaType: string;
constructor(path: string, request: OperationTypeAlias, mediaType?: undefined);
constructor(path: string, request: undefined, mediaType: string);
constructor(path: string, request: OperationTypeAlias | undefined, mediaType?: string) {
this.path = path;
this.mediaType = mediaType ?? request?.mediaType ?? 'application/json';
}
getMediaType(): string {
return this.mediaType;
}
toLine(): string {
return `'${this.path}': '${this.mediaType}',`;
}
}
async function main() {
const generatePath = './built/autogen';
await mkdir(generatePath, { recursive: true });