@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.
Files changed (156) hide show
  1. package/dist/browser.d.ts +12 -1
  2. package/dist/browser.d.ts.map +1 -1
  3. package/dist/browser.js +108 -13
  4. package/dist/browser.js.map +1 -1
  5. package/dist/commands/build.js +10 -44
  6. package/dist/commands/build.js.map +1 -1
  7. package/dist/commands/build.parser.d.ts +0 -5
  8. package/dist/commands/build.parser.d.ts.map +1 -1
  9. package/dist/commands/build.parser.js +15 -23
  10. package/dist/commands/build.parser.js.map +1 -1
  11. package/dist/commands/cli-flags.d.ts +42 -0
  12. package/dist/commands/cli-flags.d.ts.map +1 -0
  13. package/dist/commands/cli-flags.js +58 -0
  14. package/dist/commands/cli-flags.js.map +1 -0
  15. package/dist/commands/init.js +4 -12
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/preview.js +4 -37
  18. package/dist/commands/preview.js.map +1 -1
  19. package/dist/commands/preview.parser.d.ts.map +1 -1
  20. package/dist/commands/preview.parser.js +6 -4
  21. package/dist/commands/preview.parser.js.map +1 -1
  22. package/dist/config/load.d.ts +7 -0
  23. package/dist/config/load.d.ts.map +1 -0
  24. package/dist/config/load.js +72 -0
  25. package/dist/config/load.js.map +1 -0
  26. package/dist/config/merge.d.ts +4 -0
  27. package/dist/config/merge.d.ts.map +1 -0
  28. package/dist/config/merge.js +78 -0
  29. package/dist/config/merge.js.map +1 -0
  30. package/dist/{input/config.d.ts → config/resolve.d.ts} +81 -82
  31. package/dist/config/resolve.d.ts.map +1 -0
  32. package/dist/config/resolve.js +727 -0
  33. package/dist/config/resolve.js.map +1 -0
  34. package/dist/{input → config}/schema.d.ts +6023 -3542
  35. package/dist/config/schema.d.ts.map +1 -0
  36. package/dist/config/schema.js +562 -0
  37. package/dist/config/schema.js.map +1 -0
  38. package/dist/config/vite.d.ts +53 -0
  39. package/dist/config/vite.d.ts.map +1 -0
  40. package/dist/config/vite.js +19 -0
  41. package/dist/config/vite.js.map +1 -0
  42. package/dist/const.d.ts +2 -0
  43. package/dist/const.d.ts.map +1 -1
  44. package/dist/const.js +2 -0
  45. package/dist/const.js.map +1 -1
  46. package/dist/container.d.ts +12 -3
  47. package/dist/container.d.ts.map +1 -1
  48. package/dist/container.js +130 -30
  49. package/dist/container.js.map +1 -1
  50. package/dist/core/build.d.ts +3 -0
  51. package/dist/core/build.d.ts.map +1 -0
  52. package/dist/core/build.js +168 -0
  53. package/dist/core/build.js.map +1 -0
  54. package/dist/core/init.d.ts +3 -0
  55. package/dist/core/init.d.ts.map +1 -0
  56. package/dist/{init.js → core/init.js} +14 -19
  57. package/dist/core/init.js.map +1 -0
  58. package/dist/core/preview.d.ts +3 -0
  59. package/dist/core/preview.d.ts.map +1 -0
  60. package/dist/core/preview.js +93 -0
  61. package/dist/core/preview.js.map +1 -0
  62. package/dist/index.d.ts +32 -4
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +44 -3
  65. package/dist/index.js.map +1 -1
  66. package/dist/logger.d.ts +23 -0
  67. package/dist/logger.d.ts.map +1 -0
  68. package/dist/logger.js +161 -0
  69. package/dist/logger.js.map +1 -0
  70. package/dist/output/epub.d.ts.map +1 -1
  71. package/dist/output/epub.js +17 -15
  72. package/dist/output/epub.js.map +1 -1
  73. package/dist/output/pdf-postprocess.d.ts +2 -3
  74. package/dist/output/pdf-postprocess.d.ts.map +1 -1
  75. package/dist/output/pdf-postprocess.js +94 -29
  76. package/dist/output/pdf-postprocess.js.map +1 -1
  77. package/dist/output/pdf.d.ts +4 -7
  78. package/dist/output/pdf.d.ts.map +1 -1
  79. package/dist/output/pdf.js +77 -141
  80. package/dist/output/pdf.js.map +1 -1
  81. package/dist/output/webbook.d.ts +10 -10
  82. package/dist/output/webbook.d.ts.map +1 -1
  83. package/dist/output/webbook.js +44 -62
  84. package/dist/output/webbook.js.map +1 -1
  85. package/dist/processor/compile.d.ts +24 -10
  86. package/dist/processor/compile.d.ts.map +1 -1
  87. package/dist/processor/compile.js +195 -130
  88. package/dist/processor/compile.js.map +1 -1
  89. package/dist/processor/html.d.ts +29 -17
  90. package/dist/processor/html.d.ts.map +1 -1
  91. package/dist/processor/html.js +112 -88
  92. package/dist/processor/html.js.map +1 -1
  93. package/dist/processor/markdown.d.ts +1 -1
  94. package/dist/processor/markdown.d.ts.map +1 -1
  95. package/dist/processor/theme.d.ts +3 -3
  96. package/dist/processor/theme.d.ts.map +1 -1
  97. package/dist/processor/theme.js +29 -53
  98. package/dist/processor/theme.js.map +1 -1
  99. package/dist/server.d.ts +17 -38
  100. package/dist/server.d.ts.map +1 -1
  101. package/dist/server.js +76 -102
  102. package/dist/server.js.map +1 -1
  103. package/dist/util.d.ts +9 -29
  104. package/dist/util.d.ts.map +1 -1
  105. package/dist/util.js +54 -158
  106. package/dist/util.js.map +1 -1
  107. package/dist/vite/plugin-util.d.ts +6 -0
  108. package/dist/vite/plugin-util.d.ts.map +1 -0
  109. package/dist/vite/plugin-util.js +20 -0
  110. package/dist/vite/plugin-util.js.map +1 -0
  111. package/dist/vite/vite-plugin-browser.d.ts +8 -0
  112. package/dist/vite/vite-plugin-browser.d.ts.map +1 -0
  113. package/dist/vite/vite-plugin-browser.js +57 -0
  114. package/dist/vite/vite-plugin-browser.js.map +1 -0
  115. package/dist/vite/vite-plugin-dev-server.d.ts +8 -0
  116. package/dist/vite/vite-plugin-dev-server.d.ts.map +1 -0
  117. package/dist/vite/vite-plugin-dev-server.js +267 -0
  118. package/dist/vite/vite-plugin-dev-server.js.map +1 -0
  119. package/dist/vite/vite-plugin-static-serve.d.ts +8 -0
  120. package/dist/vite/vite-plugin-static-serve.d.ts.map +1 -0
  121. package/dist/vite/vite-plugin-static-serve.js +24 -0
  122. package/dist/vite/vite-plugin-static-serve.js.map +1 -0
  123. package/dist/vite/vite-plugin-viewer.d.ts +8 -0
  124. package/dist/vite/vite-plugin-viewer.d.ts.map +1 -0
  125. package/dist/vite/vite-plugin-viewer.js +52 -0
  126. package/dist/vite/vite-plugin-viewer.js.map +1 -0
  127. package/dist/vite-adapter.d.ts +3 -0
  128. package/dist/vite-adapter.d.ts.map +1 -0
  129. package/dist/vite-adapter.js +27 -0
  130. package/dist/vite-adapter.js.map +1 -0
  131. package/package.json +13 -15
  132. package/dist/build.d.ts +0 -21
  133. package/dist/build.d.ts.map +0 -1
  134. package/dist/build.js +0 -119
  135. package/dist/build.js.map +0 -1
  136. package/dist/init.d.ts +0 -16
  137. package/dist/init.d.ts.map +0 -1
  138. package/dist/init.js.map +0 -1
  139. package/dist/input/config.d.ts.map +0 -1
  140. package/dist/input/config.js +0 -807
  141. package/dist/input/config.js.map +0 -1
  142. package/dist/input/input-types.d.ts +0 -34
  143. package/dist/input/input-types.d.ts.map +0 -1
  144. package/dist/input/input-types.js +0 -34
  145. package/dist/input/input-types.js.map +0 -1
  146. package/dist/input/schema.d.ts.map +0 -1
  147. package/dist/input/schema.js +0 -233
  148. package/dist/input/schema.js.map +0 -1
  149. package/dist/output/output-types.d.ts +0 -26
  150. package/dist/output/output-types.d.ts.map +0 -1
  151. package/dist/output/output-types.js +0 -23
  152. package/dist/output/output-types.js.map +0 -1
  153. package/dist/preview.d.ts +0 -11
  154. package/dist/preview.d.ts.map +0 -1
  155. package/dist/preview.js +0 -191
  156. 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