From efb0ffc4ec1e0b9f6af922cee11481c28dd9a8d6 Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 18 Jan 2022 22:27:10 +0900 Subject: refactor: APIエンドポイントファイルの定義を良い感じにする (#8154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix API Schema Error * Delete SimpleSchema/SimpleObj and Move schemas to dedicated files * Userのスキーマを分割してみる * define packMany type * add , * Ensure enum schema and Make "as const" put once * test? * Revert "test?" This reverts commit 97dc9bfa70851bfb7d1cf38e883f8df20fb78b79. * Revert "Fix API Schema Error" This reverts commit 21b6176d974ed8e3eb73723ad21a105c5d297323. * :v: * clean up * test? * wip * wip * better schema def * :v: * fix * add minLength property * wip * wip * wip * anyOf/oneOf/allOfに対応? ~ relation.ts * refactor! * Define MinimumSchema * wip * wip * anyOf/oneOf/allOfが動作するようにUnionSchemaTypeを修正 * anyOf/oneOf/allOfが動作するようにUnionSchemaTypeを修正 * Update packages/backend/src/misc/schema.ts Co-authored-by: Acid Chicken (硫酸鶏) * fix * array oneOfをより正確な型に * array oneOfをより正確な型に * wip * :v: * なんかもういろいろ * remove * very good schema * api schema * wip * refactor: awaitAllの型定義を変えてみる * fix * specify types in awaitAll * specify types in awaitAll * :v: * wip * ... * :v: * AllowDateはやめておく * 不必要なoptional: false, nullable: falseを廃止 * Packedが展開されないように * 続packed * wip * define note type * wip * UserDetailedをMeDetailedかUserDetailedNotMeかを区別できるように * wip * wip * wip specify user type of other schemas * ok * convertSchemaToOpenApiSchemaを改修 * convertSchemaToOpenApiSchemaを改修 * Fix * fix * :v: * wip * 分割代入ではなくallOfで定義するように Co-authored-by: Acid Chicken (硫酸鶏) --- packages/backend/src/misc/schema.ts | 171 ++++++++++++++++++++--------- packages/backend/src/misc/simple-schema.ts | 15 --- 2 files changed, 120 insertions(+), 66 deletions(-) delete mode 100644 packages/backend/src/misc/simple-schema.ts (limited to 'packages/backend/src/misc') diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts index ae6f1bac86..2dae954af9 100644 --- a/packages/backend/src/misc/schema.ts +++ b/packages/backend/src/misc/schema.ts @@ -1,30 +1,44 @@ -import { SimpleObj, SimpleSchema } from './simple-schema'; -import { packedUserSchema } from '@/models/repositories/user'; -import { packedNoteSchema } from '@/models/repositories/note'; -import { packedUserListSchema } from '@/models/repositories/user-list'; -import { packedAppSchema } from '@/models/repositories/app'; -import { packedMessagingMessageSchema } from '@/models/repositories/messaging-message'; -import { packedNotificationSchema } from '@/models/repositories/notification'; -import { packedDriveFileSchema } from '@/models/repositories/drive-file'; -import { packedDriveFolderSchema } from '@/models/repositories/drive-folder'; -import { packedFollowingSchema } from '@/models/repositories/following'; -import { packedMutingSchema } from '@/models/repositories/muting'; -import { packedBlockingSchema } from '@/models/repositories/blocking'; -import { packedNoteReactionSchema } from '@/models/repositories/note-reaction'; -import { packedHashtagSchema } from '@/models/repositories/hashtag'; -import { packedPageSchema } from '@/models/repositories/page'; -import { packedUserGroupSchema } from '@/models/repositories/user-group'; -import { packedNoteFavoriteSchema } from '@/models/repositories/note-favorite'; -import { packedChannelSchema } from '@/models/repositories/channel'; -import { packedAntennaSchema } from '@/models/repositories/antenna'; -import { packedClipSchema } from '@/models/repositories/clip'; -import { packedFederationInstanceSchema } from '@/models/repositories/federation-instance'; -import { packedQueueCountSchema } from '@/models/repositories/queue'; -import { packedGalleryPostSchema } from '@/models/repositories/gallery-post'; -import { packedEmojiSchema } from '@/models/repositories/emoji'; +import { + packedUserLiteSchema, + packedUserDetailedNotMeOnlySchema, + packedMeDetailedOnlySchema, + packedUserDetailedNotMeSchema, + packedMeDetailedSchema, + packedUserDetailedSchema, + packedUserSchema, +} from '@/models/schema/user'; +import { packedNoteSchema } from '@/models/schema/note'; +import { packedUserListSchema } from '@/models/schema/user-list'; +import { packedAppSchema } from '@/models/schema/app'; +import { packedMessagingMessageSchema } from '@/models/schema/messaging-message'; +import { packedNotificationSchema } from '@/models/schema/notification'; +import { packedDriveFileSchema } from '@/models/schema/drive-file'; +import { packedDriveFolderSchema } from '@/models/schema/drive-folder'; +import { packedFollowingSchema } from '@/models/schema/following'; +import { packedMutingSchema } from '@/models/schema/muting'; +import { packedBlockingSchema } from '@/models/schema/blocking'; +import { packedNoteReactionSchema } from '@/models/schema/note-reaction'; +import { packedHashtagSchema } from '@/models/schema/hashtag'; +import { packedPageSchema } from '@/models/schema/page'; +import { packedUserGroupSchema } from '@/models/schema/user-group'; +import { packedNoteFavoriteSchema } from '@/models/schema/note-favorite'; +import { packedChannelSchema } from '@/models/schema/channel'; +import { packedAntennaSchema } from '@/models/schema/antenna'; +import { packedClipSchema } from '@/models/schema/clip'; +import { packedFederationInstanceSchema } from '@/models/schema/federation-instance'; +import { packedQueueCountSchema } from '@/models/schema/queue'; +import { packedGalleryPostSchema } from '@/models/schema/gallery-post'; +import { packedEmojiSchema } from '@/models/schema/emoji'; export const refs = { + UserLite: packedUserLiteSchema, + UserDetailedNotMeOnly: packedUserDetailedNotMeOnlySchema, + MeDetailedOnly: packedMeDetailedOnlySchema, + UserDetailedNotMe: packedUserDetailedNotMeSchema, + MeDetailed: packedMeDetailedSchema, + UserDetailed: packedUserDetailedSchema, User: packedUserSchema, + UserList: packedUserListSchema, UserGroup: packedUserGroupSchema, App: packedAppSchema, @@ -49,12 +63,50 @@ export const refs = { Emoji: packedEmojiSchema, }; -export type Packed = ObjType<(typeof refs[x])['properties']>; +// Packed = SchemaTypeDef; とすると展開されてマウスホバー時に型表示が使い物にならなくなる +// ObjTypeを指定すると(なぜか)展開されずにPacked<'Hoge'>と表示される +type PackedDef; allOf?: ReadonlyArray }> = + r['allOf'] extends ReadonlyArray ? UnionToIntersection> : + r['oneOf'] extends ReadonlyArray ? UnionSchemaType : + r['properties'] extends Obj ? ObjType : + never; +export type Packed = PackedDef; + +type TypeStringef = 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any'; +type StringDefToType = + T extends 'boolean' ? boolean : + T extends 'number' ? number : + T extends 'string' ? string | Date : + T extends 'array' ? ReadonlyArray : + T extends 'object' ? Record : + any; + +// https://swagger.io/specification/?sbsearch=optional#schema-object +type OfSchema = { + readonly anyOf?: ReadonlyArray; + readonly oneOf?: ReadonlyArray; + readonly allOf?: ReadonlyArray; +} + +export interface MinimumSchema extends OfSchema { + readonly type?: TypeStringef; + readonly nullable?: boolean; + readonly optional?: boolean; + readonly items?: MinimumSchema; + readonly properties?: Obj; + readonly description?: string; + readonly example?: any; + readonly format?: string; + readonly ref?: keyof typeof refs; + readonly enum?: ReadonlyArray; + readonly default?: (this['type'] extends TypeStringef ? StringDefToType : any) | null; + readonly maxLength?: number; + readonly minLength?: number; +} -export interface Schema extends SimpleSchema { - items?: Schema; - properties?: Obj; - ref?: keyof typeof refs; +export interface Schema extends MinimumSchema { + readonly nullable: boolean; + readonly optional: boolean; } type NonUndefinedPropertyNames = { @@ -65,22 +117,13 @@ type UndefinedPropertyNames = { [K in keyof T]: T[K]['optional'] extends true ? K : never }[keyof T]; -type OnlyRequired = Pick>; -type OnlyOptional = Pick>; - -export interface Obj extends SimpleObj { [key: string]: Schema; } +export interface Obj { [key: string]: Schema; } export type ObjType = - { [P in keyof OnlyOptional]?: SchemaType } & - { [P in keyof OnlyRequired]: SchemaType }; - -// https://qiita.com/hrsh7th@github/items/84e8968c3601009cdcf2 -type MyType = { - 0: any; - 1: SchemaType; -}[T extends Schema ? 1 : 0]; + { -readonly [P in UndefinedPropertyNames]?: SchemaType } & + { -readonly [P in NonUndefinedPropertyNames]: SchemaType }; -type NullOrUndefined

= +type NullOrUndefined

= p['nullable'] extends true ? p['optional'] extends true ? (T | null | undefined) @@ -89,15 +132,41 @@ type NullOrUndefined

= ? (T | undefined) : T; -export type SchemaType

= - p['type'] extends 'number' ? NullOrUndefined : - p['type'] extends 'string' ? NullOrUndefined : - p['type'] extends 'boolean' ? NullOrUndefined : - p['type'] extends 'array' ? NullOrUndefined>[]> : +// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; + +// https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552 +// 単純にSchemaTypeDefで判定するだけではダメ +type UnionSchemaType = X extends any ? SchemaType : never; +type ArrayUnion = T extends any ? Array : never; + +export type SchemaTypeDef

= + p['type'] extends 'number' ? number : + p['type'] extends 'string' ? ( + p['enum'] extends readonly string[] ? + p['enum'][number] : + p['format'] extends 'date-time' ? string : // Dateにする?? + string + ) : + p['type'] extends 'boolean' ? boolean : p['type'] extends 'object' ? ( - p['ref'] extends keyof typeof refs - ? NullOrUndefined> - : NullOrUndefined>> + p['ref'] extends keyof typeof refs ? Packed : + p['properties'] extends NonNullable ? ObjType : + p['anyOf'] extends ReadonlyArray ? UnionSchemaType & Partial>> : + p['allOf'] extends ReadonlyArray ? UnionToIntersection> : + any + ) : + p['type'] extends 'array' ? ( + p['items'] extends OfSchema ? ( + p['items']['anyOf'] extends ReadonlyArray ? UnionSchemaType>[] : + p['items']['oneOf'] extends ReadonlyArray ? ArrayUnion>> : + p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] : + never + ) : + p['items'] extends NonNullable ? SchemaTypeDef[] : + any[] ) : - p['type'] extends 'any' ? NullOrUndefined : + p['oneOf'] extends ReadonlyArray ? UnionSchemaType : any; + +export type SchemaType

= NullOrUndefined>; diff --git a/packages/backend/src/misc/simple-schema.ts b/packages/backend/src/misc/simple-schema.ts deleted file mode 100644 index abbb348e24..0000000000 --- a/packages/backend/src/misc/simple-schema.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface SimpleSchema { - type: 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any'; - nullable: boolean; - optional: boolean; - items?: SimpleSchema; - properties?: SimpleObj; - description?: string; - example?: any; - format?: string; - ref?: string; - enum?: string[]; - default?: boolean | null; -} - -export interface SimpleObj { [key: string]: SimpleSchema; } -- cgit v1.2.3-freya