@thegetty/quire-cli 1.0.0-rc.37 → 1.0.0-rc.39
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/package.json +5 -2
- package/src/commands/build.js +13 -6
- package/src/commands/clean.js +10 -2
- package/src/commands/clean.spec.js +10 -0
- package/src/commands/clean.test.js +122 -0
- package/src/commands/config.js +3 -1
- package/src/commands/config.test.js +42 -1
- package/src/commands/doctor.js +251 -0
- package/src/commands/doctor.spec.js +115 -0
- package/src/commands/doctor.test.js +1409 -0
- package/src/commands/epub.js +9 -2
- package/src/commands/help.js +60 -0
- package/src/commands/help.test.js +132 -0
- package/src/commands/info.js +79 -71
- package/src/commands/info.spec.js +8 -0
- package/src/commands/info.test.js +173 -76
- package/src/commands/pdf.js +10 -3
- package/src/commands/validate.js +39 -7
- package/src/commands/validate.spec.js +8 -0
- package/src/commands/validate.test.js +144 -0
- package/src/errors/help/help-topic-not-found-error.js +22 -0
- package/src/errors/help/index.js +8 -0
- package/src/errors/index.js +6 -0
- package/src/errors/input/index.js +8 -0
- package/src/errors/input/invalid-input-error.js +21 -0
- package/src/helpers/pager.js +59 -0
- package/src/helpers/pager.test.js +85 -0
- package/src/lib/README.md +77 -22
- package/src/lib/conf/README.md +6 -0
- package/src/lib/conf/build-status.js +103 -0
- package/src/lib/conf/build-status.test.js +247 -0
- package/src/lib/conf/defaults.js +14 -0
- package/src/lib/conf/format.js +1 -1
- package/src/lib/conf/schema.js +46 -1
- package/src/lib/constants.js +28 -0
- package/src/lib/doctor/README.md +667 -0
- package/src/lib/doctor/checks/environment/cli-version.js +62 -0
- package/src/lib/doctor/checks/environment/cli-version.test.js +132 -0
- package/src/lib/doctor/checks/environment/git-available.js +77 -0
- package/src/lib/doctor/checks/environment/git-available.test.js +52 -0
- package/src/lib/doctor/checks/environment/index.js +13 -0
- package/src/lib/doctor/checks/environment/node-version.js +66 -0
- package/src/lib/doctor/checks/environment/node-version.test.js +17 -0
- package/src/lib/doctor/checks/environment/npm-available.js +66 -0
- package/src/lib/doctor/checks/environment/npm-available.test.js +52 -0
- package/src/lib/doctor/checks/environment/os-info.js +48 -0
- package/src/lib/doctor/checks/environment/os-info.test.js +81 -0
- package/src/lib/doctor/checks/environment/runtime-info.js +51 -0
- package/src/lib/doctor/checks/environment/runtime-info.test.js +132 -0
- package/src/lib/doctor/checks/outputs/epub-output.js +119 -0
- package/src/lib/doctor/checks/outputs/epub-output.test.js +277 -0
- package/src/lib/doctor/checks/outputs/index.js +10 -0
- package/src/lib/doctor/checks/outputs/pdf-output.js +144 -0
- package/src/lib/doctor/checks/outputs/pdf-output.test.js +377 -0
- package/src/lib/doctor/checks/outputs/stale-build.js +122 -0
- package/src/lib/doctor/checks/outputs/stale-build.test.js +282 -0
- package/src/lib/doctor/checks/project/data-files.js +56 -0
- package/src/lib/doctor/checks/project/data-files.test.js +125 -0
- package/src/lib/doctor/checks/project/dependencies.js +53 -0
- package/src/lib/doctor/checks/project/dependencies.test.js +71 -0
- package/src/lib/doctor/checks/project/index.js +11 -0
- package/src/lib/doctor/checks/project/quire-11ty.js +98 -0
- package/src/lib/doctor/checks/project/quire-11ty.test.js +170 -0
- package/src/lib/doctor/checks/project/quire-project.js +38 -0
- package/src/lib/doctor/checks/project/quire-project.test.js +47 -0
- package/src/lib/doctor/checks/tools/index.js +10 -0
- package/src/lib/doctor/checks/tools/pandoc-available.js +82 -0
- package/src/lib/doctor/checks/tools/pandoc-available.test.js +73 -0
- package/src/lib/doctor/checks/tools/prince-available.js +81 -0
- package/src/lib/doctor/checks/tools/prince-available.test.js +73 -0
- package/src/lib/doctor/constants.js +39 -0
- package/src/lib/doctor/formatDuration.js +108 -0
- package/src/lib/doctor/formatDuration.test.js +76 -0
- package/src/lib/doctor/formatters/human.js +257 -0
- package/src/lib/doctor/formatters/human.test.js +463 -0
- package/src/lib/doctor/formatters/index.js +8 -0
- package/src/lib/doctor/formatters/json.js +78 -0
- package/src/lib/doctor/formatters/json.test.js +174 -0
- package/src/lib/doctor/formatters/shared.js +129 -0
- package/src/lib/doctor/formatters/shared.test.js +194 -0
- package/src/lib/doctor/index.js +271 -0
- package/src/lib/doctor/index.test.js +797 -0
- package/src/lib/help/frontmatter.js +77 -0
- package/src/lib/help/frontmatter.test.js +139 -0
- package/src/lib/help/index.js +135 -0
- package/src/lib/help/index.test.js +160 -0
- package/src/lib/help/topics/configuration.md +77 -0
- package/src/lib/help/topics/debugging.md +69 -0
- package/src/lib/help/topics/epub.md +74 -0
- package/src/lib/help/topics/pdf.md +74 -0
- package/src/lib/help/topics/publishing.md +80 -0
- package/src/lib/help/topics/workflows.md +50 -0
- package/src/lib/platform.js +95 -0
- package/src/lib/project/build.js +44 -25
- package/src/lib/project/build.test.js +30 -8
- package/src/lib/project/detect.js +16 -2
- package/src/lib/project/index.js +18 -2
- package/src/lib/project/output-paths.js +87 -0
- package/src/lib/project/output-paths.test.js +66 -0
- package/src/lib/project/paths.js +48 -0
- package/src/main.js +38 -3
- package/src/packageConfig.js +17 -0
- package/src/validators/validate-data-files.js +154 -0
- package/src/validators/validate-data-files.test.js +217 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: EPUB Generation
|
|
3
|
+
description: Creating e-book publications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# EPUB Generation
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
quire epub --build # Build and generate EPUB
|
|
12
|
+
quire epub --build --open # Build, generate, and open EPUB
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## EPUB Engines
|
|
16
|
+
|
|
17
|
+
Quire supports two EPUB engines:
|
|
18
|
+
|
|
19
|
+
### epubjs (Default)
|
|
20
|
+
|
|
21
|
+
JavaScript-based EPUB generation.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
quire epub # Uses epubjs by default
|
|
25
|
+
quire epub --lib epubjs # Explicit epubjs
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Pandoc
|
|
29
|
+
|
|
30
|
+
Universal document converter with EPUB support. Requires separate installation.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
quire epub --lib pandoc # Use Pandoc
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
EPUB settings in `content/_data/config.yaml`:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
epub:
|
|
42
|
+
output: _site/downloads/my-publication.epub
|
|
43
|
+
# Additional EPUB-specific settings
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Troubleshooting
|
|
47
|
+
|
|
48
|
+
### EPUB fails validation
|
|
49
|
+
|
|
50
|
+
Common issues:
|
|
51
|
+
- Missing required metadata in `content/_data/publication.yaml`
|
|
52
|
+
- Invalid image formats (use JPEG or PNG)
|
|
53
|
+
- Broken internal links
|
|
54
|
+
|
|
55
|
+
### Images not appearing
|
|
56
|
+
|
|
57
|
+
1. Check image paths are relative
|
|
58
|
+
2. Ensure images are in supported formats
|
|
59
|
+
3. Verify images exist in the build output
|
|
60
|
+
|
|
61
|
+
### EPUB not opening in reader
|
|
62
|
+
|
|
63
|
+
1. Validate the EPUB file structure
|
|
64
|
+
2. Check for malformed HTML in content
|
|
65
|
+
3. Ensure all required files are included
|
|
66
|
+
|
|
67
|
+
## Testing Your EPUB
|
|
68
|
+
|
|
69
|
+
Open in different readers to verify:
|
|
70
|
+
- Apple Books (macOS/iOS)
|
|
71
|
+
- Calibre (cross-platform)
|
|
72
|
+
- Adobe Digital Editions
|
|
73
|
+
|
|
74
|
+
See full documentation: https://quire.getty.edu/docs-v1/epub-output/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: PDF Generation
|
|
3
|
+
description: Creating print-ready PDF publications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PDF Generation
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
quire pdf --build # Build and generate PDF
|
|
12
|
+
quire pdf --build --open # Build, generate, and open PDF
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## PDF Engines
|
|
16
|
+
|
|
17
|
+
Quire supports two PDF engines:
|
|
18
|
+
|
|
19
|
+
### Paged.js (Default)
|
|
20
|
+
|
|
21
|
+
Open-source, browser-based PDF generation. No additional installation required.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
quire pdf # Uses Paged.js by default
|
|
25
|
+
quire pdf --lib pagedjs # Explicit Paged.js
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### PrinceXML
|
|
29
|
+
|
|
30
|
+
Commercial PDF engine with advanced typography features. Requires separate installation.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
quire pdf --lib prince # Use PrinceXML
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**When to use PrinceXML:**
|
|
37
|
+
- Complex typography requirements
|
|
38
|
+
- Specific print production needs
|
|
39
|
+
- Advanced CSS paged media features
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
PDF settings in `content/_data/config.yaml`:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
pdf:
|
|
47
|
+
output: _site/downloads/my-publication.pdf
|
|
48
|
+
# Additional PDF-specific settings
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Troubleshooting
|
|
52
|
+
|
|
53
|
+
### PDF is blank or missing content
|
|
54
|
+
|
|
55
|
+
1. Ensure build completed successfully: `quire build`
|
|
56
|
+
2. Check that `_site/pdf.html` exists
|
|
57
|
+
3. Run with debug: `quire pdf --debug`
|
|
58
|
+
|
|
59
|
+
### Fonts not rendering correctly
|
|
60
|
+
|
|
61
|
+
- Ensure fonts are properly installed or embedded
|
|
62
|
+
- Check font paths in your CSS
|
|
63
|
+
|
|
64
|
+
### Page breaks in wrong places
|
|
65
|
+
|
|
66
|
+
Use CSS page break properties:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
.chapter {
|
|
70
|
+
page-break-before: always;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See full documentation: https://quire.getty.edu/docs-v1/pdf-output/
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Publishing
|
|
3
|
+
description: Deploying your Quire publication
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publishing Your Publication
|
|
7
|
+
|
|
8
|
+
## Build for Production
|
|
9
|
+
|
|
10
|
+
Always use a clean build for production:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
quire clean && quire build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This ensures all files are freshly generated without stale artifacts.
|
|
17
|
+
|
|
18
|
+
## Output Formats
|
|
19
|
+
|
|
20
|
+
### Web (HTML)
|
|
21
|
+
|
|
22
|
+
The default `quire build` generates a static HTML site in `_site/`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
quire build
|
|
26
|
+
# Output: _site/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Deploy the `_site/` directory to any static hosting service.
|
|
30
|
+
|
|
31
|
+
### PDF
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
quire pdf --build
|
|
35
|
+
# Output: _site/downloads/*.pdf
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### EPUB
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
quire epub --build
|
|
42
|
+
# Output: _site/downloads/*.epub
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Complete Publication Workflow
|
|
46
|
+
|
|
47
|
+
Generate all formats in one sequence:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
quire clean && quire build && quire pdf && quire epub
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Deployment Options
|
|
54
|
+
|
|
55
|
+
### GitHub Pages
|
|
56
|
+
|
|
57
|
+
1. Push `_site/` to a `gh-pages` branch
|
|
58
|
+
2. Configure GitHub Pages in repository settings
|
|
59
|
+
3. Access at `https://username.github.io/repo-name/`
|
|
60
|
+
|
|
61
|
+
### Netlify / Vercel
|
|
62
|
+
|
|
63
|
+
1. Connect your repository
|
|
64
|
+
2. Set build command: `quire build`
|
|
65
|
+
3. Set publish directory: `_site`
|
|
66
|
+
|
|
67
|
+
### Traditional Hosting
|
|
68
|
+
|
|
69
|
+
Upload the contents of `_site/` to your web server via FTP/SFTP.
|
|
70
|
+
|
|
71
|
+
## Pre-Publication Checklist
|
|
72
|
+
|
|
73
|
+
- [ ] Run `quire validate` to check for errors
|
|
74
|
+
- [ ] Review all content for accuracy
|
|
75
|
+
- [ ] Test links and navigation
|
|
76
|
+
- [ ] Verify images display correctly
|
|
77
|
+
- [ ] Check PDF and EPUB in multiple readers
|
|
78
|
+
- [ ] Test on different devices and browsers
|
|
79
|
+
|
|
80
|
+
See full documentation: https://quire.getty.edu/docs-v1/site-deploy/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Common Workflows
|
|
3
|
+
description: Step-by-step guides for common Quire tasks
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Common Workflows
|
|
7
|
+
|
|
8
|
+
## Starting a New Project
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
quire new my-book && cd my-book && quire preview
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Building for Web
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
quire build # Generate HTML site files
|
|
18
|
+
quire clean && quire build # Clean build (recommended for production)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Generating PDF
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
quire pdf --build # Build first, then generate PDF
|
|
25
|
+
quire pdf --build --open # Generate and open PDF
|
|
26
|
+
quire pdf --lib prince # Use PrinceXML instead of Paged.js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Generating EPUB
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
quire epub --build # Build first, then generate EPUB
|
|
33
|
+
quire epub --build --open # Generate and open EPUB
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Full Publication Build
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
quire clean && quire build && quire pdf && quire epub
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Troubleshooting
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
quire validate # Check YAML files for errors
|
|
46
|
+
quire info # Show version information
|
|
47
|
+
quire build --verbose # Build with detailed output
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
See full documentation: https://quire.getty.edu/docs-v1/
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform detection utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides OS detection and platform-specific helpers for the CLI.
|
|
5
|
+
*
|
|
6
|
+
* @module lib/platform
|
|
7
|
+
*/
|
|
8
|
+
import os from 'node:os'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Platform identifiers
|
|
12
|
+
* @readonly
|
|
13
|
+
* @enum {string}
|
|
14
|
+
*/
|
|
15
|
+
export const Platform = {
|
|
16
|
+
MACOS: 'macos',
|
|
17
|
+
WINDOWS: 'windows',
|
|
18
|
+
LINUX: 'linux',
|
|
19
|
+
UNKNOWN: 'unknown',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get the current platform identifier
|
|
24
|
+
* @returns {string} Platform identifier (macos, windows, linux, or unknown)
|
|
25
|
+
*/
|
|
26
|
+
export function getPlatform() {
|
|
27
|
+
switch (process.platform) {
|
|
28
|
+
case 'darwin':
|
|
29
|
+
return Platform.MACOS
|
|
30
|
+
case 'win32':
|
|
31
|
+
return Platform.WINDOWS
|
|
32
|
+
case 'linux':
|
|
33
|
+
return Platform.LINUX
|
|
34
|
+
default:
|
|
35
|
+
return Platform.UNKNOWN
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get a human-readable platform name
|
|
41
|
+
* @returns {string} Human-readable OS name (e.g., "macOS 14.0", "Windows 11", "Linux")
|
|
42
|
+
*/
|
|
43
|
+
export function getPlatformName() {
|
|
44
|
+
const platform = getPlatform()
|
|
45
|
+
const release = os.release()
|
|
46
|
+
|
|
47
|
+
switch (platform) {
|
|
48
|
+
case Platform.MACOS: {
|
|
49
|
+
// Darwin kernel version to macOS version mapping (approximate)
|
|
50
|
+
const majorVersion = parseInt(release.split('.')[0], 10)
|
|
51
|
+
// Darwin 23.x = macOS 14 (Sonoma), 22.x = macOS 13, etc.
|
|
52
|
+
const macOSVersion = majorVersion >= 20 ? majorVersion - 9 : majorVersion - 4
|
|
53
|
+
return `macOS ${macOSVersion >= 14 ? macOSVersion : release}`
|
|
54
|
+
}
|
|
55
|
+
case Platform.WINDOWS:
|
|
56
|
+
return `Windows (${release})`
|
|
57
|
+
case Platform.LINUX:
|
|
58
|
+
return `Linux (${release})`
|
|
59
|
+
default:
|
|
60
|
+
return `${process.platform} (${release})`
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if running on macOS
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
export function isMacOS() {
|
|
69
|
+
return process.platform === 'darwin'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if running on Windows
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
export function isWindows() {
|
|
77
|
+
return process.platform === 'win32'
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if running on Linux
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
export function isLinux() {
|
|
85
|
+
return process.platform === 'linux'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
Platform,
|
|
90
|
+
getPlatform,
|
|
91
|
+
getPlatformName,
|
|
92
|
+
isMacOS,
|
|
93
|
+
isWindows,
|
|
94
|
+
isLinux,
|
|
95
|
+
}
|
package/src/lib/project/build.js
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
* Build detection module
|
|
3
3
|
*
|
|
4
4
|
* Detects if build output exists and provides build status information.
|
|
5
|
+
* Uses shared output path resolution to ensure consistency with the
|
|
6
|
+
* doctor command and generation commands.
|
|
5
7
|
*
|
|
6
8
|
* @module lib/project/build
|
|
7
9
|
*/
|
|
8
10
|
import fs from 'node:fs'
|
|
9
11
|
import path from 'node:path'
|
|
10
12
|
import paths from './paths.js'
|
|
13
|
+
import { getPdfOutputPaths, getEpubOutputPaths, getEpubBuildDir } from './output-paths.js'
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Get build output information
|
|
@@ -17,45 +20,60 @@ import paths from './paths.js'
|
|
|
17
20
|
*/
|
|
18
21
|
export function getBuildInfo(projectRoot = paths.getProjectRoot()) {
|
|
19
22
|
const sitePath = path.join(projectRoot, '_site')
|
|
20
|
-
const
|
|
21
|
-
const pdfFiles = ['pagedjs.pdf', 'prince.pdf']
|
|
23
|
+
const epubBuildPath = getEpubBuildDir({ projectRoot })
|
|
22
24
|
|
|
23
25
|
const info = {
|
|
24
26
|
site: {
|
|
25
27
|
exists: fs.existsSync(sitePath),
|
|
26
28
|
path: sitePath,
|
|
27
|
-
|
|
29
|
+
lastModified: null,
|
|
28
30
|
},
|
|
29
31
|
epub: {
|
|
30
|
-
exists:
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
exists: false,
|
|
33
|
+
paths: [],
|
|
34
|
+
buildDir: epubBuildPath,
|
|
35
|
+
buildDirExists: fs.existsSync(epubBuildPath),
|
|
36
|
+
lastModified: null,
|
|
33
37
|
},
|
|
34
38
|
pdf: {
|
|
35
39
|
exists: false,
|
|
36
40
|
paths: [],
|
|
37
|
-
|
|
41
|
+
lastModified: null,
|
|
38
42
|
},
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
// Get
|
|
45
|
+
// Get last modified times if directories exist
|
|
42
46
|
if (info.site.exists) {
|
|
43
|
-
|
|
47
|
+
const { mtime: lastModified } = fs.statSync(sitePath)
|
|
48
|
+
info.site.lastModified = lastModified
|
|
44
49
|
}
|
|
45
|
-
if (info.epub.
|
|
46
|
-
|
|
50
|
+
if (info.epub.buildDirExists) {
|
|
51
|
+
const { mtime: lastModified } = fs.statSync(epubBuildPath)
|
|
52
|
+
info.epub.lastModified = lastModified
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
// Check for
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
// Check for EPUB files using shared path resolution
|
|
56
|
+
const epubPaths = getEpubOutputPaths({ projectRoot })
|
|
57
|
+
for (const epubPath of epubPaths) {
|
|
58
|
+
if (fs.existsSync(epubPath)) {
|
|
59
|
+
info.epub.exists = true
|
|
60
|
+
info.epub.paths.push(epubPath)
|
|
61
|
+
const { mtime: lastModified } = fs.statSync(epubPath)
|
|
62
|
+
if (!info.epub.lastModified || lastModified > info.epub.lastModified) {
|
|
63
|
+
info.epub.lastModified = lastModified
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check for PDF files using shared path resolution
|
|
69
|
+
const pdfPaths = getPdfOutputPaths({ projectRoot })
|
|
70
|
+
for (const pdfPath of pdfPaths) {
|
|
52
71
|
if (fs.existsSync(pdfPath)) {
|
|
53
72
|
info.pdf.exists = true
|
|
54
73
|
info.pdf.paths.push(pdfPath)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
info.pdf.mtime = mtime
|
|
74
|
+
const { mtime: lastModified } = fs.statSync(pdfPath)
|
|
75
|
+
if (!info.pdf.lastModified || lastModified > info.pdf.lastModified) {
|
|
76
|
+
info.pdf.lastModified = lastModified
|
|
59
77
|
}
|
|
60
78
|
}
|
|
61
79
|
}
|
|
@@ -77,20 +95,21 @@ export function hasSiteOutput(projectRoot = paths.getProjectRoot()) {
|
|
|
77
95
|
/**
|
|
78
96
|
* Check if epub build output exists
|
|
79
97
|
*
|
|
98
|
+
* Checks for the intermediate _epub build directory.
|
|
99
|
+
*
|
|
80
100
|
* @param {string} [projectRoot] - Project root directory (defaults to cwd)
|
|
81
101
|
* @returns {boolean} True if _epub directory exists
|
|
82
102
|
*/
|
|
83
103
|
export function hasEpubOutput(projectRoot = paths.getProjectRoot()) {
|
|
84
|
-
const epubPath =
|
|
104
|
+
const epubPath = getEpubBuildDir({ projectRoot })
|
|
85
105
|
return fs.existsSync(epubPath)
|
|
86
106
|
}
|
|
87
107
|
|
|
88
108
|
/**
|
|
89
109
|
* Check if PDF output exists
|
|
90
110
|
*
|
|
91
|
-
*
|
|
92
|
-
* -
|
|
93
|
-
* - Specific library output when lib option provided
|
|
111
|
+
* Uses shared path resolution to check all possible PDF output locations,
|
|
112
|
+
* including config-aware custom paths and default engine-named paths.
|
|
94
113
|
*
|
|
95
114
|
* @param {Object} [options]
|
|
96
115
|
* @param {string} [options.lib] - Specific library to check ('pagedjs' or 'prince')
|
|
@@ -105,9 +124,9 @@ export function hasPdfOutput(options = {}) {
|
|
|
105
124
|
return fs.existsSync(pdfPath)
|
|
106
125
|
}
|
|
107
126
|
|
|
108
|
-
// Check
|
|
109
|
-
const
|
|
110
|
-
return
|
|
127
|
+
// Check all possible PDF output locations
|
|
128
|
+
const pdfPaths = getPdfOutputPaths({ projectRoot })
|
|
129
|
+
return pdfPaths.some((pdfPath) => fs.existsSync(pdfPath))
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
/**
|
|
@@ -84,6 +84,7 @@ test('getBuildInfo returns correct status for existing builds', async (t) => {
|
|
|
84
84
|
vol.fromJSON({
|
|
85
85
|
[memfsPath('_site', 'index.html')]: '<html></html>',
|
|
86
86
|
[memfsPath('_epub', 'content.opf')]: '<package></package>',
|
|
87
|
+
[memfsPath('epubjs.epub')]: 'PK\x03\x04',
|
|
87
88
|
[memfsPath('pagedjs.pdf')]: '%PDF-1.4',
|
|
88
89
|
})
|
|
89
90
|
|
|
@@ -95,15 +96,17 @@ test('getBuildInfo returns correct status for existing builds', async (t) => {
|
|
|
95
96
|
|
|
96
97
|
t.true(info.site.exists)
|
|
97
98
|
t.is(info.site.path, nativePath('_site'))
|
|
98
|
-
t.truthy(info.site.
|
|
99
|
+
t.truthy(info.site.lastModified)
|
|
99
100
|
|
|
100
101
|
t.true(info.epub.exists)
|
|
101
|
-
t.
|
|
102
|
-
t.
|
|
102
|
+
t.true(info.epub.buildDirExists)
|
|
103
|
+
t.is(info.epub.buildDir, nativePath('_epub'))
|
|
104
|
+
t.true(info.epub.paths.includes(nativePath('epubjs.epub')))
|
|
105
|
+
t.truthy(info.epub.lastModified)
|
|
103
106
|
|
|
104
107
|
t.true(info.pdf.exists)
|
|
105
108
|
t.deepEqual(info.pdf.paths, [nativePath('pagedjs.pdf')])
|
|
106
|
-
t.truthy(info.pdf.
|
|
109
|
+
t.truthy(info.pdf.lastModified)
|
|
107
110
|
})
|
|
108
111
|
|
|
109
112
|
test('getBuildInfo returns correct status for missing builds', async (t) => {
|
|
@@ -120,14 +123,15 @@ test('getBuildInfo returns correct status for missing builds', async (t) => {
|
|
|
120
123
|
const info = getBuildInfo(testRoot)
|
|
121
124
|
|
|
122
125
|
t.false(info.site.exists)
|
|
123
|
-
t.is(info.site.
|
|
126
|
+
t.is(info.site.lastModified, null)
|
|
124
127
|
|
|
125
128
|
t.false(info.epub.exists)
|
|
126
|
-
t.
|
|
129
|
+
t.false(info.epub.buildDirExists)
|
|
130
|
+
t.is(info.epub.lastModified, null)
|
|
127
131
|
|
|
128
132
|
t.false(info.pdf.exists)
|
|
129
133
|
t.deepEqual(info.pdf.paths, [])
|
|
130
|
-
t.is(info.pdf.
|
|
134
|
+
t.is(info.pdf.lastModified, null)
|
|
131
135
|
})
|
|
132
136
|
|
|
133
137
|
test('getBuildInfo returns multiple PDF paths when both exist', async (t) => {
|
|
@@ -148,7 +152,25 @@ test('getBuildInfo returns multiple PDF paths when both exist', async (t) => {
|
|
|
148
152
|
t.is(info.pdf.paths.length, 2)
|
|
149
153
|
t.true(info.pdf.paths.includes(nativePath('pagedjs.pdf')))
|
|
150
154
|
t.true(info.pdf.paths.includes(nativePath('prince.pdf')))
|
|
151
|
-
t.truthy(info.pdf.
|
|
155
|
+
t.truthy(info.pdf.lastModified)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('getBuildInfo detects epub build dir without .epub files', async (t) => {
|
|
159
|
+
const { vol } = t.context
|
|
160
|
+
|
|
161
|
+
vol.fromJSON({
|
|
162
|
+
[memfsPath('_epub', 'content.opf')]: '<package></package>',
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const { getBuildInfo } = await esmock('./build.js', {
|
|
166
|
+
'node:fs': createFsFromVolume(vol),
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const info = getBuildInfo(testRoot)
|
|
170
|
+
|
|
171
|
+
t.false(info.epub.exists, 'no .epub files should mean exists is false')
|
|
172
|
+
t.true(info.epub.buildDirExists, '_epub directory should be detected')
|
|
173
|
+
t.truthy(info.epub.lastModified, 'lastModified from _epub dir should be present')
|
|
152
174
|
})
|
|
153
175
|
|
|
154
176
|
test('requireBuildOutput throws when site output missing', async (t) => {
|
|
@@ -7,7 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import fs from 'node:fs'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Files that indicate a Quire project directory.
|
|
12
|
+
*
|
|
13
|
+
* These marker files are created by `quire new` or exist in Quire project templates.
|
|
14
|
+
* The presence of any one of these files indicates the directory is a Quire project root.
|
|
15
|
+
*
|
|
16
|
+
* @constant {ReadonlyArray<string>}
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Check if a file is a project marker
|
|
20
|
+
* if (PROJECT_MARKERS.includes(filename)) {
|
|
21
|
+
* console.log('This is a Quire project root')
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
export const PROJECT_MARKERS = Object.freeze([
|
|
11
25
|
'.eleventy.js',
|
|
12
26
|
'.quire',
|
|
13
27
|
'.quire-11ty',
|
|
@@ -29,5 +43,5 @@ const QUIRE_DOT_FILES = Object.freeze([
|
|
|
29
43
|
*/
|
|
30
44
|
export default function (dirpath) {
|
|
31
45
|
return fs.readdirSync(dirpath)
|
|
32
|
-
.find((entry) =>
|
|
46
|
+
.find((entry) => PROJECT_MARKERS.includes(entry))
|
|
33
47
|
}
|
package/src/lib/project/index.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Provides project-level concerns including paths, detection, configuration,
|
|
5
5
|
* build status, and version management.
|
|
6
6
|
*/
|
|
7
|
-
import paths, { Paths } from './paths.js'
|
|
8
|
-
import detect from './detect.js'
|
|
7
|
+
import paths, { DATA_DIR, Paths, REQUIRED_DATA_FILES, SOURCE_DIRECTORIES } from './paths.js'
|
|
8
|
+
import detect, { PROJECT_MARKERS } from './detect.js'
|
|
9
9
|
import { loadProjectConfig } from './config.js'
|
|
10
10
|
import {
|
|
11
11
|
getBuildInfo,
|
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
hasSiteOutput,
|
|
15
15
|
requireBuildOutput,
|
|
16
16
|
} from './build.js'
|
|
17
|
+
import {
|
|
18
|
+
getPdfOutputPaths,
|
|
19
|
+
getEpubOutputPaths,
|
|
20
|
+
getEpubBuildDir,
|
|
21
|
+
PDF_ENGINES,
|
|
22
|
+
EPUB_ENGINES,
|
|
23
|
+
} from './output-paths.js'
|
|
17
24
|
import {
|
|
18
25
|
getVersion,
|
|
19
26
|
setVersion,
|
|
@@ -23,8 +30,17 @@ import {
|
|
|
23
30
|
} from './version.js'
|
|
24
31
|
|
|
25
32
|
export {
|
|
33
|
+
DATA_DIR,
|
|
34
|
+
EPUB_ENGINES,
|
|
35
|
+
PDF_ENGINES,
|
|
36
|
+
PROJECT_MARKERS,
|
|
37
|
+
REQUIRED_DATA_FILES,
|
|
38
|
+
SOURCE_DIRECTORIES,
|
|
26
39
|
detect,
|
|
27
40
|
getBuildInfo,
|
|
41
|
+
getEpubBuildDir,
|
|
42
|
+
getEpubOutputPaths,
|
|
43
|
+
getPdfOutputPaths,
|
|
28
44
|
hasEpubOutput,
|
|
29
45
|
hasPdfOutput,
|
|
30
46
|
hasSiteOutput,
|