Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/format/jats/format-jats-postprocess.ts
6453 views
1
/*
2
* format-jats-postprocess.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { reformat } from "../../core/xml.ts";
8
import { RenderServices } from "../../command/render/types.ts";
9
import { JatsRenderSubArticle, xmlPlaceholder } from "./format-jats-types.ts";
10
11
import { dirname, join, relative } from "../../deno_ral/path.ts";
12
import { copySync } from "../../deno_ral/fs.ts";
13
import { readLines } from "io/read-lines";
14
import { ProjectContext } from "../../project/types.ts";
15
import { logProgress } from "../../core/log.ts";
16
import { kJatsSubarticle } from "../../render/notebook/notebook-types.ts";
17
import { Format } from "../../config/types.ts";
18
19
// XML Linting
20
export const reformatXmlPostProcessor = async (output: string) => {
21
await reformat(output);
22
};
23
24
// Injects the root subarticle
25
export const renderSubarticlePostProcessor = (
26
input: string,
27
format: Format,
28
subArticles: JatsRenderSubArticle[],
29
services: RenderServices,
30
project: ProjectContext,
31
quiet?: boolean,
32
) => {
33
return async (output: string) => {
34
// First ensure that we have rendered jats-subarticles
35
// for each of our articles. If needed, render any that
36
// aren't already rendered.
37
const subArticlesToRender = subArticles.filter((subArticle) => {
38
return services.notebook.get(subArticle.input, project) === undefined;
39
});
40
const total = subArticlesToRender.length;
41
if (subArticlesToRender.length > 0 && !quiet) {
42
logProgress("Rendering JATS sub-articles");
43
}
44
45
// Do the rendering
46
let count = 0;
47
for (const subArticle of subArticlesToRender) {
48
const subArticlePath = subArticle.input;
49
const nbRelPath = relative(dirname(input), subArticlePath);
50
if (!quiet) {
51
logProgress(`[${++count}/${total}] ${nbRelPath}`);
52
}
53
await services.notebook.render(
54
subArticlePath,
55
format,
56
kJatsSubarticle,
57
services,
58
undefined,
59
project,
60
);
61
}
62
63
// Go through the subarticles, embed them into the article
64
const supportingOut: string[] = [];
65
for (const subArticle of subArticles) {
66
const nb = services.notebook.get(subArticle.input, project);
67
if (nb && nb[kJatsSubarticle]) {
68
let outputContents = Deno.readTextFileSync(output);
69
70
const notebook = nb[kJatsSubarticle];
71
const jatsSubarticlePath = notebook.path;
72
const placeholder = xmlPlaceholder(
73
subArticle.token,
74
subArticle.input,
75
);
76
77
// Read the subarticle and change any cross references to not conflict
78
// by atdding a token suffix
79
const subArtReader = await Deno.open(jatsSubarticlePath);
80
const subArtLines: string[] = [];
81
for await (let line of readLines(subArtReader)) {
82
// Process ids (add a suffix to all ids and rids)
83
line = line.replaceAll(kIdRegex, `$1id="$2-${subArticle.token}"`);
84
line = line.replaceAll(kRidRegex, `$1rid="$2-${subArticle.token}"`);
85
subArtLines.push(line);
86
}
87
88
// Replace the placeholder with the rendered subarticle
89
outputContents = outputContents.replaceAll(
90
placeholder,
91
() => subArtLines.join("\n"),
92
);
93
94
// Move supporting and resource files into place
95
for (const support of notebook.supporting) {
96
// get the supporting relative path
97
const basePath = project ? project.dir : dirname(notebook.path);
98
const fromPath = join(basePath, support);
99
const toPath = join(
100
dirname(output),
101
relative(dirname(notebook.path), fromPath),
102
);
103
if (fromPath !== toPath) {
104
copySync(fromPath, toPath, { overwrite: true });
105
}
106
supportingOut.push(toPath);
107
}
108
Deno.writeTextFileSync(output, outputContents);
109
}
110
}
111
// Clean up the renderings now that they've been ingested
112
for (const subArticle of subArticles) {
113
services.notebook.removeRendering(
114
subArticle.input,
115
kJatsSubarticle,
116
supportingOut,
117
);
118
}
119
return {
120
supporting: supportingOut,
121
};
122
};
123
};
124
125
const kIdRegex = /(\s+)id="([^"]*)"/g;
126
const kRidRegex = /(\s+)rid="([^"]*)"/g;
127
128