@godcreator/word-report 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{assemble-BpllQNVY.mjs → assemble-BEt9_xsB.mjs} +23 -0
- package/dist/cli.d.mts +1 -7
- package/dist/cli.mjs +4 -30
- package/dist/core.d.mts +2 -22
- package/dist/core.mjs +3 -3
- package/dist/{convert-o7bPWP9A.mjs → export-CGvF3Wz-.mjs} +12 -160
- package/dist/{export-Da4yhrZa.d.mts → export-DMKj4gl2.d.mts} +2 -18
- package/dist/{mdx-4Rs1N1nv.mjs → mdx-B1V34o8x.mjs} +84 -337
- package/dist/node.d.mts +3 -3
- package/dist/node.mjs +3 -3
- package/dist/{page-data-CJ6nCBnW.d.mts → page-data-C1veAE55.d.mts} +1 -1
- package/dist/{report-files-BsIvifZe.mjs → report-files-DyPBOCgh.mjs} +2 -2
- package/dist/site-server.d.mts +1 -1
- package/dist/site-server.mjs +3 -3
- package/dist/site.d.mts +2 -2
- package/dist/site.mjs +1 -1
- package/dist/{types-Bcl48xQN.d.mts → types-Ea2OT6Ac.d.mts} +7 -1
- package/engine/README.md +3 -3
- package/engine/schemas/report-content.schema.json +42 -0
- package/engine/src/docreport/__main__.py +18 -2
- package/engine/src/docreport/compose.py +51 -17
- package/engine/src/docreport/mathtype.py +3 -2
- package/engine/src/docreport/plain_math.py +53 -0
- package/engine/src/docreport/verify.py +39 -0
- package/engine/src/docreport/word.py +23 -0
- package/engine/templates/project-report.dotx +0 -0
- package/package.json +1 -1
|
@@ -182,6 +182,29 @@ const schema = {
|
|
|
182
182
|
"latex": {
|
|
183
183
|
"type": "string",
|
|
184
184
|
"minLength": 1
|
|
185
|
+
},
|
|
186
|
+
"plainText": {
|
|
187
|
+
"type": "array",
|
|
188
|
+
"minItems": 1,
|
|
189
|
+
"description": "Word writes these runs as text instead of a MathType object; the web view still renders latex.",
|
|
190
|
+
"items": {
|
|
191
|
+
"type": "object",
|
|
192
|
+
"properties": {
|
|
193
|
+
"text": { "$ref": "#/$defs/line" },
|
|
194
|
+
"marks": {
|
|
195
|
+
"type": "array",
|
|
196
|
+
"items": { "enum": [
|
|
197
|
+
"em",
|
|
198
|
+
"sub",
|
|
199
|
+
"sup"
|
|
200
|
+
] },
|
|
201
|
+
"uniqueItems": true,
|
|
202
|
+
"not": { "allOf": [{ "contains": { "const": "sub" } }, { "contains": { "const": "sup" } }] }
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"required": ["text"],
|
|
206
|
+
"additionalProperties": false
|
|
207
|
+
}
|
|
185
208
|
}
|
|
186
209
|
},
|
|
187
210
|
"required": [
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as ReportExportResult, o as ReportCheckResult, t as ReportExportOptions } from "./export-DMKj4gl2.mjs";
|
|
2
2
|
//#region src/node/cli.d.ts
|
|
3
3
|
/** export、status 的入口要看磁盘上是哪种报告,由 main 补上 */
|
|
4
4
|
type CliCommand = {
|
|
@@ -9,11 +9,6 @@ type CliCommand = {
|
|
|
9
9
|
command: 'check';
|
|
10
10
|
siteDir: string;
|
|
11
11
|
json: boolean;
|
|
12
|
-
} | {
|
|
13
|
-
command: 'convert';
|
|
14
|
-
siteDir: string;
|
|
15
|
-
sourceId: string;
|
|
16
|
-
targetId: string;
|
|
17
12
|
};
|
|
18
13
|
/** 解析命令行;要显示说明时回 undefined。参数不对直接报错 */
|
|
19
14
|
declare function parseCliArgs(args: string[], cwd?: string): CliCommand | undefined;
|
|
@@ -21,7 +16,6 @@ interface CliDependencies {
|
|
|
21
16
|
reportExport?: (options: ReportExportOptions) => Promise<ReportExportResult>;
|
|
22
17
|
checkReports?: (siteDir: string) => Promise<ReportCheckResult>;
|
|
23
18
|
reportEntryIn?: (siteDir: string, reportId: string) => Promise<string>;
|
|
24
|
-
convertReportToMdx?: (siteDir: string, sourceId: string, targetId: string) => Promise<ConvertReportResult>;
|
|
25
19
|
sleep?: (milliseconds: number) => Promise<void>;
|
|
26
20
|
stdout?: (text: string) => void;
|
|
27
21
|
stderr?: (text: string) => void;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { o as reportEntryIn, s as reportEntryOf } from "./report-files-
|
|
2
|
+
import { n as reportExport, r as checkReports } from "./export-CGvF3Wz-.mjs";
|
|
3
|
+
import { o as reportEntryIn, s as reportEntryOf } from "./report-files-DyPBOCgh.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { realpathSync } from "node:fs";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
//#region src/node/cli.ts
|
|
8
8
|
const help = `用法:report-docx <export|status> <报告 id> [选项]
|
|
9
9
|
report-docx check [选项]
|
|
10
|
-
report-docx convert <JSON 报告 id> <新报告 id> [--site <目录>]
|
|
11
10
|
|
|
12
11
|
报告在站点目录的 reports/<报告 id>/:入口是 content.json(JSON 报告)或 index.mdx(MDX 报告)。
|
|
13
12
|
export 导出这份报告的 Word 与 PDF,等这次导出做完,把结果按 JSON 打出来
|
|
14
13
|
status 只看这份报告的导出状态,不启动 Word
|
|
15
14
|
check 检查站点里全部报告(JSON 报告的每份与每一章、MDX 报告整份)的格式、引用与图片,有问题时退出码非零
|
|
16
|
-
convert 把一份 JSON 报告转成一份新的 MDX 报告,转完编译回来和原报告逐项比对,对不上就删掉新目录、退出码非零;不动原报告
|
|
17
15
|
|
|
18
16
|
选项:
|
|
19
17
|
--site <目录> 站点目录(默认当前目录)
|
|
@@ -45,7 +43,7 @@ function flagValuesOf(flags, allowed) {
|
|
|
45
43
|
}
|
|
46
44
|
/** 解析命令行;要显示说明时回 undefined。参数不对直接报错 */
|
|
47
45
|
function parseCliArgs(args, cwd = process.cwd()) {
|
|
48
|
-
if (args.length === 0) throw new Error("缺少命令:export、status
|
|
46
|
+
if (args.length === 0) throw new Error("缺少命令:export、status 或 check;用 --help 查看用法");
|
|
49
47
|
if (args.includes("--help") || args.includes("-h")) return void 0;
|
|
50
48
|
const [command, ...rest] = args;
|
|
51
49
|
if (command === "check") {
|
|
@@ -56,20 +54,7 @@ function parseCliArgs(args, cwd = process.cwd()) {
|
|
|
56
54
|
json: switches.has("--json")
|
|
57
55
|
};
|
|
58
56
|
}
|
|
59
|
-
if (command
|
|
60
|
-
const [sourceId, targetId, ...flags] = rest;
|
|
61
|
-
if (sourceId === void 0 || targetId === void 0 || sourceId.startsWith("-") || targetId.startsWith("-")) throw new Error("convert 要给两个报告 id:要转的 JSON 报告、新的 MDX 报告");
|
|
62
|
-
reportEntryOf(sourceId);
|
|
63
|
-
reportEntryOf(targetId);
|
|
64
|
-
const { values } = flagValuesOf(flags, ["--site"]);
|
|
65
|
-
return {
|
|
66
|
-
command,
|
|
67
|
-
siteDir: path.resolve(cwd, values.get("--site") ?? "."),
|
|
68
|
-
sourceId,
|
|
69
|
-
targetId
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (command !== "export" && command !== "status") throw new Error(`认不出的命令 ${JSON.stringify(command)}:只有 export、status、check、convert;用 --help 查看用法`);
|
|
57
|
+
if (command !== "export" && command !== "status") throw new Error(`认不出的命令 ${JSON.stringify(command)}:只有 export、status、check;用 --help 查看用法`);
|
|
73
58
|
const [reportId, ...flags] = rest;
|
|
74
59
|
if (reportId === void 0 || reportId.startsWith("-")) throw new Error(`${command} 要给报告 id(站点 reports/ 下的目录名)`);
|
|
75
60
|
reportEntryOf(reportId);
|
|
@@ -93,12 +78,6 @@ function checkReportText(result) {
|
|
|
93
78
|
if (result.problems.length === 0) lines.push("没有问题。");
|
|
94
79
|
return `${lines.join("\n")}\n`;
|
|
95
80
|
}
|
|
96
|
-
function convertReportText(result) {
|
|
97
|
-
if (result.converted) return `转好了:${result.targetDir}\n${result.files.map((file) => ` ${file}`).join("\n")}\n`;
|
|
98
|
-
const lines = [`没有转换:${result.reason}`];
|
|
99
|
-
for (const problem of result.problems) lines.push(` ${problem}`);
|
|
100
|
-
return `${lines.join("\n")}\n`;
|
|
101
|
-
}
|
|
102
81
|
/** export 要等引擎做完同一个任务才退出:引擎在固定下来的快照上工作,进程退了就没人等它的结果 */
|
|
103
82
|
async function runExport(options, dependencies) {
|
|
104
83
|
let result = await dependencies.reportExport(options);
|
|
@@ -134,11 +113,6 @@ async function main(args, dependencies = {}) {
|
|
|
134
113
|
write(parsed.json ? `${JSON.stringify(result)}\n` : checkReportText(result));
|
|
135
114
|
return result.problems.length > 0 ? 1 : 0;
|
|
136
115
|
}
|
|
137
|
-
if (parsed.command === "convert") {
|
|
138
|
-
const result = await (dependencies.convertReportToMdx ?? convertReportToMdx)(parsed.siteDir, parsed.sourceId, parsed.targetId);
|
|
139
|
-
write(convertReportText(result));
|
|
140
|
-
return result.converted ? 0 : 1;
|
|
141
|
-
}
|
|
142
116
|
const entry = await (dependencies.reportEntryIn ?? reportEntryIn)(parsed.options.siteDir, parsed.reportId);
|
|
143
117
|
const result = await runExport({
|
|
144
118
|
...parsed.options,
|
package/dist/core.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as Section, D as TableCell, E as Table, S as ReportList, T as SourceLocation, _ as ReportBlock, a as CellBlock, b as ReportIndex, c as ContentWarning, d as FigurePanel, f as Include, g as PlainMathRun, h as Paragraph, i as Bibliography, l as Equation, m as MultiImageFigure, n as AssemblyOptions, o as Code, p as IndexEntry, r as AssemblyResult, s as CompiledReport, t as Abstract, u as Figure, v as ReportContentError, w as SingleImageFigure, x as ReportInline, y as ReportDocument } from "./types-Ea2OT6Ac.mjs";
|
|
2
2
|
//#region src/core/assemble.d.ts
|
|
3
3
|
declare function assembleDocument(entry: string, files: Record<string, string | ReportDocument>, options?: AssemblyOptions): AssemblyResult;
|
|
4
4
|
//#endregion
|
|
@@ -45,24 +45,4 @@ declare function assembleMdxReport(input: MdxReportInput, options?: AssemblyOpti
|
|
|
45
45
|
/** 编译器生成的 id 都以它开头;手写的 id 不许用,两边就不会撞 */
|
|
46
46
|
declare const GENERATED_ID_PREFIX = "auto-";
|
|
47
47
|
//#endregion
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 组装好的 docreport 文档 → 一份 MDX 报告的各个文件:convert 命令用它迁移 JSON 报告。
|
|
51
|
-
* 只有被引用的、layout.json 里出现的、文献与脚注的 id 写出来,其余交给编译器重新生成;
|
|
52
|
-
* MDX 写不出的内容记进 problems(带 JSON 指针),有一条就不该写文件
|
|
53
|
-
*/
|
|
54
|
-
interface MdxReportPlan {
|
|
55
|
-
/** 文件名(相对新报告目录)→ MDX 原文 */
|
|
56
|
-
files: Record<string, string>;
|
|
57
|
-
/** 新报告里的图片文件名(assets/ 下)→ 原图在组装结果里的路径(AssemblyResult.assets 的键) */
|
|
58
|
-
images: Record<string, string>;
|
|
59
|
-
/** 写出来的手写 id:比对时只有它们要求两边一样 */
|
|
60
|
-
keptIds: Set<string>;
|
|
61
|
-
problems: string[];
|
|
62
|
-
}
|
|
63
|
-
/** 哪些 id 要写出来:被 ref 指到的、layout.json 的键、文献与脚注(它们本来就靠 id 对应) */
|
|
64
|
-
declare function keptIdsOf(document: ReportDocument, layoutKeys: string[]): Set<string>;
|
|
65
|
-
/** 组装好的文档 → MDX 报告。assets 是组装结果的 assets(图在组装结果里的路径 → 原图路径) */
|
|
66
|
-
declare function mdxReportPlanOf(document: ReportDocument, assets: Record<string, string>, layoutKeys: string[]): MdxReportPlan;
|
|
67
|
-
//#endregion
|
|
68
|
-
export { Abstract, AssemblyOptions, AssemblyResult, Bibliography, CellBlock, Code, type CompiledMdxReport, CompiledReport, ContentWarning, Equation, Figure, FigurePanel, GENERATED_ID_PREFIX, Include, IndexEntry, MDX_ENTRY_NAME, MDX_REFERENCES_NAME, type MdxReportInput, type MdxReportPlan, MultiImageFigure, Paragraph, ReportBlock, ReportContentError, ReportDocument, ReportIndex, ReportInline, ReportList, Section, SingleImageFigure, SourceLocation, Table, TableCell, assembleDocument, assembleMdxReport, compileMdxReport, keptIdsOf, mdxReportInputsOf, mdxReportPlanOf, parseReportJson, safeRelativePath, validateDocument };
|
|
48
|
+
export { Abstract, AssemblyOptions, AssemblyResult, Bibliography, CellBlock, Code, type CompiledMdxReport, CompiledReport, ContentWarning, Equation, Figure, FigurePanel, GENERATED_ID_PREFIX, Include, IndexEntry, MDX_ENTRY_NAME, MDX_REFERENCES_NAME, type MdxReportInput, MultiImageFigure, Paragraph, PlainMathRun, ReportBlock, ReportContentError, ReportDocument, ReportIndex, ReportInline, ReportList, Section, SingleImageFigure, SourceLocation, Table, TableCell, assembleDocument, assembleMdxReport, compileMdxReport, mdxReportInputsOf, parseReportJson, safeRelativePath, validateDocument };
|
package/dist/core.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as validateDocument, n as safeRelativePath, o as parseReportJson, s as ReportContentError, t as assembleDocument } from "./assemble-
|
|
2
|
-
import { a as
|
|
3
|
-
export { GENERATED_ID_PREFIX, MDX_ENTRY_NAME, MDX_REFERENCES_NAME, ReportContentError, assembleDocument, assembleMdxReport, compileMdxReport,
|
|
1
|
+
import { i as validateDocument, n as safeRelativePath, o as parseReportJson, s as ReportContentError, t as assembleDocument } from "./assemble-BEt9_xsB.mjs";
|
|
2
|
+
import { a as mdxReportInputsOf, i as compileMdxReport, n as MDX_REFERENCES_NAME, o as GENERATED_ID_PREFIX, r as assembleMdxReport, t as MDX_ENTRY_NAME } from "./mdx-B1V34o8x.mjs";
|
|
3
|
+
export { GENERATED_ID_PREFIX, MDX_ENTRY_NAME, MDX_REFERENCES_NAME, ReportContentError, assembleDocument, assembleMdxReport, compileMdxReport, mdxReportInputsOf, parseReportJson, safeRelativePath, validateDocument };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as walk, i as validateDocument, n as safeRelativePath, o as parseReportJson,
|
|
2
|
-
import { a as
|
|
3
|
-
import { l as reportsDirName,
|
|
4
|
-
import { access,
|
|
1
|
+
import { a as walk, i as validateDocument, n as safeRelativePath, o as parseReportJson, s as ReportContentError, t as assembleDocument } from "./assemble-BEt9_xsB.mjs";
|
|
2
|
+
import { a as mdxReportInputsOf, r as assembleMdxReport, t as MDX_ENTRY_NAME } from "./mdx-B1V34o8x.mjs";
|
|
3
|
+
import { l as reportsDirName, t as JSON_ENTRY_NAME } from "./report-files-DyPBOCgh.mjs";
|
|
4
|
+
import { access, mkdir, open, readFile, readdir, realpath, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
7
|
import sharp from "sharp";
|
|
@@ -272,7 +272,7 @@ async function checkReports(siteDir) {
|
|
|
272
272
|
//#endregion
|
|
273
273
|
//#region src/node/export.ts
|
|
274
274
|
const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
275
|
-
const exists
|
|
275
|
+
const exists = async (file) => access(file).then(() => true, () => false);
|
|
276
276
|
async function saved(file) {
|
|
277
277
|
try {
|
|
278
278
|
return JSON.parse(await readFile(file, "utf8"));
|
|
@@ -324,12 +324,12 @@ async function engineFingerprint(engine, compiler) {
|
|
|
324
324
|
}
|
|
325
325
|
inputs.push(["compiler/package.json", hash(await readFile(path.join(compiler, "package.json")))]);
|
|
326
326
|
await compilerFiles("dist");
|
|
327
|
-
if (await exists
|
|
327
|
+
if (await exists(path.join(compiler, "src"))) await compilerFiles("src");
|
|
328
328
|
return hash(JSON.stringify(inputs.sort(([a], [b]) => a.localeCompare(b))));
|
|
329
329
|
}
|
|
330
|
-
async function layoutOf
|
|
330
|
+
async function layoutOf(root, entry) {
|
|
331
331
|
const file = path.join(root, path.dirname(entry), "layout.json");
|
|
332
|
-
if (!await exists
|
|
332
|
+
if (!await exists(file)) return { file };
|
|
333
333
|
const resolved = await realpath(file), relative = path.relative(await realpath(root), resolved);
|
|
334
334
|
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error("布局文件不在站点目录里");
|
|
335
335
|
const bytes = await readFile(resolved);
|
|
@@ -350,7 +350,7 @@ async function capture(site, engine, compiler, entry, mode) {
|
|
|
350
350
|
mode
|
|
351
351
|
});
|
|
352
352
|
rejectMultiImageFigures(report.document);
|
|
353
|
-
const layout = await layoutOf
|
|
353
|
+
const layout = await layoutOf(root, entry);
|
|
354
354
|
const engineHash = await engineFingerprint(engine, compiler);
|
|
355
355
|
return {
|
|
356
356
|
report,
|
|
@@ -556,9 +556,9 @@ async function reportExport(options) {
|
|
|
556
556
|
const engine = path.resolve(options.engineDir ?? process.env.DOCREPORT_ENGINE_ROOT ?? packagedEngineDir(compiler));
|
|
557
557
|
const key = keyFor(site, entry, mode), active = await latestAttempt(engine, compiler, key, site), previous = await previousJob(engine, key, site, entry, mode);
|
|
558
558
|
const outputs = await outputPaths(engine, previous);
|
|
559
|
-
if (!await exists
|
|
559
|
+
if (!await exists(path.join(engine, ".venv/Scripts/python.exe"))) return {
|
|
560
560
|
state: "unavailable",
|
|
561
|
-
message: `Word 引擎 ${engine} 里还没有 Python 环境:在那里运行 python -m venv .venv
|
|
561
|
+
message: `Word 引擎 ${engine} 里还没有 Python 环境:在那里运行 python -m venv .venv、.venv\\Scripts\\pip install -r requirements.txt 与 .venv\\Scripts\\pip install --no-build-isolation --no-deps -e .(要本机装着 Word 与 MathType);node_modules 里的路径太长时 Word 打不开图片,把 engine/ 复制到路径短的目录、用 --engine 或环境变量 DOCREPORT_ENGINE_ROOT 指过去`,
|
|
562
562
|
...outputs
|
|
563
563
|
};
|
|
564
564
|
let current;
|
|
@@ -615,152 +615,4 @@ async function reportExport(options) {
|
|
|
615
615
|
};
|
|
616
616
|
}
|
|
617
617
|
//#endregion
|
|
618
|
-
|
|
619
|
-
const MAX_LISTED_DIFFERENCES = 20;
|
|
620
|
-
async function exists(file) {
|
|
621
|
-
return stat(file).then(() => true, (error) => {
|
|
622
|
-
if (error.code === "ENOENT") return false;
|
|
623
|
-
throw error;
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
async function layoutOf(reportDir) {
|
|
627
|
-
const file = path.join(reportDir, "layout.json");
|
|
628
|
-
if (!await exists(file)) return void 0;
|
|
629
|
-
const bytes = await readFile(file);
|
|
630
|
-
return {
|
|
631
|
-
bytes,
|
|
632
|
-
keys: Object.keys(JSON.parse(bytes.toString("utf8")))
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
const MARK_ORDER = [
|
|
636
|
-
"strong",
|
|
637
|
-
"em",
|
|
638
|
-
"sub",
|
|
639
|
-
"sup",
|
|
640
|
-
"code"
|
|
641
|
-
];
|
|
642
|
-
/**
|
|
643
|
-
* 比对用的样子:只留写出来的 id(其余由编译器重新生成)、图片路径只看文件名、文档 id 不比、
|
|
644
|
-
* 相邻且标记相同的文字合并、标记按固定顺序、有序列表的起始数 1 不写、没有块的单元格当成一个空段(MDX 的空格子编译成空段,Word 里两者一样)
|
|
645
|
-
*/
|
|
646
|
-
function comparable(document, keptIds) {
|
|
647
|
-
const normalize = (value) => {
|
|
648
|
-
if (Array.isArray(value)) {
|
|
649
|
-
const items = value.map(normalize);
|
|
650
|
-
const merged = [];
|
|
651
|
-
for (const item of items) {
|
|
652
|
-
const previous = merged.at(-1);
|
|
653
|
-
if (item?.["type"] === "text" && previous?.["type"] === "text" && stableValue(previous["marks"] ?? []) === stableValue(item["marks"] ?? [])) previous["text"] = `${previous["text"]}${item["text"]}`;
|
|
654
|
-
else merged.push(item);
|
|
655
|
-
}
|
|
656
|
-
return merged;
|
|
657
|
-
}
|
|
658
|
-
if (!value || typeof value !== "object") return value;
|
|
659
|
-
const copy = {};
|
|
660
|
-
for (const [key, child] of Object.entries(value)) {
|
|
661
|
-
if (key === "id" && !keptIds.has(child)) continue;
|
|
662
|
-
if (key === "src" && typeof child === "string") copy[key] = child.slice(child.lastIndexOf("/") + 1);
|
|
663
|
-
else if (key === "marks" && Array.isArray(child)) copy[key] = MARK_ORDER.filter((mark) => child.includes(mark));
|
|
664
|
-
else copy[key] = normalize(child);
|
|
665
|
-
}
|
|
666
|
-
if (copy["type"] === "list" && copy["start"] === 1) delete copy["start"];
|
|
667
|
-
if (Array.isArray(copy["cells"])) {
|
|
668
|
-
for (const cell of copy["cells"]) if (cell["blocks"].length === 0) cell["blocks"] = [{
|
|
669
|
-
type: "paragraph",
|
|
670
|
-
content: []
|
|
671
|
-
}];
|
|
672
|
-
}
|
|
673
|
-
return copy;
|
|
674
|
-
};
|
|
675
|
-
const { id: _documentId, ...rest } = document;
|
|
676
|
-
return normalize(rest);
|
|
677
|
-
}
|
|
678
|
-
function differencesOf(before, after, pointer = "") {
|
|
679
|
-
if (stableValue(before) === stableValue(after)) return [];
|
|
680
|
-
const bothArrays = Array.isArray(before) && Array.isArray(after);
|
|
681
|
-
const bothObjects = !bothArrays && before && after && typeof before === "object" && typeof after === "object" && !Array.isArray(before) && !Array.isArray(after);
|
|
682
|
-
if (bothArrays && before.length === after.length) return before.flatMap((item, index) => differencesOf(item, after[index], `${pointer}/${index}`));
|
|
683
|
-
if (bothObjects) return [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort().flatMap((key) => differencesOf(before[key], after[key], `${pointer}/${key}`));
|
|
684
|
-
return [`${pointer || "/"}:原报告 ${JSON.stringify(before)},转回来 ${JSON.stringify(after)}`];
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* 把一份 JSON 报告转成一份新的 MDX 报告(reports/<新 id>/),不动原报告。
|
|
688
|
-
* 原报告里有 MDX 写不出的内容就一个文件都不写;写完编译回来和原报告逐项比对,对不上就删掉新目录
|
|
689
|
-
*/
|
|
690
|
-
async function convertReportToMdx(siteDir, sourceId, targetId) {
|
|
691
|
-
const site = await realpath(siteDir);
|
|
692
|
-
const sourceEntry = await reportEntryIn(site, sourceId);
|
|
693
|
-
if (isMdxEntry(sourceEntry)) throw new Error(`报告 ${sourceId} 已经是 MDX 报告`);
|
|
694
|
-
if (!/^[a-z]/.test(targetId)) throw new Error(`新报告 id「${targetId}」要以字母开头:MDX 报告的目录名就是文档 id`);
|
|
695
|
-
const targetDir = path.join(site, path.dirname(reportEntryOf(targetId)));
|
|
696
|
-
if (await exists(targetDir)) throw new Error(`reports/${targetId} 已经存在:convert 只写新目录`);
|
|
697
|
-
const source = await readReport(path.join(site, sourceEntry), {
|
|
698
|
-
root: site,
|
|
699
|
-
mode: "complete"
|
|
700
|
-
});
|
|
701
|
-
const layout = await layoutOf(path.join(site, reportsDirName, sourceId));
|
|
702
|
-
const plan = mdxReportPlanOf(source.document, source.assets, layout?.keys ?? []);
|
|
703
|
-
if (plan.problems.length) return {
|
|
704
|
-
converted: false,
|
|
705
|
-
reason: `原报告里有 ${plan.problems.length} 处 MDX 写不出来,没有写任何文件`,
|
|
706
|
-
problems: plan.problems
|
|
707
|
-
};
|
|
708
|
-
await mkdir(path.join(targetDir, "assets"), { recursive: true });
|
|
709
|
-
const written = [];
|
|
710
|
-
try {
|
|
711
|
-
for (const [name, text] of Object.entries(plan.files)) {
|
|
712
|
-
await writeFile(path.join(targetDir, name), text);
|
|
713
|
-
written.push(name);
|
|
714
|
-
}
|
|
715
|
-
for (const [name, compiledPath] of Object.entries(plan.images)) {
|
|
716
|
-
await copyFile(path.join(site, source.assets[compiledPath]), path.join(targetDir, "assets", name));
|
|
717
|
-
written.push(`assets/${name}`);
|
|
718
|
-
}
|
|
719
|
-
if (layout) {
|
|
720
|
-
await writeFile(path.join(targetDir, "layout.json"), layout.bytes);
|
|
721
|
-
written.push("layout.json");
|
|
722
|
-
}
|
|
723
|
-
let converted;
|
|
724
|
-
try {
|
|
725
|
-
converted = await readReport(path.join(targetDir, "index.mdx"), {
|
|
726
|
-
root: site,
|
|
727
|
-
mode: "complete"
|
|
728
|
-
});
|
|
729
|
-
} catch (error) {
|
|
730
|
-
await rm(targetDir, {
|
|
731
|
-
recursive: true,
|
|
732
|
-
force: true
|
|
733
|
-
});
|
|
734
|
-
return {
|
|
735
|
-
converted: false,
|
|
736
|
-
reason: "转出来的 MDX 编译不过,已删掉新目录",
|
|
737
|
-
problems: [error instanceof Error ? error.message : String(error)]
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
const differences = differencesOf(comparable(source.document, plan.keptIds), comparable(converted.document, plan.keptIds));
|
|
741
|
-
if (differences.length) {
|
|
742
|
-
await rm(targetDir, {
|
|
743
|
-
recursive: true,
|
|
744
|
-
force: true
|
|
745
|
-
});
|
|
746
|
-
return {
|
|
747
|
-
converted: false,
|
|
748
|
-
reason: `转回来和原报告有 ${differences.length} 处对不上,已删掉新目录`,
|
|
749
|
-
problems: differences.slice(0, MAX_LISTED_DIFFERENCES)
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
} catch (error) {
|
|
753
|
-
await rm(targetDir, {
|
|
754
|
-
recursive: true,
|
|
755
|
-
force: true
|
|
756
|
-
});
|
|
757
|
-
throw error;
|
|
758
|
-
}
|
|
759
|
-
return {
|
|
760
|
-
converted: true,
|
|
761
|
-
targetDir,
|
|
762
|
-
files: written.sort()
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
//#endregion
|
|
766
|
-
export { readReport as a, checkReports as i, reportEntry as n, reportExport as r, convertReportToMdx as t };
|
|
618
|
+
export { readReport as i, reportExport as n, checkReports as r, reportEntry as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ContentWarning } from "./types-
|
|
1
|
+
import { c as ContentWarning } from "./types-Ea2OT6Ac.mjs";
|
|
2
2
|
//#region src/node/check.d.ts
|
|
3
3
|
interface ReportCheckDiagnostic {
|
|
4
4
|
file: string;
|
|
@@ -26,22 +26,6 @@ interface ReportCheckResult {
|
|
|
26
26
|
*/
|
|
27
27
|
declare function checkReports(siteDir: string): Promise<ReportCheckResult>;
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region src/node/convert.d.ts
|
|
30
|
-
type ConvertReportResult = {
|
|
31
|
-
converted: true;
|
|
32
|
-
targetDir: string;
|
|
33
|
-
files: string[];
|
|
34
|
-
} | {
|
|
35
|
-
converted: false;
|
|
36
|
-
reason: string;
|
|
37
|
-
problems: string[];
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* 把一份 JSON 报告转成一份新的 MDX 报告(reports/<新 id>/),不动原报告。
|
|
41
|
-
* 原报告里有 MDX 写不出的内容就一个文件都不写;写完编译回来和原报告逐项比对,对不上就删掉新目录
|
|
42
|
-
*/
|
|
43
|
-
declare function convertReportToMdx(siteDir: string, sourceId: string, targetId: string): Promise<ConvertReportResult>;
|
|
44
|
-
//#endregion
|
|
45
29
|
//#region src/node/export.d.ts
|
|
46
30
|
type Mode = 'complete' | 'standalone';
|
|
47
31
|
type Job = {
|
|
@@ -83,4 +67,4 @@ declare function reportEntry(entry: unknown): string;
|
|
|
83
67
|
/** Package API: callers can start or inspect a render without a website or workbench process. */
|
|
84
68
|
declare function reportExport(options: ReportExportOptions): Promise<ReportExportResult>;
|
|
85
69
|
//#endregion
|
|
86
|
-
export {
|
|
70
|
+
export { ReportCheckDiagnostic as a, reportExport as i, ReportExportResult as n, ReportCheckResult as o, reportEntry as r, checkReports as s, ReportExportOptions as t };
|