Skip to content

Commit

Permalink
feat: simplify parser logic
Browse files Browse the repository at this point in the history
  • Loading branch information
hairyf committed Feb 24, 2023
1 parent a6cff98 commit a469701
Showing 1 changed file with 99 additions and 90 deletions.
189 changes: 99 additions & 90 deletions packages/swag-ts/src/parser/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import camelCase from 'lodash/camelCase'
import type { ApiPipeline, StatementFunction, StatementInterface, StatementTypeAlias } from 'apipgen'
import type { OpenAPISpecificationV2, Schema } from 'openapi-specification-types'
import type { Definitions, OpenAPISpecificationV2, Paths, Schema } from 'openapi-specification-types'
import { getFunctionOptions, getPropertieType, traversePaths } from './utils'
import { varName } from './utils/format'
import { literalFieldsToString } from './utils/other'
Expand All @@ -20,101 +20,110 @@ export function parser(configRead: ApiPipeline.ConfigRead) {
const interfaces: StatementInterface[] = []
const functions: StatementFunction[] = []

function transformPaths() {
traversePaths(source.paths, (config) => {
const { method, path, options: meta } = config
/**
* function params/function options/function use interfaces
*/
const { parameters, interfaces: interfaceUses, options } = getFunctionOptions(config)

interfaces.push(...interfaceUses)

/**
* function comments
*/
const comments = [
meta.summary && `@summary ${meta.summary}`,
meta.description && `@description ${meta.description}`,
`@method ${method}`,
meta.tags && `@tags ${meta.tags.join(' | ') || '-'}`,
meta.consumes && `@consumes ${meta.consumes.join('; ') || '-'}`,
]
/**
* function name
*/
const name = camelCase(`${method}/${path}`)
const url = `${path.replace(/({)/g, '${paths?.')}`

/**
* response type
*/
const responseType = meta.responses['200'] ? getPropertieType(meta.responses['200']) : 'void'
const prefixType = configRead.config.output?.type === false ? '' : 'OpenAPITypes.'
const genericType = `${prefixType}Response<${spliceTypeSpace(responseType)}>`

functions.push({
export: true,
name,
description: comments.filter(Boolean),
parameters,
body: [
url.includes('$') ? `const url = \`${url}\`;` : `const url = "${url}"`,
`http.request<${genericType}>>({ ${literalFieldsToString(options)} })`,
],
})
})
}
pathsPuFunctions(source.paths, {
configRead,
functions,
interfaces,
})
defPuInterfaces(source.definitions, {
configRead,
functions,
interfaces,
})

function transformDefinitions() {
for (const [name, definition] of Object.entries(source.definitions)) {
const { properties = {} } = definition

interfaces.push({
export: true,
name: varName(name),
properties: Object.keys(properties).map(name => defToFields(name, properties[name])),
})

function defToFields(name: string, propertie: Schema) {
propertie.required = definition?.required?.some(v => v === name)
if (propertie.description)
propertie.description = `@description ${propertie.description}`
return {
name,
type: getPropertieType(propertie),
description: propertie.description,
required: propertie.required,
}
}
configRead.graphs.comments = comments
configRead.graphs.functions = functions
configRead.graphs.typings = typings
configRead.graphs.interfaces = interfaces

return configRead
}

interface TransformOptions {
configRead: ApiPipeline.ConfigRead
interfaces: StatementInterface[]
functions: StatementFunction[]
}

function pathsPuFunctions(paths: Paths, { configRead, functions, interfaces }: TransformOptions) {
traversePaths(paths, (config) => {
const { method, path, options: meta } = config
/**
* function params/function options/function use interfaces
*/
const { parameters, interfaces: interfaceUses, options } = getFunctionOptions(config)

interfaces.push(...interfaceUses)

/**
* function comments
*/
const comments = [
meta.summary && `@summary ${meta.summary}`,
meta.description && `@description ${meta.description}`,
`@method ${method}`,
meta.tags && `@tags ${meta.tags.join(' | ') || '-'}`,
meta.consumes && `@consumes ${meta.consumes.join('; ') || '-'}`,
]
/**
* function name
*/
const name = camelCase(`${method}/${path}`)
const url = `${path.replace(/({)/g, '${paths?.')}`

/**
* response type
*/
const responseType = meta.responses['200'] ? getPropertieType(meta.responses['200']) : 'void'
const prefixType = configRead.config.output?.type === false ? '' : 'OpenAPITypes.'
const genericType = `${prefixType}Response<${spliceTypeSpace(responseType)}>`

function spliceTypeSpace(name: string) {
const isRenderType = configRead.config.output?.type !== false
const isSomeType = interfaces.map(v => v.name).includes(name.replace('[]', ''))
if (isRenderType && isSomeType)
return `OpenAPITypes.${name}`
return name
}
}

function transformNameSpace() {
for (const iterator of functions) {
for (const parameter of iterator.parameters || []) {
if (parameter.type)
parameter.type = spliceTypeSpace(parameter.type)
}
for (const parameter of parameters || []) {
if (parameter.type)
parameter.type = spliceTypeSpace(parameter.type)
}
}

function spliceTypeSpace(name: string) {
const isRenderType = configRead.config.output?.type !== false
const isSomeType = interfaces.map(v => v.name).includes(name.replace('[]', ''))
if (isRenderType && isSomeType)
return `OpenAPITypes.${name}`
return name
}
functions.push({
export: true,
name,
description: comments.filter(Boolean),
parameters,
body: [
url.includes('$') ? `const url = \`${url}\`;` : `const url = "${url}"`,
`http.request<${genericType}>>({ ${literalFieldsToString(options)} })`,
],
})
})
}

transformPaths()
transformDefinitions()
transformNameSpace()
function defPuInterfaces(definitions: Definitions, { interfaces }: TransformOptions) {
for (const [name, definition] of Object.entries(definitions)) {
const { properties = {} } = definition

configRead.graphs.comments = comments
configRead.graphs.functions = functions
configRead.graphs.typings = typings
configRead.graphs.interfaces = interfaces
interfaces.push({
export: true,
name: varName(name),
properties: Object.keys(properties).map(name => defToFields(name, properties[name])),
})

return configRead
function defToFields(name: string, propertie: Schema) {
propertie.required = definition?.required?.some(v => v === name)
if (propertie.description)
propertie.description = `@description ${propertie.description}`
return {
name,
type: getPropertieType(propertie),
description: propertie.description,
required: propertie.required,
}
}
}
}

0 comments on commit a469701

Please sign in to comment.