120 lines
3.4 KiB
TypeScript
120 lines
3.4 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
||
import { resolve } from 'node:path'
|
||
import { defineConfig } from 'orval'
|
||
import { upgrade } from '@scalar/openapi-parser'
|
||
|
||
const OPENAPI_FILE_PATH = resolve(process.cwd(), 'openapi.json')
|
||
const tagNameMap: Record<string, string> = {
|
||
Аутентификация: 'authentication',
|
||
'Карта компетенций: аналитика': 'competence-map-analytics',
|
||
Мониторинг: 'monitoring',
|
||
Пользователь: 'user',
|
||
'Управление пользователями': 'user-management',
|
||
}
|
||
|
||
const parseOpenApiSpec = (rawSpec: string) => {
|
||
try {
|
||
return JSON.parse(rawSpec) as Record<string, unknown>
|
||
} catch (error) {
|
||
if (!(error instanceof SyntaxError)) {
|
||
throw error
|
||
}
|
||
|
||
const positionMatch = /position (\d+)/.exec(error.message)
|
||
|
||
if (!positionMatch) {
|
||
throw error
|
||
}
|
||
|
||
const firstDocument = rawSpec.slice(0, Number(positionMatch[1])).trimEnd()
|
||
|
||
return JSON.parse(firstDocument) as Record<string, unknown>
|
||
}
|
||
}
|
||
|
||
const loadOpenApiTarget = () => {
|
||
const rawSpec = readFileSync(OPENAPI_FILE_PATH, 'utf8')
|
||
const parsedSpec = parseOpenApiSpec(rawSpec)
|
||
const { specification } = upgrade(parsedSpec)
|
||
const target = specification as Record<string, unknown>
|
||
const paths = target.paths
|
||
|
||
if (paths && typeof paths === 'object') {
|
||
for (const pathItem of Object.values(paths as Record<string, unknown>)) {
|
||
if (!pathItem || typeof pathItem !== 'object') {
|
||
continue
|
||
}
|
||
|
||
for (const operation of Object.values(pathItem as Record<string, unknown>)) {
|
||
if (!operation || typeof operation !== 'object' || !('tags' in operation)) {
|
||
continue
|
||
}
|
||
|
||
const operationWithTags = operation as { tags?: unknown }
|
||
|
||
if (Array.isArray(operationWithTags.tags)) {
|
||
operationWithTags.tags = operationWithTags.tags.map((tag) =>
|
||
typeof tag === 'string' ? (tagNameMap[tag] ?? normalizeOperationName(tag)) : tag,
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return target
|
||
}
|
||
|
||
const normalizeOperationName = (name: string) => name.replace(/[^A-Za-z0-9_$]/g, '_')
|
||
|
||
export default defineConfig({
|
||
api: {
|
||
input: {
|
||
target: loadOpenApiTarget(),
|
||
},
|
||
output: {
|
||
mode: 'tags',
|
||
target: './src/shared/api/generated-api/endpoints.ts',
|
||
client: 'vue-query',
|
||
mock: false,
|
||
clean: true,
|
||
override: {
|
||
mutator: {
|
||
path: './src/shared/api/axiosInstance.ts',
|
||
name: 'customInstance',
|
||
},
|
||
operationName: (operation, _route, verb) => {
|
||
const name = normalizeOperationName(operation.operationId || '')
|
||
const isMutation = ['post', 'put', 'patch', 'delete'].includes(verb.toLowerCase())
|
||
|
||
return isMutation ? `${name}Mutation` : name
|
||
},
|
||
query: {
|
||
useQuery: true,
|
||
useMutation: true,
|
||
signal: true,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
apiZod: {
|
||
input: {
|
||
target: loadOpenApiTarget(),
|
||
},
|
||
output: {
|
||
mode: 'tags',
|
||
target: './src/shared/model/generated-zod/endpoints.zod.ts',
|
||
client: 'zod',
|
||
mock: false,
|
||
clean: true,
|
||
override: {
|
||
operationName: (operation, _route, verb) => {
|
||
const name = normalizeOperationName(operation.operationId || '')
|
||
const isMutation = ['post', 'put', 'patch', 'delete'].includes(verb.toLowerCase())
|
||
|
||
return isMutation ? `${name}Mutation` : name
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|