Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1 +1 @@
npx --no-install commitlint --edit "$1"
npx --no-install commitlint --edit "$1"
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import normalizer from '../normalize'
import { initAST } from './utils'

export function referenceTypeParser(schema: ReferenceObject, ctx: ParserCtx): AST {
const refName = standardLoader.transformRefName(schema.$ref)
const refName = ctx.options.refNameMap?.get(schema.$ref)
|| standardLoader.transformRefName(schema.$ref)
const refernceAST: TReference = {
...initAST(schema, ctx),
type: ASTType.REFERENCE,
Expand Down
45 changes: 23 additions & 22 deletions packages/wormhole/src/core/loader/astLoader/parsers/type.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import type { AST, CommentType, OpenAPIDocument, ReferenceObject, SchemaObject, SchemaType } from '@/type'

export type ParserSchemaType = SchemaType | 'enum' | 'group' | 'tuple' | 'reference'
export interface ASTParser {
type: ParserSchemaType | ParserSchemaType[]
parse: (schema: SchemaObject, ctx: ParserCtx) => AST
}
export interface ParserOptions {
commentType: CommentType
document: OpenAPIDocument
defaultRequire?: boolean
onReference?: (ast: AST) => void
}
export interface ParserCtx {
next: (schema: SchemaObject | ReferenceObject, options: ParserOptions) => AST
keyName?: string
pathKey?: string
visited: Set<string>
pathMap: Map<string, string>
path: string[]
options: ParserOptions
}
import type { AST, CommentType, OpenAPIDocument, ReferenceObject, SchemaObject, SchemaType } from '@/type'

export type ParserSchemaType = SchemaType | 'enum' | 'group' | 'tuple' | 'reference'
export interface ASTParser {
type: ParserSchemaType | ParserSchemaType[]
parse: (schema: SchemaObject, ctx: ParserCtx) => AST
}
export interface ParserOptions {
commentType: CommentType
document: OpenAPIDocument
defaultRequire?: boolean
refNameMap?: Map<string, string>
onReference?: (ast: AST) => void
}
export interface ParserCtx {
next: (schema: SchemaObject | ReferenceObject, options: ParserOptions) => AST
keyName?: string
pathKey?: string
visited: Set<string>
pathMap: Map<string, string>
path: string[]
options: ParserOptions
}
98 changes: 50 additions & 48 deletions packages/wormhole/src/core/loader/schemaLoader/index.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
import type { GeneratorOptions } from '../astLoader/generates'
import type { AST, CommentType, Loader, MaybeSchemaObject, OpenAPIDocument } from '@/type'
import type { GeneratorOptions } from '../astLoader/generates'
import type { AST, CommentType, Loader, MaybeSchemaObject, OpenAPIDocument } from '@/type'
import { astLoader } from '../astLoader'
import { getValue } from '../astLoader/generates'

export interface Schema2TypeOptions {
deep?: boolean // Whether to parse recursively
shallowDeep?: boolean // Only the outermost layer is analytic
commentType?: CommentType // Comment style
preText?: string // annotation prefix
defaultRequire?: boolean // If there is no nullbale or require, the default is require.
noEnum?: boolean
}
export interface SchemaLoaderOptions extends Schema2TypeOptions {
document: OpenAPIDocument
onReference?: (ast: AST) => void
}
export class SchemaLoader implements Loader<MaybeSchemaObject, Promise<string>, SchemaLoaderOptions> {
name = 'schemaLoader'

async transform(schemaOrigin: MaybeSchemaObject, options: SchemaLoaderOptions) {
const ast = await astLoader.transformSchema(schemaOrigin, {
document: options.document,
commentType: options.commentType ?? 'line',
defaultRequire: options.defaultRequire,
onReference(ast) {
options.onReference?.(ast)
},
})
const genOptions: GeneratorOptions = {
deep: options.deep,
shallowDeep: options.shallowDeep,
commentType: options.commentType ?? 'line',
noEnum: options.noEnum,
}
const result = await astLoader.transform(ast, {
...genOptions,
format: true,
})
const tsStrArr = getValue(result, {
...genOptions,
})
.trim()
.split('\n')
return tsStrArr.map((line, idx) => (idx ? options.preText : '') + line).join('\n')
}
}

export const schemaLoader = new SchemaLoader()
import { getValue } from '../astLoader/generates'

export interface Schema2TypeOptions {
deep?: boolean // Whether to parse recursively
shallowDeep?: boolean // Only the outermost layer is analytic
commentType?: CommentType // Comment style
preText?: string // annotation prefix
defaultRequire?: boolean // If there is no nullbale or require, the default is require.
noEnum?: boolean
}
export interface SchemaLoaderOptions extends Schema2TypeOptions {
document: OpenAPIDocument
refNameMap?: Map<string, string>
onReference?: (ast: AST) => void
}
export class SchemaLoader implements Loader<MaybeSchemaObject, Promise<string>, SchemaLoaderOptions> {
name = 'schemaLoader'

async transform(schemaOrigin: MaybeSchemaObject, options: SchemaLoaderOptions) {
const ast = await astLoader.transformSchema(schemaOrigin, {
document: options.document,
commentType: options.commentType ?? 'line',
defaultRequire: options.defaultRequire,
refNameMap: options.refNameMap,
onReference(ast) {
options.onReference?.(ast)
},
})
const genOptions: GeneratorOptions = {
deep: options.deep,
shallowDeep: options.shallowDeep,
commentType: options.commentType ?? 'line',
noEnum: options.noEnum,
}
const result = await astLoader.transform(ast, {
...genOptions,
format: true,
})
const tsStrArr = getValue(result, {
...genOptions,
})
.trim()
.split('\n')
return tsStrArr.map((line, idx) => (idx ? options.preText : '') + line).join('\n')
}
}

export const schemaLoader = new SchemaLoader()
114 changes: 57 additions & 57 deletions packages/wormhole/src/core/loader/standardLoader/index.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
import type { Loader, OperationObject } from '@/type'
import { isValidJSIdentifier, makeIdentifier } from './helper'
import { getRandomVariable, getStandardOperationId, getStandardRefName, getStandardTags } from './standards'
export interface StandardLoaderOptions {
style: 'camelCase' | 'snakeCase'
}
export class StandardLoader implements Loader<string, string, StandardLoaderOptions> {
name = 'standardLoader'
transform(input: string, options?: StandardLoaderOptions) {
return makeIdentifier(input, options?.style ?? 'camelCase')
}
validate(input?: string): boolean {
return isValidJSIdentifier(input)
}
transformRefName(
refPath: string,
options?: {
toUpperCase?: boolean
},
) {
return getStandardRefName(refPath, {
...(options ?? {}),
standardLoader: this,
})
}
transformTags(tags?: string[]) {
return getStandardTags(tags, {
standardLoader: this,
})
}
transformOperationId(
pathObject: OperationObject,
options: {
url: string
method: string
map: Set<string>
},
) {
return getStandardOperationId(pathObject, {
...options,
standardLoader: this,
})
}
transformRadomVariable(value: string) {
return getRandomVariable(value)
}
}
export const standardLoader = new StandardLoader()
import type { Loader, OperationObject } from '@/type'
import { isValidJSIdentifier, makeIdentifier } from './helper'
import { getRandomVariable, getStandardOperationId, getStandardRefName, getStandardTags } from './standards'

export interface StandardLoaderOptions {
style: 'camelCase' | 'snakeCase'
}

export class StandardLoader implements Loader<string, string, StandardLoaderOptions> {
name = 'standardLoader'

transform(input: string, options?: StandardLoaderOptions) {
return makeIdentifier(input, options?.style ?? 'camelCase')
}

validate(input?: string): boolean {
return isValidJSIdentifier(input)
}

transformRefName(
refPath: string,
options?: {
toUpperCase?: boolean
},
) {
return getStandardRefName(refPath, {
...options,
standardLoader: this,
})
}

transformTags(tags?: string[]) {
return getStandardTags(tags, {
standardLoader: this,
})
}

transformOperationId(
pathObject: OperationObject,
options: {
url: string
method: string
map: Set<string>
},
) {
return getStandardOperationId(pathObject, {
...options,
standardLoader: this,
})
}

transformRadomVariable(value: string) {
return getRandomVariable(value)
}
}

export const standardLoader = new StandardLoader()
23 changes: 15 additions & 8 deletions packages/wormhole/src/core/parser/openApiParser/helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { OpenAPIDocument, OpenAPIV2Document, PlatformType } from '@/type'
import type { FetchOptions } from '@/utils/base'
import fs from 'node:fs/promises'
import path from 'node:path'
import importFresh from 'import-fresh'
Expand Down Expand Up @@ -38,12 +39,12 @@ async function parseLocalFile(url: string, projectPath = process.cwd()) {
}
// Parse remote openapi files

async function parseRemoteFile(url: string, platformType?: PlatformType) {
async function parseRemoteFile(url: string, platformType?: PlatformType, fetchOptions?: FetchOptions) {
// no extension and platform types
if (platformType) {
return getPlatformOpenApiData(url, platformType)
return getPlatformOpenApiData(url, platformType, fetchOptions)
}
const dataText = (await fetchData(url)) ?? ''
const dataText = (await fetchData(url, fetchOptions)) ?? ''
let data: any
try {
// 尝试解析为 JSON 格式
Expand Down Expand Up @@ -86,7 +87,7 @@ function isValidOpenApiData(data: any): boolean {
return !!(data.openapi || data.swagger || data.info || data.paths)
}

export async function getPlatformOpenApiData(url: string, platformType: PlatformType) {
export async function getPlatformOpenApiData(url: string, platformType: PlatformType, fetchOptions?: FetchOptions) {
if (!supportedPlatformType.includes(platformType)) {
throw logger.throwError(`Platform type ${platformType} is not supported.`, {
url,
Expand All @@ -99,7 +100,7 @@ export async function getPlatformOpenApiData(url: string, platformType: Platform

for (const tryUrl of urlsToTry) {
try {
const dataText = await fetchData(tryUrl)
const dataText = await fetchData(tryUrl, fetchOptions)
if (!dataText)
continue

Expand All @@ -126,18 +127,22 @@ export async function getPlatformOpenApiData(url: string, platformType: Platform

export async function getOpenApiData(
url: string,
projectPath?: string,
platformType?: PlatformType,
options?: {
projectPath?: string
platformType?: PlatformType
fetchOptions?: FetchOptions
},
): Promise<OpenAPIDocument> {
let data: OpenAPIDocument | null = null
const { projectPath, platformType, fetchOptions } = options ?? {}
try {
if (!/^https?:\/\//.test(url)) {
// local file
data = await parseLocalFile(url, projectPath)
}
else {
// remote file
data = await parseRemoteFile(url, platformType)
data = await parseRemoteFile(url, platformType, fetchOptions)
}
// If it is a swagger2 file
if (isSwagger2(data)) {
Expand All @@ -150,13 +155,15 @@ export async function getOpenApiData(
projectPath,
url,
platformType,
fetchOptions,
})
}
if (!data) {
throw logger.throwError(`Cannot read file from ${url}`, {
projectPath,
url,
platformType,
fetchOptions,
})
}
return data
Expand Down
36 changes: 19 additions & 17 deletions packages/wormhole/src/core/parser/openApiParser/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import type { OpenAPIDocument, Parser, PlatformType } from '@/type'
import { getOpenApiData } from './helper'

export interface OpenApiParserOptions {
projectPath?: string
platformType?: PlatformType
}

export class OpenApiParser implements Parser<string, OpenAPIDocument, OpenApiParserOptions> {
name = 'openapiParser'

async parse(input: string, options?: OpenApiParserOptions): Promise<OpenAPIDocument> {
return getOpenApiData(input, options?.projectPath, options?.platformType)
}
}

export const openApiParser = new OpenApiParser()
import type { OpenAPIDocument, Parser, PlatformType } from '@/type'
import type { FetchOptions } from '@/utils/base'
import { getOpenApiData } from './helper'

export interface OpenApiParserOptions {
projectPath?: string
platformType?: PlatformType
fetchOptions?: FetchOptions
}

export class OpenApiParser implements Parser<string, OpenAPIDocument, OpenApiParserOptions> {
name = 'openapiParser'

async parse(input: string, options?: OpenApiParserOptions): Promise<OpenAPIDocument> {
return getOpenApiData(input, options)
}
}

export const openApiParser = new OpenApiParser()
Loading