feat: integrate competence map analytics

This commit is contained in:
Gleb Korotkiy
2026-06-21 01:56:39 +03:00
parent 75e9616bcb
commit cf1fbb1b55
398 changed files with 36927 additions and 514 deletions

119
orval.config.ts Normal file
View File

@@ -0,0 +1,119 @@
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
},
},
},
},
})