Skip to content

Commit

Permalink
refa(lark): add paginated typings
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 6, 2025
1 parent 9531b30 commit fc60874
Show file tree
Hide file tree
Showing 47 changed files with 597 additions and 3,620 deletions.
54 changes: 43 additions & 11 deletions adapters/lark/scripts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,19 @@ function _formatType(schema: Schema, imports = new Set<string>()) {
if (schema.type === 'boolean') return 'boolean'
if (schema.type === 'object') {
if (!schema.properties) return 'unknown'
return `{\n${generateParams(schema.properties, imports)}\n}`
return `{\n${generateParams(schema.properties, imports)}}`
} else if (schema.type === 'list') {
return formatType(schema.items!, imports) + '[]'
}
return 'unknown'
}

function generateParams(properties: Schema[], imports: Set<string>): string {
if (!properties.length) return ''
const getDesc = (v: Schema) => v.description ? ` /** ${v.description.replace(/\n/g, '').trim()} */\n` : ''
return properties.map((schema: Schema) => {
return `${getDesc(schema)} ${schema.name}${schema.required ? '' : '?'}: ${formatType(schema, imports)}`
}).join('\n')
}).join('\n') + '\n'
}

function getApiName(detail: ApiDetail) {
Expand All @@ -194,6 +195,7 @@ interface Project {
responses: string[]
internals: string[]
imports: Set<string>
internalImports: Set<string>
defines: Record<string, Record<string, string>>
}

Expand All @@ -216,6 +218,7 @@ async function start() {
responses: [],
internals: [],
imports: new Set(),
internalImports: new Set(['Internal']),
defines: {},
}

Expand All @@ -224,24 +227,30 @@ async function start() {
const args: string[] = []
const extras: string[] = []
let returnType = `${apiType}Response`
// if (api.pagination) console.log(apiName, 'pagination')

for (const property of detail.request.path?.properties || []) {
args.push(`${property.name}: ${formatType(property, project.imports)}`)
}
if (detail.supportFileUpload && detail.request.body?.properties?.length) {
const name = `${apiType}Form`
args.push(`form: ${name}`)
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.body!.properties, project.imports)}\n}`)
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.body!.properties, project.imports)}}`)
extras.push(`multipart: true`)
} else if (detail.request.body?.properties?.length) {
const name = `${apiType}Request`
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.body.properties, project.imports)}\n}`)
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.body.properties, project.imports)}}`)
args.push(`body: ${name}`)
}
if (detail.request.query?.properties?.length) {
const name = `${apiType}Query`
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.query.properties, project.imports)}\n}`)
const keys = detail.request.query.properties.map(s => s.name)
if (keys.includes('page_token') && keys.includes('page_size')) {
const properties = detail.request.query.properties.filter(s => s.name !== 'page_token' && s.name !== 'page_size')
project.requests.push(`export interface ${name} extends Pagination {\n${generateParams(properties, project.imports)}}`)
project.internalImports.add('Pagination')
} else {
project.requests.push(`export interface ${name} {\n${generateParams(detail.request.query.properties, project.imports)}}`)
}
args.push(`query?: ${name}`)
}

Expand All @@ -252,7 +261,7 @@ async function start() {
} else {
const keys = (detail.response.body?.properties || []).map(v => v.name)
if (!keys.includes('code') || !keys.includes('msg')) {
console.log(`unknown response body keys: ${keys}, see https://open.feishu.cn${summary.fullPath}}`)
console.log(`unsupported response body: ${keys}, see https://open.feishu.cn${summary.fullPath}}`)
return
} else if (keys.length === 2) {
returnType = 'void'
Expand All @@ -261,10 +270,33 @@ async function start() {
if (!data.properties?.length) {
returnType = 'void'
} else {
project.responses.push(`export interface ${returnType} {\n${generateParams(data.properties, project.imports)}\n}`)
const keys = (data.properties || []).map(v => v.name)
let pagination: [string, Schema] | undefined
if (keys.includes('has_more') && keys.includes('page_token') && keys.length === 3) {
const list = (data.properties || []).find(v => v.name !== 'has_more' && v.name !== 'page_token')!
if (list.type === 'list') {
pagination = [list.name, list.items!]
}
}
if (pagination) {
const [key, item] = pagination
let inner = formatType(item, project.imports)
if (item.type === 'object' && item.properties && !item.ref) {
const name = `${apiType}Item`
project.responses.push(`export interface ${name} ${inner}`)
inner = name
}
returnType = key === 'items' ? `Paginated<${inner}>` : `Paginated<${inner}, '${key}'>`
project.internalImports.add('Paginated')
} else {
if (detail.pagination) {
console.log(`unsupported pagination (${keys.join(', ')}), see https://open.feishu.cn${summary.fullPath}}`)
}
project.responses.push(`export interface ${returnType} {\n${generateParams(data.properties, project.imports)}}`)
}
}
} else {
project.responses.push(`export interface ${returnType} extends BaseResponse {\n${generateParams(detail.response.body.properties!, project.imports)}\n}`)
project.responses.push(`export interface ${returnType} extends BaseResponse {\n${generateParams(detail.response.body.properties!, project.imports)}}`)
extras.push(`type: 'raw-json'`)
}
}
Expand Down Expand Up @@ -292,9 +324,9 @@ async function start() {
}).join('\n')
return `'${path}': {\n${content}\n },`
}).join('\n ')
const imports = [`import { Internal } from '../internal'`]
const imports = [`import { ${[...project.internalImports].sort().join(', ')} } from '../internal'`]
if (project.imports.size) {
imports.push(`import { ${[...project.imports].sort().join(', ')} } from '.'`)
imports.unshift(`import { ${[...project.imports].sort().join(', ')} } from '.'`)
}
await writeFile(path, [
imports.join('\n'),
Expand Down
12 changes: 12 additions & 0 deletions adapters/lark/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ export interface BaseResponse {
msg: string
}

export interface Pagination {
page_size?: number
page_token?: string
}

export type Paginated<T, K extends string = 'items'> = {
[P in K]: T[];
} & {
has_more: boolean
page_token: string
}

export interface InternalRoute {
name: string
multipart?: boolean
Expand Down
34 changes: 5 additions & 29 deletions adapters/lark/src/types/acs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Internal } from '../internal'
import { AccessRecord, Device, Feature, Rule, User, UserExternal } from '.'
import { Internal, Paginated, Pagination } from '../internal'

declare module '../internal' {
interface Internal {
Expand All @@ -17,7 +17,7 @@ declare module '../internal' {
* 获取用户列表
* @see https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/acs-v1/user/list
*/
listAcsUser(query?: ListAcsUserQuery): Promise<ListAcsUserResponse>
listAcsUser(query?: ListAcsUserQuery): Promise<Paginated<User>>
/**
* 上传人脸图片
* @see https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/acs-v1/user-face/update
Expand Down Expand Up @@ -67,7 +67,7 @@ declare module '../internal' {
* 获取门禁记录列表
* @see https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/acs-v1/access_record/list
*/
listAcsAccessRecord(query?: ListAcsAccessRecordQuery): Promise<ListAcsAccessRecordResponse>
listAcsAccessRecord(query?: ListAcsAccessRecordQuery): Promise<Paginated<AccessRecord>>
/**
* 下载开门时的人脸识别图片
* @see https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/acs-v1/access_record-access_photo/get
Expand All @@ -91,11 +91,7 @@ export interface GetAcsUserQuery {
user_id_type?: 'user_id' | 'union_id' | 'open_id'
}

export interface ListAcsUserQuery {
/** 分页大小 */
page_size?: number
/** 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果 */
page_token?: string
export interface ListAcsUserQuery extends Pagination {
/** 此次调用中使用的用户ID的类型 */
user_id_type?: 'user_id' | 'union_id' | 'open_id'
}
Expand Down Expand Up @@ -167,11 +163,7 @@ export interface CreateAcsVisitorQuery {
user_id_type?: 'user_id' | 'union_id' | 'open_id'
}

export interface ListAcsAccessRecordQuery {
/** 分页大小 */
page_size?: number
/** 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果 */
page_token?: string
export interface ListAcsAccessRecordQuery extends Pagination {
/** 记录开始时间,单位秒 */
from: number
/** 记录结束时间,单位秒,时间跨度不能超过30天 */
Expand All @@ -187,14 +179,6 @@ export interface GetAcsUserResponse {
user?: User
}

export interface ListAcsUserResponse {
items?: User[]
/** 分页标记,当 has_more 为 true 时,会同时返回新的 page_token,否则不返回 page_token */
page_token?: string
/** 是否还有更多项 */
has_more?: boolean
}

export interface GetAcsRuleExternalResponse {
/** 设备权限组信息 */
rules: Rule[]
Expand All @@ -214,14 +198,6 @@ export interface ListAcsDeviceResponse {
items?: Device[]
}

export interface ListAcsAccessRecordResponse {
items?: AccessRecord[]
/** 分页标记,当 has_more 为 true 时,会同时返回新的 page_token,否则不返回 page_token */
page_token?: string
/** 是否还有更多项 */
has_more?: boolean
}

Internal.define({
'/open-apis/acs/v1/users/{user_id}': {
PATCH: 'patchAcsUser',
Expand Down
Loading

0 comments on commit fc60874

Please sign in to comment.