Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/command/editor-support/crossref.ts
3583 views
1
/*
2
* command.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { join } from "../../deno_ral/path.ts";
8
import { readAll } from "../../deno_ral/io.ts";
9
import { error } from "../../deno_ral/log.ts";
10
import { encodeBase64 } from "../../deno_ral/encoding.ts";
11
12
import { Command } from "cliffy/command/mod.ts";
13
14
import { execProcess } from "../../core/process.ts";
15
import { pandocBinaryPath, resourcePath } from "../../core/resources.ts";
16
import { globalTempContext } from "../../core/temp.ts";
17
18
function parseCrossrefFlags(options: any, args: string[]): {
19
input?: string;
20
output?: string;
21
} {
22
let input: string | undefined, output: string | undefined;
23
24
// stop early with no input seems wonky in Cliffy so we need to undo the damage here
25
// by inspecting partially-parsed input...
26
if (options.input && args[0]) {
27
input = args.shift();
28
} else if (options.output && args[0]) {
29
output = args.shift();
30
}
31
const argsStack = [...args];
32
let arg = argsStack.shift();
33
while (arg !== undefined) {
34
switch (arg) {
35
case "-i":
36
case "--input":
37
arg = argsStack.shift();
38
if (arg) {
39
input = arg;
40
}
41
break;
42
43
case "-o":
44
case "--output":
45
arg = argsStack.shift();
46
if (arg) {
47
output = arg;
48
}
49
break;
50
default:
51
arg = argsStack.shift();
52
break;
53
}
54
}
55
return { input, output };
56
}
57
58
const makeCrossrefCommand = () => {
59
return new Command()
60
.description("Index cross references for content")
61
.stopEarly()
62
.arguments("[...args]")
63
.option(
64
"-i, --input",
65
"Use FILE as input (default: stdin).",
66
)
67
.option(
68
"-o, --output",
69
"Write output to FILE (default: stdout).",
70
)
71
.action(async (options, ...args: string[]) => {
72
const flags = parseCrossrefFlags(options, args);
73
const getInput = async () => {
74
if (flags.input) {
75
return Deno.readTextFileSync(flags.input);
76
} else {
77
// read input
78
const stdinContent = await readAll(Deno.stdin);
79
return new TextDecoder().decode(stdinContent);
80
}
81
};
82
const getOutputFile: () => string = () => (flags.output || "stdout");
83
84
const input = await getInput();
85
86
// create directory for indexing and write input into it
87
const indexingDir = globalTempContext().createDir();
88
89
// setup index file and input type
90
const indexFile = join(indexingDir, "index.json");
91
Deno.env.set("QUARTO_CROSSREF_INDEX_PATH", indexFile);
92
Deno.env.set("QUARTO_CROSSREF_INPUT_TYPE", "qmd");
93
94
// build command
95
const cmd = pandocBinaryPath();
96
const cmdArgs = ["+RTS", "-K512m", "-RTS"];
97
cmdArgs.push(...[
98
"--from",
99
resourcePath("filters/qmd-reader.lua"),
100
"--to",
101
"native",
102
"--data-dir",
103
resourcePath("pandoc/datadir"),
104
"--lua-filter",
105
resourcePath("filters/quarto-init/quarto-init.lua"),
106
"--lua-filter",
107
resourcePath("filters/crossref/crossref.lua"),
108
]);
109
110
// create filter params
111
const filterParams = encodeBase64(
112
JSON.stringify({
113
["crossref-index-file"]: "index.json",
114
["crossref-input-type"]: "qmd",
115
}),
116
);
117
118
// run pandoc
119
const result = await execProcess(
120
{
121
cmd,
122
args: cmdArgs,
123
cwd: indexingDir,
124
env: {
125
"QUARTO_FILTER_PARAMS": filterParams,
126
"QUARTO_SHARE_PATH": resourcePath(),
127
},
128
stdout: "piped",
129
},
130
input,
131
undefined, // mergeOutput?: "stderr>stdout" | "stdout>stderr",
132
undefined, // stderrFilter?: (output: string) => string,
133
undefined, // respectStreams?: boolean,
134
5000,
135
);
136
137
// check for error
138
if (!result.success) {
139
error("Error running Pandoc: " + result.stderr);
140
throw new Error(result.stderr);
141
}
142
143
const outputFile = getOutputFile();
144
if (outputFile === "stdout") {
145
// write back the index
146
Deno.stdout.writeSync(Deno.readFileSync(indexFile));
147
} else {
148
Deno.writeTextFileSync(outputFile, Deno.readTextFileSync(indexFile));
149
}
150
});
151
};
152
153
export const crossrefCommand = makeCrossrefCommand();
154
155