text: import fs__default, { existsSync } from 'fs';
  import sade from 'sade';
  import { exec as exec$1 } from 'child_process';
  import 'net';
  import * as url from 'url';
  import path__default from 'path';
  import { networkInterfaces, release } from 'os';
  
  let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;
  if (typeof process !== 'undefined') {
  	({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env);
  	isTTY = process.stdout && process.stdout.isTTY;
  }
  
  const $ = {
  	enabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (
  		FORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY
  	),
  
  	// modifiers
  	reset: init(0, 0),
  	bold: init(1, 22),
  	dim: init(2, 22),
  	italic: init(3, 23),
  	underline: init(4, 24),
  	inverse: init(7, 27),
  	hidden: init(8, 28),
  	strikethrough: init(9, 29),
  
  	// colors
  	black: init(30, 39),
  	red: init(31, 39),
  	green: init(32, 39),
  	yellow: init(33, 39),
  	blue: init(34, 39),
  	magenta: init(35, 39),
  	cyan: init(36, 39),
  	white: init(37, 39),
  	gray: init(90, 39),
  	grey: init(90, 39),
  
  	// background colors
  	bgBlack: init(40, 49),
  	bgRed: init(41, 49),
  	bgGreen: init(42, 49),
  	bgYellow: init(43, 49),
  	bgBlue: init(44, 49),
  	bgMagenta: init(45, 49),
  	bgCyan: init(46, 49),
  	bgWhite: init(47, 49)
  };
  
  function run(arr, str) {
  	let i=0, tmp, beg='', end='';
  	for (; i < arr.length; i++) {
  		tmp = arr[i];
  		beg += tmp.open;
  		end += tmp.close;
  		if (!!~str.indexOf(tmp.close)) {
  			str = str.replace(tmp.rgx, tmp.close + tmp.open);
  		}
  	}
  	return beg + str + end;
  }
  
  function chain(has, keys) {
  	let ctx = { has, keys };
  
  	ctx.reset = $.reset.bind(ctx);
  	ctx.bold = $.bold.bind(ctx);
  	ctx.dim = $.dim.bind(ctx);
  	ctx.italic = $.italic.bind(ctx);
  	ctx.underline = $.underline.bind(ctx);
  	ctx.inverse = $.inverse.bind(ctx);
  	ctx.hidden = $.hidden.bind(ctx);
  	ctx.strikethrough = $.strikethrough.bind(ctx);
  
  	ctx.black = $.black.bind(ctx);
  	ctx.red = $.red.bind(ctx);
  	ctx.green = $.green.bind(ctx);
  	ctx.yellow = $.yellow.bind(ctx);
  	ctx.blue = $.blue.bind(ctx);
  	ctx.magenta = $.magenta.bind(ctx);
  	ctx.cyan = $.cyan.bind(ctx);
  	ctx.white = $.white.bind(ctx);
  	ctx.gray = $.gray.bind(ctx);
  	ctx.grey = $.grey.bind(ctx);
  
  	ctx.bgBlack = $.bgBlack.bind(ctx);
  	ctx.bgRed = $.bgRed.bind(ctx);
  	ctx.bgGreen = $.bgGreen.bind(ctx);
  	ctx.bgYellow = $.bgYellow.bind(ctx);
  	ctx.bgBlue = $.bgBlue.bind(ctx);
  	ctx.bgMagenta = $.bgMagenta.bind(ctx);
  	ctx.bgCyan = $.bgCyan.bind(ctx);
  	ctx.bgWhite = $.bgWhite.bind(ctx);
  
  	return ctx;
  }
  
  function init(open, close) {
  	let blk = {
  		open: `\x1b[${open}m`,
  		close: `\x1b[${close}m`,
  		rgx: new RegExp(`\\x1b\\[${close}m`, 'g')
  	};
  	return function (txt) {
  		if (this !== void 0 && this.has !== void 0) {
  			!!~this.has.indexOf(open) || (this.has.push(open),this.keys.push(blk));
  			return txt === void 0 ? this : $.enabled ? run(this.keys, txt+'') : txt+'';
  		}
  		return txt === void 0 ? chain([open], [blk]) : $.enabled ? run([blk], txt+'') : txt+'';
  	};
  }
  
  function exec(cmd) {
  	return new Promise((fulfil, reject) => {
  		exec$1(cmd, (error, stdout, stderr) => {
  			if (error) return reject(error);
  			fulfil({ stdout, stderr });
  		});
  	});
  }
  
  async function blame(port) {
  	try {
  		const { stdout } = await exec(`lsof -i :${port} -sTCP:LISTEN -Fp`);
  
  		if (!stdout) return null;
  		const pid = parseInt(stdout.slice(1), 10);
  		if (isNaN(pid)) throw new Error(`Invalid stdout ${stdout}`);
  
  		return pid;
  	} catch (error) {
  		return null;
  	}
  }
  
  const noop = () => {};
  
  /** @typedef {import('./types').ConfigDefinition} ConfigDefinition */
  
  /** @type {Record<string, ConfigDefinition>} */
  const options = {
  	compilerOptions: {
  		type: 'leaf',
  		default: null,
  		validate: noop
  	},
  
  	extensions: {
  		type: 'leaf',
  		default: ['.svelte'],
  		validate: (option, keypath) => {
  			if (!Array.isArray(option) || !option.every((page) => typeof page === 'string')) {
  				throw new Error(`${keypath} must be an array of strings`);
  			}
  
  			option.forEach((extension) => {
  				if (extension[0] !== '.') {
  					throw new Error(`Each member of ${keypath} must start with '.' — saw '${extension}'`);
  				}
  
  				if (!/^(\.[a-z0-9]+)+$/i.test(extension)) {
  					throw new Error(`File extensions must be alphanumeric — saw '${extension}'`);
  				}
  			});
  
  			return option;
  		}
  	},
  
  	kit: {
  		type: 'branch',
  		children: {
  			adapter: {
  				type: 'leaf',
  				default: null,
  				validate: (option, keypath) => {
  					if (typeof option !== 'object' || !option.adapt) {
  						let message = `${keypath} should be an object with an "adapt" method`;
  
  						if (Array.isArray(option) || typeof option === 'string') {
  							// for the early adapter adopters
  							message += ', rather than the name of an adapter';
  						}
  
  						throw new Error(`${message}. See https://kit.svelte.dev/docs#adapters`);
  					}
  
  					return option;
  				}
  			},
  
  			amp: expect_boolean(false),
  
  			appDir: expect_string('_app', false),
  
  			files: {
  				type: 'branch',
  				children: {
  					assets: expect_string('static'),
  					hooks: expect_string('src/hooks'),
  					lib: expect_string('src/lib'),
  					routes: expect_string('src/routes'),
  					serviceWorker: expect_string('src/service-worker'),
  					// TODO remove this, eventually
  					setup: expect_string('src/setup'),
  					template: expect_string('src/app.html')
  				}
  			},
  
  			floc: expect_boolean(false),
  
  			host: expect_string(null),
  
  			hostHeader: expect_string(null),
  
  			hydrate: expect_boolean(true),
  
  			package: {
  				type: 'branch',
  				children: {
  					dir: expect_string('package'),
  					exports: {
  						type: 'branch',
  						children: {
  							include: expect_array_of_strings(['**']),
  							exclude: expect_array_of_strings(['_*', '**/_*'])
  						}
  					},
  					files: {
  						type: 'branch',
  						children: {
  							include: expect_array_of_strings(['**']),
  							exclude: expect_array_of_strings([])
  						}
  					}
  				}
  			},
  
  			paths: {
  				type: 'branch',
  				children: {
  					base: expect_string(''),
  					assets: expect_string('')
  				}
  			},
  
  			prerender: {
  				type: 'branch',
  				children: {
  					crawl: expect_boolean(true),
  					enabled: expect_boolean(true),
  					force: expect_boolean(false),
  					pages: {
  						type: 'leaf',
  						default: ['*'],
  						validate: (option, keypath) => {
  							if (!Array.isArray(option) || !option.every((page) => typeof page === 'string')) {
  								throw new Error(`${keypath} must be an array of strings`);
  							}
  
  							option.forEach((page) => {
  								if (page !== '*' && page[0] !== '/') {
  									throw new Error(
  										`Each member of ${keypath} must be either '*' or an absolute path beginning with '/' — saw '${page}'`
  									);
  								}
  							});
  
  							return option;
  						}
  					}
  				}
  			},
  
  			router: expect_boolean(true),
  
  			ssr: expect_boolean(true),
  
  			target: expect_string(null),
  
  			trailingSlash: expect_enum(['never', 'always', 'ignore']),
  
  			vite: {
  				type: 'leaf',
  				default: () => ({}),
  				validate: (option, keypath) => {
  					if (typeof option === 'object') {
  						const config = option;
  						option = () => config;
  					}
  
  					if (typeof option !== 'function') {
  						throw new Error(
  							`${keypath} must be a Vite config object (https://vitejs.dev/config) or a function that returns one`
  						);
  					}
  
  					return option;
  				}
  			}
  		}
  	},
  
  	preprocess: {
  		type: 'leaf',
  		default: null,
  		validate: noop
  	}
  };
  
  /**
   * @param {string} string
   * @param {boolean} allow_empty
   * @returns {ConfigDefinition}
   */
  function expect_string(string, allow_empty = true) {
  	return {
  		type: 'leaf',
  		default: string,
  		validate: (option, keypath) => {
  			assert_is_string(option, keypath);
  			if (!allow_empty && option === '') {
  				throw new Error(`${keypath} cannot be empty`);
  			}
  			return option;
  		}
  	};
  }
  
  /**
   * @param {string[]} array
   * @returns {ConfigDefinition}
   */
  function expect_array_of_strings(array) {
  	return {
  		type: 'leaf',
  		default: array,
  		validate: (option, keypath) => {
  			if (!Array.isArray(option) || !option.every((glob) => typeof glob === 'string')) {
  				throw new Error(`${keypath} must be an array of strings`);
  			}
  			return option;
  		}
  	};
  }
  
  /**
   * @param {boolean} boolean
   * @returns {ConfigDefinition}
   */
  function expect_boolean(boolean) {
  	return {
  		type: 'leaf',
  		default: boolean,
  		validate: (option, keypath) => {
  			if (typeof option !== 'boolean') {
  				throw new Error(`${keypath} should be true or false, if specified`);
  			}
  			return option;
  		}
  	};
  }
  
  /**
   * @param {string[]} options
   * @returns {ConfigDefinition}
   */
  function expect_enum(options, def = options[0]) {
  	return {
  		type: 'leaf',
  		default: def,
  		validate: (option, keypath) => {
  			if (!options.includes(option)) {
  				// prettier-ignore
  				const msg = options.length > 2
  					? `${keypath} should be one of ${options.slice(0, -1).map(option => `"${option}"`).join(', ')} or "${options[options.length - 1]}"`
  					: `${keypath} should be either "${options[0]}" or "${options[1]}"`;
  
  				throw new Error(msg);
  			}
  			return option;
  		}
  	};
  }
  
  /**
   * @param {any} option
   * @param {string} keypath
   */
  function assert_is_string(option, keypath) {
  	if (typeof option !== 'string') {
  		throw new Error(`${keypath} should be a string, if specified`);
  	}
  }
  
  /** @typedef {import('./types').ConfigDefinition} ConfigDefinition */
  
  /**
   * @param {Record<string, ConfigDefinition>} definition
   * @param {any} option
   * @param {string} keypath
   * @returns {any}
   */
  function validate(definition, option, keypath) {
  	for (const key in option) {
  		if (!(key in definition)) {
  			let message = `Unexpected option ${keypath}.${key}`;
  
  			if (keypath === 'config' && key in options.kit) {
  				message += ` (did you mean config.kit.${key}?)`;
  			} else if (keypath === 'config.kit' && key in options) {
  				message += ` (did you mean config.${key}?)`;
  			}
  
  			throw new Error(message);
  		}
  	}
  
  	/** @type {Record<string, any>} */
  	const merged = {};
  
  	for (const key in definition) {
  		const expected = definition[key];
  		const actual = option[key];
  
  		const child_keypath = `${keypath}.${key}`;
  
  		if (key in option) {
  			if (expected.type === 'branch') {
  				if (actual && (typeof actual !== 'object' || Array.isArray(actual))) {
  					throw new Error(`${keypath}.${key} should be an object`);
  				}
  
  				merged[key] = validate(expected.children, actual, child_keypath);
  			} else {
  				merged[key] = expected.validate(actual, child_keypath);
  			}
  		} else {
  			merged[key] =
  				expected.type === 'branch'
  					? validate(expected.children, {}, child_keypath)
  					: expected.default;
  		}
  	}
  
  	return merged;
  }
  
  /**
   * @param {string} from
   * @param {string} to
   */
  function resolve(from, to) {
  	// the `/.` is weird, but allows `${assets}/images/blah.jpg` to work
  	// when `assets` is empty
  	return remove_trailing_slash(url.resolve(add_trailing_slash(from), to)) || '/.';
  }
  
  /**
   * @param {string} str
   */
  function add_trailing_slash(str) {
  	return str.endsWith('/') ? str : `${str}/`;
  }
  
  /**
   * @param {string} str
   */
  function remove_trailing_slash(str) {
  	return str.endsWith('/') ? str.slice(0, -1) : str;
  }
  
  /**
   * @param {string} cwd
   * @param {import('types/config').ValidatedConfig} validated
   */
  function validate_template(cwd, validated) {
  	const { template } = validated.kit.files;
  	const relative = path__default.relative(cwd, template);
  
  	if (fs__default.existsSync(template)) {
  		const contents = fs__default.readFileSync(template, 'utf8');
  		const expected_tags = ['%svelte.head%', '%svelte.body%'];
  		expected_tags.forEach((tag) => {
  			if (contents.indexOf(tag) === -1) {
  				throw new Error(`${relative} is missing ${tag}`);
  			}
  		});
  	} else {
  		throw new Error(`${relative} does not exist`);
  	}
  }
  
  async function load_config({ cwd = process.cwd() } = {}) {
  	const config_file_esm = path__default.join(cwd, 'svelte.config.js');
  	const config_file = fs__default.existsSync(config_file_esm)
  		? config_file_esm
  		: path__default.join(cwd, 'svelte.config.cjs');
  	const config = await import(url.pathToFileURL(config_file).href);
  	const validated = validate_config(config.default);
  
  	validated.kit.files.assets = path__default.resolve(cwd, validated.kit.files.assets);
  	validated.kit.files.hooks = path__default.resolve(cwd, validated.kit.files.hooks);
  	validated.kit.files.lib = path__default.resolve(cwd, validated.kit.files.lib);
  	validated.kit.files.routes = path__default.resolve(cwd, validated.kit.files.routes);
  	validated.kit.files.serviceWorker = path__default.resolve(cwd, validated.kit.files.serviceWorker);
  	validated.kit.files.setup = path__default.resolve(cwd, validated.kit.files.setup);
  	validated.kit.files.template = path__default.resolve(cwd, validated.kit.files.template);
  
  	validate_template(cwd, validated);
  
  	// TODO check all the `files` exist when the config is loaded?
  
  	return validated;
  }
  
  /**
   * @param {import('types/config').Config} config
   * @returns {import('types/config').ValidatedConfig}
   */
  function validate_config(config) {
  	/** @type {import('types/config').ValidatedConfig} */
  	const validated = validate(options, config, 'config');
  
  	// resolve paths
  	const { paths } = validated.kit;
  
  	if (paths.base !== '' && !paths.base.startsWith('/')) {
  		throw new Error('config.kit.paths.base must be a root-relative path');
  	}
  
  	paths.assets = resolve(paths.base, paths.assets);
  
  	return validated;
  }
  
  async function get_config() {
  	// TODO this is temporary, for the benefit of early adopters
  	if (existsSync('svelte.config.cjs')) {
  		// prettier-ignore
  		console.error($.bold().red(
  			'svelte.config.cjs should be renamed to svelte.config.js and converted to an ES module. See https://kit.svelte.dev/docs#configuration for an example'
  		));
  	}
  
  	if (existsSync('vite.config.js')) {
  		// prettier-ignore
  		console.error($.bold().red(
  			'Please remove vite.config.js and put Vite config in svelte.config.js: https://kit.svelte.dev/docs#configuration-vite'
  		));
  	}
  
  	try {
  		return await load_config();
  	} catch (error) {
  		let message = error.message;
  
  		if (
  			error.code === 'MODULE_NOT_FOUND' &&
  			/Cannot find module svelte\.config\./.test(error.message)
  		) {
  			message = 'Missing svelte.config.js';
  		} else if (error.name === 'SyntaxError') {
  			message = 'Malformed svelte.config.js';
  		}
  
  		console.error($.bold().red(message));
  		console.error($.grey(error.stack));
  		process.exit(1);
  	}
  }
  
  /** @param {Error} error */
  function handle_error(error) {
  	console.log($.bold().red(`> ${error.message}`));
  	console.log($.gray(error.stack));
  	process.exit(1);
  }
  
  /**
   * @param {number} port
   * @param {boolean} https
   */
  async function launch(port, https) {
  	const { exec } = await import('child_process');
  	let cmd = 'open';
  	if (process.platform == 'win32') {
  		cmd = 'start';
  	} else if (process.platform == 'linux') {
  		if (/microsoft/i.test(release())) {
  			cmd = 'cmd.exe /c start';
  		} else {
  			cmd = 'xdg-open';
  		}
  	}
  	exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
  }
  
  const prog = sade('svelte-kit').version('1.0.0-next.111');
  
  prog
  	.command('dev')
  	.describe('Start a development server')
  	.option('-p, --port', 'Port', 3000)
  	.option('-h, --host', 'Host (only use this on trusted networks)', 'localhost')
  	.option('-H, --https', 'Use self-signed HTTPS certificate', false)
  	.option('-o, --open', 'Open a browser tab', false)
  	.action(async ({ port, host, https, open }) => {
  		await check_port(port);
  
  		process.env.NODE_ENV = 'development';
  		const config = await get_config();
  
  		const { dev } = await import('./chunks/index.js');
  
  		try {
  			const watcher = await dev({ port, host, https, config });
  
  			watcher.on('stdout', (data) => {
  				process.stdout.write(data);
  			});
  
  			watcher.on('stderr', (data) => {
  				process.stderr.write(data);
  			});
  
  			welcome({ port, host, https, open });
  		} catch (error) {
  			handle_error(error);
  		}
  	});
  
  prog
  	.command('build')
  	.describe('Create a production build of your app')
  	.option('--verbose', 'Log more stuff', false)
  	.action(async ({ verbose }) => {
  		process.env.NODE_ENV = 'production';
  		const config = await get_config();
  
  		try {
  			const { build } = await import('./chunks/index5.js');
  			const build_data = await build(config);
  
  			console.log(
  				`\nRun ${$.bold().cyan('npm run preview')} to preview your production build locally.`
  			);
  
  			if (config.kit.adapter) {
  				const { adapt } = await import('./chunks/index7.js');
  				await adapt(config, build_data, { verbose });
  
  				// this is necessary to close any open db connections, etc
  				process.exit(0);
  			}
  
  			console.log($.bold().yellow('\nNo adapter specified'));
  
  			// prettier-ignore
  			console.log(
  				`See ${$.bold().cyan('https://kit.svelte.dev/docs#adapters')} to learn how to configure your app to run on the platform of your choosing`
  			);
  		} catch (error) {
  			handle_error(error);
  		}
  	});
  
  prog
  	.command('preview')
  	.describe('Serve an already-built app')
  	.option('-p, --port', 'Port', 3000)
  	.option('-h, --host', 'Host (only use this on trusted networks)', 'localhost')
  	.option('-H, --https', 'Use self-signed HTTPS certificate', false)
  	.option('-o, --open', 'Open a browser tab', false)
  	.action(async ({ port, host, https, open }) => {
  		await check_port(port);
  
  		process.env.NODE_ENV = 'production';
  		const config = await get_config();
  
  		const { start } = await import('./chunks/index8.js');
  
  		try {
  			await start({ port, host, config, https });
  
  			welcome({ port, host, https, open });
  		} catch (error) {
  			handle_error(error);
  		}
  	});
  
  // TODO remove this after a few versions
  prog
  	.command('start')
  	.describe('Deprecated — use svelte-kit preview instead')
  	.option('-p, --port', 'Port', 3000)
  	.option('-h, --host', 'Host (only use this on trusted networks)', 'localhost')
  	.option('-H, --https', 'Use self-signed HTTPS certificate', false)
  	.option('-o, --open', 'Open a browser tab', false)
  	.action(async () => {
  		console.log(
  			$
  				.bold()
  				.red(
  					'"svelte-kit preview" will now preview your production build locally. Note: it is not intended for production use'
  				)
  		);
  	});
  
  prog
  	.command('package')
  	.describe('Create a package')
  	.option('-d, --dir', 'Destination directory', 'package')
  	.action(async () => {
  		const config = await get_config();
  
  		const { make_package } = await import('./chunks/index9.js');
  
  		try {
  			await make_package(config);
  		} catch (error) {
  			handle_error(error);
  		}
  	});
  
  prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` });
  
  /** @param {number} port */
  async function check_port(port) {
  	const n = await blame(port);
  
  	if (n) {
  		console.log($.bold().red(`Port ${port} is occupied`));
  
  		// prettier-ignore
  		console.log(
  			`Terminate process ${$.bold(n)} or specify a different port with ${$.bold('--port')}\n`
  		);
  
  		process.exit(1);
  	}
  }
  
  /**
   * @param {{
   *   open: boolean;
   *   host: string;
   *   https: boolean;
   *   port: number;
   * }} param0
   */
  function welcome({ port, host, https, open }) {
  	if (open) launch(port, https);
  
  	console.log($.bold().cyan(`\n  SvelteKit v${'1.0.0-next.111'}\n`));
  
  	const protocol = https ? 'https:' : 'http:';
  	const exposed = host !== 'localhost' && host !== '127.0.0.1';
  
  	Object.values(networkInterfaces()).forEach((interfaces) => {
  		interfaces.forEach((details) => {
  			if (details.family !== 'IPv4') return;
  
  			// prettier-ignore
  			if (details.internal) {
  				console.log(`  ${$.gray('local:  ')} ${protocol}//${$.bold(`localhost:${port}`)}`);
  			} else {
  				if (details.mac === '00:00:00:00:00:00') return;
  
  				if (exposed) {
  					console.log(`  ${$.gray('network:')} ${protocol}//${$.bold(`${details.address}:${port}`)}`);
  				} else {
  					console.log(`  ${$.gray('network: not exposed')}`);
  				}
  			}
  		});
  	});
  
  	if (!exposed) {
  		console.log('\n  Use --host to expose server to other devices on this network');
  	}
  
  	console.log('\n');
  }
  
  export { $ };
  