300 lines
8.5 KiB
JavaScript
300 lines
8.5 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import vm from 'node:vm'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const rootDir = path.resolve(__dirname, '..')
|
|
const dataDir = path.join(rootDir, 'src', 'data')
|
|
const apiDir = path.join(rootDir, 'public', 'api')
|
|
const apiDocPath = path.join(rootDir, 'public', 'apidoc')
|
|
|
|
function readJson(relativePath) {
|
|
return JSON.parse(fs.readFileSync(path.join(rootDir, relativePath), 'utf8'))
|
|
}
|
|
|
|
function ensureDir(dir) {
|
|
fs.mkdirSync(dir, { recursive: true })
|
|
}
|
|
|
|
function writeJson(relativePath, data) {
|
|
const target = path.join(apiDir, relativePath)
|
|
ensureDir(path.dirname(target))
|
|
fs.writeFileSync(target, `${JSON.stringify(data, null, 2)}\n`, 'utf8')
|
|
}
|
|
|
|
function cleanApiDir() {
|
|
fs.rmSync(apiDir, { recursive: true, force: true })
|
|
fs.rmSync(apiDocPath, { force: true })
|
|
ensureDir(apiDir)
|
|
}
|
|
|
|
function writeTextFile(target, content) {
|
|
ensureDir(path.dirname(target))
|
|
fs.writeFileSync(target, content, 'utf8')
|
|
}
|
|
|
|
function copyApiDoc() {
|
|
const source = path.join(rootDir, 'docs', '知识库API接口说明.md')
|
|
const content = fs.readFileSync(source, 'utf8')
|
|
writeTextFile(apiDocPath, content)
|
|
}
|
|
|
|
function extractConstArrayFromTs(filePath, constName) {
|
|
const text = fs.readFileSync(filePath, 'utf8')
|
|
const marker = `export const ${constName}`
|
|
const markerIndex = text.indexOf(marker)
|
|
if (markerIndex === -1) {
|
|
throw new Error(`未找到 ${constName}`)
|
|
}
|
|
|
|
const assignmentIndex = text.indexOf('=', markerIndex)
|
|
if (assignmentIndex === -1) {
|
|
throw new Error(`未找到 ${constName} 赋值符号`)
|
|
}
|
|
|
|
const arrayStart = text.indexOf('[', assignmentIndex)
|
|
if (arrayStart === -1) {
|
|
throw new Error(`未找到 ${constName} 数组起点`)
|
|
}
|
|
|
|
let depth = 0
|
|
let quote = null
|
|
let escaped = false
|
|
let lineComment = false
|
|
let blockComment = false
|
|
|
|
for (let index = arrayStart; index < text.length; index += 1) {
|
|
const char = text[index]
|
|
const next = text[index + 1]
|
|
|
|
if (lineComment) {
|
|
if (char === '\n') lineComment = false
|
|
continue
|
|
}
|
|
|
|
if (blockComment) {
|
|
if (char === '*' && next === '/') {
|
|
blockComment = false
|
|
index += 1
|
|
}
|
|
continue
|
|
}
|
|
|
|
if (quote) {
|
|
if (escaped) {
|
|
escaped = false
|
|
} else if (char === '\\') {
|
|
escaped = true
|
|
} else if (char === quote) {
|
|
quote = null
|
|
}
|
|
continue
|
|
}
|
|
|
|
if (char === '/' && next === '/') {
|
|
lineComment = true
|
|
index += 1
|
|
continue
|
|
}
|
|
|
|
if (char === '/' && next === '*') {
|
|
blockComment = true
|
|
index += 1
|
|
continue
|
|
}
|
|
|
|
if (char === '\'' || char === '"' || char === '`') {
|
|
quote = char
|
|
continue
|
|
}
|
|
|
|
if (char === '[') depth += 1
|
|
if (char === ']') {
|
|
depth -= 1
|
|
if (depth === 0) {
|
|
const source = text.slice(arrayStart, index + 1)
|
|
return vm.runInNewContext(`(${source})`, {}, { timeout: 1000 })
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error(`未能完整解析 ${constName}`)
|
|
}
|
|
|
|
const knowledgeAreas = readJson('src/data/knowledge-areas.json').knowledgeAreas
|
|
const processGroups = readJson('src/data/process-groups.json').processGroups
|
|
const processes = readJson('src/data/processes.json').processes
|
|
const artifacts = readJson('src/data/artifacts.json').artifacts
|
|
const tools = readJson('src/data/tools.json').tools
|
|
const performanceDomains = extractConstArrayFromTs(
|
|
path.join(dataDir, 'performance-domains.ts'),
|
|
'performanceDomains'
|
|
)
|
|
|
|
const knowledgeAreaMap = new Map(knowledgeAreas.map((item) => [item.id, item]))
|
|
const processGroupMap = new Map(processGroups.map((item) => [item.id, item]))
|
|
const artifactMap = new Map(artifacts.map((item) => [item.id, item]))
|
|
const toolMap = new Map(tools.map((item) => [item.id, item]))
|
|
|
|
function normalizeRef(ref) {
|
|
if (typeof ref === 'string') return { id: ref, details: [], note: undefined }
|
|
return {
|
|
id: ref.id,
|
|
details: Array.isArray(ref.detail) ? ref.detail.map((item) => ({ label: item.label })) : [],
|
|
note: ref.note,
|
|
}
|
|
}
|
|
|
|
function processSummary(process) {
|
|
const knowledgeArea = knowledgeAreaMap.get(process.knowledgeAreaId)
|
|
const processGroup = processGroupMap.get(process.processGroupId)
|
|
return {
|
|
id: process.id,
|
|
name: process.name,
|
|
knowledgeAreaId: process.knowledgeAreaId,
|
|
knowledgeAreaName: knowledgeArea?.name ?? '',
|
|
processGroupId: process.processGroupId,
|
|
processGroupName: processGroup?.name ?? '',
|
|
purpose: process.purpose ?? '',
|
|
}
|
|
}
|
|
|
|
function attachRefMeta(ref, entityMap) {
|
|
const normalized = normalizeRef(ref)
|
|
const entity = entityMap.get(normalized.id)
|
|
return {
|
|
id: normalized.id,
|
|
name: entity?.name ?? normalized.id,
|
|
details: normalized.details,
|
|
...(normalized.note ? { note: normalized.note } : {}),
|
|
}
|
|
}
|
|
|
|
function processItto(process) {
|
|
return {
|
|
id: process.id,
|
|
name: process.name,
|
|
inputs: process.inputs.map((ref) => attachRefMeta(ref, artifactMap)),
|
|
tools: process.tools.map((ref) => attachRefMeta(ref, toolMap)),
|
|
outputs: process.outputs.map((ref) => attachRefMeta(ref, artifactMap)),
|
|
}
|
|
}
|
|
|
|
function includesRef(refs, targetId) {
|
|
return refs.some((ref) => normalizeRef(ref).id === targetId)
|
|
}
|
|
|
|
function artifactUsage(artifact) {
|
|
return {
|
|
id: artifact.id,
|
|
name: artifact.name,
|
|
asInput: processes.filter((process) => includesRef(process.inputs, artifact.id)).map(processSummary),
|
|
asOutput: processes.filter((process) => includesRef(process.outputs, artifact.id)).map(processSummary),
|
|
}
|
|
}
|
|
|
|
function toolUsage(tool) {
|
|
return {
|
|
id: tool.id,
|
|
name: tool.name,
|
|
usedIn: processes.filter((process) => includesRef(process.tools, tool.id)).map(processSummary),
|
|
}
|
|
}
|
|
|
|
cleanApiDir()
|
|
|
|
writeJson('process-groups.json', processGroups.map((item) => ({ id: item.id, name: item.name })))
|
|
|
|
writeJson(
|
|
'knowledge-areas.json',
|
|
knowledgeAreas.map((item) => ({
|
|
id: item.id,
|
|
name: item.name,
|
|
tailoringFactors: (item.tailoringFactors ?? []).map((factor) => ({
|
|
title: factor.title,
|
|
description: factor.description,
|
|
})),
|
|
}))
|
|
)
|
|
|
|
for (const knowledgeArea of knowledgeAreas) {
|
|
writeJson(
|
|
`knowledge-areas/${knowledgeArea.id}/tailoring-factors.json`,
|
|
(knowledgeArea.tailoringFactors ?? []).map((factor) => ({
|
|
title: factor.title,
|
|
description: factor.description,
|
|
}))
|
|
)
|
|
|
|
writeJson(
|
|
`knowledge-areas/${knowledgeArea.id}/processes.json`,
|
|
processes
|
|
.filter((process) => process.knowledgeAreaId === knowledgeArea.id)
|
|
.map((process) => {
|
|
const summary = processSummary(process)
|
|
return {
|
|
id: summary.id,
|
|
name: summary.name,
|
|
processGroupId: summary.processGroupId,
|
|
processGroupName: summary.processGroupName,
|
|
purpose: summary.purpose,
|
|
}
|
|
})
|
|
)
|
|
}
|
|
|
|
for (const processGroup of processGroups) {
|
|
writeJson(
|
|
`process-groups/${processGroup.id}/processes.json`,
|
|
processes
|
|
.filter((process) => process.processGroupId === processGroup.id)
|
|
.map((process) => {
|
|
const summary = processSummary(process)
|
|
return {
|
|
id: summary.id,
|
|
name: summary.name,
|
|
knowledgeAreaId: summary.knowledgeAreaId,
|
|
knowledgeAreaName: summary.knowledgeAreaName,
|
|
purpose: summary.purpose,
|
|
}
|
|
})
|
|
)
|
|
}
|
|
|
|
writeJson('processes.json', processes.map(processSummary))
|
|
|
|
for (const process of processes) {
|
|
writeJson(`processes/${process.id}.json`, processSummary(process))
|
|
writeJson(`processes/${process.id}/itto.json`, processItto(process))
|
|
}
|
|
|
|
writeJson('performance-domains.json', performanceDomains.map((item) => ({ id: item.id, name: item.name })))
|
|
|
|
for (const domain of performanceDomains) {
|
|
writeJson(`performance-domains/${domain.id}.json`, {
|
|
id: domain.id,
|
|
name: domain.name,
|
|
expectedGoals: domain.detail?.expectedGoals ?? [],
|
|
keyPoints: domain.detail?.keyPoints ?? [],
|
|
interactions: domain.detail?.interactions ?? [],
|
|
checks: domain.detail?.checks ?? [],
|
|
})
|
|
}
|
|
|
|
writeJson('artifacts.json', artifacts.map((item) => ({ id: item.id, name: item.name })))
|
|
writeJson('tools.json', tools.map((item) => ({ id: item.id, name: item.name })))
|
|
|
|
for (const artifact of artifacts) {
|
|
writeJson(`artifacts/${artifact.id}/usage.json`, artifactUsage(artifact))
|
|
}
|
|
|
|
for (const tool of tools) {
|
|
writeJson(`tools/${tool.id}/usage.json`, toolUsage(tool))
|
|
}
|
|
|
|
copyApiDoc()
|
|
|
|
console.log(`已生成静态 API 文件:${path.relative(rootDir, apiDir)}`)
|
|
console.log(`已生成 Markdown 接口文档:${path.relative(rootDir, apiDocPath)}`)
|