Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/core/ejs.ts
3562 views
1
/*
2
* ejs.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { dirname, join } from "../deno_ral/path.ts";
8
9
import * as ld from "./lodash.ts";
10
import { lines } from "./text.ts";
11
import { InternalError } from "./lib/error.ts";
12
13
export type EjsData = {
14
[key: string]: unknown;
15
};
16
17
interface CachedTemplate {
18
mtime: number;
19
compileTemplate: CompileTemplate;
20
}
21
22
type CompileTemplate = (data: unknown) => string;
23
24
export function renderEjs(
25
file: string,
26
data: unknown,
27
removeEmptyLines = true,
28
cache = true,
29
): string {
30
// compile template
31
const template = compileTemplate(file, removeEmptyLines, cache);
32
if (!template) {
33
throw new InternalError(
34
`Rendering the template ${file} failed unexpectedly.`,
35
);
36
}
37
38
// render it, passing an include function for partials
39
return lines(template(data).trimLeft())
40
.filter((line) => !removeEmptyLines || (line.trim().length > 0))
41
.join("\n") + "\n";
42
}
43
44
// A cache that holds compiled template functions.
45
const compiledTemplates = new Map<string, CachedTemplate>();
46
47
// Compiles the template using a cache, if needed
48
function compileTemplate(
49
file: string,
50
removeEmptyLines: boolean,
51
cache = true,
52
) {
53
// Check the current file modified time
54
const mtime = Deno.statSync(file).mtime?.getTime() || Number.MAX_VALUE;
55
56
const compile = () => {
57
const template =
58
`<% const partial = (file, data) => print(include(file, data)); %>
59
${Deno.readTextFileSync(file)}`;
60
61
return ld.template(template, {
62
imports: {
63
include: (includeFile: string, includeData: unknown) => {
64
return renderEjs(
65
join(dirname(file), includeFile),
66
includeData,
67
removeEmptyLines,
68
);
69
},
70
},
71
});
72
};
73
if (!cache) {
74
return compile();
75
} else {
76
const cachedTemplate = compiledTemplates.get(file);
77
if (!cachedTemplate || cachedTemplate.mtime < mtime) {
78
compiledTemplates.set(
79
file,
80
{
81
mtime,
82
compileTemplate: compile(),
83
},
84
);
85
}
86
}
87
return compiledTemplates.get(file)?.compileTemplate;
88
}
89
90