import fs from 'node:fs'; import path from 'node:path'; import url from 'node:url'; import type { ZodTypeAny } from 'zod'; // dir 供 rewrite 解析相对资源路径;data 的 key 决定产物文件名 export interface EntryModule { schema: ZodTypeAny; data: Record; dir: string; } /** * 在 entry 的 index.ts 中调用,组装并返回一个 EntryModule。 * * 构建期不对数组数据做任何排序:产物中的行顺序完全取自源数据文件本身, * 如需特定顺序,请在 zh.json/en.json(或 inline 数据)中把行排好。 * * @param metaUrl entry index.ts 的 import.meta.url * @param schema 独立 schema.ts 导出的 zod schema * @param locales locale → 源数据映射(key 决定产物文件名,如 'zh' → zh.json) * - path 模式(默认):value = 相对 entry 目录的源文件名(如 'zh.json'),函数读盘并 JSON.parse * - inline 模式:value = 已解析的数据对象(可由 `import zh from './zh.ts'` 提供),函数深拷贝后直接使用 * @param opts 可选配置: * - localesMode:'path'(默认)或 'inline',决定 locales 值的含义 */ export function defineEntry( metaUrl: string, schema: ZodTypeAny, locales: Record, opts?: { localesMode?: 'path' }, ): EntryModule; export function defineEntry( metaUrl: string, schema: ZodTypeAny, locales: Record, opts: { localesMode: 'inline' }, ): EntryModule; export function defineEntry( metaUrl: string, schema: ZodTypeAny, locales: Record, opts?: { localesMode?: 'path' | 'inline' }, ): EntryModule { const dir = path.dirname(url.fileURLToPath(metaUrl)); const mode = opts?.localesMode ?? 'path'; const data: Record = {}; for (const [locale, value] of Object.entries(locales)) { if (mode === 'inline') { if (value === undefined || value === null) { throw new Error(`[defineEntry] inline 模式下 locale "${locale}" 的数据不能为空`); } data[locale] = structuredClone(value); } else { if (typeof value !== 'string') { throw new Error(`[defineEntry] path 模式下 locale "${locale}" 的值必须是字符串文件名`); } const abs = path.join(dir, value); if (!fs.existsSync(abs)) { throw new Error(`[defineEntry] 数据文件不存在: ${abs}`); } data[locale] = JSON.parse(fs.readFileSync(abs, 'utf8')); } } return { schema, data, dir }; }