import { C as TEMPLATE_SETTINGS, S as TEMPLATE_DEFAULT_VIVLIOSTYLE_CONFIG_JS, c as DEFAULT_CONFIG_FILENAME, l as DEFAULT_PROJECT_AUTHOR, u as DEFAULT_PROJECT_TITLE, x as TEMPLATE_DEFAULT_PACKAGE_JSON, y as LANGUAGES } from "./constants-DgZl8nng.js";
import { B as isUnicodeSupported, L as whichPm, M as toTitleCase, a as cwd, d as getDefaultBrowserTag, h as getOsLocale, i as coreVersion, l as executeWithCleanupOnInterrupt, r as cliVersion, z as Logger } from "./util-CsmUMRtR.js";
import { D as VivliostyleInlineConfigWithoutChecks, O as VivliostylePackageMetadata, w as ValidString } from "./schema-DFj2EinN.js";
import { a as _usingCtx, s as locateVivliostyleConfig, t as GlobMatcher } from "./asset-DBj3nifv.js";
import { t as PromptCancelError } from "./entry-util-Bh1ksaYK.js";
import * as v from "valibot";
import upath from "upath";
import fs from "node:fs";
import { titleCase } from "title-case";
import { blueBright, cyan, dim, gray, green, hidden, inverse, redBright, strikethrough, yellow, yellowBright } from "yoctocolors";
import { pathToFileURL } from "node:url";
import terminalLink from "terminal-link";
import { x } from "tinyexec";
import { copy } from "fs-extra/esm";
import { isUtf8 } from "node:buffer";
import { downloadTemplate } from "@bluwy/giget-core";
import { camelCase, capitalCase, kebabCase, snakeCase } from "change-case";
import Handlebars from "handlebars";
import { AutocompletePrompt, MultiSelectPrompt, SelectPrompt, TextPrompt, getColumns, isCancel } from "@clack/core";
import { limitOptions } from "@clack/prompts";
import { wrapAnsi } from "fast-wrap-ansi";
import { cursor, erase } from "sisteransi";
import { fetch } from "node-fetch-native";
import { createProxy } from "node-fetch-native/proxy";
//#region src/create-template.ts
function upper(text) {
	return text && text.toUpperCase();
}
Handlebars.registerHelper("upper", upper);
function lower(text) {
	return text && text.toLowerCase();
}
Handlebars.registerHelper("lower", lower);
function capital(text) {
	return text && capitalCase(text);
}
Handlebars.registerHelper("capital", capital);
function camel(text) {
	return text && camelCase(text);
}
Handlebars.registerHelper("camel", camel);
function snake(text) {
	return text && snakeCase(text);
}
Handlebars.registerHelper("snake", snake);
function kebab(text) {
	return text && kebabCase(text);
}
Handlebars.registerHelper("kebab", kebab);
function proper(text) {
	return text && titleCase(text);
}
Handlebars.registerHelper("proper", proper);
function lorem() {
	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.";
}
Handlebars.registerHelper("lorem", lorem);
function json(data) {
	return JSON.stringify(data);
}
Handlebars.registerHelper("json", json);
function format(text, context) {
	return Handlebars.compile(text, { noEscape: true })(context);
}
//#endregion
//#region src/interactive.ts
async function askQuestion({ question: questions, interactiveLogger, schema, validateProgressMessage }) {
	const response = {};
	while (true) {
		for (const [name, question] of Object.entries(questions)) {
			let result;
			const maxItems = 10;
			const normalizeOptions = (options) => options.map((option) => typeof option === "string" ? { value: option } : option);
			const validate = (value = "") => {
				if (!question.required || "defaultValue" in question) return;
				const { success, issues } = v.safeParse(ValidString, value);
				return success ? void 0 : issues[0].message;
			};
			if (import.meta.env?.VITEST) question.name = name;
			if (question.type === "text") result = await textPrompt({
				...question,
				validate
			});
			else if (question.type === "select") result = await selectPrompt({
				...question,
				options: normalizeOptions(question.options),
				maxItems
			});
			else if (question.type === "multiSelect") result = await multiSelectPrompt({
				...question,
				options: normalizeOptions(question.options),
				maxItems
			});
			else if (question.type === "autocomplete") result = await autocompletePrompt({
				...question,
				options: normalizeOptions(question.options),
				maxItems,
				validate
			});
			else if (question.type === "autocompleteMultiSelect") result = await autocompleteMultiSelectPrompt({
				...question,
				options: normalizeOptions(question.options),
				maxItems
			});
			else result = question;
			if (isCancel(result)) throw new PromptCancelError();
			response[name] = result;
			interactiveLogger.messageHistory.push({
				type: "question",
				message: question.message,
				answer: result
			});
		}
		let result;
		if (schema && schema.async) result = await interactiveLogger?.logLoading(validateProgressMessage ?? "", () => v.safeParseAsync(schema, response));
		else if (schema) result = v.safeParse(schema, response);
		else return response;
		const { success, output, issues } = result;
		if (success) return output;
		interactiveLogger.logWarn(issues[0].message);
	}
}
const promptStateSymbol = {
	initial: isUnicodeSupported ? "◆" : "*",
	active: isUnicodeSupported ? "◆" : "*",
	cancel: isUnicodeSupported ? "■" : "x",
	submit: isUnicodeSupported ? "◇" : "o",
	error: isUnicodeSupported ? "▲" : "x"
};
const radioActiveSymbol = isUnicodeSupported ? "◉" : ">";
const radioInactiveSymbol = isUnicodeSupported ? "◯" : " ";
const checkboxActiveSymbol = isUnicodeSupported ? "◼" : "[+]";
const checkboxInactiveSymbol = isUnicodeSupported ? "◻" : "[ ]";
const labelToString = (option) => option.label ?? String(option.value ?? "");
const renderListOption = (multiSelect, selectedValues) => (option, active) => {
	const Y = multiSelect ? checkboxActiveSymbol : radioActiveSymbol;
	const N = multiSelect ? checkboxInactiveSymbol : radioInactiveSymbol;
	if (option.disabled) return `${gray(N)} ${gray(labelToString(option))} ${gray("(disabled)")}`;
	return `${multiSelect && selectedValues?.includes(option.value) || !multiSelect && active ? green(Y) : dim(N)} ${active ? `${labelToString(option)}${option.hint ? ` ${dim(`(${option.hint})`)}` : ""}` : dim(labelToString(option))}`;
};
function textPrompt(opts) {
	return new TextPrompt({
		...opts,
		input: Logger.stdin,
		output: Logger.stdout,
		signal: Logger.signal,
		render() {
			const symbol = promptStateSymbol[this.state];
			const placeholder = opts.placeholder ? inverse(opts.placeholder[0]) + dim(opts.placeholder.slice(1)) : inverse(hidden("_"));
			const userInput = this.userInput ? this.userInputWithCursor : placeholder;
			const value = this.value ?? "";
			switch (this.state) {
				case "error": {
					const errorText = this.error ? `   ${yellow(this.error)}` : "";
					return `${yellow("║")}\n${yellow(`${symbol}─`)} ${opts.message}\n   ${userInput}\n${errorText}`;
				}
				case "submit": {
					const valueText = value ? `  ${dim(value)}` : "";
					return `${blueBright("║")}\n${blueBright(`${symbol}─`)} ${opts.message}\n${blueBright("║")}${valueText}`;
				}
				case "cancel": {
					const valueText = value ? `   ${strikethrough(dim(value))}` : "";
					return `${gray("║")}\n${gray(`${symbol}─`)} ${opts.message}\n${valueText}`;
				}
				default: return `${blueBright("║")}\n${blueBright(`${symbol}─`)} ${opts.message}\n   ${userInput}\n`;
			}
		}
	}).prompt();
}
function selectPrompt(opts, multiple = false) {
	return new (multiple ? MultiSelectPrompt : SelectPrompt)({
		...opts,
		input: Logger.stdin,
		output: Logger.stdout,
		signal: Logger.signal,
		render() {
			const symbol = promptStateSymbol[this.state];
			const values = [this.value].flat();
			const selected = this.options.filter((o) => values.includes(o.value));
			const label = selected.length > 0 ? selected.map((o) => labelToString(o)).join(", ") : "none";
			switch (this.state) {
				case "submit": return `${blueBright("║")}\n${blueBright(`${symbol}─`)} ${opts.message}\n${blueBright("║")}  ${dim(label)}`;
				case "cancel": return `${gray("║")}\n${gray(`${symbol}─`)} ${opts.message}\n   ${strikethrough(dim(label))}`;
				default: {
					const indents = "   ";
					const displayingOptions = limitOptions({
						output: opts.output,
						cursor: this.cursor,
						options: this.options,
						maxItems: opts.maxItems,
						columnPadding: 3,
						style: renderListOption(multiple, Array.isArray(this.value) ? this.value : [])
					});
					return `${blueBright("║")}\n${blueBright(`${symbol}─`)} ${opts.message}\n   ${displayingOptions.join(`\n${indents}`)}\n`;
				}
			}
		}
	}).prompt();
}
function multiSelectPrompt(opts) {
	return selectPrompt(opts, true);
}
function autocompletePrompt(opts, multiple = false) {
	return new AutocompletePrompt({
		...opts,
		multiple,
		initialValue: opts.initialValue ? [opts.initialValue] : void 0,
		filter: (searchText, option) => {
			if (!searchText) return true;
			const label = (option.label ?? String(option.value ?? "")).toLowerCase();
			const hint = (option.hint ?? "").toLowerCase();
			const value = String(option.value).toLowerCase();
			const term = searchText.toLowerCase();
			return label.includes(term) || hint.includes(term) || value.includes(term);
		},
		input: Logger.stdin,
		output: Logger.stdout,
		signal: Logger.signal,
		render() {
			const symbol = promptStateSymbol[this.state];
			const selected = this.options.filter((o) => this.selectedValues.includes(o.value));
			const label = selected.length > 0 ? selected.map((o) => labelToString(o)).join(", ") : "none";
			switch (this.state) {
				case "submit": return `${blueBright("║")}\n${blueBright(`${symbol}─`)} ${opts.message}\n${blueBright("║")}  ${dim(label)}`;
				case "cancel": {
					const userInputText = this.userInput ? `  ${strikethrough(dim(this.userInput))}` : "";
					return `${gray("║")}\n${gray(`${symbol}─`)} ${opts.message}\n${userInputText}`;
				}
				default: {
					const indents = "   ";
					let searchText = "";
					if (this.isNavigating || opts.placeholder && !this.userInput) {
						const searchTextValue = opts.placeholder ?? this.userInput;
						searchText = searchTextValue ? ` ${dim(searchTextValue)}` : "";
					} else searchText = ` ${this.userInputWithCursor}`;
					const matches = this.filteredOptions.length === this.options.length ? "" : dim(` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? "" : "es"})`);
					const headings = [
						blueBright("║"),
						`${blueBright(`${symbol}─`)} ${opts.message}`,
						`${indents}${dim("Search:")}${searchText}${matches}`
					];
					if (this.filteredOptions.length === 0 && this.userInput) headings.push(`${indents}${yellow("No matches found")}`);
					if (this.state === "error") headings.push(`${indents}${yellow(`Error: ${this.error ?? ""}`)}`);
					const footers = [multiple ? `${indents}${dim("↑/↓ to navigate • Space/Tab: select • Enter: confirm • Type: to search")}` : `${indents}${dim("↑/↓ to select • Enter: confirm • Type: to search")}`];
					const displayingOptions = limitOptions({
						output: opts.output,
						cursor: this.cursor,
						options: this.filteredOptions,
						maxItems: opts.maxItems,
						columnPadding: 3,
						rowPadding: headings.length + footers.length,
						style: renderListOption(multiple, this.selectedValues)
					});
					return [
						...headings,
						...displayingOptions.map((s) => `${indents}${s}`),
						...footers
					].join("\n");
				}
			}
		}
	}).prompt();
}
function autocompleteMultiSelectPrompt(opts) {
	return autocompletePrompt(opts, true);
}
var InteractiveLogger = class {
	constructor() {
		this.messageHistory = [];
	}
	async logLoading(message, fn, deferredTimeMs = 300) {
		this.messageHistory.push({
			type: "loading",
			message
		});
		if (!Logger.isInteractive || import.meta.env?.VITEST) return fn();
		const output = Logger.stdout;
		const columns = getColumns(output);
		const showMessage = (msg) => {
			const wrapped = wrapAnsi(msg, columns, {
				hard: true,
				trim: false
			});
			output.write(wrapped);
			return () => {
				const prevLines = wrapped.split("\n");
				if (prevLines.length > 1) output.write(cursor.up(prevLines.length - 1));
				output.write(cursor.to(0));
				output.write(erase.down());
			};
		};
		let timer;
		let clearMessage;
		const promise = new Promise((resolve) => {
			timer = setTimeout(() => {
				output.write(`${blueBright("║")}\n`);
				clearMessage = showMessage(`${blueBright(`${promptStateSymbol.active}─`)} ${dim(message)}\n`);
				resolve();
			}, deferredTimeMs);
		});
		const result = await fn().then((r) => {
			if (!clearMessage) return r;
			return new Promise((resolve) => {
				setTimeout(() => resolve(r), deferredTimeMs);
			});
		}).catch(async (e) => {
			await promise;
			clearMessage?.();
			showMessage(`${redBright(`${promptStateSymbol.error}─`)} ${dim(message)}\n\n`);
			throw e;
		});
		clearTimeout(timer);
		if (clearMessage) {
			clearMessage();
			showMessage(`${blueBright(`${promptStateSymbol.submit}─`)} ${dim(message)}\n`);
		}
		return result;
	}
	logInfo(message) {
		this.messageHistory.push({
			type: "info",
			message
		});
		if (import.meta.env?.VITEST) return;
		Logger.stdout.write(`${blueBright(`${promptStateSymbol.submit}─`)} ${message.split("\n").join(`\n${blueBright("║")}  `)}\n`);
	}
	logWarn(message) {
		this.messageHistory.push({
			type: "warn",
			message
		});
		if (import.meta.env?.VITEST) return;
		Logger.stdout.write(`${yellowBright(`${promptStateSymbol.error}─`)} ${yellowBright(message.split("\n").join(`\n${yellowBright("║")}  `))}\n`);
	}
	logOutro(message) {
		this.messageHistory.push({
			type: "outro",
			message
		});
		if (import.meta.env?.VITEST) return;
		Logger.stdout.write(`${blueBright("║")}\n${blueBright("╙─")} ${message}\n\n`);
	}
};
//#endregion
//#region src/npm.ts
function createFetch(options) {
	const proxyUrl = options.proxyServer ?? process.env.HTTP_PROXY;
	const proxy = proxyUrl ? createProxy({
		url: proxyUrl,
		noProxy: options.proxyBypass ?? process.env.NO_PROXY ?? void 0
	}) : void 0;
	const token = options.proxyUser && options.proxyPass ? `Basic ${Buffer.from(`${options.proxyUser}:${options.proxyPass}`).toString("base64")}` : void 0;
	if (proxy && token) {
		const proxyHeadersKey = Object.getOwnPropertySymbols(proxy.dispatcher).find((symbol) => symbol.description === "proxy headers");
		if (proxyHeadersKey) proxy.dispatcher[proxyHeadersKey]["proxy-authorization"] = token;
	}
	return (url, fetchOptions) => {
		const signal = fetchOptions?.signal ?? options.signal;
		return fetch(url, {
			...proxy,
			...fetchOptions,
			signal
		}).catch((error) => {
			signal?.throwIfAborted();
			throw error;
		}).then((response) => {
			if (!response.ok) throw new Error(`Failed to fetch ${response.url}: ${response.status} ${response.statusText}`);
			return response;
		});
	};
}
function listVivliostyleThemes({ fetch }) {
	return fetch(`https://registry.npmjs.org/-/v1/search?text=keywords:vivliostyle-theme&size=250`).then((response) => response.json());
}
function fetchPackageMetadata({ fetch, packageName, version }) {
	return fetch(`https://registry.npmjs.org/${packageName}/${version}`).then((response) => response.json());
}
//#endregion
//#region src/core/create.ts
async function create(inlineConfig) {
	Logger.setLogOptions(inlineConfig);
	Logger.debug("create > inlineConfig %O", inlineConfig);
	const fetch = createFetch(inlineConfig);
	const interactiveLogger = new InteractiveLogger();
	let { projectPath, cwd: cwd$1 = cwd, title, author, language, theme, template, installDependencies, createConfigFileOnly = false } = inlineConfig;
	let extraTemplateVariables = {};
	let themePackage;
	let useLocalTemplate = false;
	if (template && !/^([\w.\-]+):/v.test(template)) {
		const absTemplatePath = upath.resolve(cwd$1, template);
		useLocalTemplate = fs.existsSync(upath.resolve(cwd$1, template)) && fs.statSync(upath.resolve(cwd$1, template)).isDirectory();
		const usingPresetTemplate = TEMPLATE_SETTINGS.find((t) => t.value === template);
		if (useLocalTemplate) {
			template = absTemplatePath;
			interactiveLogger.logInfo(`Using the specified local template directory\n${dim(upath.relative(cwd$1, absTemplatePath) || ".")}`);
		} else if (usingPresetTemplate) template = usingPresetTemplate.template;
		else interactiveLogger.logWarn(`The specified theme ${green(template)} was not found as a local directory. Proceeding to fetch it from GitHub repository.`);
	}
	if (!projectPath) ({projectPath} = await askProjectPath({ interactiveLogger }));
	const dist = upath.join(cwd$1, projectPath);
	if (createConfigFileOnly) {
		if (fs.existsSync(upath.join(dist, "vivliostyle.config.js"))) throw new Error(`${DEFAULT_CONFIG_FILENAME} already exists. Aborting.`);
	} else if (projectPath === "." && fs.readdirSync(dist).some((n) => !n.startsWith(".")) || projectPath !== "." && fs.existsSync(dist)) throw new Error(`Destination ${dist} is not empty.`);
	if (!title) ({title} = createConfigFileOnly ? { title: DEFAULT_PROJECT_TITLE } : await askTitle({
		projectPath,
		interactiveLogger
	}));
	if (!author) ({author} = createConfigFileOnly ? { author: DEFAULT_PROJECT_AUTHOR } : await askAuthor({ interactiveLogger }));
	if (!language) ({language} = createConfigFileOnly ? { language: getOsLocale() } : await askLanguage({ interactiveLogger }));
	if (!createConfigFileOnly) {
		let presetTemplate;
		if (!template) {
			({presetTemplate} = await askPresetTemplate({ interactiveLogger }));
			if (presetTemplate) template = presetTemplate.template;
		}
		if (!theme && theme !== false) ({theme, themePackage} = await askTheme({
			presetTemplate,
			template,
			fetch,
			interactiveLogger
		}));
		if (!template) ({template, extraTemplateVariables} = await askThemeTemplate({
			themeMetadata: themePackage?.vivliostyle,
			interactiveLogger
		}));
		if (typeof installDependencies !== "boolean") ({installDependencies} = await askInstallDependencies({ interactiveLogger }));
	}
	const browserType = "chrome";
	const browserTag = getDefaultBrowserTag(browserType);
	const explicitTemplateVariables = {
		...extraTemplateVariables,
		projectPath,
		title,
		author,
		language,
		theme: (() => {
			if (!theme) return;
			const arr = theme.map((t) => t.import ? t : t.specifier);
			return arr.length === 1 ? arr[0] : arr;
		})(),
		themePackage,
		template,
		cliVersion,
		coreVersion,
		browser: {
			type: browserType,
			tag: browserTag
		}
	};
	Logger.debug("create > explicitTemplateVariables %O", explicitTemplateVariables);
	if (createConfigFileOnly) setupConfigFile({
		projectPath,
		cwd: cwd$1,
		templateVariables: {
			...inlineConfig,
			...explicitTemplateVariables
		}
	});
	else try {
		var _usingCtx$1 = _usingCtx();
		if (interactiveLogger.messageHistory.length > 0) interactiveLogger.logOutro("All configurations are set! Creating your project...");
		_usingCtx$1.u(Logger.startLogging(useLocalTemplate ? "Copying a local template" : "Downloading a template"));
		/* v8 ignore next 3 */
		if (!template) throw new Error("No template is set to create a project.");
		await setupTemplate({
			projectPath,
			cwd: cwd$1,
			template,
			signal: inlineConfig.signal,
			templateVariables: {
				...inlineConfig,
				...explicitTemplateVariables
			},
			useLocalTemplate
		});
		if (installDependencies) try {
			var _usingCtx3 = _usingCtx();
			const pm = whichPm();
			_usingCtx3.u(Logger.suspendLogging(`Installing dependencies with ${pm}`));
			await performInstallDependencies({
				projectPath,
				cwd: cwd$1,
				pm,
				signal: inlineConfig.signal
			});
		} catch (_) {
			_usingCtx3.e = _;
		} finally {
			_usingCtx3.d();
		}
	} catch (_) {
		_usingCtx$1.e = _;
	} finally {
		_usingCtx$1.d();
	}
	const output = createConfigFileOnly ? upath.join(dist, DEFAULT_CONFIG_FILENAME) : dist;
	const relativeOutput = upath.relative(cwd$1, output) || ".";
	const formattedOutput = terminalLink(cyan(relativeOutput), pathToFileURL(output).href, { fallback: (text) => text });
	if (createConfigFileOnly) Logger.logSuccess(`Successfully created a config file at ${formattedOutput}`);
	else caveat(`Successfully created a project at ${formattedOutput}`, {
		relativeOutput,
		installDependencies: Boolean(installDependencies)
	});
}
function askProjectPath({ interactiveLogger }) {
	return askQuestion({
		question: { projectPath: {
			type: "text",
			message: "Where should we create your project?",
			placeholder: "Specify \".\" to create files in the current directory.",
			required: true
		} },
		schema: v.required(v.pick(VivliostyleInlineConfigWithoutChecks, ["projectPath"])),
		interactiveLogger
	});
}
function askTitle({ projectPath, interactiveLogger }) {
	return askQuestion({
		question: { title: {
			type: "text",
			message: "What's the title of your publication?",
			defaultValue: toTitleCase(projectPath) || "My Title",
			placeholder: toTitleCase(projectPath) || "My Title"
		} },
		schema: v.required(v.pick(VivliostyleInlineConfigWithoutChecks, ["title"])),
		interactiveLogger
	});
}
function askAuthor({ interactiveLogger }) {
	return askQuestion({
		question: { author: {
			type: "text",
			message: "What's the author name?",
			defaultValue: DEFAULT_PROJECT_AUTHOR,
			placeholder: DEFAULT_PROJECT_AUTHOR
		} },
		schema: v.required(v.pick(VivliostyleInlineConfigWithoutChecks, ["author"])),
		interactiveLogger
	});
}
function askLanguage({ interactiveLogger }) {
	const initialValue = getOsLocale();
	return askQuestion({
		question: { language: {
			type: "autocomplete",
			message: "What's the language?",
			options: Object.entries(LANGUAGES).map(([value, displayName]) => ({
				value,
				label: displayName,
				hint: value
			})),
			initialValue
		} },
		schema: v.required(v.pick(VivliostyleInlineConfigWithoutChecks, ["language"])),
		interactiveLogger
	});
}
const PRESET_TEMPLATE_NOT_USE = "Use templates from the community theme";
async function askPresetTemplate({ interactiveLogger }) {
	const { presetTemplate } = await askQuestion({
		question: { presetTemplate: {
			type: "select",
			message: "What's the project template?",
			options: [...TEMPLATE_SETTINGS, {
				value: PRESET_TEMPLATE_NOT_USE,
				label: PRESET_TEMPLATE_NOT_USE,
				hint: "If a theme includes a template, you can choose it in the next step."
			}]
		} },
		schema: v.object({ presetTemplate: v.pipe(v.string(), v.transform((value) => value === "Use templates from the community theme" ? void 0 : TEMPLATE_SETTINGS.find((t) => t.value === value))) }),
		interactiveLogger
	});
	return { presetTemplate };
}
const TRUNCATE_LENGTH = 60;
const truncateString = (str) => {
	const trimmed = str.replaceAll(/\s+/gv, " ");
	return trimmed.length > TRUNCATE_LENGTH ? trimmed.slice(0, TRUNCATE_LENGTH) + "…" : trimmed;
};
const THEME_ANSWER_NOT_USE = "Not use Vivliostyle theme";
const THEME_ANSWER_MANUAL = "Install other themes from npm";
async function askTheme({ template, presetTemplate, fetch, interactiveLogger }) {
	const useCommunityThemes = !presetTemplate && !template;
	const themePackages = await interactiveLogger.logLoading("Fetching a list of Vivliostyle themes...", async () => {
		let themes = (await listVivliostyleThemes({ fetch })).objects;
		if (useCommunityThemes) themes = themes.filter((theme) => !theme.package.name.startsWith("@vivliostyle/"));
		themes.sort((a, b) => {
			const aIsOfficial = a.package.name.startsWith("@vivliostyle/") ? 1 : 0;
			const bIsOfficial = b.package.name.startsWith("@vivliostyle/") ? 1 : 0;
			return aIsOfficial ^ bIsOfficial ? bIsOfficial - aIsOfficial : b.downloads.monthly - a.downloads.monthly;
		});
		return themes.map((theme) => theme.package);
	});
	let themePackage;
	const fetchedPackages = {};
	const validateThemeMetadataSchema = v.customAsync(async (value) => {
		if (value === "Not use Vivliostyle theme" || value === "Install other themes from npm") return true;
		if (typeof value !== "string") return false;
		fetchedPackages[value] ??= await fetchPackageMetadata({
			fetch,
			packageName: value,
			version: "latest"
		});
		const pkg = fetchedPackages[value];
		const ret = v.safeParse(v.object({
			name: v.string(),
			version: v.string(),
			vivliostyle: v.optional(VivliostylePackageMetadata)
		}), pkg);
		if (ret.success) themePackage = ret.output;
		return ret.success;
	}, "Invalid theme package. Please check the schema of the `vivliostyle` field.");
	let { theme } = await askQuestion({
		question: { theme: {
			type: "autocomplete",
			message: "What's the project theme?",
			options: [
				...useCommunityThemes ? [] : [{
					label: THEME_ANSWER_NOT_USE,
					value: THEME_ANSWER_NOT_USE
				}],
				{
					label: THEME_ANSWER_MANUAL,
					value: THEME_ANSWER_MANUAL
				},
				...themePackages.map((pkg) => ({
					label: pkg.name,
					value: pkg.name,
					hint: truncateString(pkg.description || "")
				}))
			],
			initialValue: themePackages[0].name
		} },
		schema: v.objectAsync({ theme: validateThemeMetadataSchema }),
		validateProgressMessage: "Fetching package metadata...",
		interactiveLogger
	});
	if (theme === "Not use Vivliostyle theme") return {
		theme: void 0,
		themePackage: void 0
	};
	if (theme === "Install other themes from npm") theme = await askQuestion({
		question: { themeManualInput: {
			type: "text",
			message: "Input npm package name:",
			required: true
		} },
		schema: v.objectAsync({ themeManualInput: v.pipeAsync(v.string(), v.customAsync(async (packageName) => {
			if (typeof packageName !== "string") return false;
			try {
				fetchedPackages[packageName] = await fetchPackageMetadata({
					fetch,
					packageName,
					version: "latest"
				});
				return true;
			} catch (error) {
				return false;
			}
		}, "Package not found"), validateThemeMetadataSchema) }),
		validateProgressMessage: "Fetching package metadata...",
		interactiveLogger
	}).then((ret) => ret.themeManualInput);
	return {
		theme: [{ specifier: themePackage ? `${theme}@^${themePackage.version}` : theme }],
		themePackage
	};
}
async function askThemeTemplate({ interactiveLogger, themeMetadata }) {
	const themeTemplate = themeMetadata?.template;
	const options = Object.entries(themeTemplate ?? {}).map(([value, tmpl]) => ({
		label: tmpl.name || value,
		value,
		hint: truncateString(tmpl.description || "")
	}));
	if (!themeTemplate || options.length === 0) {
		interactiveLogger.logWarn("The chosen theme does not set template settings. Applying the minimal template.");
		const minimalTemplate = TEMPLATE_SETTINGS.find((t) => t.value === "minimal");
		/* v8 ignore next 3 */
		if (!minimalTemplate) throw new Error("The minimal template setting is not found.");
		return {
			template: minimalTemplate.template,
			extraTemplateVariables: {}
		};
	}
	const { usingTemplate } = await askQuestion({
		question: { usingTemplate: {
			type: "autocomplete",
			message: "Which template do you want to use?",
			options
		} },
		schema: v.object({ usingTemplate: v.pipe(v.string(), v.transform((input) => themeTemplate[input])) }),
		interactiveLogger
	});
	let extraTemplateVariables = {};
	if (usingTemplate.prompt?.length) extraTemplateVariables = await askQuestion({
		question: Object.fromEntries(usingTemplate.prompt.map((q) => [q.name, q])),
		interactiveLogger
	});
	return {
		template: usingTemplate.source,
		extraTemplateVariables
	};
}
function askInstallDependencies({ interactiveLogger }) {
	return askQuestion({
		question: { installDependencies: {
			type: "select",
			message: "Should we install dependencies? (You can install them later.)",
			options: [{
				label: "Yes",
				value: true
			}, {
				label: "No",
				value: false
			}]
		} },
		schema: v.object({ installDependencies: v.boolean() }),
		interactiveLogger
	});
}
async function setupTemplate({ cwd, projectPath, template, templateVariables, useLocalTemplate, signal }) {
	signal?.throwIfAborted();
	if (useLocalTemplate) {
		const files = await new GlobMatcher([{
			patterns: ["**"],
			ignore: ["**/node_modules/**", "**/.git/**"],
			dot: true,
			cwd: template
		}]).glob({ followSymbolicLinks: true });
		signal?.throwIfAborted();
		Logger.debug("setupTemplate > files from local template %O", files);
		for (const file of files) {
			signal?.throwIfAborted();
			const targetPath = upath.join(cwd, projectPath, file);
			fs.mkdirSync(upath.dirname(targetPath), { recursive: true });
			await copy(upath.join(template, file), targetPath);
			signal?.throwIfAborted();
		}
	} else {
		const tmpDownloadDir = upath.join(cwd, projectPath, `.vs-template-${Date.now()}`);
		Logger.debug("setupTemplate > tmpDownloadDir %s", tmpDownloadDir);
		await executeWithCleanupOnInterrupt(`Removing the temporary directory: ${tmpDownloadDir}`, async () => {
			try {
				await downloadTemplate(template, { dir: tmpDownloadDir });
				signal?.throwIfAborted();
				for (const entry of fs.readdirSync(tmpDownloadDir)) {
					fs.renameSync(upath.join(tmpDownloadDir, entry), upath.join(cwd, projectPath, entry));
					signal?.throwIfAborted();
				}
			} catch (error) {
				signal?.throwIfAborted();
				throw error;
			}
		}, () => {
			fs.rmSync(tmpDownloadDir, {
				recursive: true,
				force: true
			});
		});
	}
	const packageJsonPath = upath.join(cwd, projectPath, "package.json");
	if (!fs.existsSync(packageJsonPath)) fs.writeFileSync(packageJsonPath, TEMPLATE_DEFAULT_PACKAGE_JSON, "utf8");
	if (!locateVivliostyleConfig({ cwd: upath.join(cwd, projectPath) })) fs.writeFileSync(upath.join(cwd, projectPath, DEFAULT_CONFIG_FILENAME), TEMPLATE_DEFAULT_VIVLIOSTYLE_CONFIG_JS, "utf8");
	const replaceTemplateVariable = (dir) => {
		for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
			const entryPath = upath.join(dir, entry.name);
			if (entry.isDirectory()) replaceTemplateVariable(entryPath);
			else {
				const buf = fs.readFileSync(entryPath);
				if (!isUtf8(buf)) continue;
				fs.writeFileSync(entryPath, format(buf.toString(), templateVariables), "utf8");
			}
		}
	};
	replaceTemplateVariable(upath.join(cwd, projectPath));
}
function setupConfigFile({ cwd, projectPath, templateVariables }) {
	const targetPath = upath.join(cwd, projectPath, DEFAULT_CONFIG_FILENAME);
	const content = TEMPLATE_DEFAULT_VIVLIOSTYLE_CONFIG_JS;
	fs.mkdirSync(upath.dirname(targetPath), { recursive: true });
	fs.writeFileSync(targetPath, format(content, templateVariables), "utf8");
}
async function performInstallDependencies({ pm, cwd, projectPath, signal }) {
	signal?.throwIfAborted();
	const proc = x(pm, ["install"], {
		throwOnError: true,
		signal,
		nodeOptions: {
			cwd: upath.join(cwd, projectPath),
			stdio: Logger.isInteractive ? "inherit" : void 0
		}
	});
	await executeWithCleanupOnInterrupt("Waiting for dependency installation to stop", async () => {
		try {
			if (Logger.isInteractive) await proc;
			else for await (const line of proc) Logger.log(line);
			signal?.throwIfAborted();
		} catch (error) {
			signal?.throwIfAborted();
			throw error;
		}
	});
}
function caveat(message, { relativeOutput, installDependencies }) {
	const steps = [];
	if (relativeOutput !== ".") steps.push(`Navigate to ${green(relativeOutput)}`);
	if (!installDependencies) steps.push(`${cyan("npm install")} to install dependencies`);
	steps.push("Create and edit Markdown files", `Modify the ${cyan("entry")} field in ${green("vivliostyle.config.js")}`, `${cyan("npm run preview")} to open a preview browser window`, `${cyan("npm run build")} to generate the output file`);
	Logger.logSuccess(message);
	Logger.log(`
Next steps:
${steps.map((s, i) => gray(`${i + 1}. `) + s).join("\n")}

For more information, visit ${terminalLink(yellow("https://docs.vivliostyle.org"), "https://docs.vivliostyle.org", { fallback: (text) => text })}.

🖋 Happy writing!`);
}
//#endregion
export { create as t };

//# sourceMappingURL=create-BF3vSlSR.js.map