Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/format/typst/format-typst.ts
3498 views
1
/*
2
* format-typst.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { join } from "../../deno_ral/path.ts";
8
9
import { RenderServices } from "../../command/render/types.ts";
10
import {
11
kCiteproc,
12
kColumns,
13
kDefaultImageExtension,
14
kFigFormat,
15
kFigHeight,
16
kFigWidth,
17
kLogo,
18
kNumberSections,
19
kSectionNumbering,
20
kShiftHeadingLevelBy,
21
kVariant,
22
kWrap,
23
} from "../../config/constants.ts";
24
import {
25
Format,
26
FormatExtras,
27
FormatPandoc,
28
Metadata,
29
PandocFlags,
30
} from "../../config/types.ts";
31
import { formatResourcePath } from "../../core/resources.ts";
32
import { createFormat } from "../formats-shared.ts";
33
import { hasLevelOneHeadings as hasL1Headings } from "../../core/lib/markdown-analysis/level-one-headings.ts";
34
import {
35
BrandNamedLogo,
36
LogoLightDarkSpecifier,
37
} from "../../resources/types/schema-types.ts";
38
import { fillLogoPaths, resolveLogo } from "../../core/brand/brand.ts";
39
import { LogoLightDarkSpecifierPathOptional } from "../../resources/types/zod/schema-types.ts";
40
41
export function typstFormat(): Format {
42
return createFormat("Typst", "pdf", {
43
execute: {
44
[kFigWidth]: 5.5,
45
[kFigHeight]: 3.5,
46
[kFigFormat]: "svg",
47
},
48
pandoc: {
49
standalone: true,
50
[kDefaultImageExtension]: "svg",
51
[kWrap]: "none",
52
[kCiteproc]: false,
53
},
54
resolveFormat: typstResolveFormat,
55
formatExtras: async (
56
_input: string,
57
markdown: string,
58
flags: PandocFlags,
59
format: Format,
60
_libDir: string,
61
_services: RenderServices,
62
): Promise<FormatExtras> => {
63
const pandoc: FormatPandoc = {};
64
const metadata: Metadata = {};
65
66
// provide default section numbering if required
67
if (
68
(flags?.[kNumberSections] === true ||
69
format.pandoc[kNumberSections] === true)
70
) {
71
// number-sections imples section-numbering
72
if (!format.metadata?.[kSectionNumbering]) {
73
metadata[kSectionNumbering] = "1.1.a";
74
}
75
}
76
77
// unless otherwise specified, pdfs with only level 2 or greater headings get their
78
// heading level shifted by -1.
79
const hasLevelOneHeadings = await hasL1Headings(markdown);
80
if (
81
!hasLevelOneHeadings &&
82
flags?.[kShiftHeadingLevelBy] === undefined &&
83
format.pandoc?.[kShiftHeadingLevelBy] === undefined
84
) {
85
pandoc[kShiftHeadingLevelBy] = -1;
86
}
87
88
const brand = format.render.brand;
89
const logoSpec = format
90
.metadata[kLogo] as LogoLightDarkSpecifierPathOptional;
91
const sizeOrder: BrandNamedLogo[] = [
92
"small",
93
"medium",
94
"large",
95
];
96
// temporary: if document logo has object or light/dark objects
97
// without path, do our own findLogo to add the path
98
// typst is the exception not needing path but we'll probably deprecate this
99
const logo = fillLogoPaths(brand, logoSpec, sizeOrder);
100
format.metadata[kLogo] = resolveLogo(brand, logo, sizeOrder);
101
// force columns to wrap and move any 'columns' setting to metadata
102
const columns = format.pandoc[kColumns];
103
if (columns) {
104
pandoc[kColumns] = undefined;
105
metadata[kColumns] = columns;
106
}
107
108
// Provide a template and partials
109
const templateDir = formatResourcePath("typst", join("pandoc", "quarto"));
110
const templateContext = {
111
template: join(templateDir, "template.typ"),
112
partials: [
113
"definitions.typ",
114
"typst-template.typ",
115
"page.typ",
116
"typst-show.typ",
117
"notes.typ",
118
"biblio.typ",
119
].map((partial) => join(templateDir, partial)),
120
};
121
122
return {
123
pandoc,
124
metadata,
125
templateContext,
126
};
127
},
128
});
129
}
130
131
function typstResolveFormat(format: Format) {
132
// Pandoc citeproc with typst output requires adjustment
133
// https://github.com/jgm/pandoc/commit/e89a3edf24a025d5bb0fe8c4c7a8e6e0208fa846
134
if (
135
format.pandoc?.[kCiteproc] === true &&
136
!format.pandoc.to?.includes("-citations") &&
137
!format.render[kVariant]?.includes("-citations")
138
) {
139
// citeproc: false is the default, so user setting it to true means they want to use
140
// Pandoc's citeproc which requires `citations` extensions to be disabled (e.g typst-citations)
141
// This adds the variants for them if not set already
142
format.render[kVariant] = [format.render?.[kVariant], "-citations"].join(
143
"",
144
);
145
}
146
}
147
148