@thegetty/quire-cli 1.0.0-rc.0 → 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node --no-warnings
1
+ #!/usr/bin/env -S node --no-warnings
2
2
 
3
3
  import cli from '#src/main.js'
4
4
  import packageConfig from '#root/package.json' assert { type: 'json' }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thegetty/quire-cli",
3
3
  "description": "Quire command-line interface",
4
- "version": "1.0.0-rc.0",
4
+ "version": "1.0.0-rc.2",
5
5
  "author": "Getty Digital",
6
6
  "license": "SEE LICENSE IN https://github.com/thegetty/quire/blob/main/LICENSE",
7
7
  "bugs": {
@@ -45,30 +45,29 @@
45
45
  "#lib/*.js": "./src/lib/*.js"
46
46
  },
47
47
  "dependencies": {
48
- "boxen": "^7.0.0",
49
- "chalk": "^5.1.2",
50
- "commander": "^9.4.1",
51
- "conf": "^10.2.0",
48
+ "boxen": "^7.0.1",
49
+ "chalk": "^5.2.0",
50
+ "commander": "^10.0.0",
51
+ "conf": "^11.0.1",
52
52
  "cross-env": "^7.0.3",
53
53
  "del": "^7.0.0",
54
- "epubjs": "^0.4.2",
54
+ "epubjs-cli": "^0.1.1",
55
55
  "execa": "^6.1.0",
56
- "fs-extra": "^11.0.0",
56
+ "fs-extra": "^11.1.0",
57
57
  "hosted-git-info": "^6.1.1",
58
- "i18next": "^22.0.4",
58
+ "i18next": "^22.4.9",
59
59
  "inquirer": "^9.1.4",
60
60
  "install-npm-version": "^1.0.8",
61
- "loglevel": "^1.8.0",
61
+ "loglevel": "^1.8.1",
62
62
  "open": "^8.4.0",
63
63
  "ora": "^6.1.2",
64
- "pagedjs-cli": "^0.3.1",
64
+ "pagedjs-cli": "^0.3.3",
65
65
  "semver": "^7.3.8",
66
- "simple-git": "^3.15.0",
66
+ "simple-git": "^3.16.0",
67
67
  "update-notifier": "^6.0.2"
68
68
  },
69
69
  "devDependencies": {
70
- "del-cli": "^5.0.0",
71
- "eslint": "^8.28.0"
70
+ "eslint": "^8.32.0"
72
71
  },
73
72
  "engines": {
74
73
  "node": ">=14.16"
@@ -42,41 +42,17 @@ Note that this command is distinct from the [quire/11ty package](https://github.
42
42
  quire clean --dry-run
43
43
  ```
44
44
 
45
- ### `configure`
45
+ ### `configure` **not yet implemented**
46
46
 
47
- Edit a Quire project configuration.
47
+ Edit the Quire CLI configuration.
48
48
 
49
49
  ```sh
50
50
  quire configure
51
51
  ```
52
52
 
53
- ### `debug`
53
+ ### `install` **not yet implemented**
54
54
 
55
- Display Quire debugging information in the console.
56
-
57
- ```sh
58
- quire debug
59
- ```
60
-
61
- ### `dev`
62
-
63
- Clone `quire/packages/11ty` into the local project.
64
-
65
- ```sh
66
- quire dev
67
- ```
68
-
69
- ### `edit`
70
-
71
- Open or create a new content file in the default editor.
72
-
73
- ```sh
74
- quire edit
75
- ```
76
-
77
- ### `install`
78
-
79
- Clone an existing project from a git repository.
55
+ Clone an existing Quire project from a git repository.
80
56
 
81
57
  ```sh
82
58
  quire install <repository>
@@ -112,7 +88,7 @@ Build and server the Quire site in development mode.
112
88
  quire preview --port 8080
113
89
  ```
114
90
 
115
- #### `epub`
91
+ #### `epub` **not yet implemented**
116
92
 
117
93
  Preview the Quire publication epub in the default application.
118
94
 
@@ -120,17 +96,7 @@ Preview the Quire publication epub in the default application.
120
96
  quire preview epub --open
121
97
  ```
122
98
 
123
- To preview the epub in Apple iBooks or Kindle Previewer
124
-
125
- ```sh
126
- quire preview epub --open iBooks
127
- ```
128
-
129
- ```sh
130
- quire preview epub --open Kindle
131
- ```
132
-
133
- #### `pdf`
99
+ #### `pdf` **not yet implemented**
134
100
 
135
101
  Preview the Quire publication PDF in the default application.
136
102
 
@@ -138,13 +104,7 @@ Preview the Quire publication PDF in the default application.
138
104
  quire preview pdf --open
139
105
  ```
140
106
 
141
- Preview the Quire publication PDF in an application.
142
-
143
- ```sh
144
- quire preview pdf --open <Application>
145
- ```
146
-
147
- #### `site`
107
+ #### `site` **default subcommand**
148
108
 
149
109
  Build and serve the Quire site in development mode.
150
110
 
@@ -152,7 +112,7 @@ Build and serve the Quire site in development mode.
152
112
  quire preview site
153
113
  ```
154
114
 
155
- #### `server`
115
+ ### `server` **not yet implemented**
156
116
 
157
117
  Start a local web server to serve a previously built Quire site.
158
118
 
@@ -160,7 +120,7 @@ Start a local web server to serve a previously built Quire site.
160
120
  quire server --port 8080
161
121
  ```
162
122
 
163
- ### `version`
123
+ ### `version` **partial implementation**
164
124
 
165
125
  Sets the Quire version to use when running commands on the project.
166
126
 
@@ -48,8 +48,8 @@ export default class EpubCommand extends Command {
48
48
 
49
49
  const output = path.join(projectRoot, `${options.lib}.epub`)
50
50
 
51
- const epubLib = await libEpub(options.lib, { ...options.debug })
52
- await epubLib(input, output, { ...options.debug })
51
+ const epubLib = await libEpub(options.lib, { debug: options.debug })
52
+ await epubLib(input, output)
53
53
 
54
54
  if (fs.existsSync(output) && options.open) open(output)
55
55
  }
@@ -50,8 +50,8 @@ export default class PDFCommand extends Command {
50
50
 
51
51
  const output = path.join(projectRoot, `${options.lib}.pdf`)
52
52
 
53
- const pdfLib = await libPdf(options.lib, { ...options.debug })
54
- await pdfLib(input, output, { ...options.debug })
53
+ const pdfLib = await libPdf(options.lib, { debug: options.debug })
54
+ await pdfLib(input, output)
55
55
 
56
56
  try {
57
57
  if (fs.existsSync(output) && options.open) open(output)
@@ -40,7 +40,7 @@ export default class PreviewCommand extends Command {
40
40
  super(PreviewCommand.definition)
41
41
  }
42
42
 
43
- action(options, command) {
43
+ async action(options, command) {
44
44
  if (options.debug) {
45
45
  console.debug('[CLI] Command \'%s\' called with arguments [%o] and options %o', this.name(), options)
46
46
  }
@@ -13,9 +13,9 @@ import paths, { eleventyRoot, projectRoot } from './paths.js'
13
13
  const factory = async (options = {}) => {
14
14
  const { config, input, output } = paths
15
15
 
16
- console.info(`[CLI:11ty] projectRoot ${projectRoot}`)
17
-
18
- console.debug('[CLI:11ty] %o', paths)
16
+ if (options.debug) {
17
+ console.debug('[CLI:11ty] projectRoot %s\n%o', projectRoot, paths)
18
+ }
19
19
 
20
20
  /**
21
21
  * Dynamically import the correct version of Eleventy
@@ -113,8 +113,8 @@ export default {
113
113
  if (options.debug) process.env.DEBUG = 'Eleventy*'
114
114
 
115
115
  const eleventy = await factory(options)
116
+
116
117
  eleventy.setDryRun(options.dryrun)
117
- eleventy.setIncrementalBuild(true)
118
118
 
119
119
  await eleventy.write()
120
120
  },
@@ -127,7 +127,6 @@ export default {
127
127
  if (options.debug) process.env.DEBUG = 'Eleventy*'
128
128
 
129
129
  const eleventy = await factory(options)
130
- eleventy.setIncrementalBuild(true)
131
130
 
132
131
  await eleventy.serve(options.port)
133
132
  }
@@ -11,9 +11,9 @@ import paths, { eleventyRoot, projectRoot } from './paths.js'
11
11
  const factory = (options = {}) => {
12
12
  const { config, input, output } = paths
13
13
 
14
- console.info(`[CLI:11ty] projectRoot ${projectRoot}`)
15
-
16
- console.debug('[CLI:11ty] %o', paths)
14
+ if (options.debug) {
15
+ console.debug('[CLI:11ty] projectRoot %s\n%o', projectRoot, paths)
16
+ }
17
17
 
18
18
  /**
19
19
  * Use the version of Eleventy installed to `lib/quire/versions`
@@ -0,0 +1,16 @@
1
+ /**
2
+ * { item_description }
3
+ */
4
+ module.export = (eleventyConfig) => {
5
+ /**
6
+ * The `eleventy.before` event runs every time Eleventy starts building,
7
+ * it will run before the start of each stand-alone build, as well as
8
+ * each time building starts as either part of `--watch` or `--serve`.
9
+ * @see https://www.11ty.dev/docs/events/#eleventy.before
10
+ */
11
+ eleventyConfig.on('eleventy.before', async () => {
12
+ console.debug('[11ty] before build')
13
+ })
14
+
15
+ return eleventyConfig
16
+ }
@@ -1,9 +1,27 @@
1
- // import epub from 'epubjs'
1
+ import { ManifestToEpub } from 'epubjs-cli'
2
+ import fs from 'fs-extra'
3
+ import { pathToFileURL } from 'node:url'
2
4
 
3
5
  /**
4
6
  * A façade module for the EPUB.js library
5
- * @see https://github.com/futurepress/epub.js
7
+ * @see https://github.com/futurepress/epubjs-cli
6
8
  */
7
- export default async (input, output, options) => {
8
- console.info('[CLI:lib/epubjs] integration with epub.js is not yet implemented.')
9
+ export default async (input, output, options = {}) => {
10
+ try {
11
+ console.info(`[CLI:lib/epub/epubjs] Generating ePub from ${input}`)
12
+
13
+ const url = pathToFileURL(`${input}/manifest.json`).toString()
14
+
15
+ const epub = await new ManifestToEpub(url)
16
+ .catch((error) => console.error(error))
17
+
18
+ const file = await epub.save()
19
+ .catch((error) => console.error(error))
20
+
21
+ if (file && output) {
22
+ fs.writeFile(output, file, (error) => { if (error) throw error })
23
+ }
24
+ } catch (ERR_FILE_NOT_FOUND) {
25
+ console.error(`[CLI:lib/epub/epubjs] file not found ${input}`)
26
+ }
9
27
  }
@@ -8,29 +8,31 @@ const __dirname = path.dirname(__filename)
8
8
  /**
9
9
  * A façade delegation module for EPUB libraries
10
10
  */
11
- export default async (lib = 'epubjs', options = {}) => {
12
- let libName, libPath
11
+ export default async (name = 'epubjs', options = {}) => {
12
+ const lib = { name, options, path }
13
13
 
14
14
  switch (lib.toLowerCase()) {
15
15
  case 'epubjs': {
16
- libName = 'Epub.js'
17
- libPath = path.join(__dirname, 'epub.js')
16
+ lib.name = 'Epub.js'
17
+ lib.options = {}
18
+ lib.path = path.join(__dirname, 'epub.js')
18
19
  break
19
20
  }
20
21
  case 'pandoc': {
21
- libName = 'Pandoc'
22
- libPath = path.join(__dirname, 'pandoc.js')
22
+ lib.name = 'Pandoc'
23
+ lib.options = {}
24
+ lib.path = path.join(__dirname, 'pandoc.js')
23
25
  break
24
26
  }
25
27
  default:
26
- console.error(`[CLI:lib/pdf] Unrecognized EPUB library '${lib}'`)
28
+ console.error(`[CLI:lib/pdf] Unrecognized EPUB library '${name}'`)
27
29
  return
28
30
  }
29
31
 
30
- const { default: epubLib } = await dynamicImport(libPath)
32
+ const { default: epubLib } = await dynamicImport(lib.path)
31
33
 
32
- return async (input, output, options = {}) => {
33
- console.info(`[CLI:lib/epub] generating EPUB using ${libName}`)
34
- return await epubLib(input, output, options)
34
+ return async (input, output) => {
35
+ console.info(`[CLI:lib/epub] generating EPUB using ${lib.name}`)
36
+ return await epubLib(input, output, lib.options)
35
37
  }
36
38
  }
@@ -20,7 +20,7 @@ const xhtmlFiles = (dirent) => {
20
20
  * A façade module for interacting with Pandoc CLI.
21
21
  * @see https://pandoc.org/MANUAL.html#general-options
22
22
  */
23
- export default async (input, output, options) => {
23
+ export default async (input, output, options = {}) => {
24
24
  which('pandoc')
25
25
 
26
26
  const inputs = fs.readdirSync(input)
@@ -8,31 +8,33 @@ const __dirname = path.dirname(__filename)
8
8
  /**
9
9
  * A façade delegation module for PDF generation libraries
10
10
  */
11
- export default async (lib = 'pagedjs', options = {}) => {
12
- let libName, libPath
11
+ export default async (name = 'pagedjs', options = {}) => {
12
+ const lib = { name, options, path }
13
13
 
14
- switch (lib.toLowerCase()) {
14
+ switch (name.toLowerCase()) {
15
15
  case 'paged':
16
16
  case 'pagedjs': {
17
- libName = 'Paged.js'
18
- libPath = path.join(__dirname, 'paged.js')
17
+ lib.name = 'Paged.js'
18
+ lib.options = { debug: options.debug }
19
+ lib.path = path.join(__dirname, 'paged.js')
19
20
  break
20
21
  }
21
22
  case 'prince':
22
23
  case 'princexml': {
23
- libName = 'Prince'
24
- libPath = path.join(__dirname, 'prince.js')
24
+ lib.name = 'Prince'
25
+ lib.options = { debug: options.debug, verbose: options.verbose }
26
+ lib.path = path.join(__dirname, 'prince.js')
25
27
  break
26
28
  }
27
29
  default:
28
- console.error(`[CLI:lib/pdf] Unrecognized PDF library '${lib}'`)
30
+ console.error(`[CLI:lib/pdf] Unrecognized PDF library '${name}'`)
29
31
  return
30
32
  }
31
33
 
32
- const { default: pdfLib } = await dynamicImport(libPath)
34
+ const { default: pdfLib } = await dynamicImport(lib.path)
33
35
 
34
- return async (input, output, options = {}) => {
35
- console.info(`[CLI:lib/pdf] generating PDF using ${libName}`)
36
- return await pdfLib(input, output, options)
36
+ return async (input, output) => {
37
+ console.info(`[CLI:lib/pdf] generating PDF using ${lib.name}`)
38
+ return await pdfLib(input, output, lib.options)
37
39
  }
38
40
  }
@@ -13,10 +13,30 @@ export default async (input, output, options = {}) => {
13
13
  const printerOptions = {
14
14
  allowLocal: true,
15
15
  debug: options.debug || false,
16
+ enableWarnings: options.debug || false,
17
+ }
18
+
19
+ if (options.debug) {
20
+ const optionsOutput = JSON.stringify(printerOptions, null, 2)
21
+ console.debug(`[CLI:lib/pdf/pagedjs] Printer options\n${optionsOutput}`)
16
22
  }
17
23
 
18
24
  const printer = new Printer(printerOptions)
19
25
 
26
+ printer.on('page', (page) => {
27
+ if (page.position === 0) {
28
+ console.info(`[CLI:lib/pdf/pagedjs] loaded`)
29
+ }
30
+ })
31
+
32
+ printer.on('rendered', (msg) => {
33
+ console.info(`[CLI:lib/pdf/pagedjs] ${msg}`)
34
+ })
35
+
36
+ printer.on('postprocessing', () => {
37
+ console.info(`[CLI:lib/pdf/pagedjs] post-processing`)
38
+ })
39
+
20
40
  /**
21
41
  * Configure the Paged.js PDF options
22
42
  * @see
@@ -28,13 +48,22 @@ export default async (input, output, options = {}) => {
28
48
  outlineTags: options.outlineTags || ['h1'],
29
49
  }
30
50
 
51
+ if (options.debug) {
52
+ const optionsOutput = JSON.stringify(pdfOptions, null, 2)
53
+ console.debug(`[CLI:lib/pdf/pagedjs] PDF options\n${optionsOutput}`)
54
+ }
55
+
31
56
  try {
32
57
  console.info(`[CLI:lib/pdf/pagedjs] printing ${input}`)
58
+
33
59
  const file = await printer.pdf(input, pdfOptions)
34
60
  .catch((error) => console.error(error))
35
61
 
62
+ printer.close()
63
+
36
64
  if (file && output) {
37
- fs.writeFile(output, file, (error) => { if (error) throw error })
65
+ await fs.promises.writeFile(output, file)
66
+ .catch((error) => console.error(error))
38
67
  }
39
68
  } catch (ERR_FILE_NOT_FOUND) {
40
69
  console.error(`[CLI:lib/pdf/pagedjs] file not found ${input}`)
@@ -8,10 +8,16 @@ import which from '#helpers/which.js'
8
8
  export default async (input, output, options = {}) => {
9
9
  which('prince')
10
10
 
11
+ /**
12
+ * @see https://www.princexml.com/doc/command-line/#options
13
+ */
11
14
  const cmdOptions = [
12
15
  `--output=${output}`,
13
16
  ]
14
17
 
18
+ if (options.debug) cmdOptions.push('--debug')
19
+ if (options.verbose) cmdOptions.push('--verbose')
20
+
15
21
  const { stderror, stdout } = await execa('prince', [...cmdOptions, input])
16
22
  return { stderror, stdout }
17
23
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Quire constants
3
+ */
4
+ export const CONSTANTS = Object.freeze({
5
+ PACKAGE_NAME: '@thegetty/quire-11ty'
6
+ })
@@ -0,0 +1,104 @@
1
+ import { CONSTANT } from 'constants.js'
2
+ import fs from 'fs-extra'
3
+ import path from 'node:path'
4
+
5
+ const { PACKAGE_NAME } = CONSTANT
6
+
7
+ /**
8
+ * Read the required `quire-11ty` version from starter `package.json` `peerDependencies`
9
+ *
10
+ * @param {String} projectPath Absolute system path to the project root
11
+ *
12
+ * @return {String} version Quire-11ty semantic version with caret or other
13
+ * comparators trimmed off the beginning
14
+ *
15
+ * @TODO refactor `latest()` function to programmatically return a specific
16
+ * version of `@thegetty/quire-11ty` from a semantic version string
17
+ * (i.e `^1.0.0-pre-release.0` => `1.0.0-pre-release.2`) so this string-trimming
18
+ * logic can be removed
19
+ */
20
+ async function getVersion(projectPath) {
21
+ const packageConfig = fs.readFileSync(path.join(projectPath, 'package.json'), { encoding:'utf8' })
22
+ const { peerDependencies } = JSON.parse(packageConfig)
23
+ const version = peerDependencies[PACKAGE_NAME]
24
+ return version === 'latest'
25
+ ? await latest()
26
+ : version.substr(version.search(/\d/))
27
+ }
28
+
29
+ /**
30
+ * Clone or copy a Quire starter project
31
+ *
32
+ * @param {String} starter A repository URL or an absolute path to local starter
33
+ * @TODO resolve both absolute and relative paths to local starter repositories
34
+ * @param {String} projectPath Absolute system path to the project root
35
+ *
36
+ * @return {String} quireVersion A string indicating the current version
37
+ * of quire being used with a new project
38
+ */
39
+ async function init (starter, projectPath) {
40
+ projectPath = projectPath || cwd()
41
+
42
+ // ensure that the target path exists
43
+ fs.ensureDirSync(projectPath)
44
+
45
+ // if the target directory exists it must be empty
46
+ if (!isEmpty(projectPath)) {
47
+ const location = projectPath === '.' ? 'the current directory' : projectPath
48
+ console.error(`[CLI] cannot create a starter project in ${location} because it is not empty`)
49
+ // @TODO cleanup directories from failed new command
50
+ return
51
+ }
52
+
53
+ starter = starter || 'https://github.com/thegetty/quire-starter-default'
54
+
55
+ console.debug('[CLI:quire] init-starter',
56
+ `\n project root: "${projectPath}"`,
57
+ `\n starter: "${starter}"`
58
+ )
59
+
60
+ /**
61
+ * Clone starter project repository
62
+ * @todo pipe `git clone` status to stdout for better UX
63
+ */
64
+ await git
65
+ .cwd(projectPath)
66
+ .clone(starter, '.')
67
+ .catch((error) => console.error('[CLI:error] ', error))
68
+
69
+ /**
70
+ * Determine `quire-11ty` version required by the starter project
71
+ * and write a `.quire` file with the semantic version string.
72
+ */
73
+ const quireVersion = await getVersion(projectPath)
74
+ setVersion(projectPath, quireVersion)
75
+
76
+ // Re-initialize project directory as a new git repository
77
+ await fs.remove(path.join(projectPath, '.git'))
78
+
79
+ /**
80
+ * Remove the starter repository package config file
81
+ * and create a new package config for the project
82
+ * (this is necessary for Eleventy to resolve project paths)
83
+ * @todo allow interactive init using a custom questionnaire
84
+ * @see https://docs.npmjs.com/creating-a-package-json-file#customizing-the-packagejson-questionnaire
85
+ */
86
+ await fs.remove(path.join(projectPath, 'package.json'))
87
+ await execaCommand('npm init --yes', { cwd: projectPath })
88
+
89
+ /**
90
+ * Create an initial commit of files in new repository
91
+ * @todo use a localized string for the commit message
92
+ */
93
+ const projectFiles = fs.readdirSync(projectPath)
94
+ await git.init().add(projectFiles).commit('Initial Commit')
95
+
96
+ return quireVersion
97
+ }
98
+
99
+ /**
100
+ * Update quire-11ty
101
+ *
102
+ * @return {Promise} { description_of_the_return_value }
103
+ */
104
+ async function update () {}
package/src/main.js CHANGED
@@ -14,7 +14,7 @@ const program = new Command()
14
14
  program
15
15
  .name('quire-cli')
16
16
  .description('Quire command-line interface')
17
- .version(packageConfig.version)
17
+ .version(packageConfig.version, '-v, --version', 'output quire version number')
18
18
  .configureHelp({
19
19
  helpWidth: 80,
20
20
  sortOptions: false,