Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/package/src/common/update-pandoc.ts
6450 views
1
/*
2
* update-pandoc.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*
6
*/
7
import { Command } from "cliffy/command/mod.ts";
8
import { join } from "../../../src/deno_ral/path.ts";
9
import { ensureDirSync } from "../../../src/deno_ral/fs.ts";
10
import { info } from "../../../src/deno_ral/log.ts";
11
12
import {
13
Configuration,
14
readConfiguration,
15
withWorkingDir,
16
} from "../common/config.ts";
17
import { lines } from "../../../src/core/text.ts";
18
import { pandoc } from "./dependencies/pandoc.ts";
19
import { archiveBinaryDependency } from "./archive-binary-dependencies.ts";
20
21
import { configureDependency } from "./dependencies/dependencies.ts";
22
import { download, unzip } from "../util/utils.ts";
23
import {
24
pandocListFormatDefaultExtensions,
25
pandocListFormats,
26
} from "../../../src/core/pandoc/pandoc-formats.ts";
27
28
import {
29
bgBlack,
30
bold,
31
brightWhite,
32
} from "../../../src/core/lib/external/colors.ts";
33
34
import * as ld from "../../../src/core/lodash.ts";
35
36
export function updatePandoc() {
37
return new Command()
38
.name("update-pandoc")
39
.arguments("<version:string>")
40
.description("Updates Pandoc to the specified version")
41
.action(async (_args, version: string) => {
42
info(`Updating Pandoc to ${version}`);
43
44
const configuration = readConfiguration();
45
46
// Update the configuration file
47
info(" updating configuration file.");
48
const configFilePath = join(
49
configuration.directoryInfo.root,
50
"configuration",
51
);
52
const configText = Deno.readTextFileSync(configFilePath);
53
const configLines = lines(configText);
54
const outputLines: string[] = [];
55
for (const line of configLines) {
56
if (line.startsWith("export PANDOC=")) {
57
outputLines.push(`export PANDOC=${version}`);
58
} else {
59
outputLines.push(line);
60
}
61
}
62
Deno.writeTextFileSync(configFilePath, outputLines.join("\n"));
63
64
const pandocDependency = pandoc(version);
65
66
// Call archive-bin-deps for this file
67
await withWorkingDir(async (workingDir) => {
68
await archiveBinaryDependency(pandocDependency, workingDir);
69
70
// Configure this version of pandoc
71
await configureDependency(
72
pandocDependency,
73
join(configuration.directoryInfo.bin, "tools"),
74
configuration,
75
);
76
77
// Generate templates
78
await writePandocTemplates(configuration, version, workingDir);
79
80
// Generate variants
81
await writeVariants(configuration);
82
});
83
84
// print the warning to complete the checklist
85
console.log(bgBlack(brightWhite(bold(
86
"\n** Remember to complete the checklist in /dev-docs/update-pandoc-checklist.md! **",
87
))));
88
});
89
}
90
91
// Starting in Pandoc 3, we saw a number of variants that appear to be supported
92
// disappear from the --list-extensions command, so for the time being we're just
93
// hard adding them here
94
const kExtendedVariants: string[] = [
95
"amuse",
96
"attributes",
97
"element_citations",
98
"empty_paragraphs",
99
"epub_html_exts",
100
"native_numbering",
101
"ntb",
102
"raw_markdown",
103
"sourcepos",
104
"styles",
105
"xrefs_name",
106
"xrefs_number",
107
];
108
109
async function writeVariants(
110
config: Configuration,
111
) {
112
info("Generating Pandoc extensions source file...");
113
info("Reading pandoc formats and extensions");
114
const formats = await pandocListFormats();
115
const extensions: Set<string> = new Set();
116
for (const format of formats) {
117
const formatExtensions = await pandocListFormatDefaultExtensions(format);
118
formatExtensions.forEach((ext) => {
119
const bareExtension = ext.replace(/^[\+\-]/, "");
120
extensions.add(bareExtension);
121
});
122
}
123
const extArr = Array.from(extensions.values());
124
info(` Pandoc Alone Reporting:`);
125
info(` ${formats.length} formats.`);
126
info(` ${extArr.length} extensions.`);
127
128
extArr.push(...kExtendedVariants);
129
const extended = ld.uniq(extArr);
130
info(` ${extended.length} extensions (after adding extended).`);
131
132
const extArrExpanded = extended.toSorted().flatMap((ext: string) => {
133
return [`"+${ext}"`, `"-${ext}"`];
134
});
135
136
const extensionFile = join(
137
config.directoryInfo.src,
138
"core",
139
"pandoc",
140
"format-extension.ts",
141
);
142
143
// Generate the extension list
144
const tsContents = `
145
/*
146
* pandoc-extensions.ts
147
*
148
* Copyright (C) 2020-2022 Posit Software, PBC
149
*
150
*/
151
//
152
// THIS FILE IS GENERATED BY update-pandoc.ts. DO NOT EDIT MANUALLY
153
//
154
155
export const kPandocExtensions = [
156
${extArrExpanded.join(",\n ")}
157
];
158
`;
159
160
// Write the file
161
Deno.writeTextFileSync(extensionFile, tsContents);
162
}
163
164
async function writePandocTemplates(
165
config: Configuration,
166
version: string,
167
workingDir: string,
168
) {
169
info("Reading pandoc templates...");
170
const formatSrcDir = join(
171
config.directoryInfo.src,
172
"resources",
173
"formats",
174
);
175
176
const srcZipUrl =
177
`https://github.com/jgm/pandoc/archive/refs/tags/${version}.zip`;
178
179
const pandocDir = `pandoc-${version}`;
180
const zipFile = join(workingDir, "pandoc");
181
await download(srcZipUrl, zipFile);
182
await unzip(zipFile, workingDir);
183
184
// Jats templates are multi-part templates that
185
// are not properly emitted by pandoc itself, so download
186
// them from source instead
187
const templateDir = join(workingDir, pandocDir, "data", "templates");
188
const jatsOutDir = join(
189
formatSrcDir,
190
"jats",
191
"pandoc",
192
"default-templates",
193
);
194
const htmlOutdir = join(
195
formatSrcDir,
196
"html",
197
"pandoc",
198
);
199
const latexOutdir = join(formatSrcDir, "pdf", "pandoc");
200
const revealOutdir = join(formatSrcDir, "revealjs", "pandoc");
201
const beamerOutdir = join(formatSrcDir, "beamer", "pandoc");
202
const asciidocOutdir = join(formatSrcDir, "asciidoc", "pandoc");
203
const typstOutdir = join(formatSrcDir, "typst", "pandoc");
204
205
const templateDirFiles: Record<string, Array<{ from: string; to?: string }>> =
206
{
207
[jatsOutDir]: [
208
{ from: "affiliations.jats" },
209
{ from: "article.jats_publishing" },
210
{ from: "default.jats_archiving" },
211
{ from: "default.jats_articleauthoring" },
212
{ from: "default.jats_publishing" },
213
],
214
[htmlOutdir]: [
215
{ from: "default.html5", to: "html.template" },
216
{ from: "styles.html", to: "html.styles" },
217
],
218
[revealOutdir]: [
219
{ from: "default.revealjs", to: "revealjs.template" },
220
],
221
[latexOutdir]: [
222
{ from: "default.latex", to: "latex.template" },
223
// Template we need to tweak
224
{ from: "common.latex", to: "latex.common" },
225
// Template kept unchanged
226
{ from: "after-header-includes.latex" },
227
{ from: "hypersetup.latex" },
228
{ from: "font-settings.latex" },
229
{ from: "fonts.latex" },
230
{ from: "passoptions.latex" },
231
],
232
[beamerOutdir]: [
233
{ from: "default.beamer", to: "beamer.template" },
234
// Template we need to tweak
235
{ from: "common.latex", to: "latex.common" },
236
// Template kept unchanged
237
{ from: "after-header-includes.latex" },
238
{ from: "hypersetup.latex" },
239
{ from: "font-settings.latex" },
240
{ from: "fonts.latex" },
241
{ from: "passoptions.latex" },
242
],
243
[asciidocOutdir]: [
244
{ from: "default.asciidoc", to: "asciidoc.template" },
245
],
246
[typstOutdir]: [
247
{ from: "default.typst", to: "typst.template" },
248
{ from: "template.typst" }
249
]
250
};
251
252
// Move templates
253
for (const outDir of Object.keys(templateDirFiles)) {
254
ensureDirSync(outDir);
255
for (const file of templateDirFiles[outDir]) {
256
info(`> ${file.from}`);
257
Deno.copyFileSync(
258
join(templateDir, file.from),
259
join(outDir, file.to || file.from),
260
);
261
}
262
}
263
264
info("done.");
265
info("");
266
}
267
268