11#!/usr/bin/env node
22const { program } = require ( "commander" ) ;
3- const { load, DEFAULT_WIDTH , DEFAULT_HEIGHT } = require ( "../src" ) ;
3+ const { load } = require ( "../src" ) ;
44const {
5- parseArgRedefines,
6- parseArgRedefineFiles,
7- valueOfFile,
5+ applyBrowserOptions,
6+ applyRedefineOptions,
7+ getNotebookConfig,
8+ runRedefines,
9+ consolidateFormat,
810} = require ( "./utils.js" ) ;
9- const { join, isAbsolute } = require ( "path" ) ;
11+ const { join } = require ( "path" ) ;
1012const { writeFileSync } = require ( "rw" ) . dash ;
1113
1214const formatOptions = new Set ( [
@@ -20,19 +22,10 @@ const formatOptions = new Set([
2022 "json" ,
2123] ) ;
2224
23- program
25+ let p = program
2426 . version ( require ( "../package.json" ) . version )
2527 . arguments ( "<notebook> [cells...]" )
2628 . description ( "Pre-render an Observable notebook." )
27- . option ( "--redefine <cell:value...>" , "Redefine a cell (string only)" )
28- . option (
29- "--redefine-file <cell:<string,json,ndjson,csv>:value...>" ,
30- "Redefine a cell with a file"
31- )
32- . option (
33- "--file-attachments <file attachment:path...>" ,
34- "Redefine a file attachment with a local file"
35- )
3629 . option (
3730 "-f, --format [format]" ,
3831 `Type of output: One of ${ Array . from ( formatOptions ) . join ( ", " ) } .` ,
@@ -50,135 +43,67 @@ program
5043 "--token <token>" ,
5144 "An observablehq.com API token to access the notebook."
5245 )
53- . option (
54- "--no-headless" ,
55- "Turn off headless mode on the Puppeteer browser, meaning open the browser to the user."
56- )
57- . option (
58- "-w, --width <value>" ,
59- `Width of the Puppeteer browser. Default ${ DEFAULT_WIDTH } `
60- )
61- . option (
62- "-h, --height <value>" ,
63- `Height of the Puppeteer browser. Default ${ DEFAULT_HEIGHT } `
64- )
65- . option ( "-v, --verbose" , "Print logs to follow progress." )
66- . action ( function ( argNotebook , argCells ) {
67- const opts = program . opts ( ) ;
68- const {
69- version,
70- redefine = [ ] ,
71- redefineFile = [ ] ,
72- fileAttachments = [ ] ,
73- out,
74- token,
75- outDir,
76- headless,
77- verbose,
78- } = opts ;
46+ . option ( "-v, --verbose" , "Print logs to follow progress." ) ;
7947
80- let { width, height, format } = opts ;
48+ p = applyBrowserOptions ( p ) ;
49+ p = applyRedefineOptions ( p ) ;
8150
82- if ( width ) width = + width ;
83- if ( height ) height = + height ;
51+ p . action ( function ( argNotebook , argCells ) {
52+ const opts = program . opts ( ) ;
53+ const { out, outDir, verbose } = opts ;
54+ let { format } = opts ;
8455
85- if ( out && argCells . length > 1 ) {
86- console . error (
87- `Only 1 cell could be passed into 'cells' when '--out' is specified. ${ argCells . length } were passed in.`
88- ) ;
89- process . exit ( 1 ) ;
90- }
56+ const notebookConfig = getNotebookConfig ( opts ) ;
9157
92- if ( out && outDir ) {
93- console . error ( `Only 1 of --out and --out-dir can be specified.` ) ;
94- process . exit ( 1 ) ;
95- }
58+ if ( out && argCells . length > 1 ) {
59+ console . error (
60+ `Only 1 cell could be passed into 'cells' when '--out' is specified. ${ argCells . length } were passed in.`
61+ ) ;
62+ process . exit ( 1 ) ;
63+ }
9664
97- if ( out && out !== "-" ) {
98- const outFileFormat = out . substring ( out . lastIndexOf ( "." ) + 1 ) ;
99- if ( formatOptions . has ( outFileFormat ) ) {
100- format = outFileFormat ;
101- } else {
102- if ( ! format ) {
103- console . error (
104- `Unknown file type "${ outFileFormat } " passed in for --out parameter. Use the --format flag, or ave the path with one of ${ Array . from (
105- formatOptions
106- )
107- . map ( ( d ) => `.${ d } ` )
108- . join ( ", " ) } .`
109- ) ;
110- process . exit ( 1 ) ;
111- }
112- }
113- } else {
114- if ( ! format ) format = "svg" ;
115- }
65+ if ( out && outDir ) {
66+ console . error ( `Only 1 of --out and --out-dir can be specified.` ) ;
67+ process . exit ( 1 ) ;
68+ }
11669
117- const redefines = parseArgRedefines ( redefine ) ;
118- const redefineFiles = parseArgRedefineFiles ( redefineFile ) ;
119- const redefineFileAttachments = parseArgRedefines ( fileAttachments ) ;
70+ format = consolidateFormat ( out , format , formatOptions , "svg" ) ;
12071
121- const config = {
122- width,
123- height,
124- headless,
125- } ;
126- if ( token ) config [ "OBSERVABLEHQ_API_KEY" ] = token ;
72+ if ( verbose )
73+ console . log ( `Loading notebook "${ argNotebook } " with cells ` , argCells ) ;
12774
128- if ( verbose )
129- console . log ( `Loading notebook " ${ argNotebook } " with cells ` , argCells ) ;
75+ load ( argNotebook , argCells , notebookConfig ) . then ( async ( notebook ) => {
76+ await runRedefines ( notebook , opts , verbose ) ;
13077
131- load ( argNotebook , argCells , config ) . then ( async ( notebook ) => {
132- for ( const redefine of redefines ) {
133- const { cell, value, format } = redefine ;
134- if ( verbose ) console . log ( `Redefining ${ cell } with format ${ format } ` ) ;
135- const val = format === "number" ? + value : value ;
136- notebook . redefine ( cell , val ) ;
137- }
78+ await Promise . all (
79+ argCells . map ( async ( cell ) => {
80+ const path = out
81+ ? out
82+ : join ( outDir || process . cwd ( ) , `${ cell } .${ format } ` ) ;
13883
139- for ( const redefineFile of redefineFiles ) {
140- const { cell, value, format : redefineFileFormat } = redefineFile ;
14184 if ( verbose )
142- console . log (
143- `Redefining ${ cell } with file ${ value } with format ${ redefineFileFormat } `
85+ console . log ( `Saving cell ${ cell } as a ${ format } file to ${ path } ` ) ;
86+
87+ if ( format === "svg" ) return notebook . svg ( cell , path ) ;
88+ if ( format === "html" ) return notebook . html ( cell , path ) ;
89+ if ( format === "text" || format === "txt" )
90+ return writeFileSync ( path , await notebook . value ( cell ) ) ;
91+ if ( format === "json" )
92+ return writeFileSync (
93+ path ,
94+ JSON . stringify ( await notebook . value ( cell ) )
14495 ) ;
145- const data = await valueOfFile ( value , redefineFileFormat ) ;
146- notebook . redefine ( cell , data ) ;
147- }
148-
149- if ( redefineFileAttachments . length > 0 ) {
150- const files = { } ;
151- for ( const { cell, value } of redefineFileAttachments ) {
152- if ( verbose )
153- console . log ( `Replacing FileAttachment ${ cell } with file ${ value } ` ) ;
154- files [ cell ] = isAbsolute ( value ) ? value : join ( process . cwd ( ) , value ) ;
155- }
156- await notebook . fileAttachments ( files ) ;
157- }
158-
159- await Promise . all (
160- argCells . map ( async ( cell ) => {
161- const path = out
162- ? out
163- : join ( outDir || process . cwd ( ) , `${ cell } .${ format } ` ) ;
164-
165- if ( verbose )
166- console . log ( `Saving cell ${ cell } as a ${ format } file to ${ path } ` ) ;
167-
168- if ( format === "svg" ) return notebook . svg ( cell , path ) ;
169- if ( format === "html" ) return notebook . html ( cell , path ) ;
170- if ( format === "text" || format === "txt" )
171- return writeFileSync ( path , await notebook . value ( cell ) ) ;
172- if ( format === "json" )
173- return writeFileSync (
174- path ,
175- JSON . stringify ( await notebook . value ( cell ) )
176- ) ;
177- return notebook . screenshot ( cell , path , { type : format } ) ;
178- } )
179- ) ;
180- notebook . browser . close ( ) ;
96+ return notebook . screenshot ( cell , path , { type : format } ) ;
97+ } )
98+ ) . catch ( async ( error ) => {
99+ console . error ( `Error encountered when rendering cells` ) ;
100+ console . error ( error ) ;
101+ notebook . close ( ) ;
102+ process . exit ( 1 ) ;
181103 } ) ;
104+ notebook . close ( ) ;
105+ process . exit ( 0 ) ;
182106 } ) ;
107+ } ) ;
183108
184109program . parse ( process . argv ) ;
0 commit comments