@@ -15,6 +15,7 @@ import { pathWithForwardSlashes, safeExistsSync } from "../../core/path.ts";
1515
1616import {
1717 DependencyFile ,
18+ DependencyServiceWorker ,
1819 FormatDependency ,
1920 FormatExtras ,
2021 kDependencies ,
@@ -31,6 +32,8 @@ import {
3132import { fixupCssReferences , isCssFile } from "../../core/css.ts" ;
3233
3334import { ensureDirSync } from "fs/mod.ts" ;
35+ import { ProjectContext } from "../../project/types.ts" ;
36+ import { projectOutputDir } from "../../project/project-shared.ts" ;
3437
3538export function writeDependencies (
3639 dependenciesFile : string ,
@@ -54,6 +57,7 @@ export function readAndInjectDependencies(
5457 inputDir : string ,
5558 libDir : string ,
5659 doc : Document ,
60+ project ?: ProjectContext ,
5761) {
5862 const dependencyJsonStream = Deno . readTextFileSync ( dependenciesFile ) ;
5963 const htmlDependencies : FormatDependency [ ] = [ ] ;
@@ -77,6 +81,7 @@ export function readAndInjectDependencies(
7781 inputDir ,
7882 libDir ,
7983 injector ,
84+ project ,
8085 ) ;
8186 injectedDependencies . push ( ...injected ) ;
8287 // Finalize the injection
@@ -119,6 +124,7 @@ export function resolveDependencies(
119124 inputDir : string ,
120125 libDir : string ,
121126 temp : TempContext ,
127+ project ?: ProjectContext ,
122128) {
123129 // deep copy to not mutate caller's object
124130 extras = ld . cloneDeep ( extras ) ;
@@ -133,6 +139,7 @@ export function resolveDependencies(
133139 inputDir ,
134140 libDir ,
135141 injector ,
142+ project ,
136143 ) ;
137144 // Finalize the injection
138145 injector . finalizeInjection ( ) ;
@@ -196,6 +203,7 @@ function processHtmlDependencies(
196203 inputDir : string ,
197204 libDir : string ,
198205 injector : HtmlInjector ,
206+ project ?: ProjectContext ,
199207) {
200208 const copiedDependencies : FormatDependency [ ] = [ ] ;
201209 for ( const dependency of dependencies ) {
@@ -260,6 +268,60 @@ function processHtmlDependencies(
260268 } ) ;
261269 }
262270
271+ // Process Service Workers
272+ if ( dependency . serviceworkers ) {
273+ dependency . serviceworkers . forEach ( ( serviceWorker ) => {
274+ const resolveDestination = (
275+ worker : DependencyServiceWorker ,
276+ inputDir : string ,
277+ project ?: ProjectContext ,
278+ ) => {
279+ // First make sure there is a destination. If omitted, provide
280+ // a default based upon the context
281+ if ( ! worker . destination ) {
282+ if ( project ) {
283+ worker . destination = `/${ basename ( worker . source ) } ` ;
284+ } else {
285+ worker . destination = `${ basename ( worker . source ) } ` ;
286+ }
287+ }
288+
289+ // Now return either a project path or an input
290+ // relative path
291+ if ( worker . destination . startsWith ( "/" ) ) {
292+ if ( project ) {
293+ // This is a project relative path
294+ const projectDir = projectOutputDir ( project ) ;
295+ return join ( projectDir , worker . destination . slice ( 1 ) ) ;
296+ } else {
297+ throw new Error (
298+ "A service worker is being provided with a project relative destination path but no valid Quarto project was found." ,
299+ ) ;
300+ }
301+ } else {
302+ // this is an input relative path
303+ return join ( inputDir , worker . destination ) ;
304+ }
305+ } ;
306+
307+ // Compute the path to the destination
308+ const destinationFile = resolveDestination (
309+ serviceWorker ,
310+ inputDir ,
311+ project ,
312+ ) ;
313+ const destinationDir = dirname ( destinationFile ) ;
314+
315+ // Ensure the directory exists and copy the source file
316+ // to the destination
317+ ensureDirSync ( destinationDir ) ;
318+ copyFileIfNewer (
319+ serviceWorker . source ,
320+ destinationFile ,
321+ ) ;
322+ } ) ;
323+ }
324+
263325 // Process head HTML
264326 if ( dependency . head ) {
265327 injector . injectHtml ( dependency . head ) ;
0 commit comments