@thegetty/quire-cli 1.0.0-rc.34 → 1.0.0-rc.36
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/CHANGELOG.md +36 -0
- package/README.md +9 -0
- package/bin/cli.js +19 -1
- package/package.json +21 -8
- package/schemas/config.schema.json +194 -0
- package/schemas/figures.schema.json +56 -0
- package/schemas/layout.schema.json +5 -0
- package/schemas/objects.schema.json +62 -0
- package/schemas/publication.schema.json +140 -0
- package/schemas/references.schema.json +29 -0
- package/src/Command.js +26 -6
- package/src/Command.spec.js +99 -0
- package/src/commands/README.md +213 -122
- package/src/commands/build.js +46 -37
- package/src/commands/build.spec.js +113 -0
- package/src/commands/build.test.js +402 -0
- package/src/commands/clean.js +25 -19
- package/src/commands/clean.spec.js +108 -0
- package/src/commands/clean.test.js +260 -0
- package/src/commands/config.js +251 -0
- package/src/commands/config.spec.js +107 -0
- package/src/commands/config.test.js +715 -0
- package/src/commands/create.js +42 -14
- package/src/commands/create.spec.js +112 -0
- package/src/commands/create.test.js +415 -0
- package/src/commands/epub.js +59 -30
- package/src/commands/epub.spec.js +114 -0
- package/src/commands/epub.test.js +503 -0
- package/src/commands/index.js +9 -2
- package/src/commands/info.js +18 -24
- package/src/commands/info.spec.js +64 -0
- package/src/commands/info.test.js +415 -0
- package/src/commands/pdf.js +58 -84
- package/src/commands/pdf.spec.js +114 -0
- package/src/commands/pdf.test.js +464 -0
- package/src/commands/preview.js +26 -31
- package/src/commands/preview.spec.js +97 -0
- package/src/commands/preview.test.js +250 -0
- package/src/commands/use.js +56 -0
- package/src/commands/use.spec.js +61 -0
- package/src/commands/use.test.js +280 -0
- package/src/commands/validate.js +31 -19
- package/src/commands/validate.spec.js +82 -0
- package/src/commands/validate.test.js +234 -0
- package/src/commands/workflows.js +70 -0
- package/src/errors/build/build-failed-error.js +19 -0
- package/src/errors/build/config-field-missing-error.js +20 -0
- package/src/errors/build/config-file-not-found-error.js +20 -0
- package/src/errors/build/index.js +11 -0
- package/src/errors/index.js +48 -0
- package/src/errors/install/dependency-install-error.js +19 -0
- package/src/errors/install/directory-not-empty-error.js +25 -0
- package/src/errors/install/index.js +12 -0
- package/src/errors/install/invalid-path-error.js +31 -0
- package/src/errors/install/invalid-starter-error.js +27 -0
- package/src/errors/install/version-not-found-error.js +35 -0
- package/src/errors/output/epub-generation-error.js +19 -0
- package/src/errors/output/index.js +14 -0
- package/src/errors/output/invalid-epub-library-error.js +20 -0
- package/src/errors/output/invalid-pdf-library-error.js +20 -0
- package/src/errors/output/missing-build-output-error.js +21 -0
- package/src/errors/output/pdf-generation-error.js +24 -0
- package/src/errors/output/tool-not-found-error.js +37 -0
- package/src/errors/project/index.js +10 -0
- package/src/errors/project/not-in-project-error.js +20 -0
- package/src/errors/project/project-create-error.js +21 -0
- package/src/errors/quire-error.js +27 -0
- package/src/errors/validation/validation-error.js +20 -11
- package/src/helpers/clean.js +1 -1
- package/src/helpers/docs-url.js +32 -0
- package/src/helpers/test-cwd.js +5 -6
- package/src/helpers/test-cwd.test.js +192 -0
- package/src/helpers/which.js +10 -4
- package/src/lib/11ty/README.md +135 -19
- package/src/lib/11ty/api.js +176 -93
- package/src/lib/11ty/cli.js +77 -35
- package/src/lib/11ty/index.js +64 -5
- package/src/lib/11ty/index.test.js +655 -0
- package/src/lib/README.md +275 -0
- package/src/lib/commander/index.js +100 -0
- package/src/lib/commander/index.test.js +86 -0
- package/src/lib/commander/options.js +195 -0
- package/src/lib/commander/options.test.js +109 -0
- package/src/lib/conf/README.md +84 -73
- package/src/lib/conf/config.js +5 -3
- package/src/lib/conf/config.test.js +281 -0
- package/src/lib/conf/defaults.js +44 -0
- package/src/lib/conf/format.js +60 -0
- package/src/lib/conf/format.test.js +106 -0
- package/src/lib/conf/helpers.js +91 -0
- package/src/lib/conf/helpers.test.js +136 -0
- package/src/lib/conf/index.js +22 -0
- package/src/lib/conf/schema.js +53 -8
- package/src/lib/epub/README.md +133 -2
- package/src/lib/epub/engines.js +46 -0
- package/src/lib/epub/epub.js +36 -11
- package/src/lib/epub/index.js +111 -21
- package/src/lib/epub/index.test.js +518 -0
- package/src/lib/epub/pandoc.js +33 -4
- package/src/lib/epub/pandoc.test.js +122 -0
- package/src/lib/epub/schema.js +21 -0
- package/src/lib/error/README.md +170 -0
- package/src/lib/error/handler.js +107 -0
- package/src/lib/git/README.md +151 -2
- package/src/lib/git/index.js +217 -13
- package/src/lib/git/index.spec.js +80 -0
- package/src/lib/git/index.test.js +453 -0
- package/src/lib/installer/index.js +309 -0
- package/src/lib/installer/index.spec.js +83 -0
- package/src/lib/installer/index.test.js +545 -0
- package/src/lib/logger/README.md +424 -0
- package/src/lib/logger/debug.js +90 -0
- package/src/lib/logger/debug.spec.js +130 -0
- package/src/lib/logger/index.js +228 -0
- package/src/lib/logger/index.spec.js +131 -0
- package/src/lib/logger/index.test.js +477 -0
- package/src/lib/npm/README.md +127 -0
- package/src/lib/npm/index.js +198 -0
- package/src/lib/npm/index.spec.js +60 -0
- package/src/lib/npm/index.test.js +355 -0
- package/src/lib/pdf/README.md +131 -0
- package/src/lib/pdf/engines.js +46 -0
- package/src/lib/pdf/index.js +124 -21
- package/src/lib/pdf/index.test.js +708 -0
- package/src/lib/pdf/paged.js +100 -52
- package/src/lib/pdf/paged.test.js +366 -0
- package/src/lib/pdf/prince.js +115 -37
- package/src/lib/pdf/prince.test.js +202 -0
- package/src/lib/pdf/schema.js +21 -0
- package/src/lib/pdf/split.js +61 -33
- package/src/lib/pdf/split.test.js +445 -0
- package/src/lib/process/manager.js +110 -0
- package/src/lib/process/manager.test.js +55 -0
- package/src/lib/project/build.js +143 -0
- package/src/lib/project/build.test.js +253 -0
- package/src/lib/project/config.js +48 -0
- package/src/lib/project/config.test.js +134 -0
- package/src/{helpers/is-quire.js → lib/project/detect.js} +5 -3
- package/src/lib/project/detect.test.js +157 -0
- package/src/lib/project/index.js +40 -0
- package/src/lib/project/paths.js +224 -0
- package/src/lib/project/version.js +110 -0
- package/src/lib/project/version.test.js +350 -0
- package/src/lib/reporter/README.md +211 -2
- package/src/lib/reporter/index.js +512 -0
- package/src/lib/reporter/index.test.js +593 -0
- package/src/main.js +134 -47
- package/src/main.spec.js +61 -0
- package/src/main.test.js +347 -0
- package/src/validators/utils.js +2 -1
- package/src/commands/conf.js +0 -43
- package/src/commands/version.js +0 -43
- package/src/lib/11ty/paths.js +0 -103
- package/src/lib/i18n/README.md +0 -3
- package/src/lib/i18n/config.js +0 -53
- package/src/lib/i18n/index.js +0 -43
- package/src/lib/i18n/localeService.js +0 -58
- package/src/lib/quire/README.md +0 -19
- package/src/lib/quire/index.js +0 -350
package/src/lib/11ty/api.js
CHANGED
|
@@ -1,133 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quire11ty façade for Eleventy integration
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for Eleventy operations with path resolution.
|
|
5
|
+
* Follows the singleton pattern like lib/npm and lib/git for consistency
|
|
6
|
+
* and easy mocking in tests.
|
|
7
|
+
*
|
|
8
|
+
* @example Production usage
|
|
9
|
+
* import eleventy from '#lib/11ty/index.js'
|
|
10
|
+
* await eleventy.build({ debug: true })
|
|
11
|
+
* const outputDir = eleventy.paths.getOutputDir()
|
|
12
|
+
*
|
|
13
|
+
* @example Path-only usage
|
|
14
|
+
* import { paths } from '#lib/11ty/index.js'
|
|
15
|
+
* const projectRoot = paths.getProjectRoot()
|
|
16
|
+
*
|
|
17
|
+
* @example Test mocking
|
|
18
|
+
* const mockEleventy = {
|
|
19
|
+
* build: sandbox.stub().resolves(),
|
|
20
|
+
* serve: sandbox.stub().resolves(),
|
|
21
|
+
* paths: {
|
|
22
|
+
* getProjectRoot: () => '/project',
|
|
23
|
+
* getOutputDir: () => '_site'
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* const MyCommand = await esmock('./mycommand.js', {
|
|
27
|
+
* '#lib/11ty/index.js': { default: mockEleventy }
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* @see https://www.11ty.dev/docs/programmatic/
|
|
31
|
+
* @module lib/11ty
|
|
32
|
+
*/
|
|
1
33
|
import { dynamicImport } from '#helpers/os-utils.js'
|
|
2
|
-
import { pathToFileURL } from 'node:url'
|
|
3
34
|
import path from 'node:path'
|
|
4
|
-
import paths
|
|
35
|
+
import paths from '#lib/project/index.js'
|
|
36
|
+
import { logger } from '#lib/logger/index.js'
|
|
37
|
+
import createDebug from '#debug'
|
|
38
|
+
|
|
39
|
+
const debug = createDebug('lib:11ty:api')
|
|
5
40
|
|
|
6
41
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
42
|
+
* Configure environment variables required for Eleventy.
|
|
43
|
+
*
|
|
44
|
+
* These must be set before the Eleventy instance is created and the
|
|
45
|
+
* `.eleventy.js` configuration file is parsed.
|
|
9
46
|
*
|
|
10
|
-
* @
|
|
11
|
-
*
|
|
47
|
+
* @see https://github.com/11ty/eleventy/issues/2655
|
|
48
|
+
*
|
|
49
|
+
* @param {Object} options
|
|
50
|
+
* @param {'production'|'development'} options.mode - Build mode
|
|
51
|
+
* @param {boolean} options.debug - Enable Eleventy debug output
|
|
12
52
|
*/
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
53
|
+
const configureEleventyEnv = ({ mode = 'production', debug = false } = {}) => {
|
|
54
|
+
// Path configuration for decoupling quire-11ty from project input directory
|
|
55
|
+
process.env.ELEVENTY_DATA = paths.getDataDir()
|
|
56
|
+
process.env.ELEVENTY_INCLUDES = paths.getIncludesDir()
|
|
57
|
+
process.env.ELEVENTY_LAYOUTS = paths.getLayoutsDir()
|
|
58
|
+
|
|
59
|
+
// Build mode
|
|
60
|
+
process.env.ELEVENTY_ENV = mode
|
|
61
|
+
|
|
62
|
+
// Debug output
|
|
63
|
+
if (debug) {
|
|
64
|
+
process.env.DEBUG = 'Eleventy*'
|
|
18
65
|
}
|
|
66
|
+
}
|
|
19
67
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Create an instance of Eleventy configured for Quire projects
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} options - Eleventy configuration options
|
|
72
|
+
* @param {boolean} [options.debug=false] - Enable debug output
|
|
73
|
+
* @param {boolean} [options.quiet=false] - Suppress output
|
|
74
|
+
* @param {string} [options.config] - Custom config path override
|
|
75
|
+
* @param {'build'|'serve'|'watch'} [options.runMode='build'] - Eleventy run mode
|
|
76
|
+
* @returns {Promise<Eleventy>} Configured Eleventy instance
|
|
77
|
+
*/
|
|
78
|
+
const createEleventyInstance = async (options = {}) => {
|
|
79
|
+
const config = paths.getConfigPath()
|
|
80
|
+
const eleventyRoot = paths.getEleventyRoot()
|
|
81
|
+
const input = paths.getInputDir()
|
|
82
|
+
const output = paths.getOutputDir()
|
|
83
|
+
const projectRoot = paths.getProjectRoot()
|
|
25
84
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* @see https://www.11ty.dev/docs/copy/#advanced-options
|
|
29
|
-
* @see https://github.com/timkendrick/recursive-copy
|
|
30
|
-
*/
|
|
31
|
-
const copyOptions = {
|
|
32
|
-
debug: options.debug || false
|
|
33
|
-
}
|
|
85
|
+
debug('projectRoot: %s', projectRoot)
|
|
86
|
+
debug('paths: %O', paths.toObject())
|
|
34
87
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* Nota bene: environment variables read into the eleventy configuration
|
|
39
|
-
* file _must_ be set before the eleventy configuration file is parsed.
|
|
40
|
-
* @see https://github.com/11ty/eleventy/issues/2655
|
|
41
|
-
*/
|
|
42
|
-
process.env.ELEVENTY_DATA = paths.data
|
|
43
|
-
process.env.ELEVENTY_INCLUDES = paths.includes
|
|
44
|
-
process.env.ELEVENTY_LAYOUTS = paths.layouts
|
|
88
|
+
// Dynamically import the correct version of Eleventy
|
|
89
|
+
const modulePath = path.join(eleventyRoot, 'node_modules', '@11ty', 'eleventy', 'src', 'Eleventy.js')
|
|
90
|
+
const { default: Eleventy } = await dynamicImport(modulePath)
|
|
45
91
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
* @see https://github.com/11ty/eleventy/blob/src/Eleventy.js
|
|
49
|
-
*
|
|
50
|
-
* @param {String} input Path from which to read content templates
|
|
51
|
-
* @param {String} output Path where rendered files will be written
|
|
52
|
-
* @param {Object} options Options are merged with the Eleventy UserConfig
|
|
53
|
-
* @param {Object} config An eleventy configurtion object
|
|
54
|
-
*
|
|
55
|
-
* @returns {module:11ty/eleventy/Eleventy~Eleventy}
|
|
56
|
-
*/
|
|
92
|
+
// Create Eleventy instance
|
|
93
|
+
// @see https://github.com/11ty/eleventy/blob/src/Eleventy.js
|
|
57
94
|
const eleventy = new Eleventy(input, output, {
|
|
58
95
|
config: (eleventyConfig) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* @see https://www.11ty.dev/docs/copy/#passthrough-file-copy
|
|
62
|
-
* Nota bene: Eleventy addPassthroughCopy assumes paths are _relative_
|
|
63
|
-
* to the `config` file however the quire-cli separates 11ty from the
|
|
64
|
-
* project directory (`input`) and needs to use absolute system paths.
|
|
65
|
-
*/
|
|
66
|
-
const addPassthroughCopy = eleventyConfig.addPassthroughCopy.bind(eleventyConfig)
|
|
67
|
-
eleventyConfig.addPassthroughCopy = (entry) => {
|
|
68
|
-
if (typeof entry === 'string') {
|
|
69
|
-
const filePath = path.resolve(entry) //path.join(projectRoot, file)
|
|
70
|
-
// console.debug('[11ty:API] passthrough copy %s', filePath)
|
|
71
|
-
return addPassthroughCopy(filePath, copyOptions)
|
|
72
|
-
} else {
|
|
73
|
-
// console.debug('[11ty:API] passthrough copy %o', entry)
|
|
74
|
-
entry = Object.fromEntries(
|
|
75
|
-
Object.entries(entry).map(([ src, dest ]) => {
|
|
76
|
-
return [ path.join(eleventyRoot, src), path.resolve(dest) ]
|
|
77
|
-
})
|
|
78
|
-
)
|
|
79
|
-
// console.debug('[11ty:API] passthrough copy %o', entry)
|
|
80
|
-
return addPassthroughCopy(entry, copyOptions)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Event callback when a build completes
|
|
86
|
-
* @see https://www.11ty.dev/docs/events/#eleventy.after
|
|
87
|
-
*/
|
|
96
|
+
// Event callback when a build completes
|
|
97
|
+
// @see https://www.11ty.dev/docs/events/#eleventy.after
|
|
88
98
|
eleventyConfig.on('eleventy.after', async () => {
|
|
89
|
-
|
|
99
|
+
debug('build complete')
|
|
90
100
|
})
|
|
91
101
|
|
|
92
102
|
return eleventyConfig
|
|
93
103
|
},
|
|
94
104
|
configPath: options.config || config,
|
|
95
105
|
quietMode: options.quiet || false,
|
|
106
|
+
runMode: options.runMode || 'build',
|
|
96
107
|
})
|
|
97
108
|
|
|
98
109
|
return eleventy
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
113
|
+
* Quire11ty façade class
|
|
114
|
+
*
|
|
115
|
+
* Provides abstracted Eleventy operations with unified logging,
|
|
116
|
+
* error handling, and path resolution. Stores active Eleventy
|
|
117
|
+
* instance for cleanup registration with ProcessManager.
|
|
105
118
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
class Quire11ty {
|
|
120
|
+
/**
|
|
121
|
+
* Create Quire11ty instance
|
|
122
|
+
* @param {Object} pathsInstance - Paths instance for path resolution
|
|
123
|
+
*/
|
|
124
|
+
constructor(pathsInstance) {
|
|
125
|
+
this.paths = pathsInstance
|
|
126
|
+
/**
|
|
127
|
+
* Active Eleventy instance (for API mode)
|
|
128
|
+
* @type {Eleventy|null}
|
|
129
|
+
*/
|
|
130
|
+
this.activeInstance = null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if an Eleventy process is currently active
|
|
135
|
+
* @returns {boolean}
|
|
136
|
+
*/
|
|
137
|
+
isActive() {
|
|
138
|
+
return this.activeInstance !== null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Gracefully close any active Eleventy process
|
|
143
|
+
*
|
|
144
|
+
* Calls eleventy.close() to stop the dev server and file watchers.
|
|
145
|
+
* This method is registered with ProcessManager for signal handling.
|
|
146
|
+
*
|
|
147
|
+
* @returns {Promise<void>}
|
|
148
|
+
*/
|
|
149
|
+
async close() {
|
|
150
|
+
if (this.activeInstance) {
|
|
151
|
+
debug('shutting down Eleventy')
|
|
152
|
+
try {
|
|
153
|
+
await this.activeInstance.close()
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// Ignore errors during shutdown (may already be closing)
|
|
156
|
+
debug('close error (may be expected): %s', error.message)
|
|
157
|
+
}
|
|
158
|
+
this.activeInstance = null
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Run Eleventy production build
|
|
164
|
+
*
|
|
165
|
+
* @param {Object} options - Build options
|
|
166
|
+
* @param {boolean} [options.debug=false] - Enable debug output
|
|
167
|
+
* @param {boolean} [options.dryRun=false] - Perform dry run without writing files
|
|
168
|
+
* @param {boolean} [options.quiet=false] - Suppress output
|
|
169
|
+
* @returns {Promise<void>}
|
|
170
|
+
*/
|
|
171
|
+
async build(options = {}) {
|
|
172
|
+
const projectRoot = this.paths.getProjectRoot()
|
|
173
|
+
process.chdir(projectRoot)
|
|
109
174
|
|
|
110
|
-
|
|
175
|
+
logger.info('Building site...')
|
|
111
176
|
|
|
112
|
-
|
|
113
|
-
if (options.debug) process.env.DEBUG = 'Eleventy*'
|
|
177
|
+
configureEleventyEnv({ mode: 'production', debug: options.debug })
|
|
114
178
|
|
|
115
|
-
const eleventy = await
|
|
179
|
+
const eleventy = await createEleventyInstance(options)
|
|
116
180
|
|
|
117
|
-
eleventy.setDryRun(options.
|
|
181
|
+
eleventy.setDryRun(options.dryRun)
|
|
118
182
|
|
|
119
183
|
await eleventy.write()
|
|
120
|
-
}
|
|
121
|
-
serve: async (options = {}) => {
|
|
122
|
-
process.cwd(projectRoot)
|
|
184
|
+
}
|
|
123
185
|
|
|
124
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Run Eleventy development server
|
|
188
|
+
*
|
|
189
|
+
* @param {Object} options - Serve options
|
|
190
|
+
* @param {boolean} [options.debug=false] - Enable debug output
|
|
191
|
+
* @param {number} [options.port] - Server port
|
|
192
|
+
* @param {boolean} [options.quiet=false] - Suppress output
|
|
193
|
+
* @returns {Promise<void>}
|
|
194
|
+
*/
|
|
195
|
+
async serve(options = {}) {
|
|
196
|
+
const projectRoot = this.paths.getProjectRoot()
|
|
197
|
+
process.chdir(projectRoot)
|
|
198
|
+
|
|
199
|
+
logger.info('Starting development server...')
|
|
125
200
|
|
|
126
|
-
|
|
127
|
-
if (options.debug) process.env.DEBUG = 'Eleventy*'
|
|
201
|
+
configureEleventyEnv({ mode: 'development', debug: options.debug })
|
|
128
202
|
|
|
129
|
-
const eleventy =
|
|
203
|
+
const eleventy =
|
|
204
|
+
await createEleventyInstance({ ...options, runMode: 'serve' })
|
|
205
|
+
|
|
206
|
+
// Store reference for lifecycle management (graceful shutdown)
|
|
207
|
+
this.activeInstance = eleventy
|
|
208
|
+
|
|
209
|
+
// Initialize Eleventy before serving (required for eleventyServe)
|
|
210
|
+
await eleventy.init()
|
|
130
211
|
|
|
131
212
|
await eleventy.serve(options.port)
|
|
132
213
|
}
|
|
133
214
|
}
|
|
215
|
+
|
|
216
|
+
export { Quire11ty, createEleventyInstance, configureEleventyEnv }
|
package/src/lib/11ty/cli.js
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
import { execa } from 'execa'
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
-
import paths
|
|
4
|
+
import paths from '#lib/project/index.js'
|
|
5
|
+
import processManager from '#lib/process/manager.js'
|
|
6
|
+
import { BuildFailedError } from '#src/errors/index.js'
|
|
7
|
+
import { logger } from '#lib/logger/index.js'
|
|
8
|
+
import createDebug from '#debug'
|
|
9
|
+
|
|
10
|
+
const debug = createDebug('lib:11ty')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Spawn a cancellable subprocess with output piped to stdout
|
|
14
|
+
*
|
|
15
|
+
* @param {string[]} command - Command arguments for node
|
|
16
|
+
* @param {Object} options - Spawn options
|
|
17
|
+
* @param {string} options.cwd - Working directory
|
|
18
|
+
* @param {Object} options.env - Environment variables
|
|
19
|
+
* @returns {import('execa').ExecaChildProcess}
|
|
20
|
+
*/
|
|
21
|
+
const spawn = (command, { cwd, env }) => {
|
|
22
|
+
const subprocess = execa('node', command, {
|
|
23
|
+
all: true,
|
|
24
|
+
cwd,
|
|
25
|
+
env,
|
|
26
|
+
execPath: process.execPath,
|
|
27
|
+
cancelSignal: processManager.signal,
|
|
28
|
+
gracefulCancel: true,
|
|
29
|
+
})
|
|
30
|
+
subprocess.all.pipe(process.stdout)
|
|
31
|
+
return subprocess
|
|
32
|
+
}
|
|
5
33
|
|
|
6
34
|
/**
|
|
7
35
|
* A factory function to configure an Eleventy CLI command
|
|
@@ -10,20 +38,21 @@ import paths, { eleventyRoot, projectRoot } from './paths.js'
|
|
|
10
38
|
* @return {Array} Eleventy CLI options
|
|
11
39
|
*/
|
|
12
40
|
const factory = (options = {}) => {
|
|
13
|
-
const
|
|
41
|
+
const config = paths.getConfigPath()
|
|
42
|
+
const eleventyRoot = paths.getEleventyRoot()
|
|
43
|
+
const input = paths.getInputDir()
|
|
44
|
+
const output = paths.getOutputDir()
|
|
45
|
+
const projectRoot = paths.getProjectRoot()
|
|
14
46
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
47
|
+
debug('projectRoot: %s', projectRoot)
|
|
48
|
+
debug('paths: %O', paths.toObject())
|
|
18
49
|
|
|
19
50
|
/**
|
|
20
51
|
* Use the version of Eleventy installed to `lib/quire/versions`
|
|
21
|
-
*
|
|
22
|
-
* NB: in eleventy v3 the CLI extension (".cjs") is load-bearing but v2 is simply ".js"
|
|
23
|
-
*
|
|
52
|
+
* Nota bene: in eleventy v3 the CLI extension (".cjs") is load-bearing but v2 is simply ".js"
|
|
24
53
|
*/
|
|
25
54
|
const eleventyModuleDir = path.join(eleventyRoot, 'node_modules', '@11ty', 'eleventy')
|
|
26
|
-
const packagePath = path.join(eleventyModuleDir,'package.json')
|
|
55
|
+
const packagePath = path.join(eleventyModuleDir,'package.json')
|
|
27
56
|
|
|
28
57
|
const pack = JSON.parse(fs.readFileSync(packagePath))
|
|
29
58
|
|
|
@@ -59,14 +88,14 @@ const factory = (options = {}) => {
|
|
|
59
88
|
* @see https://github.com/11ty/eleventy/issues/2655
|
|
60
89
|
*/
|
|
61
90
|
const env = {
|
|
62
|
-
ELEVENTY_DATA: paths.
|
|
63
|
-
ELEVENTY_INCLUDES: paths.
|
|
64
|
-
ELEVENTY_LAYOUTS: paths.
|
|
91
|
+
ELEVENTY_DATA: paths.getDataDir(),
|
|
92
|
+
ELEVENTY_INCLUDES: paths.getIncludesDir(),
|
|
93
|
+
ELEVENTY_LAYOUTS: paths.getLayoutsDir(),
|
|
65
94
|
}
|
|
66
95
|
|
|
67
96
|
if (options.debug) env.DEBUG = 'Eleventy*'
|
|
68
97
|
|
|
69
|
-
return { command, env }
|
|
98
|
+
return { command, env, projectRoot }
|
|
70
99
|
}
|
|
71
100
|
|
|
72
101
|
/**
|
|
@@ -74,33 +103,43 @@ const factory = (options = {}) => {
|
|
|
74
103
|
* @see https://www.11ty.dev/docs/usage/#command-line-usage
|
|
75
104
|
*/
|
|
76
105
|
export default {
|
|
106
|
+
/**
|
|
107
|
+
* Run Eleventy build via CLI
|
|
108
|
+
* @param {Object} options - Build options
|
|
109
|
+
*/
|
|
77
110
|
build: async (options = {}) => {
|
|
78
|
-
|
|
111
|
+
logger.info('Building site...')
|
|
79
112
|
|
|
80
|
-
const { command, env } = factory(options)
|
|
113
|
+
const { command, env, projectRoot } = factory(options)
|
|
81
114
|
|
|
82
115
|
if (options.dryRun) command.push('--dryrun')
|
|
83
116
|
|
|
84
117
|
env.ELEVENTY_ENV = 'production'
|
|
85
118
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
try {
|
|
120
|
+
const build = spawn(command, { cwd: projectRoot, env })
|
|
121
|
+
await build
|
|
122
|
+
|
|
123
|
+
if (build.exitCode !== 0) {
|
|
124
|
+
throw new BuildFailedError(`Eleventy exited with code ${build.exitCode}`)
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (error.isCanceled) {
|
|
128
|
+
debug('build cancelled')
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
throw error
|
|
97
132
|
}
|
|
98
133
|
},
|
|
99
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Run Eleventy development server via CLI
|
|
137
|
+
* @param {Object} options - Serve options
|
|
138
|
+
*/
|
|
100
139
|
serve: async (options = {}) => {
|
|
101
|
-
|
|
140
|
+
logger.info('Starting development server...')
|
|
102
141
|
|
|
103
|
-
const { command, env } = factory(options)
|
|
142
|
+
const { command, env, projectRoot } = factory(options)
|
|
104
143
|
|
|
105
144
|
command.push('--serve')
|
|
106
145
|
|
|
@@ -108,11 +147,14 @@ export default {
|
|
|
108
147
|
|
|
109
148
|
env.ELEVENTY_ENV = 'development'
|
|
110
149
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
try {
|
|
151
|
+
await spawn(command, { cwd: projectRoot, env })
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error.isCanceled) {
|
|
154
|
+
debug('server stopped')
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
throw error
|
|
158
|
+
}
|
|
159
|
+
},
|
|
118
160
|
}
|
package/src/lib/11ty/index.js
CHANGED
|
@@ -1,11 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Quire Eleventy integration module
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified façade for Eleventy operations following the singleton
|
|
5
|
+
* pattern established by lib/npm and lib/git. Integrates with the central
|
|
6
|
+
* ProcessManager for graceful shutdown on process signals.
|
|
7
|
+
*
|
|
8
|
+
* @example Recommended usage
|
|
9
|
+
* import eleventy from '#lib/11ty/index.js'
|
|
10
|
+
* await eleventy.build({ debug: true })
|
|
11
|
+
* const outputDir = eleventy.paths.getOutputDir()
|
|
12
|
+
*
|
|
13
|
+
* @example Path-only usage (for consumers that only need paths)
|
|
14
|
+
* import { paths } from '#lib/11ty/index.js'
|
|
15
|
+
* const projectRoot = paths.getProjectRoot()
|
|
16
|
+
*
|
|
17
|
+
* @example Legacy usage (deprecated)
|
|
18
|
+
* import { api, cli, paths } from '#lib/11ty/index.js'
|
|
19
|
+
*
|
|
20
|
+
* @module lib/11ty
|
|
21
|
+
*/
|
|
22
|
+
import { Quire11ty } from './api.js'
|
|
23
|
+
import cliModule from './cli.js'
|
|
24
|
+
import paths, { Paths } from '#lib/project/index.js'
|
|
25
|
+
import processManager from '#lib/process/manager.js'
|
|
4
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Quire11ty singleton instance
|
|
29
|
+
* @type {Quire11ty}
|
|
30
|
+
*/
|
|
31
|
+
const eleventy = new Quire11ty(paths)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* CLI wrapper - delegates to cli.js which imports processManager directly
|
|
35
|
+
*/
|
|
36
|
+
const cli = {
|
|
37
|
+
build: async (options) => cliModule.build(options),
|
|
38
|
+
serve: async (options) => cliModule.serve(options),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Legacy API export for backwards compatibility
|
|
43
|
+
*
|
|
44
|
+
* Wraps the singleton methods to register cleanup handlers with
|
|
45
|
+
* ProcessManager for graceful shutdown support.
|
|
46
|
+
*
|
|
47
|
+
* @deprecated Use default export instead: `import eleventy from '#lib/11ty/index.js'`
|
|
48
|
+
*/
|
|
49
|
+
const api = {
|
|
50
|
+
build: async (options) => eleventy.build(options),
|
|
51
|
+
serve: async (options) => {
|
|
52
|
+
processManager.onShutdown('eleventy', () => eleventy.close())
|
|
53
|
+
try {
|
|
54
|
+
return await eleventy.serve(options)
|
|
55
|
+
} finally {
|
|
56
|
+
processManager.onShutdownComplete('eleventy')
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Default export: unified façade
|
|
62
|
+
export default eleventy
|
|
63
|
+
|
|
64
|
+
// Named exports for backwards compatibility and path-only consumers
|
|
5
65
|
export {
|
|
6
66
|
api,
|
|
7
67
|
cli,
|
|
8
|
-
eleventyRoot,
|
|
9
68
|
paths,
|
|
10
|
-
|
|
69
|
+
Paths,
|
|
11
70
|
}
|