Files
spaceflow/core/src/config/schema-generator.service.ts
2026-02-15 22:02:21 +08:00

130 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Injectable } from "@nestjs/common";
import { z } from "zod";
import * as fs from "fs";
import * as path from "path";
/** Schema 注册信息 */
export interface SchemaRegistry {
/** 配置 key */
configKey: string;
/** zod schema 工厂函数 */
schemaFactory: () => z.ZodType;
/** 描述 */
description?: string;
}
/** 全局 schema 注册表 */
const schemaRegistry = new Map<string, SchemaRegistry>();
/**
* 注册插件配置 schema由插件加载器调用
*/
export function registerPluginSchema(registry: SchemaRegistry): void {
schemaRegistry.set(registry.configKey, registry);
}
/**
* 获取所有已注册的 schema
*/
export function getRegisteredSchemas(): Map<string, SchemaRegistry> {
return schemaRegistry;
}
/**
* Schema 生成服务
* 用于生成 JSON Schema 文件
*/
@Injectable()
export class SchemaGeneratorService {
/**
* 生成完整的 spaceflow.json 的 JSON Schema
* @param outputPath 输出路径
*/
generateJsonSchema(outputPath: string): void {
const properties: Record<string, unknown> = {
dependencies: {
type: "object",
description: "已安装的技能包注册表",
additionalProperties: { type: "string" },
},
support: {
type: "array",
description: "支持的编辑器列表",
items: { type: "string" },
},
};
// 添加所有插件的 schema
for (const [configKey, registry] of schemaRegistry) {
try {
const schema = registry.schemaFactory();
const jsonSchema = z.toJSONSchema(schema, {
target: "draft-07",
});
properties[configKey] = {
...jsonSchema,
description: registry.description || `${configKey} 插件配置`,
};
} catch (error) {
console.warn(`⚠️ 无法转换 ${configKey} 的 schema:`, error);
}
}
const fullSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
title: "Spaceflow Configuration",
description: "Spaceflow 配置文件 schema",
type: "object",
properties,
additionalProperties: true,
};
// 确保目录存在
const dir = path.dirname(outputPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// 写入文件
fs.writeFileSync(outputPath, JSON.stringify(fullSchema, null, 2), "utf-8");
console.log(`✅ JSON Schema 已生成: ${outputPath}`);
// 自动添加到 .gitignore
this.addToGitignore(dir, path.basename(outputPath));
}
/**
* 生成 JSON Schema 到默认路径 (.spaceflow/config-schema.json)
*/
generate(): void {
const outputPath = path.join(process.cwd(), ".spaceflow", "config-schema.json");
this.generateJsonSchema(outputPath);
}
/**
* 将文件添加到 .gitignore如果不存在
*/
private addToGitignore(dir: string, filename: string): void {
const gitignorePath = path.join(dir, ".gitignore");
let content = "";
if (fs.existsSync(gitignorePath)) {
content = fs.readFileSync(gitignorePath, "utf-8");
// 检查是否已存在
const lines = content.split("\n").map((line) => line.trim());
if (lines.includes(filename)) {
return;
}
} else {
content = "# 自动生成的 .gitignore\n";
}
// 追加文件名
const newContent = content.endsWith("\n")
? `${content}${filename}\n`
: `${content}\n${filename}\n`;
fs.writeFileSync(gitignorePath, newContent, "utf-8");
}
}