@vivliostyle/cli 8.17.0 → 9.0.0-next.0
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/dist/browser.d.ts +12 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +108 -13
- package/dist/browser.js.map +1 -1
- package/dist/commands/build.js +10 -44
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/build.parser.d.ts +0 -5
- package/dist/commands/build.parser.d.ts.map +1 -1
- package/dist/commands/build.parser.js +15 -23
- package/dist/commands/build.parser.js.map +1 -1
- package/dist/commands/cli-flags.d.ts +42 -0
- package/dist/commands/cli-flags.d.ts.map +1 -0
- package/dist/commands/cli-flags.js +58 -0
- package/dist/commands/cli-flags.js.map +1 -0
- package/dist/commands/init.js +4 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/preview.js +4 -37
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/preview.parser.d.ts.map +1 -1
- package/dist/commands/preview.parser.js +6 -4
- package/dist/commands/preview.parser.js.map +1 -1
- package/dist/config/load.d.ts +7 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +72 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/merge.d.ts +4 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +78 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/{input/config.d.ts → config/resolve.d.ts} +81 -82
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +727 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/{input → config}/schema.d.ts +6023 -3542
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +562 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/vite.d.ts +53 -0
- package/dist/config/vite.d.ts.map +1 -0
- package/dist/config/vite.js +19 -0
- package/dist/config/vite.js.map +1 -0
- package/dist/const.d.ts +2 -0
- package/dist/const.d.ts.map +1 -1
- package/dist/const.js +2 -0
- package/dist/const.js.map +1 -1
- package/dist/container.d.ts +12 -3
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +130 -30
- package/dist/container.js.map +1 -1
- package/dist/core/build.d.ts +3 -0
- package/dist/core/build.d.ts.map +1 -0
- package/dist/core/build.js +168 -0
- package/dist/core/build.js.map +1 -0
- package/dist/core/init.d.ts +3 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/{init.js → core/init.js} +14 -19
- package/dist/core/init.js.map +1 -0
- package/dist/core/preview.d.ts +3 -0
- package/dist/core/preview.d.ts.map +1 -0
- package/dist/core/preview.js +93 -0
- package/dist/core/preview.js.map +1 -0
- package/dist/index.d.ts +32 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -3
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +161 -0
- package/dist/logger.js.map +1 -0
- package/dist/output/epub.d.ts.map +1 -1
- package/dist/output/epub.js +17 -15
- package/dist/output/epub.js.map +1 -1
- package/dist/output/pdf-postprocess.d.ts +2 -3
- package/dist/output/pdf-postprocess.d.ts.map +1 -1
- package/dist/output/pdf-postprocess.js +94 -29
- package/dist/output/pdf-postprocess.js.map +1 -1
- package/dist/output/pdf.d.ts +4 -7
- package/dist/output/pdf.d.ts.map +1 -1
- package/dist/output/pdf.js +77 -141
- package/dist/output/pdf.js.map +1 -1
- package/dist/output/webbook.d.ts +10 -10
- package/dist/output/webbook.d.ts.map +1 -1
- package/dist/output/webbook.js +44 -62
- package/dist/output/webbook.js.map +1 -1
- package/dist/processor/compile.d.ts +24 -10
- package/dist/processor/compile.d.ts.map +1 -1
- package/dist/processor/compile.js +195 -130
- package/dist/processor/compile.js.map +1 -1
- package/dist/processor/html.d.ts +29 -17
- package/dist/processor/html.d.ts.map +1 -1
- package/dist/processor/html.js +112 -88
- package/dist/processor/html.js.map +1 -1
- package/dist/processor/markdown.d.ts +1 -1
- package/dist/processor/markdown.d.ts.map +1 -1
- package/dist/processor/theme.d.ts +3 -3
- package/dist/processor/theme.d.ts.map +1 -1
- package/dist/processor/theme.js +29 -53
- package/dist/processor/theme.js.map +1 -1
- package/dist/server.d.ts +17 -38
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +76 -102
- package/dist/server.js.map +1 -1
- package/dist/util.d.ts +9 -29
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +54 -158
- package/dist/util.js.map +1 -1
- package/dist/vite/plugin-util.d.ts +6 -0
- package/dist/vite/plugin-util.d.ts.map +1 -0
- package/dist/vite/plugin-util.js +20 -0
- package/dist/vite/plugin-util.js.map +1 -0
- package/dist/vite/vite-plugin-browser.d.ts +8 -0
- package/dist/vite/vite-plugin-browser.d.ts.map +1 -0
- package/dist/vite/vite-plugin-browser.js +57 -0
- package/dist/vite/vite-plugin-browser.js.map +1 -0
- package/dist/vite/vite-plugin-dev-server.d.ts +8 -0
- package/dist/vite/vite-plugin-dev-server.d.ts.map +1 -0
- package/dist/vite/vite-plugin-dev-server.js +267 -0
- package/dist/vite/vite-plugin-dev-server.js.map +1 -0
- package/dist/vite/vite-plugin-static-serve.d.ts +8 -0
- package/dist/vite/vite-plugin-static-serve.d.ts.map +1 -0
- package/dist/vite/vite-plugin-static-serve.js +24 -0
- package/dist/vite/vite-plugin-static-serve.js.map +1 -0
- package/dist/vite/vite-plugin-viewer.d.ts +8 -0
- package/dist/vite/vite-plugin-viewer.d.ts.map +1 -0
- package/dist/vite/vite-plugin-viewer.js +52 -0
- package/dist/vite/vite-plugin-viewer.js.map +1 -0
- package/dist/vite-adapter.d.ts +3 -0
- package/dist/vite-adapter.d.ts.map +1 -0
- package/dist/vite-adapter.js +27 -0
- package/dist/vite-adapter.js.map +1 -0
- package/package.json +13 -15
- package/dist/build.d.ts +0 -21
- package/dist/build.d.ts.map +0 -1
- package/dist/build.js +0 -119
- package/dist/build.js.map +0 -1
- package/dist/init.d.ts +0 -16
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js.map +0 -1
- package/dist/input/config.d.ts.map +0 -1
- package/dist/input/config.js +0 -807
- package/dist/input/config.js.map +0 -1
- package/dist/input/input-types.d.ts +0 -34
- package/dist/input/input-types.d.ts.map +0 -1
- package/dist/input/input-types.js +0 -34
- package/dist/input/input-types.js.map +0 -1
- package/dist/input/schema.d.ts.map +0 -1
- package/dist/input/schema.js +0 -233
- package/dist/input/schema.js.map +0 -1
- package/dist/output/output-types.d.ts +0 -26
- package/dist/output/output-types.d.ts.map +0 -1
- package/dist/output/output-types.js +0 -23
- package/dist/output/output-types.js.map +0 -1
- package/dist/preview.d.ts +0 -11
- package/dist/preview.d.ts.map +0 -1
- package/dist/preview.js +0 -191
- package/dist/preview.js.map +0 -1
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
import { VFM } from '@vivliostyle/vfm';
|
|
2
|
+
import { lookup as mime } from 'mime-types';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import upath from 'upath';
|
|
6
|
+
import { getExecutableBrowserPath } from '../browser.js';
|
|
7
|
+
import { COVER_HTML_FILENAME, COVER_HTML_IMAGE_ALT, EPUB_OUTPUT_VERSION, MANIFEST_FILENAME, TOC_FILENAME, TOC_TITLE, } from '../const.js';
|
|
8
|
+
import { CONTAINER_IMAGE, CONTAINER_LOCAL_HOSTNAME } from '../container.js';
|
|
9
|
+
import { Logger } from '../logger.js';
|
|
10
|
+
import { readMarkdownMetadata } from '../processor/markdown.js';
|
|
11
|
+
import { parsePackageName } from '../processor/theme.js';
|
|
12
|
+
import { cwd as defaultCwd, getEpubRootDir, isInContainer, isValidUri, pathEquals, readJSON, statFileSync, touchTmpFile, } from '../util.js';
|
|
13
|
+
export const manuscriptMediaTypes = [
|
|
14
|
+
'text/markdown',
|
|
15
|
+
'text/html',
|
|
16
|
+
'application/xhtml+xml',
|
|
17
|
+
];
|
|
18
|
+
const DEFAULT_ASSET_EXTENSIONS = [
|
|
19
|
+
'png',
|
|
20
|
+
'jpg',
|
|
21
|
+
'jpeg',
|
|
22
|
+
'svg',
|
|
23
|
+
'gif',
|
|
24
|
+
'webp',
|
|
25
|
+
'apng',
|
|
26
|
+
'ttf',
|
|
27
|
+
'otf',
|
|
28
|
+
'woff',
|
|
29
|
+
'woff2',
|
|
30
|
+
];
|
|
31
|
+
function isManuscriptMediaType(mediaType) {
|
|
32
|
+
return !!(mediaType && manuscriptMediaTypes.includes(mediaType));
|
|
33
|
+
}
|
|
34
|
+
export function isWebPubConfig(config) {
|
|
35
|
+
return config.viewerInput.type === 'webpub';
|
|
36
|
+
}
|
|
37
|
+
// parse theme locator
|
|
38
|
+
export function parseTheme({ theme, context, workspaceDir, themesDir, }) {
|
|
39
|
+
const { specifier, import: importPath } = typeof theme === 'string' ? { specifier: theme, import: undefined } : theme;
|
|
40
|
+
// url
|
|
41
|
+
if (isValidUri(specifier)) {
|
|
42
|
+
return {
|
|
43
|
+
type: 'uri',
|
|
44
|
+
name: upath.basename(specifier),
|
|
45
|
+
location: specifier,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// bare .css file
|
|
49
|
+
const stylePath = upath.resolve(context, specifier);
|
|
50
|
+
if (fs.existsSync(stylePath) && stylePath.endsWith('.css')) {
|
|
51
|
+
const sourceRelPath = upath.relative(context, stylePath);
|
|
52
|
+
return {
|
|
53
|
+
type: 'file',
|
|
54
|
+
name: upath.basename(specifier),
|
|
55
|
+
source: stylePath,
|
|
56
|
+
location: upath.resolve(workspaceDir, sourceRelPath),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// node_modules, local pkg
|
|
60
|
+
const parsed = parsePackageName(specifier, context);
|
|
61
|
+
if (!parsed) {
|
|
62
|
+
throw new Error(`Invalid package name: ${specifier}`);
|
|
63
|
+
}
|
|
64
|
+
// To security reason, Vivliostyle CLI disallow other than npm registry or local file as download source
|
|
65
|
+
// TODO: Add option that user can allow an unofficial registry explicitly
|
|
66
|
+
if (!parsed.registry && parsed.type !== 'directory') {
|
|
67
|
+
throw new Error(`This package specifier is not allowed: ${specifier}`);
|
|
68
|
+
}
|
|
69
|
+
let name = parsed.name;
|
|
70
|
+
let resolvedSpecifier = specifier;
|
|
71
|
+
if (parsed.type === 'directory' && parsed.fetchSpec) {
|
|
72
|
+
const pkgJsonPath = upath.join(parsed.fetchSpec, 'package.json');
|
|
73
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
74
|
+
const packageJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
75
|
+
name = packageJson.name;
|
|
76
|
+
resolvedSpecifier = parsed.fetchSpec;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!name) {
|
|
80
|
+
throw new Error(`Could not determine the package name: ${specifier}`);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
type: 'package',
|
|
84
|
+
name,
|
|
85
|
+
specifier: resolvedSpecifier,
|
|
86
|
+
location: upath.join(themesDir, 'node_modules', name),
|
|
87
|
+
importPath,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function parsePageSize(size) {
|
|
91
|
+
const [width, height, ...others] = `${size}`.split(',');
|
|
92
|
+
if (!width || others.length) {
|
|
93
|
+
throw new Error(`Cannot parse size: ${size}`);
|
|
94
|
+
}
|
|
95
|
+
else if (width && height) {
|
|
96
|
+
return {
|
|
97
|
+
width,
|
|
98
|
+
height,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
return {
|
|
103
|
+
format: width,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function parseFileMetadata({ contentType, sourcePath, workspaceDir, themesDir, }) {
|
|
108
|
+
const sourceDir = upath.dirname(sourcePath);
|
|
109
|
+
let title;
|
|
110
|
+
let themes;
|
|
111
|
+
if (contentType === 'text/markdown') {
|
|
112
|
+
const metadata = readMarkdownMetadata(sourcePath);
|
|
113
|
+
title = metadata.title;
|
|
114
|
+
if (metadata.vfm?.theme && themesDir) {
|
|
115
|
+
themes = [metadata.vfm.theme]
|
|
116
|
+
.flat()
|
|
117
|
+
.filter((entry) => !!entry && (typeof entry === 'string' || typeof entry === 'object'))
|
|
118
|
+
.map((theme) => parseTheme({
|
|
119
|
+
theme,
|
|
120
|
+
context: sourceDir,
|
|
121
|
+
workspaceDir,
|
|
122
|
+
themesDir,
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const content = fs.readFileSync(sourcePath, 'utf8');
|
|
128
|
+
title = content.match(/<title>([^<]*)<\/title>/)?.[1] || undefined;
|
|
129
|
+
}
|
|
130
|
+
return { title, themes };
|
|
131
|
+
}
|
|
132
|
+
export function resolveTaskConfig(config, options) {
|
|
133
|
+
const context = options.cwd ?? defaultCwd;
|
|
134
|
+
Logger.debug('context directory', context);
|
|
135
|
+
Logger.debug('inlineOptions', options);
|
|
136
|
+
Logger.debug('vivliostyle.config.js', config);
|
|
137
|
+
const entryContextDir = config.entryContext
|
|
138
|
+
? upath.resolve(context, config.entryContext)
|
|
139
|
+
: context;
|
|
140
|
+
const language = config.language;
|
|
141
|
+
const readingProgression = config.readingProgression;
|
|
142
|
+
const size = config.size ? parsePageSize(config.size) : undefined;
|
|
143
|
+
const cropMarks = options.cropMarks ?? false;
|
|
144
|
+
const bleed = options.bleed;
|
|
145
|
+
const cropOffset = options.cropOffset;
|
|
146
|
+
const css = options.css;
|
|
147
|
+
const customStyle = options.style &&
|
|
148
|
+
(isValidUri(options.style)
|
|
149
|
+
? options.style
|
|
150
|
+
: pathToFileURL(options.style).href);
|
|
151
|
+
const customUserStyle = options.userStyle &&
|
|
152
|
+
(isValidUri(options.userStyle)
|
|
153
|
+
? options.userStyle
|
|
154
|
+
: pathToFileURL(options.userStyle).href);
|
|
155
|
+
const singleDoc = options.singleDoc ?? false;
|
|
156
|
+
const quick = options.quick ?? false;
|
|
157
|
+
const temporaryFilePrefix = config.temporaryFilePrefix ?? `.vs-${Date.now()}.`;
|
|
158
|
+
const documentProcessorFactory = config?.documentProcessor ?? VFM;
|
|
159
|
+
const vfmOptions = {
|
|
160
|
+
...config?.vfm,
|
|
161
|
+
hardLineBreaks: config?.vfm?.hardLineBreaks ?? false,
|
|
162
|
+
disableFormatHtml: config?.vfm?.disableFormatHtml ?? false,
|
|
163
|
+
};
|
|
164
|
+
const timeout = config.timeout ?? 120_000; // 2 minutes
|
|
165
|
+
const sandbox = options.sandbox ?? false;
|
|
166
|
+
const browserType = config.browser ?? 'chromium';
|
|
167
|
+
const proxyServer = options.proxyServer ?? process.env.HTTP_PROXY ?? undefined;
|
|
168
|
+
const proxy = proxyServer
|
|
169
|
+
? {
|
|
170
|
+
server: proxyServer,
|
|
171
|
+
bypass: options.proxyBypass ?? process.env.NOPROXY ?? undefined,
|
|
172
|
+
username: options.proxyUser,
|
|
173
|
+
password: options.proxyPass,
|
|
174
|
+
}
|
|
175
|
+
: undefined;
|
|
176
|
+
const executableBrowser = options.executableBrowser ?? getExecutableBrowserPath(browserType);
|
|
177
|
+
const image = config.image ?? CONTAINER_IMAGE;
|
|
178
|
+
const viewer = config.viewer ?? undefined;
|
|
179
|
+
const viewerParam = config.viewerParam ?? undefined;
|
|
180
|
+
const logLevel = options.logLevel ?? 'silent';
|
|
181
|
+
const ignoreHttpsErrors = options.ignoreHttpsErrors ?? false;
|
|
182
|
+
const base = config.base ?? '/vivliostyle';
|
|
183
|
+
const staticRoutes = config.static ?? {};
|
|
184
|
+
const viteConfig = config.vite;
|
|
185
|
+
const viteConfigFile = config.viteConfigFile ?? true;
|
|
186
|
+
const outputs = (() => {
|
|
187
|
+
const defaultPdfOptions = {
|
|
188
|
+
format: 'pdf',
|
|
189
|
+
renderMode: 'local',
|
|
190
|
+
preflight: config.pressReady ? 'press-ready' : undefined,
|
|
191
|
+
preflightOption: [],
|
|
192
|
+
};
|
|
193
|
+
if (config.output) {
|
|
194
|
+
return config.output.map((target) => {
|
|
195
|
+
const outputPath = upath.resolve(context, target.path);
|
|
196
|
+
const format = target.format;
|
|
197
|
+
switch (format) {
|
|
198
|
+
case 'pdf':
|
|
199
|
+
return {
|
|
200
|
+
...defaultPdfOptions,
|
|
201
|
+
...target,
|
|
202
|
+
format,
|
|
203
|
+
path: outputPath,
|
|
204
|
+
};
|
|
205
|
+
case 'epub':
|
|
206
|
+
return {
|
|
207
|
+
...target,
|
|
208
|
+
format,
|
|
209
|
+
path: outputPath,
|
|
210
|
+
version: EPUB_OUTPUT_VERSION,
|
|
211
|
+
};
|
|
212
|
+
case 'webpub':
|
|
213
|
+
return {
|
|
214
|
+
...target,
|
|
215
|
+
format,
|
|
216
|
+
path: outputPath,
|
|
217
|
+
};
|
|
218
|
+
default:
|
|
219
|
+
return format;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
// Outputs a pdf file if any output configuration is not set
|
|
224
|
+
const filename = config.title ? `${config.title}.pdf` : 'output.pdf';
|
|
225
|
+
return [
|
|
226
|
+
{
|
|
227
|
+
...defaultPdfOptions,
|
|
228
|
+
path: upath.resolve(context, filename),
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
})();
|
|
232
|
+
const { server, rootUrl } = (() => {
|
|
233
|
+
let host = config.server?.host ?? false;
|
|
234
|
+
const port = config.server?.port ?? 13000;
|
|
235
|
+
if (outputs.some((target) => target.format === 'pdf' && target.renderMode === 'docker')) {
|
|
236
|
+
// Docker render mode requires wildcard host to allow access from the container
|
|
237
|
+
host = true;
|
|
238
|
+
}
|
|
239
|
+
const rootHostname = isInContainer()
|
|
240
|
+
? CONTAINER_LOCAL_HOSTNAME
|
|
241
|
+
: !host
|
|
242
|
+
? 'localhost'
|
|
243
|
+
: host === true
|
|
244
|
+
? '0.0.0.0'
|
|
245
|
+
: host;
|
|
246
|
+
return {
|
|
247
|
+
server: {
|
|
248
|
+
host,
|
|
249
|
+
port,
|
|
250
|
+
proxy: config.server?.proxy ?? {},
|
|
251
|
+
},
|
|
252
|
+
rootUrl: `http://${rootHostname}:${port}`,
|
|
253
|
+
};
|
|
254
|
+
})();
|
|
255
|
+
const cover = config.cover && {
|
|
256
|
+
src: upath.resolve(entryContextDir, config.cover.src),
|
|
257
|
+
name: config.cover.name || COVER_HTML_IMAGE_ALT,
|
|
258
|
+
};
|
|
259
|
+
const copyAsset = {
|
|
260
|
+
includes: config.copyAsset?.includes ?? config.includeAssets ?? [],
|
|
261
|
+
excludes: config.copyAsset?.excludes ?? [],
|
|
262
|
+
fileExtensions: [
|
|
263
|
+
...new Set([
|
|
264
|
+
...DEFAULT_ASSET_EXTENSIONS,
|
|
265
|
+
...(config.copyAsset?.includeFileExtensions ?? []),
|
|
266
|
+
]),
|
|
267
|
+
].filter((ext) => !(config.copyAsset?.excludeFileExtensions ?? []).includes(ext)),
|
|
268
|
+
};
|
|
269
|
+
const themeIndexes = new Set();
|
|
270
|
+
const projectConfig = !options.config && options.input
|
|
271
|
+
? resolveSingleInputConfig({
|
|
272
|
+
config,
|
|
273
|
+
input: options.input,
|
|
274
|
+
context,
|
|
275
|
+
temporaryFilePrefix,
|
|
276
|
+
themeIndexes,
|
|
277
|
+
})
|
|
278
|
+
: resolveComposedProjectConfig({
|
|
279
|
+
config,
|
|
280
|
+
context,
|
|
281
|
+
entryContextDir,
|
|
282
|
+
outputs,
|
|
283
|
+
temporaryFilePrefix,
|
|
284
|
+
themeIndexes,
|
|
285
|
+
rootUrl,
|
|
286
|
+
cover,
|
|
287
|
+
});
|
|
288
|
+
const resolvedConfig = {
|
|
289
|
+
...projectConfig,
|
|
290
|
+
context,
|
|
291
|
+
entryContextDir,
|
|
292
|
+
outputs,
|
|
293
|
+
themeIndexes,
|
|
294
|
+
copyAsset,
|
|
295
|
+
temporaryFilePrefix,
|
|
296
|
+
size,
|
|
297
|
+
cropMarks,
|
|
298
|
+
bleed,
|
|
299
|
+
cropOffset,
|
|
300
|
+
css,
|
|
301
|
+
customStyle,
|
|
302
|
+
customUserStyle,
|
|
303
|
+
singleDoc,
|
|
304
|
+
quick,
|
|
305
|
+
language,
|
|
306
|
+
readingProgression,
|
|
307
|
+
documentProcessorFactory,
|
|
308
|
+
vfmOptions,
|
|
309
|
+
cover,
|
|
310
|
+
timeout,
|
|
311
|
+
sandbox,
|
|
312
|
+
executableBrowser,
|
|
313
|
+
browserType,
|
|
314
|
+
proxy,
|
|
315
|
+
image,
|
|
316
|
+
viewer,
|
|
317
|
+
viewerParam,
|
|
318
|
+
logLevel,
|
|
319
|
+
ignoreHttpsErrors,
|
|
320
|
+
base,
|
|
321
|
+
server,
|
|
322
|
+
static: staticRoutes,
|
|
323
|
+
rootUrl,
|
|
324
|
+
viteConfig,
|
|
325
|
+
viteConfigFile,
|
|
326
|
+
};
|
|
327
|
+
Logger.debug('resolvedConfig', JSON.stringify(resolvedConfig, null, 2));
|
|
328
|
+
return resolvedConfig;
|
|
329
|
+
}
|
|
330
|
+
function resolveSingleInputConfig({ config, input, context, temporaryFilePrefix, themeIndexes, }) {
|
|
331
|
+
Logger.debug('entering single entry config mode');
|
|
332
|
+
let sourcePath;
|
|
333
|
+
let workspaceDir;
|
|
334
|
+
const inputFormat = input.format;
|
|
335
|
+
const title = config?.title;
|
|
336
|
+
const author = config?.author;
|
|
337
|
+
const entries = [];
|
|
338
|
+
const exportAliases = [];
|
|
339
|
+
if (isValidUri(input.entry)) {
|
|
340
|
+
sourcePath = input.entry;
|
|
341
|
+
workspaceDir = context;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
sourcePath = upath.resolve(context, input.entry);
|
|
345
|
+
// Check file exists
|
|
346
|
+
statFileSync(sourcePath);
|
|
347
|
+
switch (input.format) {
|
|
348
|
+
case 'webbook':
|
|
349
|
+
workspaceDir = context;
|
|
350
|
+
break;
|
|
351
|
+
case 'markdown':
|
|
352
|
+
case 'pub-manifest':
|
|
353
|
+
case 'epub':
|
|
354
|
+
workspaceDir = upath.dirname(sourcePath);
|
|
355
|
+
break;
|
|
356
|
+
case 'epub-opf': {
|
|
357
|
+
const rootDir = getEpubRootDir(sourcePath);
|
|
358
|
+
if (!rootDir) {
|
|
359
|
+
throw new Error(`Could not determine the EPUB root directory for the OPF file: ${sourcePath}`);
|
|
360
|
+
}
|
|
361
|
+
workspaceDir = rootDir;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
default:
|
|
365
|
+
return input.format;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const themesDir = upath.resolve(workspaceDir, 'themes');
|
|
369
|
+
if (input.format === 'markdown') {
|
|
370
|
+
// Single input file; create temporary file
|
|
371
|
+
const contentType = 'text/markdown';
|
|
372
|
+
const metadata = parseFileMetadata({
|
|
373
|
+
contentType,
|
|
374
|
+
sourcePath,
|
|
375
|
+
workspaceDir,
|
|
376
|
+
});
|
|
377
|
+
const relDir = upath.relative(context, upath.dirname(sourcePath));
|
|
378
|
+
const target = upath
|
|
379
|
+
.resolve(workspaceDir, relDir, `${temporaryFilePrefix}${upath.basename(sourcePath)}`)
|
|
380
|
+
.replace(/\.md$/, '.html');
|
|
381
|
+
touchTmpFile(target);
|
|
382
|
+
const themes = metadata.themes ??
|
|
383
|
+
config.theme?.map((theme) => parseTheme({
|
|
384
|
+
theme,
|
|
385
|
+
context,
|
|
386
|
+
workspaceDir,
|
|
387
|
+
themesDir,
|
|
388
|
+
})) ??
|
|
389
|
+
[];
|
|
390
|
+
themes.forEach((t) => themeIndexes.add(t));
|
|
391
|
+
entries.push({
|
|
392
|
+
contentType,
|
|
393
|
+
source: {
|
|
394
|
+
type: 'file',
|
|
395
|
+
pathname: sourcePath,
|
|
396
|
+
contentType,
|
|
397
|
+
},
|
|
398
|
+
target,
|
|
399
|
+
title: metadata.title,
|
|
400
|
+
themes,
|
|
401
|
+
});
|
|
402
|
+
exportAliases.push({
|
|
403
|
+
source: target,
|
|
404
|
+
target: upath.resolve(upath.dirname(target), upath.basename(sourcePath).replace(/\.md$/, '.html')),
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
let fallbackTitle;
|
|
408
|
+
let viewerInput;
|
|
409
|
+
if (inputFormat === 'markdown') {
|
|
410
|
+
// create temporary manifest file
|
|
411
|
+
const manifestPath = upath.resolve(workspaceDir, `${temporaryFilePrefix}${MANIFEST_FILENAME}`);
|
|
412
|
+
touchTmpFile(manifestPath);
|
|
413
|
+
exportAliases.push({
|
|
414
|
+
source: manifestPath,
|
|
415
|
+
target: upath.resolve(workspaceDir, MANIFEST_FILENAME),
|
|
416
|
+
});
|
|
417
|
+
fallbackTitle =
|
|
418
|
+
entries.length === 1 && entries[0].title
|
|
419
|
+
? entries[0].title
|
|
420
|
+
: upath.basename(sourcePath);
|
|
421
|
+
viewerInput = {
|
|
422
|
+
type: 'webpub',
|
|
423
|
+
manifestPath,
|
|
424
|
+
needToGenerateManifest: true,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
else if (inputFormat === 'webbook') {
|
|
428
|
+
const url = isValidUri(sourcePath)
|
|
429
|
+
? new URL(sourcePath)
|
|
430
|
+
: pathToFileURL(sourcePath);
|
|
431
|
+
// Ensures trailing slash or explicit HTML extensions
|
|
432
|
+
if (/^https?:/i.test(url.protocol) &&
|
|
433
|
+
!url.pathname.endsWith('/') &&
|
|
434
|
+
!/\.html?$/.test(url.pathname)) {
|
|
435
|
+
url.pathname = `${url.pathname}/`;
|
|
436
|
+
}
|
|
437
|
+
viewerInput = { type: 'webbook', webbookEntryUrl: url.href };
|
|
438
|
+
}
|
|
439
|
+
else if (inputFormat === 'pub-manifest') {
|
|
440
|
+
viewerInput = {
|
|
441
|
+
type: 'webpub',
|
|
442
|
+
manifestPath: sourcePath,
|
|
443
|
+
needToGenerateManifest: false,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
else if (inputFormat === 'epub-opf') {
|
|
447
|
+
viewerInput = { type: 'epub-opf', epubOpfPath: sourcePath };
|
|
448
|
+
}
|
|
449
|
+
else if (inputFormat === 'epub') {
|
|
450
|
+
viewerInput = {
|
|
451
|
+
type: 'epub',
|
|
452
|
+
epubPath: sourcePath,
|
|
453
|
+
epubTmpOutputDir: upath.join(sourcePath, `../${temporaryFilePrefix}${upath.basename(sourcePath)}`),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
return inputFormat;
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
workspaceDir,
|
|
461
|
+
themesDir,
|
|
462
|
+
entries,
|
|
463
|
+
input: {
|
|
464
|
+
format: inputFormat,
|
|
465
|
+
entry: sourcePath,
|
|
466
|
+
},
|
|
467
|
+
viewerInput,
|
|
468
|
+
exportAliases,
|
|
469
|
+
title: title || fallbackTitle,
|
|
470
|
+
author,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function resolveComposedProjectConfig({ config, context, entryContextDir, outputs, temporaryFilePrefix, themeIndexes, rootUrl, cover, }) {
|
|
474
|
+
Logger.debug('entering composed project config mode');
|
|
475
|
+
const workspaceDir = upath.resolve(context, config.workspaceDir ?? '.vivliostyle');
|
|
476
|
+
const themesDir = upath.resolve(workspaceDir, 'themes');
|
|
477
|
+
const pkgJsonPath = upath.resolve(entryContextDir, 'package.json');
|
|
478
|
+
const pkgJson = fs.existsSync(pkgJsonPath)
|
|
479
|
+
? readJSON(pkgJsonPath)
|
|
480
|
+
: undefined;
|
|
481
|
+
if (pkgJson) {
|
|
482
|
+
Logger.debug('located package.json path', pkgJsonPath);
|
|
483
|
+
}
|
|
484
|
+
const exportAliases = [];
|
|
485
|
+
const rootThemes = config.theme?.map((theme) => parseTheme({
|
|
486
|
+
theme,
|
|
487
|
+
context,
|
|
488
|
+
workspaceDir,
|
|
489
|
+
themesDir,
|
|
490
|
+
})) ?? [];
|
|
491
|
+
const tocConfig = {
|
|
492
|
+
tocTitle: config.toc?.title ?? config?.tocTitle ?? TOC_TITLE,
|
|
493
|
+
target: upath.resolve(workspaceDir, config.toc?.htmlPath ?? TOC_FILENAME),
|
|
494
|
+
sectionDepth: config.toc?.sectionDepth ?? 0,
|
|
495
|
+
transform: {
|
|
496
|
+
transformDocumentList: config.toc?.transformDocumentList,
|
|
497
|
+
transformSectionList: config.toc?.transformSectionList,
|
|
498
|
+
},
|
|
499
|
+
};
|
|
500
|
+
const coverHtml = config.cover &&
|
|
501
|
+
('htmlPath' in config.cover && !config.cover.htmlPath
|
|
502
|
+
? undefined
|
|
503
|
+
: upath.resolve(workspaceDir, config.cover?.htmlPath || COVER_HTML_FILENAME));
|
|
504
|
+
const ensureCoverImage = (src) => {
|
|
505
|
+
const absPath = src && upath.resolve(entryContextDir, src);
|
|
506
|
+
if (absPath) {
|
|
507
|
+
statFileSync(absPath, {
|
|
508
|
+
errorMessage: 'Specified cover image does not exist',
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
return absPath;
|
|
512
|
+
};
|
|
513
|
+
const projectTitle = config?.title ?? pkgJson?.name;
|
|
514
|
+
const projectAuthor = config?.author ?? pkgJson?.author;
|
|
515
|
+
const isContentsEntry = (entry) => entry.rel === 'contents';
|
|
516
|
+
const isCoverEntry = (entry) => entry.rel === 'cover';
|
|
517
|
+
const isArticleEntry = (entry) => !isContentsEntry(entry) && !isCoverEntry(entry);
|
|
518
|
+
function parseEntry(entry) {
|
|
519
|
+
const getInputInfo = (entryPath) => {
|
|
520
|
+
if (/^https?:/.test(entryPath)) {
|
|
521
|
+
return {
|
|
522
|
+
type: 'uri',
|
|
523
|
+
href: entryPath,
|
|
524
|
+
rootDir: upath.join(workspaceDir, new URL(entryPath).host),
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
else if (entryPath.startsWith('/')) {
|
|
528
|
+
return {
|
|
529
|
+
type: 'uri',
|
|
530
|
+
href: `${rootUrl}${entryPath}`,
|
|
531
|
+
rootDir: upath.join(workspaceDir, 'localhost'),
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const pathname = upath.resolve(entryContextDir, entryPath);
|
|
535
|
+
statFileSync(pathname);
|
|
536
|
+
const contentType = mime(pathname);
|
|
537
|
+
if (!isManuscriptMediaType(contentType)) {
|
|
538
|
+
throw new Error(`Invalid manuscript type ${contentType} detected: ${entry}`);
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
type: 'file',
|
|
542
|
+
pathname,
|
|
543
|
+
contentType,
|
|
544
|
+
metadata: parseFileMetadata({
|
|
545
|
+
contentType,
|
|
546
|
+
sourcePath: pathname,
|
|
547
|
+
workspaceDir,
|
|
548
|
+
themesDir,
|
|
549
|
+
}),
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
const getTargetPath = (source) => {
|
|
553
|
+
switch (source.type) {
|
|
554
|
+
case 'file':
|
|
555
|
+
return upath.resolve(workspaceDir, upath
|
|
556
|
+
.relative(entryContextDir, source.pathname)
|
|
557
|
+
.replace(/\.md$/, '.html'));
|
|
558
|
+
case 'uri': {
|
|
559
|
+
const url = new URL(source.href, 'a://dummy');
|
|
560
|
+
let pathname = url.pathname;
|
|
561
|
+
if (!/\.html?$/.test(pathname)) {
|
|
562
|
+
pathname = `${pathname.replace(/\/$/, '')}/index.html`;
|
|
563
|
+
}
|
|
564
|
+
return upath.join(source.rootDir, pathname);
|
|
565
|
+
}
|
|
566
|
+
default:
|
|
567
|
+
return source;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
if ((isContentsEntry(entry) || isCoverEntry(entry)) && entry.path) {
|
|
571
|
+
const source = upath.resolve(entryContextDir, entry.path);
|
|
572
|
+
try {
|
|
573
|
+
statFileSync(source);
|
|
574
|
+
/* v8 ignore next 10 */
|
|
575
|
+
}
|
|
576
|
+
catch (error) {
|
|
577
|
+
// For backward compatibility, we allow missing files then assume that option as `output` field.
|
|
578
|
+
Logger.logWarn(`The "path" option is set but the file does not exist: ${source}\nMaybe you want to set the "output" field instead.`);
|
|
579
|
+
entry.output = entry.path;
|
|
580
|
+
entry.path = undefined;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (isContentsEntry(entry)) {
|
|
584
|
+
const inputInfo = entry.path ? getInputInfo(entry.path) : undefined;
|
|
585
|
+
const { metadata, ...template } = inputInfo || {};
|
|
586
|
+
let target = entry.output
|
|
587
|
+
? upath.resolve(workspaceDir, entry.output)
|
|
588
|
+
: inputInfo && getTargetPath(inputInfo);
|
|
589
|
+
const themes = entry.theme
|
|
590
|
+
? [entry.theme].flat().map((theme) => parseTheme({
|
|
591
|
+
theme,
|
|
592
|
+
context,
|
|
593
|
+
workspaceDir,
|
|
594
|
+
themesDir,
|
|
595
|
+
}))
|
|
596
|
+
: (metadata?.themes ?? [...rootThemes]);
|
|
597
|
+
themes.forEach((t) => themeIndexes.add(t));
|
|
598
|
+
target ??= tocConfig.target;
|
|
599
|
+
if (inputInfo?.type === 'file' &&
|
|
600
|
+
pathEquals(inputInfo.pathname, target)) {
|
|
601
|
+
const tmpPath = upath.resolve(upath.dirname(target), `${temporaryFilePrefix}${upath.basename(target)}`);
|
|
602
|
+
exportAliases.push({ source: tmpPath, target });
|
|
603
|
+
touchTmpFile(tmpPath);
|
|
604
|
+
target = tmpPath;
|
|
605
|
+
}
|
|
606
|
+
const parsedEntry = {
|
|
607
|
+
rel: 'contents',
|
|
608
|
+
...tocConfig,
|
|
609
|
+
target,
|
|
610
|
+
title: entry.title ?? metadata?.title ?? projectTitle,
|
|
611
|
+
themes,
|
|
612
|
+
pageBreakBefore: entry.pageBreakBefore,
|
|
613
|
+
pageCounterReset: entry.pageCounterReset,
|
|
614
|
+
...('type' in template && { template }),
|
|
615
|
+
};
|
|
616
|
+
return parsedEntry;
|
|
617
|
+
}
|
|
618
|
+
if (isCoverEntry(entry)) {
|
|
619
|
+
const inputInfo = entry.path ? getInputInfo(entry.path) : undefined;
|
|
620
|
+
const { metadata, ...template } = inputInfo || {};
|
|
621
|
+
let target = entry.output
|
|
622
|
+
? upath.resolve(workspaceDir, entry.output)
|
|
623
|
+
: inputInfo && getTargetPath(inputInfo);
|
|
624
|
+
const themes = entry.theme
|
|
625
|
+
? [entry.theme].flat().map((theme) => parseTheme({
|
|
626
|
+
theme,
|
|
627
|
+
context,
|
|
628
|
+
workspaceDir,
|
|
629
|
+
themesDir,
|
|
630
|
+
}))
|
|
631
|
+
: (metadata?.themes ?? []); // Don't inherit rootThemes for cover documents
|
|
632
|
+
themes.forEach((t) => themeIndexes.add(t));
|
|
633
|
+
const coverImageSrc = ensureCoverImage(entry.imageSrc || cover?.src);
|
|
634
|
+
if (!coverImageSrc) {
|
|
635
|
+
throw new Error(`A CoverEntryConfig is set in the entry list but a location of cover file is not set. Please set 'cover' property in your config file.`);
|
|
636
|
+
}
|
|
637
|
+
target ??= upath.resolve(workspaceDir, entry.path || coverHtml || COVER_HTML_FILENAME);
|
|
638
|
+
if (inputInfo?.type === 'file' &&
|
|
639
|
+
pathEquals(inputInfo.pathname, target)) {
|
|
640
|
+
const tmpPath = upath.resolve(upath.dirname(target), `${temporaryFilePrefix}${upath.basename(target)}`);
|
|
641
|
+
exportAliases.push({ source: tmpPath, target });
|
|
642
|
+
touchTmpFile(tmpPath);
|
|
643
|
+
target = tmpPath;
|
|
644
|
+
}
|
|
645
|
+
const parsedEntry = {
|
|
646
|
+
rel: 'cover',
|
|
647
|
+
target,
|
|
648
|
+
title: entry.title ?? metadata?.title ?? projectTitle,
|
|
649
|
+
themes,
|
|
650
|
+
coverImageSrc,
|
|
651
|
+
coverImageAlt: entry.imageAlt || cover?.name || COVER_HTML_IMAGE_ALT,
|
|
652
|
+
pageBreakBefore: entry.pageBreakBefore,
|
|
653
|
+
...('type' in template && { template }),
|
|
654
|
+
};
|
|
655
|
+
return parsedEntry;
|
|
656
|
+
}
|
|
657
|
+
if (isArticleEntry(entry)) {
|
|
658
|
+
const inputInfo = getInputInfo(entry.path);
|
|
659
|
+
const { metadata, ...source } = inputInfo;
|
|
660
|
+
const target = entry.output
|
|
661
|
+
? upath.resolve(workspaceDir, entry.output)
|
|
662
|
+
: getTargetPath(inputInfo);
|
|
663
|
+
const themes = entry.theme
|
|
664
|
+
? [entry.theme]
|
|
665
|
+
.flat()
|
|
666
|
+
.map((theme) => parseTheme({ theme, context, workspaceDir, themesDir }))
|
|
667
|
+
: (metadata?.themes ?? [...rootThemes]);
|
|
668
|
+
themes.forEach((t) => themeIndexes.add(t));
|
|
669
|
+
const parsedEntry = {
|
|
670
|
+
contentType: inputInfo.type === 'file' ? inputInfo.contentType : 'text/html',
|
|
671
|
+
source,
|
|
672
|
+
target,
|
|
673
|
+
title: entry.title ?? metadata?.title ?? projectTitle,
|
|
674
|
+
themes,
|
|
675
|
+
...(entry.rel && { rel: entry.rel }),
|
|
676
|
+
};
|
|
677
|
+
return parsedEntry;
|
|
678
|
+
}
|
|
679
|
+
/* v8 ignore next */
|
|
680
|
+
return entry;
|
|
681
|
+
}
|
|
682
|
+
const entries = config.entry.map(parseEntry);
|
|
683
|
+
let fallbackProjectTitle;
|
|
684
|
+
if (!projectTitle) {
|
|
685
|
+
if (entries.length === 1 && entries[0].title) {
|
|
686
|
+
fallbackProjectTitle = entries[0].title;
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
fallbackProjectTitle = upath.basename(outputs[0].path);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (!!config?.toc && !entries.find(({ rel }) => rel === 'contents')) {
|
|
693
|
+
entries.unshift({
|
|
694
|
+
rel: 'contents',
|
|
695
|
+
...tocConfig,
|
|
696
|
+
themes: [...rootThemes],
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
if (cover && coverHtml && !entries.find(({ rel }) => rel === 'cover')) {
|
|
700
|
+
entries.unshift({
|
|
701
|
+
rel: 'cover',
|
|
702
|
+
target: coverHtml,
|
|
703
|
+
title: projectTitle,
|
|
704
|
+
themes: [], // Don't inherit rootThemes for cover documents
|
|
705
|
+
coverImageSrc: ensureCoverImage(cover.src),
|
|
706
|
+
coverImageAlt: cover.name,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
return {
|
|
710
|
+
workspaceDir,
|
|
711
|
+
themesDir,
|
|
712
|
+
entries,
|
|
713
|
+
input: {
|
|
714
|
+
format: 'pub-manifest',
|
|
715
|
+
entry: upath.join(workspaceDir, MANIFEST_FILENAME),
|
|
716
|
+
},
|
|
717
|
+
viewerInput: {
|
|
718
|
+
type: 'webpub',
|
|
719
|
+
manifestPath: upath.join(workspaceDir, MANIFEST_FILENAME),
|
|
720
|
+
needToGenerateManifest: true,
|
|
721
|
+
},
|
|
722
|
+
exportAliases,
|
|
723
|
+
title: projectTitle || fallbackProjectTitle,
|
|
724
|
+
author: projectAuthor,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
//# sourceMappingURL=resolve.js.map
|