Skip to content

Commit 41b53df

Browse files
committed
Merge branch 'main' of github.com:quarto-dev/quarto-cli into main
2 parents a795bb5 + 00091af commit 41b53df

File tree

8 files changed

+150
-47
lines changed

8 files changed

+150
-47
lines changed

news/changelog-1.2.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
## Lua Filters
4242

4343
- Harden `quarto.utils.dump` so it works with pandoc's builtin global variables (#2254)
44+
- Add new LUA function `attachToDependency` to attach files to html dependencies. This function will copy a file into the lib dir for a named HTML dependency.
4445

4546
## Miscellaneous
4647

src/command/render/pandoc-dependencies-html.ts

Lines changed: 90 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import { kIncludeAfterBody, kIncludeInHeader } from "../../config/constants.ts";
2323
import { TempContext } from "../../core/temp.ts";
2424
import { lines } from "../../core/lib/text.ts";
2525
import { copyFileIfNewer } from "../../core/copy.ts";
26-
import { ProjectContext } from "../../project/types.ts";
2726
import {
2827
appendDependencies,
28+
HtmlAttachmentDependency,
2929
HtmlFormatDependency,
3030
} from "./pandoc-dependencies.ts";
3131
import { fixupCssReferences, isCssFile } from "../../core/css.ts";
@@ -54,32 +54,60 @@ export function readAndInjectDependencies(
5454
inputDir: string,
5555
libDir: string,
5656
doc: Document,
57-
project?: ProjectContext,
5857
) {
5958
const dependencyJsonStream = Deno.readTextFileSync(dependenciesFile);
6059
const htmlDependencies: FormatDependency[] = [];
60+
const htmlAttachments: HtmlAttachmentDependency[] = [];
6161
lines(dependencyJsonStream).forEach((json) => {
6262
if (json) {
6363
const dependency = JSON.parse(json);
6464
if (dependency.type === "html") {
6565
htmlDependencies.push(dependency.content);
66+
} else if (dependency.type === "html-attachment") {
67+
htmlAttachments.push(dependency);
6668
}
6769
}
6870
});
6971

72+
const injectedDependencies = [];
7073
if (htmlDependencies.length > 0) {
7174
const injector = domDependencyInjector(doc);
72-
processHtmlDependencies(
75+
const injected = processHtmlDependencies(
7376
htmlDependencies,
7477
inputDir,
7578
libDir,
7679
injector,
77-
project,
7880
);
81+
injectedDependencies.push(...injected);
7982
// Finalize the injection
8083
injector.finalizeInjection();
8184
}
8285

86+
if (htmlAttachments.length > 0) {
87+
for (const attachment of htmlAttachments) {
88+
// Find the 'parent' dependencies for this attachment
89+
const parentDependency = injectedDependencies.find((dep) => {
90+
return dep.name === attachment.content.name;
91+
});
92+
93+
if (parentDependency) {
94+
// Compute the target directory
95+
const directoryInfo = targetDirectoryInfo(
96+
inputDir,
97+
libDir,
98+
parentDependency,
99+
);
100+
101+
// copy the file
102+
copyDependencyFile(
103+
attachment.content.file,
104+
directoryInfo.absolute,
105+
!!parentDependency.external,
106+
);
107+
}
108+
}
109+
}
110+
83111
return Promise.resolve({
84112
resources: [],
85113
supporting: [],
@@ -91,7 +119,6 @@ export function resolveDependencies(
91119
inputDir: string,
92120
libDir: string,
93121
temp: TempContext,
94-
project: ProjectContext | undefined,
95122
) {
96123
// deep copy to not mutate caller's object
97124
extras = ld.cloneDeep(extras);
@@ -106,7 +133,6 @@ export function resolveDependencies(
106133
inputDir,
107134
libDir,
108135
injector,
109-
project,
110136
);
111137
// Finalize the injection
112138
injector.finalizeInjection();
@@ -170,25 +196,24 @@ function processHtmlDependencies(
170196
inputDir: string,
171197
libDir: string,
172198
injector: HtmlInjector,
173-
project?: ProjectContext,
174199
) {
175-
const copiedDependencies: string[] = [];
200+
const copiedDependencies: FormatDependency[] = [];
176201
for (const dependency of dependencies) {
177202
// Ensure that we copy (and render HTML for) each named dependency only once
178-
if (copiedDependencies.includes(dependency.name)) {
203+
if (
204+
copiedDependencies.find((copiedDep) => {
205+
return copiedDep.name === dependency.name;
206+
})
207+
) {
179208
continue;
180209
}
181210

182211
// provide a format libs (i.e. freezer protected) scope for injected deps
183-
const targetLibDir = dependency.external
184-
? join(libDir, "quarto-contrib")
185-
: libDir;
186-
187-
// Directory information for the dependency
188-
const dir = dependency.version
189-
? `${dependency.name}-${dependency.version}`
190-
: dependency.name;
191-
const targetDir = join(inputDir, targetLibDir, dir);
212+
const directoryInfo = targetDirectoryInfo(
213+
inputDir,
214+
libDir,
215+
dependency,
216+
);
192217

193218
const copyFile = (
194219
file: DependencyFile,
@@ -198,22 +223,13 @@ function processHtmlDependencies(
198223
afterBody?: boolean,
199224
) => void,
200225
) => {
201-
const targetPath = join(targetDir, file.name);
202-
// If this is a user resource, treat it as a resource (resource ref discovery)
203-
// if this something that we're injecting, just copy it
204-
if (dependency.external) {
205-
ensureDirSync(dirname(targetPath));
206-
copyFileIfNewer(file.path, targetPath);
207-
console.log("Copying " + file.path + " to " + targetPath);
208-
if (isCssFile(file.path)) {
209-
processCssFile(dirname(file.path), targetPath);
210-
}
211-
} else {
212-
copyFileIfNewer(file.path, targetPath);
213-
}
214-
215-
const href = join(targetLibDir, dir, file.name);
226+
copyDependencyFile(
227+
file,
228+
directoryInfo.absolute,
229+
dependency.external || false,
230+
);
216231
if (inject) {
232+
const href = join(directoryInfo.relative, file.name);
217233
inject(href, file.attribs, file.afterBody);
218234
}
219235
};
@@ -260,10 +276,50 @@ function processHtmlDependencies(
260276
dependency.resources.forEach((resource) => copyFile(resource));
261277
}
262278

263-
copiedDependencies.push(dependency.name);
279+
copiedDependencies.push(dependency);
280+
}
281+
return copiedDependencies;
282+
}
283+
284+
function copyDependencyFile(
285+
file: DependencyFile,
286+
targetDir: string,
287+
external: boolean,
288+
) {
289+
const targetPath = join(targetDir, file.name);
290+
// If this is a user resource, treat it as a resource (resource ref discovery)
291+
// if this something that we're injecting, just copy it
292+
ensureDirSync(dirname(targetPath));
293+
copyFileIfNewer(file.path, targetPath);
294+
295+
if (external && isCssFile(file.path)) {
296+
processCssFile(dirname(file.path), targetPath);
264297
}
265298
}
266299

300+
function targetDirectoryInfo(
301+
inputDir: string,
302+
libDir: string,
303+
dependency: FormatDependency,
304+
) {
305+
// provide a format libs (i.e. freezer protected) scope for injected deps
306+
const targetLibDir = dependency.external
307+
? join(libDir, "quarto-contrib")
308+
: libDir;
309+
310+
// Directory information for the dependency
311+
const dir = dependency.version
312+
? `${dependency.name}-${dependency.version}`
313+
: dependency.name;
314+
315+
const relativeTargetDir = join(targetLibDir, dir);
316+
const absoluteTargetDir = join(inputDir, relativeTargetDir);
317+
return {
318+
absolute: absoluteTargetDir,
319+
relative: relativeTargetDir,
320+
};
321+
}
322+
267323
// fixup root ('/') css references and also copy references to other
268324
// stylesheet or resources (e.g. images) to alongside the destFile
269325
function processCssFile(

src/command/render/pandoc-dependencies.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@
55
*
66
*/
77

8-
import { FormatDependency } from "../../config/types.ts";
8+
import { DependencyFile, FormatDependency } from "../../config/types.ts";
99
import { appendTextFile } from "../../core/file.ts";
1010

1111
export interface HtmlFormatDependency {
1212
type: "html";
1313
content: FormatDependency;
1414
}
1515

16+
export interface HtmlAttachmentDependency {
17+
type: "html-attachment";
18+
content: {
19+
name: string;
20+
file: DependencyFile;
21+
};
22+
}
23+
1624
export interface FormatResourceDependency {
1725
type: "format-resources";
1826
content: {
@@ -47,6 +55,7 @@ export function appendDependencies(
4755
dependenciesFile: string,
4856
dependencies: Array<
4957
| HtmlFormatDependency
58+
| HtmlAttachmentDependency
5059
| FormatResourceDependency
5160
| TextDependency
5261
| FileDependency

src/command/render/pandoc.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import {
3636
} from "../../config/types.ts";
3737
import {
3838
isBeamerOutput,
39-
isDocxOutput,
4039
isEpubOutput,
4140
isHtmlDocOutput,
4241
isHtmlFileOutput,
@@ -71,11 +70,7 @@ import {
7170
pandocDefaultsMessage,
7271
writeDefaultsFile,
7372
} from "./defaults.ts";
74-
import {
75-
filterParamsJson,
76-
quartoInitFilter,
77-
removeFilterParams,
78-
} from "./filters.ts";
73+
import { filterParamsJson, removeFilterParams } from "./filters.ts";
7974
import {
8075
kAbstract,
8176
kAbstractTitle,
@@ -1052,7 +1047,6 @@ async function resolveExtras(
10521047
inputDir,
10531048
libDir,
10541049
doc,
1055-
project,
10561050
),
10571051
);
10581052
};

src/command/render/render-files.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ export async function renderFiles(
313313
dirname(context.target.source),
314314
context.libDir,
315315
tempContext,
316-
project,
317316
);
318317
if (extras[kIncludeInHeader]) {
319318
executeResult.includes[kIncludeInHeader] = [

src/execute/ojs/compile.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,6 @@ export async function ojsCompile(
797797
dirname(options.source),
798798
options.libDir,
799799
options.temp,
800-
project,
801800
);
802801

803802
const ojsBundleTempFiles = [];

src/project/project-index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
*/
77

8-
import { dirname, extname, join, relative } from "path/mod.ts";
8+
import { dirname, join, relative } from "path/mod.ts";
99
import { existsSync } from "fs/mod.ts";
1010

1111
import * as ld from "../core/lodash.ts";
@@ -20,7 +20,7 @@ import {
2020
pathWithForwardSlashes,
2121
removeIfExists,
2222
} from "../core/path.ts";
23-
import { kOutputFile, kTitle } from "../config/constants.ts";
23+
import { kTitle } from "../config/constants.ts";
2424
import { renderFormats } from "../command/render/render-contexts.ts";
2525
import { fileExecutionEngine } from "../execute/engine.ts";
2626

src/resources/pandoc/datadir/init.lua

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,11 @@ local function resolvePath(path)
13221322
end
13231323

13241324
local function resolvePathExt(path)
1325-
return resolvePath(pandoc.path.join({scriptDir(), path}))
1325+
if isRelativeRef(path) then
1326+
return resolvePath(pandoc.path.join({scriptDir(), path}))
1327+
else
1328+
return path
1329+
end
13261330
end
13271331

13281332
-- converts the friendly Quartio location names
@@ -1629,6 +1633,47 @@ quarto = {
16291633
head = htmlDependency.head,
16301634
}))
16311635
end,
1636+
1637+
attachToDependency = function(name, pathOrFileObj)
1638+
1639+
if name == nil then
1640+
error("The target dependency name for an attachment cannot be nil. Please provide a valid dependency name.")
1641+
os.exit(1)
1642+
end
1643+
1644+
-- path can be a string or an obj { name, path }
1645+
local resolvedFile = {}
1646+
if type(pathOrFileObj) == "table" then
1647+
1648+
-- validate that there is at least a path
1649+
if pathOrFileObj.path == nil then
1650+
error("Error attaching to dependency '" .. name .. "'.\nYou must provide a 'path' when adding an attachment to a dependency.")
1651+
os.exit(1)
1652+
end
1653+
1654+
-- resolve a name, if one isn't provided
1655+
local name = pathOrFileObj.name
1656+
if name == nil then
1657+
name = pandoc.path.filename(pathOrfileObj.path)
1658+
end
1659+
1660+
-- the full resolved file
1661+
resolvedFile = {
1662+
name = name,
1663+
path = resolvePathExt(pathOrFileObj.path)
1664+
}
1665+
else
1666+
resolvedFile = {
1667+
name = pandoc.path.filename(pathOrFileObj),
1668+
path = resolvePathExt(pathOrFileObj)
1669+
}
1670+
end
1671+
1672+
writeToDependencyFile(dependency("html-attachment", {
1673+
name = name,
1674+
file = resolvedFile
1675+
}))
1676+
end,
16321677

16331678
useLatexPackage = function(package, options)
16341679
writeToDependencyFile(dependency("usepackage", {package = package, options = options }))

0 commit comments

Comments
 (0)