@sanity/plugin-kit

7.0.28.0.0
dist/init-BDY7XRmJ.js
+dist/init-BDY7XRmJ.jsNew file
+824
Index: package/dist/init-BDY7XRmJ.js
===================================================================
--- package/dist/init-BDY7XRmJ.js
+++ package/dist/init-BDY7XRmJ.js
@@ -0,0 +1,824 @@
+import { n as defaultOutDir } from "./constants-BLTUL_Wd.js";
+import { n as sharedFlags_default, t as log_default } from "./log-DgQL-Rv9.js";
+import { B as writeFileWithOverwritePrompt, H as promptForPackageName, L as readFile, M as copyFileWithOverwritePrompt, N as ensureDir, P as fileExists, R as readJsonFile, U as promptForRepoOrigin, V as prompt, a as getPackage, c as writePackageJsonDirect, f as errorToUndefined, i as forceDependencyVersions, l as resolveLatestVersions, m as forcedPackageVersions, n as addPackageJsonScripts, o as sortKeys, p as forcedDevPackageVersions, r as addScript, s as writePackageJson, t as addBuildScripts, z as writeFile } from "./package-BrKrShA_.js";
+import { n as name, r as version } from "./package-z3cLp2Jt.js";
+import chalk from "chalk";
+import path from "path";
+import outdent, { outdent as outdent$1 } from "outdent";
+import { fileURLToPath } from "url";
+import licenses from "@rexxars/choosealicense-list";
+import gitRemoteOriginUrl from "git-remote-origin-url";
+import { execSync } from "child_process";
+import { validate } from "email-validator";
+import xdgBasedir from "xdg-basedir";
+import { createRequester } from "get-it";
+function defaultSourceJs(pkg) {
+	return outdent`
+  import {definePlugin} from 'sanity'
+
+  /**
+   * Usage in sanity.config.js (or .ts)
+   *
+   * \`\`\`js
+   * import {defineConfig} from 'sanity'
+   * import {myPlugin} from '${pkg.name}'
+   *
+   * export default defineConfig({
+   *   // ...
+   *   plugins: [myPlugin({})],
+   * })
+   * \`\`\`
+   *
+   * @public
+   */
+  export const myPlugin = definePlugin((_config = {}) => {
+    // oxlint-disable-next-line no-console
+    console.log(\`hello from ${pkg.name}\`)
+    return {
+      name: '${pkg.name}',
+    }
+  })
+`.trimStart() + "\n";
+}
+function defaultSourceTs(pkg) {
+	return outdent`
+  import {definePlugin} from 'sanity'
+
+  interface MyPluginConfig {
+    /* nothing here yet */
+  }
+
+  /**
+   * Usage in \`sanity.config.ts\` (or .js)
+   *
+   * \`\`\`ts
+   * import {defineConfig} from 'sanity'
+   * import {myPlugin} from '${pkg.name}'
+   *
+   * export default defineConfig({
+   *   // ...
+   *   plugins: [myPlugin()],
+   * })
+   * \`\`\`
+   *
+   * @public
+   */
+  export const myPlugin = definePlugin<MyPluginConfig | void>((_config = {}) => {
+    // oxlint-disable-next-line no-console
+    console.log('hello from ${pkg.name}')
+    return {
+      name: '${pkg.name}',
+    }
+  })
+`.trimStart() + "\n";
+}
+function gitignoreTemplate() {
+	return {
+		type: "template",
+		to: ".gitignore",
+		value: outdent$1`
+      # Logs
+      logs
+      *.log
+      npm-debug.log*
+
+      # Runtime data
+      pids
+      *.pid
+      *.seed
+
+      # Directory for instrumented libs generated by jscoverage/JSCover
+      lib-cov
+
+      # Coverage directory used by tools like istanbul
+      coverage
+
+      # nyc test coverage
+      .nyc_output
+
+      # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+      .grunt
+
+      # node-waf configuration
+      .lock-wscript
+
+      # Compiled binary addons (http://nodejs.org/api/addons.html)
+      build/Release
+
+      # Dependency directories
+      node_modules
+      jspm_packages
+
+      # Optional npm cache directory
+      .npm
+
+      # Optional REPL history
+      .node_repl_history
+
+      # macOS finder cache file
+      .DS_Store
+
+      # VS Code settings
+      .vscode
+
+      # IntelliJ
+      .idea
+      *.iml
+
+      # Cache
+      .cache
+
+      # Yalc
+      .yalc
+      yalc.lock
+
+      # npm package zips
+      *.tgz
+    `
+	};
+}
+function oxfmtConfigTemplate(options) {
+	let { flags } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: "oxfmt.config.ts",
+		value: "export {default} from '@sanity/plugin-kit/oxfmt'"
+	};
+}
+function oxlintConfigTemplate(options) {
+	let { flags } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: "oxlint.config.ts",
+		value: "export {default} from '@sanity/plugin-kit/oxlint'"
+	};
+}
+function pkgConfigTemplate(options) {
+	let { flags, outDir } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: "package.config.ts",
+		value: outdent$1`
+      import {defineConfig} from '@sanity/pkg-utils'
+
+      export default defineConfig({
+        dist: '${outDir}',
+        tsconfig: 'tsconfig.${outDir}.json',
+
+        // Remove this block to enable strict export validation
+        extract: {
+          rules: {
+            'ae-incompatible-release-tags': 'off',
+            'ae-internal-missing-underscore': 'off',
+            'ae-missing-release-tag': 'off',
+          },
+        },
+      })
+    `
+	};
+}
+function tsconfigTemplate(options) {
+	let { flags } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: "tsconfig.json",
+		value: outdent$1`
+      {
+        "extends": "./tsconfig.settings",
+        "include": ["./src", "./package.config.ts"]
+      }
+    `
+	};
+}
+function tsconfigTemplateDist(options) {
+	let { flags, outDir } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: `tsconfig.${outDir}.json`,
+		value: outdent$1`
+      {
+        "extends": "./tsconfig.settings",
+        "include": ["./src"],
+        "exclude": [
+          "./src/**/__fixtures__",
+          "./src/**/__mocks__",
+          "./src/**/*.test.ts",
+          "./src/**/*.test.tsx"
+        ]
+      }
+    `
+	};
+}
+function tsconfigTemplateSettings(options) {
+	let { flags, outDir } = options;
+	return {
+		type: "template",
+		force: flags.force,
+		to: "tsconfig.settings.json",
+		value: outdent$1`
+      {
+        "compilerOptions": {
+          "rootDir": ".",
+          "outDir": "./${outDir}",
+
+          "target": "esnext",
+          "jsx": "preserve",
+          "module": "preserve",
+          "moduleResolution": "bundler",
+          "esModuleInterop": true,
+          "resolveJsonModule": true,
+          "moduleDetection": "force",
+          "strict": true,
+          "allowSyntheticDefaultImports": true,
+          "skipLibCheck": true,
+          "forceConsistentCasingInFileNames": true,
+          "isolatedModules": true,
+
+          // Don't emit by default, pkg-utils will ignore this when generating .d.ts files
+          "noEmit": true
+        }
+      }
+    `
+	};
+}
+const renovatePreset = {
+	name: "renovatebot",
+	description: "Files to enable renovatebot.",
+	apply: applyPreset$2
+};
+async function applyPreset$2(options) {
+	await writeAssets([{
+		type: "copy",
+		from: ["renovatebot", "renovate.json"],
+		to: "renovate.json"
+	}], options);
+}
+function generateReadme(data) {
+	let { user, pluginName, license } = data;
+	return outdent`
+    # ${pluginName}
+
+
+    ${installationSnippet(pluginName ?? "unknown")}
+
+    ## Usage
+
+    Add it as a plugin in \`sanity.config.ts\` (or .js):
+
+    \`\`\`ts
+    import {defineConfig} from 'sanity'
+    import {myPlugin} from '${pluginName}'
+
+    export default defineConfig({
+      //...
+      plugins: [myPlugin({})],
+    })
+    \`\`\`
+
+    ${getLicenseText(license?.id, user?.name ? user : void 0)}
+    ${developTestSnippet()}
+  ` + "\n";
+}
+function installationSnippet(packageName) {
+	return outdent`
+    ## Installation
+
+    \`\`\`sh
+    npm install ${packageName}
+    \`\`\`
+    `;
+}
+function developTestSnippet() {
+	return outdent`
+    ## Develop & test
+
+    This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
+    with default configuration for build & watch scripts.
+
+    See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
+    on how to run this plugin with hotreload in the studio.
+  `;
+}
+function getLicenseText(licenseId, user) {
+	if (!licenseId) return "";
+	let license = licenses.find(licenseId), licenseName = license ? license.title : void 0;
+	licenseName = licenseName?.replace(/\s+license$/i, "");
+	let licenseText = "## License\n";
+	return licenseText = licenseName && user?.name ? `${licenseText}\n[${licenseName}](LICENSE) © ${user?.name}\n` : licenseName ? `${licenseText}\n[${licenseName}](LICENSE)\n` : `${licenseText}\nSee [LICENSE](LICENSE)`, licenseText;
+}
+function isDefaultGitHubReadme(readme) {
+	if (!readme) return !1;
+	let lines = readme.split("\n", 20).filter(Boolean);
+	return lines.length <= 2 && lines[0].startsWith("#");
+}
+const requester = createRequester({
+	headers: { "User-Agent": `${name}@${version}` },
+	as: "json"
+});
+async function getUserInfo({ requireUserConfirmation, flags }, pkg) {
+	let userInfo = getPackageUserInfo({ author: flags.author ?? pkg?.author }) || await getSanityUserInfo() || await getGitUserInfo();
+	return requireUserConfirmation ? promptForInfo(userInfo) : userInfo;
+}
+function getPackageUserInfo(pkg) {
+	let author = pkg?.author;
+	if (!author) return;
+	if (author && typeof author != "string") return author;
+	if (!author.includes("@")) return { name: author };
+	let [pre, ...post] = author.replace(/[<>[\]]/g, "").split(/@/), nameParts = pre.split(/\s+/), email = [nameParts[nameParts.length - 1], ...post].join("@");
+	return {
+		name: nameParts.slice(0, -1).join(" "),
+		email
+	};
+}
+async function promptForInfo(defValue) {
+	return {
+		name: await prompt("Author name", {
+			filter: filterString,
+			default: defValue && defValue.name,
+			validate: requiredString
+		}),
+		email: await prompt("Author email", {
+			filter: filterString,
+			default: defValue && defValue.email,
+			validate: validOrEmptyEmail
+		})
+	};
+}
+async function getSanityUserInfo() {
+	try {
+		let token = (await readJsonFile(path.join(xdgBasedir.config ?? "", "sanity", "config.json")))?.authToken;
+		if (!token) return;
+		let { body: user } = await requester({
+			url: "https://api.sanity.io/v1/users/me",
+			as: "json",
+			headers: { Authorization: `Bearer ${token}` }
+		});
+		if (!user) return;
+		let { name, email } = user;
+		return {
+			name,
+			email
+		};
+	} catch {
+		return;
+	}
+}
+async function getGitUserInfo() {
+	try {
+		let name = execSync("git config user.name", { encoding: "utf8" }).trim(), email = execSync("git config user.email", { encoding: "utf8" }).trim();
+		return name ? {
+			name,
+			email: email || void 0
+		} : void 0;
+	} catch {
+		return;
+	}
+}
+function filterString(val) {
+	return (val || "").trim();
+}
+function requiredString(value) {
+	return value.length > 1 || "Required";
+}
+function validOrEmptyEmail(value) {
+	return value ? validate(value) ? !0 : "Must either be a valid email or empty" : !0;
+}
+const semverWorkflowPreset = {
+	name: "semver-workflow",
+	description: "Files and dependencies for conventional-commits, github workflow and semantic-release.",
+	apply: applyPreset$1
+}, info = (write, msg, ...args) => write && log_default.info(msg, ...args);
+async function applyPreset$1(options) {
+	await writeAssets(semverWorkflowFiles(), options), await addPrepareScript(options), await addDevDependencies$1(options), await updateReadme(options);
+}
+async function addPrepareScript(options) {
+	let didWrite = await addPackageJsonScripts(await getPackage(options), options, (scripts) => (scripts.prepare = addScript("husky", scripts.prepare), scripts));
+	info(didWrite, "Added prepare script to package.json");
+}
+async function addDevDependencies$1(options) {
+	let pkg = await getPackage(options), devDeps = sortKeys({
+		...pkg.devDependencies,
+		...await semverWorkflowDependencies()
+	}), newPkg = { ...pkg };
+	newPkg.devDependencies = devDeps, await writePackageJsonDirect(newPkg, options), log_default.info("Updated devDependencies."), log_default.info(chalk.green(outdent`
+        semantic-release preset injected.
+
+        Please confer
+        https://github.com/sanity-io/plugin-kit/blob/main/docs/semver-workflow.md#manual-steps-after-inject
+        to finalize configuration for this preset.
+  `.trim()));
+}
+async function updateReadme(options) {
+	let { basePath } = options, readmePath = path.join(basePath, "README.md"), readme = await readFile(readmePath, "utf8").catch(errorToUndefined) ?? "", { install, usage, developTest, license, releaseSnippet } = await readmeSnippets(options), prependSections = missingSections(readme, [install, usage]), appendSections = missingSections(readme, [
+		license,
+		developTest,
+		releaseSnippet
+	]);
+	(prependSections.length || appendSections.length) && (await writeFile(readmePath, [
+		...prependSections,
+		readme,
+		...appendSections
+	].filter(Boolean).join("\n\n"), { encoding: "utf8" }), log_default.info("Updated README. Please review the changes."));
+}
+async function readmeSnippets(options) {
+	let pkg = await getPackage(options), user = await getUserInfo(options, pkg), bestEffortUrl = readmeBaseurl(pkg), install = installationSnippet(pkg.name ?? "unknown"), usage = outdent`
+    ## Usage
+  `, license = getLicenseText(typeof pkg.license == "string" ? pkg.license : void 0, user), releaseSnippet = outdent`
+    ### Release new version
+
+    Run ["CI & Release" workflow](${bestEffortUrl}/actions/workflows/main.yml).
+    Make sure to select the main branch and check "Release new version".
+
+    Semantic release will only release on configured branches, so it is safe to run release on any branch.
+  `;
+	return {
+		install,
+		usage,
+		license,
+		developTest: developTestSnippet(),
+		releaseSnippet
+	};
+}
+/**
+* Returns sections that do not exist "close enough" in readme
+*/
+function missingSections(readme, sections) {
+	return sections.filter((section) => !closeEnough(section, readme));
+}
+/**
+* a and b are considered "close enough" if > 50% of a lines exist in b lines
+* @param a
+* @param b
+*/
+function closeEnough(a, b) {
+	let aLines = a.split("\n"), bLines = b.split("\n");
+	return aLines.filter((line) => bLines.find((bLine) => bLine === line)).length >= aLines.length * .5;
+}
+function semverWorkflowFiles() {
+	return [
+		{
+			type: "copy",
+			from: [
+				".github",
+				"workflows",
+				"main.yml"
+			],
+			to: [
+				".github",
+				"workflows",
+				"main.yml"
+			]
+		},
+		{
+			type: "copy",
+			from: [".husky", "commit-msg"],
+			to: [".husky", "commit-msg"]
+		},
+		{
+			type: "copy",
+			from: [".husky", "pre-commit"],
+			to: [".husky", "pre-commit"]
+		},
+		{
+			type: "copy",
+			from: [".releaserc.json"],
+			to: ".releaserc.json"
+		},
+		{
+			type: "copy",
+			from: ["commitlint.template.js"],
+			to: "commitlint.config.js"
+		},
+		{
+			type: "copy",
+			from: ["lint-staged.template.js"],
+			to: "lint-staged.config.js"
+		}
+	].map((fromTo) => fromTo.type === "copy" ? {
+		...fromTo,
+		from: ["semver-workflow", ...fromTo.from]
+	} : fromTo);
+}
+async function semverWorkflowDependencies() {
+	return resolveLatestVersions([
+		"@commitlint/cli",
+		"@commitlint/config-conventional",
+		"@sanity/semantic-release-preset",
+		"husky",
+		"lint-staged"
+	]);
+}
+function readmeBaseurl(pkg) {
+	return (pkg.repository?.url ?? pkg.homepage ?? "TODO").replace(/.+:\/\//g, "https://").replace(/\.git/g, "").replace(/[email protected]\//g, "github.com/").replace(/[email protected]:/g, "https://github.com/").replace(/#.+/g, "");
+}
+const ui = {
+	name: "ui",
+	description: "`@sanity/ui` and dependencies",
+	apply: applyPreset
+};
+async function applyPreset(options) {
+	await addDependencies(options), await addDevDependencies(options), log_default.info(chalk.green("ui preset injected"));
+}
+async function addDependencies(options) {
+	let pkg = await getPackage(options), newDeps = sortKeys(forceDependencyVersions({
+		...pkg.dependencies,
+		...await resolveDependencyList()
+	}, forcedPackageVersions)), newPkg = { ...pkg };
+	newPkg.dependencies = newDeps, await writePackageJsonDirect(newPkg, options), log_default.info("Updated dependencies.");
+}
+async function addDevDependencies(options) {
+	let pkg = await getPackage(options), newDeps = sortKeys(forceDependencyVersions({
+		...pkg.devDependencies,
+		...await resolveDevDependencyList()
+	}, forcedDevPackageVersions)), newPkg = { ...pkg };
+	newPkg.devDependencies = newDeps, await writePackageJsonDirect(newPkg, options), log_default.info("Updated devDependencies.");
+}
+async function resolveDependencyList() {
+	return resolveLatestVersions(["@sanity/icons", "@sanity/ui"]);
+}
+async function resolveDevDependencyList() {
+	return resolveLatestVersions([
+		"react",
+		"react-dom",
+		"styled-components"
+	]);
+}
+const presets = [
+	semverWorkflowPreset,
+	renovatePreset,
+	ui
+], presetNames = presets.map((p) => p?.name);
+function presetHelpList(padStart) {
+	return presets.map((p) => `${"".padStart(padStart)}${p.name.padEnd(20)}${p.description}`).join("\n");
+}
+async function injectPresets(options) {
+	if (options.flags.presetOnly && !options.flags.preset?.length) throw Error("--preset-only, but no --preset [preset-name] was provided.");
+	let applyPresets = presetsFromInput(options.flags.preset);
+	for (let preset of applyPresets) await preset.apply(options);
+}
+function presetsFromInput(inputPresets) {
+	if (!inputPresets) return [];
+	let unknownPresets = inputPresets.filter((p) => !presetNames.includes(p));
+	if (unknownPresets.length) throw Error(`Unknown --preset(s): [${unknownPresets.join(", ")}]. Must be one of: [${presetNames.join(", ")}]`);
+	return inputPresets.filter(onlyUnique).map((presetName) => presets.find((p) => p.name === presetName)).filter((p) => !!p);
+}
+function onlyUnique(value, index, arr) {
+	return arr.indexOf(value) === index;
+}
+const bannedFields = [
+	"login",
+	"description",
+	"projecturl",
+	"email"
+], preferredLicenses = [
+	"MIT",
+	"ISC",
+	"BSD-3-Clause"
+], otherLicenses = Object.keys(licenses.list).filter((id) => {
+	let license = licenses.list[id];
+	return !preferredLicenses.includes(id) && !bannedFields.some((field) => license.body.includes(`[${field}]`));
+});
+async function inject(options) {
+	options.flags.presetOnly ? log_default.info("Only apply presets, skipping default inject.") : await injectBase(options), await injectPresets(options);
+}
+async function injectBase(options) {
+	let { basePath, flags, requireUserConfirmation } = options, info = (write, msg, ...args) => write && log_default.info(msg, ...args), pkg = await getPackage(options).catch(errorToUndefined);
+	log_default.debug("Plugin has package.json: %s", pkg ? "yes" : "no");
+	let user = await getUserInfo(options, pkg);
+	log_default.debug("User information: %o", user);
+	let pkgName = flags.name ?? pkg?.name, pluginName = requireUserConfirmation || !pkgName ? await promptForPackageName(options, pkgName) : pkgName;
+	log_default.debug("Plugin name: %s", pluginName);
+	let license = await getLicense(flags, {
+		user,
+		pluginName,
+		pkg,
+		requireUserConfirmation
+	}), licenseChanged = (pkg && pkg.license) !== (license && license.id);
+	log_default.debug("License: %s", license ? license.id : "<none>");
+	let description = await getProjectDescription(basePath, pkg, requireUserConfirmation);
+	log_default.debug("Description: %s", description || "<none>");
+	let repoUrl = flags.repo ?? (await gitRemoteOriginUrl(basePath).catch(errorToUndefined) || pkg?.repository?.url), gitOrigin = requireUserConfirmation ? await promptForRepoOrigin(options, repoUrl) : repoUrl;
+	log_default.debug("Remote origin: %s", gitOrigin || "<none>");
+	let data = {
+		user,
+		pluginName,
+		license,
+		description,
+		pkg,
+		gitOrigin
+	}, didWrite, newPkg = await writePackageJson(data, options);
+	info(newPkg !== pkg, "Wrote package.json"), data.pkg = newPkg, didWrite = await writeLicense(data, options, licenseChanged), info(didWrite, "Wrote license file (LICENSE)"), didWrite = await writeReadme(data, options), info(didWrite, "Wrote readme file (README.md)"), didWrite = await writeStaticAssets(options), info(didWrite.length > 0, "Wrote static asset files: %s", didWrite.join(", ")), didWrite = await addBuildScripts(newPkg, options), info(didWrite, "Added build scripts to package.json"), didWrite = await addCompileDirToGitIgnore(options), info(didWrite, "Added compilation output directory to .gitignore");
+}
+async function writeReadme(data, options) {
+	let { basePath } = options, readmePath = path.join(basePath, "README.md"), readme = await readFile(readmePath, "utf8").catch(errorToUndefined);
+	return readme && !isDefaultGitHubReadme(readme) ? !1 : (await writeFileWithOverwritePrompt(readmePath, generateReadme(data), {
+		encoding: "utf8",
+		force: options.flags.force
+	}), !0);
+}
+async function writeLicense({ license }, options, licenseChanged) {
+	let { basePath, flags } = options;
+	if (flags.license === !1 || !license) return !1;
+	let hasLicenseMdFile = await fileExists(path.join(basePath, "LICENSE.md"));
+	return await writeFileWithOverwritePrompt(path.join(basePath, hasLicenseMdFile ? "LICENSE.md" : "LICENSE"), license.text, {
+		encoding: "utf8",
+		default: licenseChanged,
+		force: flags.force
+	}), !0;
+}
+async function getLicense(flags, { user, pluginName, pkg, requireUserConfirmation }) {
+	let license = await getLicenseIdentifier(flags, pkg, requireUserConfirmation);
+	if (!license) return;
+	let text = license.body.replace(/\[fullname\]/g, user?.name ?? "").replace(/\[project\]/g, pluginName ?? "").replace(/\[year\]/g, String((/* @__PURE__ */ new Date()).getFullYear()));
+	return {
+		id: license.id,
+		text
+	};
+}
+async function getLicenseIdentifier(flags, pkg, requireUserConfirmation = !1) {
+	if (flags.license === !1) return null;
+	if (typeof flags.license == "string") {
+		let license = licenses.find(`${flags.license}`);
+		if (!license) throw Error(`License "${flags.license}" not found`);
+		return license;
+	}
+	if (pkg && pkg.license && !requireUserConfirmation) {
+		let license = licenses.find(`${pkg.license}`);
+		if (license) return license;
+		log_default.warn(`package.json contains license "${pkg.license}", which is not recognized`);
+	}
+	let licenseId = await prompt("Which license do you want to use?", {
+		default: pkg && pkg.license && licenses.find(pkg.license) ? pkg.license : preferredLicenses[0],
+		choices: [
+			prompt.separator(),
+			...preferredLicenses.map((value) => ({
+				value,
+				name: licenses.list[value].title
+			})),
+			prompt.separator(),
+			...otherLicenses.map((value) => ({
+				value,
+				name: licenses.list[value].title
+			}))
+		]
+	});
+	return licenses.find(licenseId);
+}
+async function getProjectDescription(basePath, pkg, requireUserConfirmation = !1) {
+	let description = await resolveProjectDescription(basePath, pkg);
+	return requireUserConfirmation && (description = await prompt("Plugin description", { default: description || "" })), description ?? "";
+}
+async function resolveProjectDescription(basePath, pkg) {
+	if (pkg && typeof pkg.description == "string" && pkg.description.length > 5) return pkg.description;
+	try {
+		let [title, description] = (await readFile(path.join(basePath, "README.md"), "utf8")).split("\n").filter(Boolean);
+		if (!title || !description || !title.match(/^#\s+\w+/)) return null;
+		let unlinked = description.replace(/\[(.*?)\]\(.*?\)/g, "$1");
+		return /^[^#]/.test(unlinked) ? unlinked : null;
+	} catch (err) {
+		return errorToUndefined(err);
+	}
+}
+async function writeAssets(injectables, { basePath, flags }) {
+	let assetsDir = await findAssetsDir(), from = (...segments) => path.join(assetsDir, "inject", ...segments), to = (...segments) => path.join(basePath, ...segments), writes = [];
+	for (let injectable of injectables) {
+		if (injectable.type === "copy") {
+			let fromPath = asArray(injectable.from), toPath = asArray(injectable.to);
+			await copyFileWithOverwritePrompt(from(...fromPath), to(...toPath), flags) && writes.push(path.join(...toPath));
+			continue;
+		}
+		if (injectable.type === "template") {
+			let toPath = asArray(injectable.to);
+			await writeFileWithOverwritePrompt(to(...toPath), `${injectable.value.trim()}\n`, {
+				default: "n",
+				force: injectable.force || flags.force
+			}), writes.push(path.join(...toPath));
+			continue;
+		}
+		throw Error(`Unknown operation type "${injectable.type}"`);
+	}
+	return writes;
+}
+async function writeStaticAssets(options) {
+	let { outDir, flags } = options;
+	return writeAssets([
+		flags.oxlint && oxlintConfigTemplate({ flags: options.flags }),
+		{
+			type: "copy",
+			from: "editorconfig",
+			to: ".editorconfig"
+		},
+		pkgConfigTemplate({
+			outDir,
+			flags: options.flags
+		}),
+		flags.gitignore && gitignoreTemplate(),
+		flags.typescript && tsconfigTemplate({ flags: options.flags }),
+		flags.typescript && tsconfigTemplateDist({
+			outDir,
+			flags: options.flags
+		}),
+		flags.typescript && tsconfigTemplateSettings({
+			outDir,
+			flags: options.flags
+		}),
+		flags.oxfmt && oxfmtConfigTemplate({ flags: options.flags })
+	].map((f) => f || void 0).filter((f) => !!f), options);
+}
+function asArray(input) {
+	return typeof input == "string" ? [input] : input;
+}
+/**
+* assets dir might be in higher or lower in the dir hierarchy depending on
+* if we run from `dist` or `src`
+*/
+async function findAssetsDir() {
+	let maxBackpaddle = 3, currDir = path.dirname(fileURLToPath(import.meta.url)), assetsDir = "";
+	for (; !assetsDir && maxBackpaddle;) {
+		currDir = path.join(currDir, "..");
+		let assets = path.join(currDir, "assets");
+		await fileExists(assets) ? assetsDir = assets : maxBackpaddle--;
+	}
+	if (!assetsDir) throw Error("Could not find assets directory!");
+	return assetsDir;
+}
+async function addCompileDirToGitIgnore(options) {
+	let gitIgnorePath = path.join(options.basePath, ".gitignore"), gitignore = await readFile(gitIgnorePath, "utf8").catch(errorToUndefined);
+	if (!gitignore) return !1;
+	let ignore = options.outDir.replace(/^[./]+/, "").split("/")[0];
+	if (!ignore) return !1;
+	let lines = gitignore.trim().split("\n");
+	return lines.includes(ignore) ? !1 : (lines.push("", "# Compiled plugin", ignore), await writeFile(gitIgnorePath, lines.join("\n") + "\n", { encoding: "utf8" }), !0);
+}
+const initFlags = {
+	...sharedFlags_default,
+	scripts: {
+		type: "boolean",
+		default: !0
+	},
+	oxlint: {
+		type: "boolean",
+		default: !0
+	},
+	typescript: {
+		type: "boolean",
+		default: !0
+	},
+	oxfmt: {
+		type: "boolean",
+		default: !0
+	},
+	license: { type: "string" },
+	editorconfig: {
+		type: "boolean",
+		default: !0
+	},
+	gitignore: {
+		type: "boolean",
+		default: !0
+	},
+	force: {
+		type: "boolean",
+		default: !1
+	},
+	install: {
+		type: "boolean",
+		default: !0
+	},
+	name: { type: "string" },
+	author: { type: "string" },
+	repo: { type: "string" },
+	presetOnly: {
+		type: "boolean",
+		default: !1
+	},
+	preset: {
+		type: "string",
+		isMultiple: !0
+	}
+};
+async function init(options) {
+	let dependencies = {}, devDependencies = {}, peerDependencies = {};
+	await inject({
+		...options,
+		outDir: defaultOutDir,
+		requireUserConfirmation: !options.flags.force,
+		dependencies,
+		devDependencies,
+		peerDependencies,
+		validate: !1
+	});
+	let packageJson = await getPackage({
+		basePath: options.basePath,
+		validate: !1
+	}), typescript = options.flags.typescript, source = typescript ? defaultSourceTs(packageJson) : defaultSourceJs(packageJson), filename = typescript ? "index.ts" : "index.js", srcDir = path.resolve(options.basePath, "src");
+	await ensureDir(srcDir), await writeFile(path.join(srcDir, filename), source, { encoding: "utf8" });
+}
+export { presetHelpList as i, initFlags as n, inject as r, init as t };
+
+//# sourceMappingURL=init-BDY7XRmJ.js.map
\ No newline at end of file