mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
use parser hooks
This commit is contained in:
@ -14,12 +14,8 @@ export const defaultConfig: OrpcPlugin['Config'] = {
|
||||
resolveConfig: (plugin) => {
|
||||
plugin.config.output = plugin.config.output ?? 'orpc'
|
||||
plugin.config.exportFromIndex = plugin.config.exportFromIndex ?? false
|
||||
plugin.config.groupBy = plugin.config.groupBy ?? 'tag'
|
||||
plugin.config.contractNameBuilder = plugin.config.contractNameBuilder
|
||||
?? ((id: string) => `${id}Contract`)
|
||||
plugin.config.fileStrategy = plugin.config.fileStrategy ?? 'single'
|
||||
plugin.config.filePathBuilder = plugin.config.filePathBuilder
|
||||
?? ((tag: string) => `orpc/${tag.toLowerCase()}`)
|
||||
plugin.config.defaultTag = plugin.config.defaultTag ?? 'default'
|
||||
},
|
||||
}
|
||||
|
||||
@ -73,10 +73,6 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
const {
|
||||
contractNameBuilder,
|
||||
defaultTag,
|
||||
filePathBuilder,
|
||||
fileStrategy,
|
||||
groupBy,
|
||||
output,
|
||||
} = plugin.config
|
||||
|
||||
const operations: OperationInfo[] = []
|
||||
@ -87,22 +83,6 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
operations.push(info)
|
||||
})
|
||||
|
||||
// Helper to get file path for a tag
|
||||
const getFilePathForTag = (tag: string) => {
|
||||
if (fileStrategy === 'single') {
|
||||
return output
|
||||
}
|
||||
return filePathBuilder(tag)
|
||||
}
|
||||
|
||||
// Get all unique tags
|
||||
const allTags = new Set<string>()
|
||||
for (const op of operations) {
|
||||
for (const tag of op.tags) {
|
||||
allTags.add(tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Register external symbols for imports
|
||||
const symbolOc = plugin.symbol('oc', {
|
||||
exported: false,
|
||||
@ -110,59 +90,26 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
})
|
||||
const symbolZ = plugin.external('zod.z')
|
||||
|
||||
// Create base contract symbol - one per file when using byTags
|
||||
const baseSymbols: Record<string, ReturnType<typeof plugin.symbol>> = {}
|
||||
// Create base contract symbol
|
||||
const baseSymbol = plugin.symbol('base', {
|
||||
exported: true,
|
||||
meta: {
|
||||
pluginName: 'orpc',
|
||||
},
|
||||
})
|
||||
|
||||
if (fileStrategy === 'byTags') {
|
||||
// Create base symbol for each tag file
|
||||
for (const tag of allTags) {
|
||||
const filePath = getFilePathForTag(tag)
|
||||
baseSymbols[tag] = plugin.symbol('base', {
|
||||
exported: true,
|
||||
getFilePath: () => filePath,
|
||||
meta: {
|
||||
category: 'schema',
|
||||
tag,
|
||||
},
|
||||
})
|
||||
|
||||
const baseNode = $.const(baseSymbols[tag])
|
||||
.export()
|
||||
.assign(
|
||||
$(symbolOc)
|
||||
.attr('$route')
|
||||
.call(
|
||||
$.object()
|
||||
.prop('inputStructure', $.literal('detailed'))
|
||||
.prop('outputStructure', $.literal('detailed')),
|
||||
),
|
||||
)
|
||||
plugin.node(baseNode)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Single base symbol for all operations
|
||||
const baseSymbol = plugin.symbol('base', {
|
||||
exported: true,
|
||||
meta: {
|
||||
category: 'schema',
|
||||
},
|
||||
})
|
||||
baseSymbols.__default__ = baseSymbol
|
||||
|
||||
const baseNode = $.const(baseSymbol)
|
||||
.export()
|
||||
.assign(
|
||||
$(symbolOc)
|
||||
.attr('$route')
|
||||
.call(
|
||||
$.object()
|
||||
.prop('inputStructure', $.literal('detailed'))
|
||||
.prop('outputStructure', $.literal('detailed')),
|
||||
),
|
||||
)
|
||||
plugin.node(baseNode)
|
||||
}
|
||||
const baseNode = $.const(baseSymbol)
|
||||
.export()
|
||||
.assign(
|
||||
$(symbolOc)
|
||||
.attr('$route')
|
||||
.call(
|
||||
$.object()
|
||||
.prop('inputStructure', $.literal('detailed'))
|
||||
.prop('outputStructure', $.literal('detailed')),
|
||||
),
|
||||
)
|
||||
plugin.node(baseNode)
|
||||
|
||||
// Create contract for each operation
|
||||
// Store symbols for later use in contracts object
|
||||
@ -170,26 +117,18 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
|
||||
for (const op of operations) {
|
||||
const contractName = contractNameBuilder(op.id)
|
||||
const primaryTag = op.tags[0]
|
||||
const filePath = getFilePathForTag(primaryTag)
|
||||
|
||||
const contractSymbol = plugin.symbol(contractName, {
|
||||
exported: true,
|
||||
getFilePath: fileStrategy === 'byTags' ? () => filePath : undefined,
|
||||
meta: {
|
||||
category: 'schema',
|
||||
pluginName: 'orpc',
|
||||
resource: 'operation',
|
||||
resourceId: op.id,
|
||||
tag: primaryTag,
|
||||
tags: op.tags,
|
||||
},
|
||||
})
|
||||
contractSymbols[op.id] = contractSymbol
|
||||
|
||||
// Get the appropriate base symbol
|
||||
const baseSymbol = fileStrategy === 'byTags'
|
||||
? baseSymbols[primaryTag]
|
||||
: baseSymbols.__default__
|
||||
|
||||
// Build the route config object with all available properties
|
||||
const routeConfig = $.object()
|
||||
.prop('path', $.literal(op.path))
|
||||
@ -235,7 +174,7 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
.call($(zodDataSymbol))
|
||||
}
|
||||
|
||||
// .output(z.object({ status: z.literal(200), body: zodResponseSchema })) if has output (detailed outputStructure)
|
||||
// .output(z.object({ body: zodResponseSchema, status: z.literal(200) })) if has output (detailed outputStructure)
|
||||
if (op.hasOutput) {
|
||||
// Reference zod response schema symbol dynamically from zod plugin
|
||||
const zodResponseSymbol = plugin.referenceSymbol({
|
||||
@ -285,120 +224,38 @@ export const handler: OrpcPlugin['Handler'] = ({ plugin }) => {
|
||||
plugin.node(contractNode)
|
||||
}
|
||||
|
||||
// Create contracts object export (only for single file strategy)
|
||||
// For byTags, each file has its own exports
|
||||
if (fileStrategy === 'single') {
|
||||
const contractsSymbol = plugin.symbol('contracts', {
|
||||
exported: true,
|
||||
meta: {
|
||||
category: 'schema',
|
||||
},
|
||||
})
|
||||
// Create contracts object export
|
||||
const contractsSymbol = plugin.symbol('contracts', {
|
||||
exported: true,
|
||||
meta: {
|
||||
pluginName: 'orpc',
|
||||
},
|
||||
})
|
||||
|
||||
if (groupBy === 'tag') {
|
||||
// Group operations by tag
|
||||
const operationsByTag = new Map<string, OperationInfo[]>()
|
||||
for (const op of operations) {
|
||||
const tag = op.tags[0]
|
||||
if (!operationsByTag.has(tag)) {
|
||||
operationsByTag.set(tag, [])
|
||||
}
|
||||
operationsByTag.get(tag)!.push(op)
|
||||
}
|
||||
|
||||
// Build contracts object grouped by tag
|
||||
const contractsObject = $.object()
|
||||
for (const [tag, tagOps] of operationsByTag) {
|
||||
const tagKey = tag.charAt(0).toLowerCase() + tag.slice(1)
|
||||
const tagObject = $.object()
|
||||
for (const op of tagOps) {
|
||||
const contractSymbol = contractSymbols[op.id]
|
||||
if (contractSymbol) {
|
||||
const contractName = contractNameBuilder(op.id)
|
||||
tagObject.prop(contractName, $(contractSymbol))
|
||||
}
|
||||
}
|
||||
contractsObject.prop(tagKey, tagObject)
|
||||
}
|
||||
|
||||
const contractsNode = $.const(contractsSymbol)
|
||||
.export()
|
||||
.assign(contractsObject)
|
||||
plugin.node(contractsNode)
|
||||
}
|
||||
else {
|
||||
// Flat structure without grouping
|
||||
const contractsObject = $.object()
|
||||
for (const op of operations) {
|
||||
const contractSymbol = contractSymbols[op.id]
|
||||
if (contractSymbol) {
|
||||
const contractName = contractNameBuilder(op.id)
|
||||
contractsObject.prop(contractName, $(contractSymbol))
|
||||
}
|
||||
}
|
||||
|
||||
const contractsNode = $.const(contractsSymbol)
|
||||
.export()
|
||||
.assign(contractsObject)
|
||||
plugin.node(contractsNode)
|
||||
}
|
||||
|
||||
// Create type export: export type Contracts = typeof contracts
|
||||
const contractsTypeSymbol = plugin.symbol('Contracts', {
|
||||
exported: true,
|
||||
meta: {
|
||||
category: 'type',
|
||||
},
|
||||
})
|
||||
|
||||
const contractsTypeNode = $.type.alias(contractsTypeSymbol)
|
||||
.export()
|
||||
.type($.type.query($(contractsSymbol)))
|
||||
plugin.node(contractsTypeNode)
|
||||
}
|
||||
else {
|
||||
// For byTags strategy, create contracts object per file
|
||||
for (const tag of allTags) {
|
||||
const filePath = getFilePathForTag(tag)
|
||||
const tagOps = operations.filter(op => op.tags[0] === tag)
|
||||
|
||||
const contractsSymbol = plugin.symbol('contracts', {
|
||||
exported: true,
|
||||
getFilePath: () => filePath,
|
||||
meta: {
|
||||
category: 'schema',
|
||||
tag,
|
||||
},
|
||||
})
|
||||
|
||||
const contractsObject = $.object()
|
||||
for (const op of tagOps) {
|
||||
const contractSymbol = contractSymbols[op.id]
|
||||
if (contractSymbol) {
|
||||
const contractName = contractNameBuilder(op.id)
|
||||
contractsObject.prop(contractName, $(contractSymbol))
|
||||
}
|
||||
}
|
||||
|
||||
const contractsNode = $.const(contractsSymbol)
|
||||
.export()
|
||||
.assign(contractsObject)
|
||||
plugin.node(contractsNode)
|
||||
|
||||
// Create type export per file
|
||||
const contractsTypeSymbol = plugin.symbol('Contracts', {
|
||||
exported: true,
|
||||
getFilePath: () => filePath,
|
||||
meta: {
|
||||
category: 'type',
|
||||
tag,
|
||||
},
|
||||
})
|
||||
|
||||
const contractsTypeNode = $.type.alias(contractsTypeSymbol)
|
||||
.export()
|
||||
.type($.type.query($(contractsSymbol)))
|
||||
plugin.node(contractsTypeNode)
|
||||
const contractsObject = $.object()
|
||||
for (const op of operations) {
|
||||
const contractSymbol = contractSymbols[op.id]
|
||||
if (contractSymbol) {
|
||||
const contractName = contractNameBuilder(op.id)
|
||||
contractsObject.prop(contractName, $(contractSymbol))
|
||||
}
|
||||
}
|
||||
|
||||
const contractsNode = $.const(contractsSymbol)
|
||||
.export()
|
||||
.assign(contractsObject)
|
||||
plugin.node(contractsNode)
|
||||
|
||||
// Create type export: export type Contracts = typeof contracts
|
||||
const contractsTypeSymbol = plugin.symbol('Contracts', {
|
||||
exported: true,
|
||||
meta: {
|
||||
pluginName: 'orpc',
|
||||
},
|
||||
})
|
||||
|
||||
const contractsTypeNode = $.type.alias(contractsTypeSymbol)
|
||||
.export()
|
||||
.type($.type.query($(contractsSymbol)))
|
||||
plugin.node(contractsTypeNode)
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import type { DefinePlugin } from '@hey-api/openapi-ts'
|
||||
|
||||
export type FileStrategy = 'single' | 'byTags'
|
||||
|
||||
export type Config = { name: 'orpc' } & {
|
||||
/**
|
||||
* Name of the generated file (when fileStrategy is 'single').
|
||||
* Name of the generated file.
|
||||
* @default 'orpc'
|
||||
*/
|
||||
output?: string
|
||||
@ -18,25 +16,6 @@ export type Config = { name: 'orpc' } & {
|
||||
* @default (id) => `${id}Contract`
|
||||
*/
|
||||
contractNameBuilder?: (operationId: string) => string
|
||||
/**
|
||||
* How to group contracts in the exported object.
|
||||
* - 'tag': Group by OpenAPI tags (default)
|
||||
* - 'none': Flat structure without grouping
|
||||
* @default 'tag'
|
||||
*/
|
||||
groupBy?: 'tag' | 'none'
|
||||
/**
|
||||
* File generation strategy.
|
||||
* - 'single': All contracts in one file (default)
|
||||
* - 'byTags': One file per tag (e.g., orpc/chat.ts, orpc/files.ts)
|
||||
* @default 'single'
|
||||
*/
|
||||
fileStrategy?: FileStrategy
|
||||
/**
|
||||
* Custom file path builder when fileStrategy is 'byTags'.
|
||||
* @default (tag) => `orpc/${tag}`
|
||||
*/
|
||||
filePathBuilder?: (tag: string) => string
|
||||
/**
|
||||
* Default tag name for operations without tags.
|
||||
* @default 'default'
|
||||
@ -49,9 +28,6 @@ export type ResolvedConfig = {
|
||||
output: string
|
||||
exportFromIndex: boolean
|
||||
contractNameBuilder: (operationId: string) => string
|
||||
groupBy: 'tag' | 'none'
|
||||
fileStrategy: FileStrategy
|
||||
filePathBuilder: (tag: string) => string
|
||||
defaultTag: string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user