@vivliostyle/cli 9.9.0 → 10.0.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 (55) hide show
  1. package/README.md +74 -30
  2. package/dist/{chunk-QWX5MAON.js → chunk-2M2KXPDN.js} +16 -17
  3. package/dist/chunk-2M2KXPDN.js.map +1 -0
  4. package/dist/{chunk-OZ4XTSAH.js → chunk-5DB6XVJN.js} +2 -2
  5. package/dist/chunk-5DB6XVJN.js.map +1 -0
  6. package/dist/{chunk-3O3N2V7D.js → chunk-5K3NGLBV.js} +6 -7
  7. package/dist/chunk-5K3NGLBV.js.map +1 -0
  8. package/dist/{chunk-UYKCTF6F.js → chunk-IIKRNYAM.js} +445 -228
  9. package/dist/chunk-IIKRNYAM.js.map +1 -0
  10. package/dist/{chunk-G3GROLBN.js → chunk-MQYXBSRJ.js} +397 -88
  11. package/dist/chunk-MQYXBSRJ.js.map +1 -0
  12. package/dist/chunk-RPMMYPTR.js +1076 -0
  13. package/dist/chunk-RPMMYPTR.js.map +1 -0
  14. package/dist/{chunk-WELNNHOB.js → chunk-YN3JNBNT.js} +415 -384
  15. package/dist/chunk-YN3JNBNT.js.map +1 -0
  16. package/dist/{chunk-6UU7DEUR.js → chunk-YVNDJXMI.js} +32 -33
  17. package/dist/chunk-YVNDJXMI.js.map +1 -0
  18. package/dist/{chunk-FXUEYQRY.js → chunk-ZIK6DINS.js} +3 -3
  19. package/dist/chunk-ZIK6DINS.js.map +1 -0
  20. package/dist/chunk-ZKEIYNLT.js +331 -0
  21. package/dist/chunk-ZKEIYNLT.js.map +1 -0
  22. package/dist/cli.js +7 -8
  23. package/dist/cli.js.map +1 -1
  24. package/dist/commands/build.js +29 -17
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/create.d.ts +2 -0
  27. package/dist/commands/create.js +64 -0
  28. package/dist/commands/create.js.map +1 -0
  29. package/dist/commands/init.js +23 -14
  30. package/dist/commands/init.js.map +1 -1
  31. package/dist/commands/preview.js +26 -20
  32. package/dist/commands/preview.js.map +1 -1
  33. package/dist/config/schema.d.ts +7815 -4012
  34. package/dist/config/schema.js +16 -4
  35. package/dist/index.d.ts +46 -7
  36. package/dist/index.js +24 -16
  37. package/dist/index.js.map +1 -1
  38. package/dist/node-modules.d.ts +5 -5
  39. package/dist/node-modules.js +1 -1
  40. package/dist/vite-adapter.d.ts +1 -0
  41. package/dist/vite-adapter.js +6 -6
  42. package/package.json +37 -26
  43. package/dist/chunk-3O3N2V7D.js.map +0 -1
  44. package/dist/chunk-4IIM6RSG.js +0 -71
  45. package/dist/chunk-4IIM6RSG.js.map +0 -1
  46. package/dist/chunk-6KEOMYDZ.js +0 -89
  47. package/dist/chunk-6KEOMYDZ.js.map +0 -1
  48. package/dist/chunk-6UU7DEUR.js.map +0 -1
  49. package/dist/chunk-FXUEYQRY.js.map +0 -1
  50. package/dist/chunk-G3GROLBN.js.map +0 -1
  51. package/dist/chunk-OZ4XTSAH.js.map +0 -1
  52. package/dist/chunk-QWX5MAON.js.map +0 -1
  53. package/dist/chunk-UYKCTF6F.js.map +0 -1
  54. package/dist/chunk-WELNNHOB.js.map +0 -1
  55. package/types/playwright.d.ts +0 -49
@@ -0,0 +1,1076 @@
1
+ import {
2
+ GlobMatcher,
3
+ Logger,
4
+ cwd,
5
+ getDefaultBrowserTag,
6
+ getOsLocale,
7
+ isUnicodeSupported,
8
+ registerExitHandler,
9
+ toTitleCase,
10
+ whichPm
11
+ } from "./chunk-MQYXBSRJ.js";
12
+ import {
13
+ ValidString,
14
+ VivliostyleInlineConfigWithoutChecks,
15
+ VivliostylePackageMetadata
16
+ } from "./chunk-IIKRNYAM.js";
17
+ import {
18
+ DEFAULT_CONFIG_FILENAME,
19
+ DEFAULT_PROJECT_AUTHOR,
20
+ DEFAULT_PROJECT_TITLE,
21
+ TEMPLATE_DEFAULT_FILES,
22
+ TEMPLATE_SETTINGS,
23
+ cliVersion,
24
+ coreVersion,
25
+ languages
26
+ } from "./chunk-ZKEIYNLT.js";
27
+ import {
28
+ importNodeModule
29
+ } from "./chunk-ZIK6DINS.js";
30
+ import {
31
+ __callDispose,
32
+ __using
33
+ } from "./chunk-I7BWSAN6.js";
34
+
35
+ // src/core/create.ts
36
+ import { downloadTemplate } from "@bluwy/giget-core";
37
+ import { copy } from "fs-extra/esm";
38
+ import { isUtf8 } from "node:buffer";
39
+ import fs from "node:fs";
40
+ import { pathToFileURL } from "node:url";
41
+ import terminalLink from "terminal-link";
42
+ import upath from "upath";
43
+ import * as v2 from "valibot";
44
+ import { cyan, dim as dim2, gray as gray2, green as green2, yellow as yellow2 } from "yoctocolors";
45
+
46
+ // src/create-template.ts
47
+ import { camelCase, capitalCase, kebabCase, snakeCase } from "change-case";
48
+ import Handlebars from "handlebars";
49
+ import { titleCase } from "title-case";
50
+ function upper(text) {
51
+ return text && text.toUpperCase();
52
+ }
53
+ Handlebars.registerHelper("upper", upper);
54
+ function lower(text) {
55
+ return text && text.toLowerCase();
56
+ }
57
+ Handlebars.registerHelper("lower", lower);
58
+ function capital(text) {
59
+ return text && capitalCase(text);
60
+ }
61
+ Handlebars.registerHelper("capital", capital);
62
+ function camel(text) {
63
+ return text && camelCase(text);
64
+ }
65
+ Handlebars.registerHelper("camel", camel);
66
+ function snake(text) {
67
+ return text && snakeCase(text);
68
+ }
69
+ Handlebars.registerHelper("snake", snake);
70
+ function kebab(text) {
71
+ return text && kebabCase(text);
72
+ }
73
+ Handlebars.registerHelper("kebab", kebab);
74
+ function proper(text) {
75
+ return text && titleCase(text);
76
+ }
77
+ Handlebars.registerHelper("proper", proper);
78
+ function lorem() {
79
+ return "Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio, maxime et saepe facilis dolor aut maiores cupiditate rem voluptatem placeat accusamus voluptates laborum ratione enim blanditiis nisi voluptas non mollitia.";
80
+ }
81
+ Handlebars.registerHelper("lorem", lorem);
82
+ function json(data) {
83
+ return JSON.stringify(data);
84
+ }
85
+ Handlebars.registerHelper("json", json);
86
+ function format(text, context) {
87
+ const template = Handlebars.compile(text.toString(), { noEscape: true });
88
+ return template(context);
89
+ }
90
+
91
+ // src/interactive.ts
92
+ import {
93
+ AutocompletePrompt,
94
+ getColumns,
95
+ isCancel,
96
+ MultiSelectPrompt,
97
+ SelectPrompt,
98
+ TextPrompt
99
+ } from "@clack/core";
100
+ import { limitOptions } from "@clack/prompts";
101
+ import { wrapAnsi } from "fast-wrap-ansi";
102
+ import { cursor, erase } from "sisteransi";
103
+ import * as v from "valibot";
104
+ import {
105
+ blueBright,
106
+ dim,
107
+ gray,
108
+ green,
109
+ hidden,
110
+ inverse,
111
+ redBright,
112
+ strikethrough,
113
+ yellow,
114
+ yellowBright
115
+ } from "yoctocolors";
116
+ async function askQuestion({
117
+ question: questions,
118
+ schema,
119
+ validateProgressMessage
120
+ }) {
121
+ const response = {};
122
+ while (true) {
123
+ for (const [name, question] of Object.entries(questions)) {
124
+ let result2;
125
+ const maxItems = 10;
126
+ const normalizeOptions = (options) => options.map((v3) => typeof v3 === "string" ? { value: v3 } : v3);
127
+ const validate = (value = "") => {
128
+ if (!question.required || "defaultValue" in question) {
129
+ return;
130
+ }
131
+ const { success: success2, issues: issues2 } = v.safeParse(ValidString, value);
132
+ return success2 ? void 0 : issues2[0].message;
133
+ };
134
+ if (import.meta.env?.VITEST) {
135
+ question.name = name;
136
+ }
137
+ if (question.type === "text") {
138
+ result2 = await textPrompt({ ...question, validate });
139
+ } else if (question.type === "select") {
140
+ result2 = await selectPrompt({
141
+ ...question,
142
+ options: normalizeOptions(question.options),
143
+ maxItems
144
+ });
145
+ } else if (question.type === "multiSelect") {
146
+ result2 = await multiSelectPrompt({
147
+ ...question,
148
+ options: normalizeOptions(question.options),
149
+ maxItems
150
+ });
151
+ } else if (question.type === "autocomplete") {
152
+ result2 = await autocompletePrompt({
153
+ ...question,
154
+ options: normalizeOptions(question.options),
155
+ maxItems,
156
+ validate
157
+ });
158
+ } else if (question.type === "autocompleteMultiSelect") {
159
+ result2 = await autocompleteMultiSelectPrompt({
160
+ ...question,
161
+ options: normalizeOptions(question.options),
162
+ maxItems
163
+ });
164
+ } else {
165
+ result2 = question;
166
+ }
167
+ if (isCancel(result2)) {
168
+ process.exit(0);
169
+ }
170
+ response[name] = result2;
171
+ }
172
+ let result;
173
+ if (schema && schema.async) {
174
+ result = await interactiveLogLoading(
175
+ validateProgressMessage ?? "",
176
+ () => v.safeParseAsync(schema, response)
177
+ );
178
+ } else if (schema) {
179
+ result = v.safeParse(schema, response);
180
+ } else {
181
+ return response;
182
+ }
183
+ const { success, output, issues } = result;
184
+ if (success) {
185
+ return output;
186
+ }
187
+ interactiveLogWarn(issues[0].message);
188
+ }
189
+ }
190
+ var promptStateSymbol = {
191
+ initial: isUnicodeSupported ? "\u25C6" : "*",
192
+ active: isUnicodeSupported ? "\u25C6" : "*",
193
+ cancel: isUnicodeSupported ? "\u25A0" : "x",
194
+ submit: isUnicodeSupported ? "\u25C7" : "o",
195
+ error: isUnicodeSupported ? "\u25B2" : "x"
196
+ };
197
+ var radioActiveSymbol = isUnicodeSupported ? "\u25C9" : ">";
198
+ var radioInactiveSymbol = isUnicodeSupported ? "\u25EF" : " ";
199
+ var checkboxActiveSymbol = isUnicodeSupported ? "\u25FC" : "[+]";
200
+ var checkboxInactiveSymbol = isUnicodeSupported ? "\u25FB" : "[ ]";
201
+ var labelToString = (option) => option.label ?? String(option.value ?? "");
202
+ var renderListOption = (multiSelect, selectedValues) => (option, active) => {
203
+ const Y = multiSelect ? checkboxActiveSymbol : radioActiveSymbol;
204
+ const N = multiSelect ? checkboxInactiveSymbol : radioInactiveSymbol;
205
+ if (option.disabled) {
206
+ return `${gray(N)} ${gray(labelToString(option))} ${gray("(disabled)")}`;
207
+ }
208
+ return `${multiSelect && selectedValues?.includes(option.value) || !multiSelect && active ? green(Y) : dim(N)} ${active ? `${labelToString(option)}${option.hint ? ` ${dim(`(${option.hint})`)}` : ""}` : dim(labelToString(option))}`;
209
+ };
210
+ function textPrompt(opts) {
211
+ return new TextPrompt({
212
+ ...opts,
213
+ input: Logger.stdin,
214
+ output: Logger.stdout,
215
+ signal: Logger.signal,
216
+ render() {
217
+ const symbol = promptStateSymbol[this.state];
218
+ const placeholder = opts.placeholder ? inverse(opts.placeholder[0]) + dim(opts.placeholder.slice(1)) : inverse(hidden("_"));
219
+ const userInput = !this.userInput ? placeholder : this.userInputWithCursor;
220
+ const value = this.value ?? "";
221
+ switch (this.state) {
222
+ case "error": {
223
+ const errorText = this.error ? ` ${yellow(this.error)}` : "";
224
+ return `${yellow("\u2551")}
225
+ ${yellow(`${symbol}\u2500`)} ${opts.message}
226
+ ${userInput}
227
+ ${errorText}`;
228
+ }
229
+ case "submit": {
230
+ const valueText = value ? ` ${dim(value)}` : "";
231
+ return `${blueBright("\u2551")}
232
+ ${blueBright(`${symbol}\u2500`)} ${opts.message}
233
+ ${blueBright("\u2551")}${valueText}`;
234
+ }
235
+ case "cancel": {
236
+ const valueText = value ? ` ${strikethrough(dim(value))}` : "";
237
+ return `${gray("\u2551")}
238
+ ${gray(`${symbol}\u2500`)} ${opts.message}
239
+ ${valueText}`;
240
+ }
241
+ default:
242
+ return `${blueBright("\u2551")}
243
+ ${blueBright(`${symbol}\u2500`)} ${opts.message}
244
+ ${userInput}
245
+ `;
246
+ }
247
+ }
248
+ }).prompt();
249
+ }
250
+ function selectPrompt(opts, multiple = false) {
251
+ return new (multiple ? MultiSelectPrompt : SelectPrompt)({
252
+ ...opts,
253
+ input: Logger.stdin,
254
+ output: Logger.stdout,
255
+ signal: Logger.signal,
256
+ render() {
257
+ const symbol = promptStateSymbol[this.state];
258
+ const values = [this.value].flat();
259
+ const selected = this.options.filter((o) => values.includes(o.value));
260
+ const label = selected.length > 0 ? selected.map(labelToString).join(", ") : "none";
261
+ switch (this.state) {
262
+ case "submit": {
263
+ return `${blueBright("\u2551")}
264
+ ${blueBright(`${symbol}\u2500`)} ${opts.message}
265
+ ${blueBright("\u2551")} ${dim(label)}`;
266
+ }
267
+ case "cancel": {
268
+ return `${gray("\u2551")}
269
+ ${gray(`${symbol}\u2500`)} ${opts.message}
270
+ ${strikethrough(dim(label))}`;
271
+ }
272
+ default: {
273
+ const indents = " ";
274
+ const displayingOptions = limitOptions({
275
+ output: opts.output,
276
+ cursor: this.cursor,
277
+ options: this.options,
278
+ maxItems: opts.maxItems,
279
+ columnPadding: indents.length,
280
+ style: renderListOption(
281
+ multiple,
282
+ Array.isArray(this.value) ? this.value : []
283
+ )
284
+ });
285
+ return `${blueBright("\u2551")}
286
+ ${blueBright(`${symbol}\u2500`)} ${opts.message}
287
+ ${displayingOptions.join(`
288
+ ${indents}`)}
289
+ `;
290
+ }
291
+ }
292
+ }
293
+ }).prompt();
294
+ }
295
+ function multiSelectPrompt(opts) {
296
+ return selectPrompt(opts, true);
297
+ }
298
+ function autocompletePrompt(opts, multiple = false) {
299
+ return new AutocompletePrompt({
300
+ ...opts,
301
+ multiple,
302
+ initialValue: opts.initialValue ? [opts.initialValue] : void 0,
303
+ filter: (searchText, option) => {
304
+ if (!searchText) {
305
+ return true;
306
+ }
307
+ const label = (option.label ?? String(option.value ?? "")).toLowerCase();
308
+ const hint = (option.hint ?? "").toLowerCase();
309
+ const value = String(option.value).toLowerCase();
310
+ const term = searchText.toLowerCase();
311
+ return label.includes(term) || hint.includes(term) || value.includes(term);
312
+ },
313
+ input: Logger.stdin,
314
+ output: Logger.stdout,
315
+ signal: Logger.signal,
316
+ render() {
317
+ const symbol = promptStateSymbol[this.state];
318
+ const selected = this.options.filter(
319
+ (o) => this.selectedValues.includes(o.value)
320
+ );
321
+ const label = selected.length > 0 ? selected.map(labelToString).join(", ") : "none";
322
+ switch (this.state) {
323
+ case "submit": {
324
+ return `${blueBright("\u2551")}
325
+ ${blueBright(`${symbol}\u2500`)} ${opts.message}
326
+ ${blueBright("\u2551")} ${dim(label)}`;
327
+ }
328
+ case "cancel": {
329
+ const userInputText = this.userInput ? ` ${strikethrough(dim(this.userInput))}` : "";
330
+ return `${gray("\u2551")}
331
+ ${gray(`${symbol}\u2500`)} ${opts.message}
332
+ ${userInputText}`;
333
+ }
334
+ default: {
335
+ const indents = " ";
336
+ let searchText = "";
337
+ if (this.isNavigating || opts.placeholder && !this.userInput) {
338
+ const searchTextValue = opts.placeholder ?? this.userInput;
339
+ searchText = searchTextValue ? ` ${dim(searchTextValue)}` : "";
340
+ } else {
341
+ searchText = ` ${this.userInputWithCursor}`;
342
+ }
343
+ const matches = this.filteredOptions.length !== this.options.length ? dim(
344
+ ` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? "" : "es"})`
345
+ ) : "";
346
+ const headings = [
347
+ blueBright("\u2551"),
348
+ `${blueBright(`${symbol}\u2500`)} ${opts.message}`,
349
+ `${indents}${dim("Search:")}${searchText}${matches}`
350
+ ];
351
+ if (this.filteredOptions.length === 0 && this.userInput) {
352
+ headings.push(`${indents}${yellow("No matches found")}`);
353
+ }
354
+ if (this.state === "error") {
355
+ headings.push(`${indents}${yellow(`Error: ${this.error ?? ""}`)}`);
356
+ }
357
+ const footers = [
358
+ multiple ? `${indents}${dim("\u2191/\u2193 to navigate \u2022 Space/Tab: select \u2022 Enter: confirm \u2022 Type: to search")}` : `${indents}${dim("\u2191/\u2193 to select \u2022 Enter: confirm \u2022 Type: to search")}`
359
+ ];
360
+ const displayingOptions = limitOptions({
361
+ output: opts.output,
362
+ cursor: this.cursor,
363
+ options: this.filteredOptions,
364
+ maxItems: opts.maxItems,
365
+ columnPadding: indents.length,
366
+ rowPadding: headings.length + footers.length,
367
+ style: renderListOption(multiple, this.selectedValues)
368
+ });
369
+ return [
370
+ ...headings,
371
+ ...displayingOptions.map((s) => `${indents}${s}`),
372
+ ...footers
373
+ ].join("\n");
374
+ }
375
+ }
376
+ }
377
+ }).prompt();
378
+ }
379
+ function autocompleteMultiSelectPrompt(opts) {
380
+ return autocompletePrompt(opts, true);
381
+ }
382
+ async function interactiveLogLoading(message, fn, deferredTimeMs = 300) {
383
+ if (!Logger.isInteractive) {
384
+ return await fn();
385
+ }
386
+ const output = Logger.stdout;
387
+ const columns = getColumns(output);
388
+ const showMessage = (msg) => {
389
+ const wrapped = wrapAnsi(msg, columns, { hard: true, trim: false });
390
+ output.write(wrapped);
391
+ return () => {
392
+ const prevLines = wrapped.split("\n");
393
+ if (prevLines.length > 1) {
394
+ output.write(cursor.up(prevLines.length - 1));
395
+ }
396
+ output.write(cursor.to(0));
397
+ output.write(erase.down());
398
+ };
399
+ };
400
+ let timer;
401
+ let clearMessage;
402
+ const promise = new Promise((resolve) => {
403
+ timer = setTimeout(() => {
404
+ output.write(`${blueBright("\u2551")}
405
+ `);
406
+ clearMessage = showMessage(
407
+ `${blueBright(`${promptStateSymbol.active}\u2500`)} ${dim(message)}
408
+ `
409
+ );
410
+ resolve();
411
+ }, deferredTimeMs);
412
+ });
413
+ const result = await fn().then((r) => {
414
+ if (!clearMessage) {
415
+ return r;
416
+ }
417
+ return new Promise(
418
+ (resolve) => setTimeout(() => resolve(r), deferredTimeMs)
419
+ );
420
+ }).catch(async (e) => {
421
+ await promise;
422
+ clearMessage?.();
423
+ showMessage(
424
+ `${redBright(`${promptStateSymbol.error}\u2500`)} ${dim(message)}
425
+
426
+ `
427
+ );
428
+ throw e;
429
+ });
430
+ clearTimeout(timer);
431
+ if (clearMessage) {
432
+ clearMessage();
433
+ showMessage(
434
+ `${blueBright(`${promptStateSymbol.submit}\u2500`)} ${dim(message)}
435
+ `
436
+ );
437
+ }
438
+ return result;
439
+ }
440
+ function interactiveLogInfo(message) {
441
+ if (import.meta.env?.VITEST) {
442
+ return;
443
+ }
444
+ Logger.stdout.write(
445
+ `${blueBright(`${promptStateSymbol.submit}\u2500`)} ${message.split("\n").join(`
446
+ ${blueBright("\u2551")} `)}
447
+ `
448
+ );
449
+ }
450
+ function interactiveLogWarn(message) {
451
+ if (import.meta.env?.VITEST) {
452
+ return;
453
+ }
454
+ Logger.stdout.write(
455
+ `${yellowBright(`${promptStateSymbol.error}\u2500`)} ${yellowBright(message.split("\n").join(`
456
+ ${yellowBright("\u2551")} `))}
457
+ `
458
+ );
459
+ }
460
+ function interactiveLogOutro(message) {
461
+ if (import.meta.env?.VITEST) {
462
+ return;
463
+ }
464
+ Logger.stdout.write(`${blueBright("\u2551")}
465
+ ${blueBright("\u2559\u2500")} ${message}
466
+
467
+ `);
468
+ }
469
+
470
+ // src/npm.ts
471
+ import { fetch as _fetch } from "node-fetch-native";
472
+ import { createProxy } from "node-fetch-native/proxy";
473
+ function createFetch(options) {
474
+ const url = options.proxyServer ?? process.env.HTTP_PROXY;
475
+ const proxy = url ? createProxy({
476
+ url,
477
+ noProxy: options.proxyBypass ?? process.env.NO_PROXY ?? void 0
478
+ }) : void 0;
479
+ const token = options.proxyUser && options.proxyPass ? `Basic ${Buffer.from(
480
+ `${options.proxyUser}:${options.proxyPass}`
481
+ ).toString("base64")}` : void 0;
482
+ if (proxy && token) {
483
+ const proxyHeadersKey = Object.getOwnPropertySymbols(proxy.dispatcher).find(
484
+ (symbol) => symbol.description === "proxy headers"
485
+ );
486
+ if (proxyHeadersKey) {
487
+ proxy.dispatcher[proxyHeadersKey]["proxy-authorization"] = token;
488
+ }
489
+ }
490
+ return (url2, fetchOptions) => _fetch(url2, { ...proxy ?? {}, ...fetchOptions }).then((response) => {
491
+ if (!response.ok) {
492
+ throw new Error(
493
+ `Failed to fetch ${url2}: ${response.status} ${response.statusText}`
494
+ );
495
+ }
496
+ return response;
497
+ });
498
+ }
499
+ async function listVivliostyleThemes({
500
+ fetch
501
+ }) {
502
+ const keyword = "vivliostyle-theme";
503
+ return await fetch(
504
+ `https://registry.npmjs.org/-/v1/search?text=keywords:${keyword}&size=250`
505
+ ).then((response) => response.json());
506
+ }
507
+ async function fetchPackageMetadata({
508
+ fetch,
509
+ packageName,
510
+ version
511
+ }) {
512
+ return fetch(`https://registry.npmjs.org/${packageName}/${version}`).then(
513
+ (response) => response.json()
514
+ );
515
+ }
516
+
517
+ // src/core/create.ts
518
+ async function create(inlineConfig) {
519
+ Logger.setLogOptions(inlineConfig);
520
+ Logger.debug("create > inlineConfig %O", inlineConfig);
521
+ const fetch = createFetch(inlineConfig);
522
+ let {
523
+ projectPath,
524
+ cwd: cwd2 = cwd,
525
+ title,
526
+ author,
527
+ language,
528
+ theme,
529
+ template,
530
+ createConfigFileOnly = false
531
+ } = inlineConfig;
532
+ let extraTemplateVariables = {};
533
+ let themePackage;
534
+ let installDependencies;
535
+ let useLocalTemplate = false;
536
+ if (template && !/^([\w-.]+):/.test(template)) {
537
+ const absTemplatePath = upath.resolve(cwd2, template);
538
+ useLocalTemplate = fs.existsSync(upath.resolve(cwd2, template)) && fs.statSync(upath.resolve(cwd2, template)).isDirectory();
539
+ if (useLocalTemplate) {
540
+ template = absTemplatePath;
541
+ interactiveLogInfo(
542
+ `Using the specified local template directory
543
+ ${dim2(upath.relative(cwd2, absTemplatePath) || ".")}`
544
+ );
545
+ } else {
546
+ interactiveLogWarn(
547
+ `The specified theme ${green2(template)} was not found as a local directory. Proceeding to fetch it from GitHub repository.`
548
+ );
549
+ }
550
+ }
551
+ if (!projectPath) {
552
+ ({ projectPath } = await askProjectPath());
553
+ }
554
+ const dist = upath.join(cwd2, projectPath);
555
+ if (createConfigFileOnly) {
556
+ if (fs.existsSync(upath.join(dist, DEFAULT_CONFIG_FILENAME))) {
557
+ throw new Error(`${DEFAULT_CONFIG_FILENAME} already exists. Aborting.`);
558
+ }
559
+ } else if (projectPath === "." && fs.readdirSync(dist).filter((n) => !n.startsWith(".")).length > 0 || projectPath !== "." && fs.existsSync(dist)) {
560
+ throw new Error(`Destination ${dist} is not empty.`);
561
+ }
562
+ if (!title) {
563
+ ({ title } = createConfigFileOnly ? { title: DEFAULT_PROJECT_TITLE } : await askTitle({ projectPath }));
564
+ }
565
+ if (!author) {
566
+ ({ author } = createConfigFileOnly ? { author: DEFAULT_PROJECT_AUTHOR } : await askAuthor());
567
+ }
568
+ if (!language) {
569
+ ({ language } = createConfigFileOnly ? { language: await getOsLocale() } : await askLanguage());
570
+ }
571
+ if (!createConfigFileOnly) {
572
+ let presetTemplate;
573
+ if (!template) {
574
+ ({ presetTemplate } = await askPresetTemplate());
575
+ if (presetTemplate) {
576
+ template = presetTemplate.template;
577
+ }
578
+ }
579
+ if (!theme) {
580
+ ({ theme, themePackage } = await askTheme({
581
+ presetTemplate,
582
+ template,
583
+ fetch
584
+ }));
585
+ }
586
+ if (!template) {
587
+ ({ template, extraTemplateVariables } = await askThemeTemplate(
588
+ themePackage?.vivliostyle
589
+ ));
590
+ }
591
+ ({ installDependencies } = await askInstallDependencies());
592
+ }
593
+ const browserType = "chrome";
594
+ const browserTag = getDefaultBrowserTag(browserType);
595
+ const explicitTemplateVariables = {
596
+ ...extraTemplateVariables,
597
+ projectPath,
598
+ title,
599
+ author,
600
+ language,
601
+ theme: (() => {
602
+ if (!theme) {
603
+ return;
604
+ }
605
+ const arr = theme.map((t) => t.import ? t : t.specifier);
606
+ return arr.length === 1 ? arr[0] : arr;
607
+ })(),
608
+ themePackage,
609
+ template,
610
+ cliVersion,
611
+ coreVersion,
612
+ browser: { type: browserType, tag: browserTag }
613
+ };
614
+ Logger.debug(
615
+ "create > explicitTemplateVariables %O",
616
+ explicitTemplateVariables
617
+ );
618
+ if (createConfigFileOnly) {
619
+ setupConfigFile({
620
+ projectPath,
621
+ cwd: cwd2,
622
+ templateVariables: {
623
+ ...inlineConfig,
624
+ ...explicitTemplateVariables
625
+ }
626
+ });
627
+ } else {
628
+ var _stack2 = [];
629
+ try {
630
+ interactiveLogOutro("All configurations are set! Creating your project...");
631
+ const _3 = __using(_stack2, Logger.startLogging(
632
+ useLocalTemplate ? "Copying a local template" : "Downloading a template"
633
+ ));
634
+ await setupTemplate({
635
+ projectPath,
636
+ cwd: cwd2,
637
+ template,
638
+ templateVariables: {
639
+ ...inlineConfig,
640
+ ...explicitTemplateVariables
641
+ },
642
+ useLocalTemplate
643
+ });
644
+ if (installDependencies) {
645
+ var _stack = [];
646
+ try {
647
+ const pm = whichPm();
648
+ const _4 = __using(_stack, Logger.suspendLogging(`Installing dependencies with ${pm}`));
649
+ await performInstallDependencies({ projectPath, cwd: cwd2, pm });
650
+ } catch (_) {
651
+ var _error = _, _hasError = true;
652
+ } finally {
653
+ __callDispose(_stack, _error, _hasError);
654
+ }
655
+ }
656
+ } catch (_2) {
657
+ var _error2 = _2, _hasError2 = true;
658
+ } finally {
659
+ __callDispose(_stack2, _error2, _hasError2);
660
+ }
661
+ }
662
+ const output = createConfigFileOnly ? upath.join(dist, DEFAULT_CONFIG_FILENAME) : dist;
663
+ const relativeOutput = upath.relative(cwd2, output) || ".";
664
+ const formattedOutput = terminalLink(
665
+ cyan(relativeOutput),
666
+ pathToFileURL(output).href,
667
+ { fallback: (text) => text }
668
+ );
669
+ if (createConfigFileOnly) {
670
+ Logger.logSuccess(
671
+ `Successfully created a config file at ${formattedOutput}`
672
+ );
673
+ } else {
674
+ caveat(`Successfully created a project at ${formattedOutput}`, {
675
+ relativeOutput,
676
+ installDependencies: Boolean(installDependencies)
677
+ });
678
+ }
679
+ }
680
+ async function askProjectPath() {
681
+ return await askQuestion({
682
+ question: {
683
+ projectPath: {
684
+ type: "text",
685
+ message: "Where should we create your project?",
686
+ placeholder: 'Specify "." to create files in the current directory.',
687
+ required: true
688
+ }
689
+ },
690
+ schema: v2.required(
691
+ v2.pick(VivliostyleInlineConfigWithoutChecks, ["projectPath"])
692
+ )
693
+ });
694
+ }
695
+ async function askTitle({ projectPath }) {
696
+ return await askQuestion({
697
+ question: {
698
+ title: {
699
+ type: "text",
700
+ message: "What's the title of your publication?",
701
+ defaultValue: toTitleCase(projectPath) || DEFAULT_PROJECT_TITLE,
702
+ placeholder: toTitleCase(projectPath) || DEFAULT_PROJECT_TITLE
703
+ }
704
+ },
705
+ schema: v2.required(v2.pick(VivliostyleInlineConfigWithoutChecks, ["title"]))
706
+ });
707
+ }
708
+ async function askAuthor() {
709
+ return await askQuestion({
710
+ question: {
711
+ author: {
712
+ type: "text",
713
+ message: "What's the author name?",
714
+ defaultValue: DEFAULT_PROJECT_AUTHOR,
715
+ placeholder: DEFAULT_PROJECT_AUTHOR
716
+ }
717
+ },
718
+ schema: v2.required(
719
+ v2.pick(VivliostyleInlineConfigWithoutChecks, ["author"])
720
+ )
721
+ });
722
+ }
723
+ async function askLanguage() {
724
+ const initialValue = await getOsLocale();
725
+ return await askQuestion({
726
+ question: {
727
+ language: {
728
+ type: "autocomplete",
729
+ message: "What's the language?",
730
+ options: Object.entries(languages).map(([value, displayName]) => ({
731
+ value,
732
+ label: displayName,
733
+ hint: value
734
+ })),
735
+ initialValue
736
+ }
737
+ },
738
+ schema: v2.required(
739
+ v2.pick(VivliostyleInlineConfigWithoutChecks, ["language"])
740
+ )
741
+ });
742
+ }
743
+ var PRESET_TEMPLATE_NOT_USE = "Use templates from the community theme";
744
+ async function askPresetTemplate() {
745
+ const { presetTemplate } = await askQuestion({
746
+ question: {
747
+ presetTemplate: {
748
+ type: "select",
749
+ message: "What's the project template?",
750
+ options: [
751
+ ...TEMPLATE_SETTINGS,
752
+ {
753
+ value: PRESET_TEMPLATE_NOT_USE,
754
+ label: PRESET_TEMPLATE_NOT_USE,
755
+ hint: "If a theme includes a template, you can choose it in the next step."
756
+ }
757
+ ]
758
+ }
759
+ },
760
+ schema: v2.object({
761
+ presetTemplate: v2.pipe(
762
+ v2.string(),
763
+ v2.transform(
764
+ (value) => value === PRESET_TEMPLATE_NOT_USE ? void 0 : TEMPLATE_SETTINGS.find((t) => t.value === value)
765
+ )
766
+ )
767
+ })
768
+ });
769
+ return { presetTemplate };
770
+ }
771
+ var TRUNCATE_LENGTH = 60;
772
+ var truncateString = (str) => {
773
+ const trimmed = str.replace(/\s+/g, " ");
774
+ return trimmed.length > TRUNCATE_LENGTH ? trimmed.slice(0, TRUNCATE_LENGTH) + "\u2026" : trimmed;
775
+ };
776
+ var THEME_ANSWER_NOT_USE = "Not use Vivliostyle theme";
777
+ var THEME_ANSWER_MANUAL = "Install other themes from npm";
778
+ async function askTheme({
779
+ template,
780
+ presetTemplate,
781
+ fetch
782
+ }) {
783
+ const useCommunityThemes = !presetTemplate && !template;
784
+ const themePackages = await interactiveLogLoading(
785
+ "Fetching a list of Vivliostyle themes...",
786
+ async () => {
787
+ let themes = (await listVivliostyleThemes({ fetch })).objects;
788
+ if (useCommunityThemes) {
789
+ themes = themes.filter(
790
+ (theme2) => !theme2.package.name.startsWith("@vivliostyle/")
791
+ );
792
+ }
793
+ themes.sort((a, b) => {
794
+ const aIsOfficial = a.package.name.startsWith("@vivliostyle/") ? 1 : 0;
795
+ const bIsOfficial = b.package.name.startsWith("@vivliostyle/") ? 1 : 0;
796
+ return aIsOfficial ^ bIsOfficial ? bIsOfficial - aIsOfficial : b.downloads.monthly - a.downloads.monthly;
797
+ });
798
+ return themes.map((theme2) => theme2.package);
799
+ }
800
+ );
801
+ let themePackage;
802
+ const fetchedPackages = {};
803
+ const validateThemeMetadataSchema = v2.customAsync(async (value) => {
804
+ if (value === THEME_ANSWER_NOT_USE || value === THEME_ANSWER_MANUAL) {
805
+ return true;
806
+ }
807
+ if (typeof value !== "string") {
808
+ return false;
809
+ }
810
+ fetchedPackages[value] ??= await fetchPackageMetadata({
811
+ fetch,
812
+ packageName: value,
813
+ version: "latest"
814
+ });
815
+ const pkg = fetchedPackages[value];
816
+ const ret = v2.safeParse(
817
+ v2.object({
818
+ name: v2.string(),
819
+ version: v2.string(),
820
+ vivliostyle: v2.optional(VivliostylePackageMetadata)
821
+ }),
822
+ pkg
823
+ );
824
+ if (ret.success) {
825
+ themePackage = ret.output;
826
+ }
827
+ return ret.success;
828
+ }, "Invalid theme package. Please check the schema of the `vivliostyle` field.");
829
+ let { theme } = await askQuestion({
830
+ question: {
831
+ theme: {
832
+ type: "autocomplete",
833
+ message: "What's the project theme?",
834
+ options: [
835
+ ...!useCommunityThemes ? [{ label: THEME_ANSWER_NOT_USE, value: THEME_ANSWER_NOT_USE }] : [],
836
+ { label: THEME_ANSWER_MANUAL, value: THEME_ANSWER_MANUAL },
837
+ ...themePackages.map((pkg) => ({
838
+ label: pkg.name,
839
+ value: pkg.name,
840
+ hint: truncateString(pkg.description || "")
841
+ }))
842
+ ],
843
+ initialValue: themePackages[0].name
844
+ }
845
+ },
846
+ schema: v2.objectAsync({ theme: validateThemeMetadataSchema }),
847
+ validateProgressMessage: "Fetching package metadata..."
848
+ });
849
+ if (theme === THEME_ANSWER_NOT_USE) {
850
+ return { theme: void 0, themePackage: void 0 };
851
+ }
852
+ if (theme === THEME_ANSWER_MANUAL) {
853
+ theme = await askQuestion({
854
+ question: {
855
+ themeManualInput: {
856
+ type: "text",
857
+ message: "Input npm package name:",
858
+ required: true
859
+ }
860
+ },
861
+ schema: v2.objectAsync({
862
+ themeManualInput: v2.pipeAsync(
863
+ v2.string(),
864
+ v2.customAsync(async (packageName) => {
865
+ if (typeof packageName !== "string") {
866
+ return false;
867
+ }
868
+ try {
869
+ fetchedPackages[packageName] = await fetchPackageMetadata({
870
+ fetch,
871
+ packageName,
872
+ version: "latest"
873
+ });
874
+ return true;
875
+ } catch (error) {
876
+ return false;
877
+ }
878
+ }, "Package not found"),
879
+ validateThemeMetadataSchema
880
+ )
881
+ }),
882
+ validateProgressMessage: "Fetching package metadata..."
883
+ }).then((ret) => ret.themeManualInput);
884
+ }
885
+ return {
886
+ theme: [
887
+ { specifier: themePackage ? `${theme}@^${themePackage.version}` : theme }
888
+ ],
889
+ themePackage
890
+ };
891
+ }
892
+ async function askThemeTemplate(themeMetadata) {
893
+ const themeTemplate = themeMetadata?.template;
894
+ const options = Object.entries(themeTemplate || {}).map(([value, tmpl]) => ({
895
+ label: tmpl.name || value,
896
+ value,
897
+ hint: truncateString(tmpl.description || "")
898
+ }));
899
+ if (!themeTemplate || options.length === 0) {
900
+ interactiveLogWarn(
901
+ "The chosen theme does not set template settings. Applying the minimal template."
902
+ );
903
+ return {
904
+ template: TEMPLATE_SETTINGS.find((t) => t.value === "minimal").template,
905
+ extraTemplateVariables: {}
906
+ };
907
+ }
908
+ const { usingTemplate } = await askQuestion({
909
+ question: {
910
+ usingTemplate: {
911
+ type: "autocomplete",
912
+ message: "Which template do you want to use?",
913
+ options
914
+ }
915
+ },
916
+ schema: v2.object({
917
+ usingTemplate: v2.pipe(
918
+ v2.string(),
919
+ v2.transform((input) => themeTemplate[input])
920
+ )
921
+ })
922
+ });
923
+ let extraTemplateVariables = {};
924
+ if (usingTemplate.prompt?.length) {
925
+ extraTemplateVariables = await askQuestion({
926
+ question: Object.fromEntries(
927
+ usingTemplate.prompt.map((q) => [q.name, q])
928
+ )
929
+ });
930
+ }
931
+ return { template: usingTemplate.source, extraTemplateVariables };
932
+ }
933
+ async function askInstallDependencies() {
934
+ return await askQuestion({
935
+ question: {
936
+ installDependencies: {
937
+ type: "select",
938
+ message: "Should we install dependencies? (You can install them later.)",
939
+ options: [
940
+ { label: "Yes", value: true },
941
+ { label: "No", value: false }
942
+ ]
943
+ }
944
+ },
945
+ schema: v2.object({
946
+ installDependencies: v2.boolean()
947
+ })
948
+ });
949
+ }
950
+ async function setupTemplate({
951
+ cwd: cwd2,
952
+ projectPath,
953
+ template,
954
+ templateVariables,
955
+ useLocalTemplate
956
+ }) {
957
+ if (useLocalTemplate) {
958
+ const matcher = new GlobMatcher([
959
+ {
960
+ patterns: ["**"],
961
+ ignore: ["**/node_modules/**", "**/.git/**"],
962
+ dot: true,
963
+ cwd: template
964
+ }
965
+ ]);
966
+ const files = await matcher.glob({ followSymbolicLinks: true });
967
+ Logger.debug("setupTemplate > files from local template %O", files);
968
+ for (const file of files) {
969
+ const targetPath = upath.join(cwd2, projectPath, file);
970
+ fs.mkdirSync(upath.dirname(targetPath), { recursive: true });
971
+ await copy(upath.join(template, file), targetPath);
972
+ }
973
+ } else {
974
+ const tmpDownloadDir = upath.join(
975
+ cwd2,
976
+ projectPath,
977
+ `.vs-template-${Date.now()}`
978
+ );
979
+ Logger.debug("setupTemplate > tmpDownloadDir %s", tmpDownloadDir);
980
+ const cleanupExitHandler = registerExitHandler(
981
+ `Removing the temporary directory: ${tmpDownloadDir}`,
982
+ () => {
983
+ fs.rmSync(tmpDownloadDir, { recursive: true, force: true });
984
+ }
985
+ );
986
+ await downloadTemplate(template, { dir: tmpDownloadDir });
987
+ for (const entry of fs.readdirSync(tmpDownloadDir)) {
988
+ fs.renameSync(
989
+ upath.join(tmpDownloadDir, entry),
990
+ upath.join(cwd2, projectPath, entry)
991
+ );
992
+ }
993
+ cleanupExitHandler()?.();
994
+ }
995
+ for (const [file, content] of Object.entries(TEMPLATE_DEFAULT_FILES)) {
996
+ const targetPath = upath.join(cwd2, projectPath, file);
997
+ if (fs.existsSync(targetPath)) {
998
+ continue;
999
+ }
1000
+ fs.mkdirSync(upath.dirname(targetPath), { recursive: true });
1001
+ fs.writeFileSync(targetPath, content, "utf8");
1002
+ }
1003
+ const replaceTemplateVariable = (dir) => {
1004
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
1005
+ const entryPath = upath.join(dir, entry.name);
1006
+ if (entry.isDirectory()) {
1007
+ replaceTemplateVariable(entryPath);
1008
+ } else {
1009
+ const buf = fs.readFileSync(entryPath);
1010
+ if (!isUtf8(buf)) {
1011
+ continue;
1012
+ }
1013
+ fs.writeFileSync(
1014
+ entryPath,
1015
+ format(buf.toString(), templateVariables),
1016
+ "utf8"
1017
+ );
1018
+ }
1019
+ }
1020
+ };
1021
+ replaceTemplateVariable(upath.join(cwd2, projectPath));
1022
+ }
1023
+ function setupConfigFile({
1024
+ cwd: cwd2,
1025
+ projectPath,
1026
+ templateVariables
1027
+ }) {
1028
+ const targetPath = upath.join(cwd2, projectPath, DEFAULT_CONFIG_FILENAME);
1029
+ const content = TEMPLATE_DEFAULT_FILES[DEFAULT_CONFIG_FILENAME];
1030
+ fs.mkdirSync(upath.dirname(targetPath), { recursive: true });
1031
+ fs.writeFileSync(targetPath, format(content, templateVariables), "utf8");
1032
+ }
1033
+ async function performInstallDependencies({
1034
+ pm,
1035
+ cwd: cwd2,
1036
+ projectPath
1037
+ }) {
1038
+ const { execa } = await importNodeModule("execa");
1039
+ await execa(pm, ["install"], {
1040
+ cwd: upath.join(cwd2, projectPath),
1041
+ stdio: "inherit"
1042
+ });
1043
+ }
1044
+ function caveat(message, {
1045
+ relativeOutput,
1046
+ installDependencies
1047
+ }) {
1048
+ const steps = [];
1049
+ if (relativeOutput !== ".") {
1050
+ steps.push(`Navigate to ${green2(relativeOutput)}`);
1051
+ }
1052
+ if (!installDependencies) {
1053
+ steps.push(`${cyan("npm install")} to install dependencies`);
1054
+ }
1055
+ steps.push("Create and edit Markdown files");
1056
+ steps.push(
1057
+ `Modify the ${cyan("entry")} field in ${green2("vivliostyle.config.js")}`
1058
+ );
1059
+ steps.push(`${cyan("npm run preview")} to open a preview browser window`);
1060
+ steps.push(`${cyan("npm run build")} to generate the output file`);
1061
+ Logger.logSuccess(message);
1062
+ Logger.log(
1063
+ `
1064
+ Next steps:
1065
+ ${steps.map((s, i) => gray2(`${i + 1}. `) + s).join("\n")}
1066
+
1067
+ For more information, visit ${terminalLink(yellow2("https://docs.vivliostyle.org"), "https://docs.vivliostyle.org", { fallback: (text) => text })}.
1068
+
1069
+ \u{1F58B} Happy writing!`
1070
+ );
1071
+ }
1072
+
1073
+ export {
1074
+ create
1075
+ };
1076
+ //# sourceMappingURL=chunk-RPMMYPTR.js.map