UNPKG

sandhog

Version:

A virtual Open Source project maintainer

760 lines (722 loc) 26.9 kB
import { SECTION_KINDS, findLicense, findPackage } from "./chunk-4KN5GL56.js"; import { formatContributor } from "./chunk-VWKPPDPS.js"; import { listFormat } from "./chunk-VZLM7UUV.js"; import { getContributorsFromPackage } from "./chunk-H3ZAQGMJ.js"; import { CONSTANT } from "./chunk-VYUMLP7D.js"; // src/code-style/find-code-style/find-code-styles.ts import _fs from "fs"; import prettier from "prettier"; import path from "crosspath"; import eslintModule from "eslint"; // src/badge/generate-badge-url/generate-badge-url.ts function generateBadgeUrl({ color, status, subject }) { return `${CONSTANT.shieldRestEndpoint}/${subject}/${status}/${color}.svg`; } // src/code-style/get-code-style-for-code-style-kind/get-code-style-for-code-style-kind.ts function getCodeStyleForCodeStyleKind(kind) { switch (kind) { case "prettier" /* PRETTIER */: return { kind, badgeUrl: "https://img.shields.io/badge/code_style-prettier-ff69b4.svg", url: "https://github.com/prettier/prettier" }; case "Standard" /* STANDARD */: return { kind, badgeUrl: "https://img.shields.io/badge/code%20style-standard-green.svg", url: "https://github.com/feross/standard" }; case "Airbnb" /* AIRBNB */: return { kind, badgeUrl: "https://badgen.net/badge/code%20style/airbnb/ff5a5f", url: "https://github.com/airbnb/javascript" }; case "Idiomatic.js" /* IDIOMATIC */: return { kind, badgeUrl: generateBadgeUrl({ subject: "code style", status: kind, color: "green" }), url: "https://github.com/rwaldron/idiomatic.js" }; case "Google" /* GOOGLE */: return { kind, badgeUrl: generateBadgeUrl({ subject: "code style", status: kind, color: "green" }), url: "https://google.github.io/styleguide/jsguide.html" }; case "XO" /* XO */: return { kind, badgeUrl: "https://img.shields.io/badge/code_style-XO-5ed9c7.svg", url: "https://github.com/xojs/xo" }; } } // src/code-style/find-code-style/find-code-styles.ts async function findCodeStyles({ logger, root = process.cwd(), fs = { existsSync: _fs.existsSync, readFileSync: _fs.readFileSync }, pkg }) { if (pkg == null) { pkg = (await findPackage({ root, logger, fs })).pkg; } const codeStyles = []; logger.debug(`Trying to detect code style from root: '${root}'`); if (await isPrettier(root)) { logger.debug(`Detected "Prettier" as a project code style.`); codeStyles.push("prettier" /* PRETTIER */); } if (isXo(pkg)) { logger.debug(`Detected "XO" as a project code style.`); codeStyles.push("XO" /* XO */); } if (isStandard(pkg)) { logger.debug(`Detected "Standard" as a project code style.`); codeStyles.push("Standard" /* STANDARD */); } const eslintConfig = await findEslintConfig(root); if (eslintConfig != null) { logger.debug(`Found an ESLint config within the root. Parsing it for code styles`); const eslintCodeStyles = getCodeStylesFromEslintConfig(eslintConfig); eslintCodeStyles.length > 0 ? logger.debug( `Detected ${listFormat( eslintCodeStyles.map((style) => `"${style}"`), "and" )} as project code style${eslintCodeStyles.length === 1 ? "" : "s"}` ) : logger.debug(`No code styles detected inside ESLint config`); codeStyles.push(...eslintCodeStyles); } return [...new Set(codeStyles)].map(getCodeStyleForCodeStyleKind); } function getCodeStylesFromEslintConfig(config) { const codeStyles = []; const pluginNames = new Set(Object.keys(config.plugins ?? {})); const containsAirbnb = pluginNames.has(CONSTANT.eslintAirbnbCodeStyleName); if (containsAirbnb) { codeStyles.push("Airbnb" /* AIRBNB */); } const containsGoogle = pluginNames.has(CONSTANT.eslintGoogleCodeStyleName); if (containsGoogle) { codeStyles.push("Google" /* GOOGLE */); } const containsPrettier = pluginNames.has(CONSTANT.eslintPrettierCodeStyleName); if (containsPrettier) { codeStyles.push("prettier" /* PRETTIER */); } const containsIdiomatic = pluginNames.has(CONSTANT.eslintIdiomaticCodeStyleName); if (containsIdiomatic) { codeStyles.push("Idiomatic.js" /* IDIOMATIC */); } const containsStandard = pluginNames.has(CONSTANT.eslintStandardCodeStyleName); if (containsStandard) { codeStyles.push("Standard" /* STANDARD */); } const containsXo = pluginNames.has(CONSTANT.eslintXoCodeStyleName); if (containsXo) { codeStyles.push("XO" /* XO */); } return codeStyles; } async function findEslintConfig(root) { const eslint = new eslintModule.ESLint({}); try { return await eslint.calculateConfigForFile(path.native.join(root, "package.js")); } catch { return void 0; } } async function isPrettier(root) { try { const config = await prettier.resolveConfig(root); return config != null; } catch { return true; } } function isXo(pkg) { return "xo" in pkg || pkg.dependencies != null && "xo" in pkg.dependencies || pkg.devDependencies != null && "xo" in pkg.devDependencies; } function isStandard(pkg) { return "standard" in pkg || pkg.dependencies != null && "standard" in pkg.dependencies || pkg.devDependencies != null && "standard" in pkg.devDependencies; } // src/markdown/format-url/format-url.ts function formatUrl({ inner, url }) { return `<a href="${url}">${inner}</a>`; } // src/markdown/format-image/format-image.ts function formatImage({ alt, url, height, width, kind = "html" }) { if (kind === "html") { return `<img ${alt != null ? `alt="${alt}"` : ""} src="${url}" ${height == null ? "" : `height="${height}"`} ${width == null ? "" : `width="${width}"`} />`; } else { return `![${alt ?? ""}](${url})`; } } // src/package/take-github-repository-name/take-github-repository-name.ts var REGEX = /(http?s?:\/\/?)?(www\.)?github.com\//g; function takeGithubRepositoryName(pkg) { if (pkg.repository?.url == null) return void 0; return pkg.repository.url.replace(REGEX, "").replace(".git", ""); } // src/license/get-license-for-license-name/get-license-for-license-name.ts function getLicenseForLicenseName(licenseName) { switch (licenseName) { case "APACHE-2.0": return { licenseName, url: "https://opensource.org/licenses/Apache-2.0", badgeUrl: "https://img.shields.io/badge/License-Apache%202.0-blue.svg" }; case "BSD-2-CLAUSE": return { licenseName, url: "https://opensource.org/licenses/BSD-2-Clause", badgeUrl: "https://img.shields.io/badge/License-BSD%202--Clause-orange.svg" }; case "BSD-3-CLAUSE": return { licenseName, url: "https://opensource.org/licenses/BSD-3-Clause", badgeUrl: "https://img.shields.io/badge/License-BSD%203--Clause-blue.svg" }; case "CC-BY-4.0": return { licenseName, url: "https://creativecommons.org/licenses/by/4.0/", badgeUrl: "https://img.shields.io/badge/License-CC%20BY%204.0-lightgrey.svg" }; case "CC-BY-SA-4.0": return { licenseName, url: "https://creativecommons.org/licenses/by-sa/4.0/", badgeUrl: "https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg" }; case "EPL-1.0": return { licenseName, url: "https://opensource.org/licenses/EPL-1.0", badgeUrl: "https://img.shields.io/badge/License-EPL%201.0-red.svg" }; case "GPL-3.0": return { licenseName, url: "https://img.shields.io/badge/License-GPL%20v3-blue.svg", badgeUrl: "https://www.gnu.org/licenses/gpl-3.0" }; case "GPL-2.0": return { licenseName, url: "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html", badgeUrl: "https://img.shields.io/badge/License-GPL%20v2-blue.svg" }; case "AGPL-3.0": return { licenseName, url: "https://www.gnu.org/licenses/agpl-3.0", badgeUrl: "https://img.shields.io/badge/License-AGPL%20v3-blue.svg" }; case "LGPL-3.0": return { licenseName, url: "https://www.gnu.org/licenses/lgpl-3.0", badgeUrl: "https://img.shields.io/badge/License-LGPL%20v3-blue.svg" }; case "MIT": return { licenseName, url: "https://opensource.org/licenses/MIT", badgeUrl: "https://img.shields.io/badge/License-MIT-yellow.svg" }; case "MPL-2.0": return { licenseName, url: "https://opensource.org/licenses/MPL-2.0", badgeUrl: "https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg" }; case "ARTISTIC-2.0": return { licenseName, url: "https://opensource.org/licenses/Artistic-2.0", badgeUrl: "https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg" }; case "ZLIB": return { licenseName, url: "https://opensource.org/licenses/Zlib", badgeUrl: "https://img.shields.io/badge/License-Zlib-lightgrey.svg" }; } } // src/badge/get-badges/get-badges.ts async function getBadges(options) { const result = {}; const badgeOptions = options.config.readme.badges; const excluded = new Set(badgeOptions.exclude); const encodedName = options.pkg.name == null ? void 0 : encodeURIComponent(options.pkg.name); const repoUrl = takeGithubRepositoryName(options.pkg); const encodedRepoUrl = repoUrl == null ? void 0 : encodeURIComponent(repoUrl); if (!excluded.has("downloads") && encodedName != null) { result.downloads = [ formatUrl({ url: `https://npmcharts.com/compare/${encodedName}?minimal=true`, inner: formatImage({ alt: "Downloads per month", url: `https://img.shields.io/npm/dm/${encodedName}.svg` }) }) ]; } if (!excluded.has("npm") && encodedName != null) { result.npm = [ formatUrl({ url: `https://www.npmjs.com/package/${encodedName}`, inner: formatImage({ url: `https://badge.fury.io/js/${encodedName}.svg`, alt: `NPM version` }) }) ]; } if (!excluded.has("dependencies") && repoUrl != null && encodedRepoUrl != null) { result.dependencies = [ formatImage({ alt: `Dependencies`, url: `https://img.shields.io/librariesio/github/${encodedRepoUrl}.svg` }) ]; } if (!excluded.has("contributors") && encodedName != null && repoUrl != null && encodedRepoUrl != null) { result.contributors = [ formatUrl({ url: `https://github.com/${repoUrl}/graphs/contributors`, inner: formatImage({ alt: `Contributors`, url: `https://img.shields.io/github/contributors/${encodedRepoUrl}.svg` }) }) ]; } if (!excluded.has("code_style")) { const codeStyles = await findCodeStyles(options); if (codeStyles.length > 0) { result.code_style = codeStyles.map( ({ kind, url, badgeUrl }) => formatUrl({ url, inner: formatImage({ alt: `code style: ${kind}`, url: badgeUrl }) }) ); } } if (!excluded.has("license")) { const licenseName = await findLicense(options); if (licenseName != null) { const { badgeUrl, url } = getLicenseForLicenseName(licenseName); result.license = [ formatUrl({ url, inner: formatImage({ alt: `License: ${licenseName}`, url: badgeUrl }) }) ]; } } if (!excluded.has("patreon") && options.config.donate?.patreon?.userId != null) { result.patreon = [ formatUrl({ url: CONSTANT.patreonDonateUrl(options.config.donate.patreon.userId), inner: formatImage({ alt: `Support on Patreon`, url: `https://img.shields.io/badge/patreon-donate-green.svg` }) }) ]; } if (!excluded.has("open_collective_donate") && options.config.donate?.openCollective?.project != null) { result.open_collective_donate = [ formatUrl({ url: CONSTANT.openCollectiveDonateUrl(options.config.donate.openCollective.project), inner: formatImage({ alt: `Support on Open Collective`, url: `https://img.shields.io/badge/opencollective-donate-green.svg` }) }) ]; } if (!excluded.has("open_collective_backers") && options.config.donate?.openCollective?.project != null) { result.open_collective_backers = [ formatUrl({ url: CONSTANT.openCollectiveContributorsUrl(options.config.donate.openCollective.project), inner: formatImage({ alt: `Backers on Open Collective`, url: `https://opencollective.com/${options.config.donate.openCollective.project}/backers/badge.svg` }) }) ]; } if (!excluded.has("open_collective_sponsors") && options.config.donate?.openCollective?.project != null) { result.open_collective_sponsors = [ formatUrl({ url: CONSTANT.openCollectiveContributorsUrl(options.config.donate.openCollective.project), inner: formatImage({ alt: `Sponsors on Open Collective`, url: `https://opencollective.com/${options.config.donate.openCollective.project}/sponsors/badge.svg` }) }) ]; } return result; } // src/section/get-relevant-sections/get-relevant-sections.ts function getRelevantSections({ config }) { const excluded = new Set(config.readme.sections.exclude ?? []); return new Set(SECTION_KINDS.filter((value) => !excluded.has(value))); } // src/readme/get-shadow-section-mark/get-shadow-section-mark.ts function getShadowSectionMark(kind, startOrEnd) { return `<!-- SHADOW_SECTION_${kind}_${startOrEnd} -->`.toUpperCase(); } // src/readme/generate-readme/generate-readme.ts import toc from "@effect/markdown-toc"; import path2 from "crosspath"; async function generateReadme(options) { const sections = getRelevantSections(options); const context = { ...options, sections, str: options.existingReadme ?? "" }; if (sections.has("logo")) { generateLogoSection(context); } if (sections.has("description_short")) { generateDescriptionShortSection(context); } if (sections.has("badges")) { generateBadgesSection(context); } if (sections.has("description_long")) { generateDescriptionLongSection(context); } if (sections.has("features")) { generateFeaturesSection(context); } if (sections.has("feature_image")) { generateFeatureImageSection(context); } if (sections.has("backers")) { generateBackersSection(context); } if (sections.has("toc")) { generateTableOfContentsSection(context, true); } if (sections.has("install")) { generateInstallSection(context); } if (sections.has("usage")) { generateUsageSection(context); } if (sections.has("contributing")) { generateContributingSection(context); } if (sections.has("maintainers")) { generateMaintainersSection(context); } if (sections.has("faq")) { generateFaqSection(context); } if (sections.has("license")) { await generateLicenseSection(context); } if (sections.has("toc")) { generateTableOfContentsSection(context, false); } return options.prettier.format(context.str, { ...options.config.prettier, parser: "markdown" }); } function setSection(context, sectionKind, content, outro) { const startMark = getShadowSectionMark(sectionKind, "start"); const endMark = getShadowSectionMark(sectionKind, "end"); const startMarkIndex = context.str.indexOf(startMark); const endMarkIndex = context.str.indexOf(endMark); const markedContent = startMark + "\n\n" + content + "\n\n" + endMark + "\n\n" + (outro == null ? "" : outro + "\n\n"); if (startMarkIndex >= 0 && endMarkIndex >= 0) { const before = context.str.slice(0, startMarkIndex); const after = context.str.slice(endMarkIndex + endMark.length); context.str = before + markedContent + after; } else { context.str += markedContent; } } function generateLogoSection(context) { setSection( context, "logo", // Don't proceed if there is no logo to generate an image for context.config.logo.url == null ? "" : `<div>${formatImage({ url: context.config.logo.url, alt: "Logo", height: context.config.logo.height })}</div>` ); } function generateFeatureImageSection(context) { setSection( context, "feature_image", // Don't proceed if there is no feature image to generate an image for context.config.featureImage.url == null ? "" : `<div>${formatImage({ url: context.config.featureImage.url, alt: "Feature image", height: context.config.featureImage.height })}</div><br>` ); } function generateTableOfContentsSection(context, reserveOnly = false) { setSection( context, "toc", `## Table of Contents ` + (reserveOnly ? ( // Only reserve the spot within the README with an empty placeholder that can be replaced later on `` ) : toc(context.str).content) ); } async function generateBadgesSection(context) { const badges = await getBadges(context); const content = Object.values(badges).map((value) => { if (value == null) return ""; return value.join("\n"); }).join("\n"); setSection(context, "badges", content); } function generateDescriptionShortSection(context) { if (context.pkg.description == null) return; setSection(context, "description_short", `> ${context.pkg.description}`); } function generateDescriptionLongSection(context) { setSection(context, "description_long", `## Description`); } function generateFeaturesSection(context) { setSection(context, "features", `### Features `); } function generateFaqSection(context) { setSection(context, "faq", `## FAQ `); } function generateNpxStep(binName, requiredPeerDependencies, context) { const canUseShorthand = binName === context.pkg.name; const simpleCommand = `\`\`\` $ npx ${canUseShorthand ? `${context.pkg.name}` : `-p ${context.pkg.name} ${binName}`} \`\`\``; if (requiredPeerDependencies.length < 1) { return simpleCommand; } else if (canUseShorthand) { return `First, add ${requiredPeerDependencies.length === 1 ? "the peer dependency" : "the peer dependencies"} ${listFormat( requiredPeerDependencies, "and", (element) => `\`${element}\`` )} as${requiredPeerDependencies.length === 1 ? " a" : ""}${context.config.isDevelopmentPackage ? " development " : ""}${requiredPeerDependencies.length === 1 ? " dependency" : "dependencies"} to the package from which you're going to run \`${binName}\`. Alternatively, if you want to run it from _anywhere_, you can also install ${requiredPeerDependencies.length === 1 ? "it" : "them"} globally: \`npm i -g ${requiredPeerDependencies.join(" ")}\`. Now, you can simply run: ` + simpleCommand + ` You can also run \`${binName}\` along with its peer dependencies in one combined command: \`\`\` $ npx${requiredPeerDependencies.map((requiredPeerDependency) => ` -p ${requiredPeerDependency}`).join("")} -p ${context.pkg.name} ${binName} \`\`\` `; } else { return `\`\`\` $ npx${requiredPeerDependencies.map((requiredPeerDependency) => ` -p ${requiredPeerDependency}`).join("")} -p ${context.pkg.name} ${binName} \`\`\` `; } } function generateInstallSection(context) { if (context.pkg.name == null) return; const peerDependencies = context.pkg.peerDependencies == null ? [] : Object.keys(context.pkg.peerDependencies).map((peerDependency) => ({ peerDependency, optional: Boolean(context.pkg.peerDependenciesMeta?.[peerDependency]?.optional) })); const requiredPeerDependencies = peerDependencies.filter(({ optional }) => !optional).map(({ peerDependency }) => peerDependency); const optionalPeerDependencies = peerDependencies.filter(({ optional }) => optional).map(({ peerDependency }) => peerDependency); const firstBinName = context.pkg.bin == null ? void 0 : Object.keys(context.pkg.bin)[0]; setSection( context, "install", `## Install ### npm \`\`\` $ npm install ${context.pkg.name}${context.config.isDevelopmentPackage ? ` --save-dev` : ``} \`\`\` ### Yarn \`\`\` $ yarn add ${context.pkg.name}${context.config.isDevelopmentPackage ? ` --dev` : ``} \`\`\` ### pnpm \`\`\` $ pnpm add ${context.pkg.name}${context.config.isDevelopmentPackage ? ` --save-dev` : ``} \`\`\`` + (firstBinName == null ? "" : ` ### Run once with npx ` + generateNpxStep(firstBinName, requiredPeerDependencies, context)) + (peerDependencies.length < 1 ? "" : ` ### Peer Dependencies ` + (requiredPeerDependencies.length < 1 ? "" : `\`${context.pkg.name}\` depends on ${listFormat(requiredPeerDependencies, "and", (element) => `\`${element}\``)}, so you need to manually install ${requiredPeerDependencies.length === 1 ? "this" : "these"}${context.config.isDevelopmentPackage ? ` as ${requiredPeerDependencies.length === 1 ? "a development dependency" : "development dependencies"}` : ``} as well.`) + (optionalPeerDependencies.length < 1 ? "" : (requiredPeerDependencies.length < 1 ? `You may` : ` You may also`) + ` need to install ${optionalPeerDependencies.length < 2 ? `\`${optionalPeerDependencies[0]}\`` : `${requiredPeerDependencies.length < 1 ? "" : "additional "}peer dependencies such as ${listFormat( optionalPeerDependencies, "or", (element) => `\`${element}\`` )}`} depending on the features you are going to use. Refer to the documentation for the specific cases where ${optionalPeerDependencies.length < 2 ? "it" : "any of these"} may be relevant.`)) ); } function generateUsageSection(context) { setSection(context, "usage", `## Usage`); } function generateContributingSection(context) { const contributingFilePath = path2.join(context.root, CONSTANT.codeOfConductFilename); const nativeContributingFilePath = path2.native.normalize(contributingFilePath); setSection( context, "contributing", !context.fs.existsSync(nativeContributingFilePath) ? "" : `## Contributing Do you want to contribute? Awesome! Please follow [these recommendations](./${CONSTANT.contributingFilename}).` ); } function generateContributorTable(contributors) { let str = "\n|"; contributors.forEach((contributor) => { const inner = contributor.imageUrl == null ? void 0 : formatImage({ alt: contributor.name, url: contributor.imageUrl, height: CONSTANT.contributorImageUrlHeight }); const formattedImageWithUrl = inner == null ? "" : contributor.email != null ? formatUrl({ url: `mailto:${contributor.email}`, inner }) : contributor.url != null ? formatUrl({ url: contributor.url, inner }) : inner; str += formattedImageWithUrl; str += "|"; }); str += "\n|"; contributors.forEach(() => { str += "-----------|"; }); str += "\n|"; contributors.forEach((contributor) => { if (contributor.name != null) { if (contributor.email != null) { str += `[${contributor.name}](mailto:${contributor.email})`; } else if (contributor.url != null) { str += `[${contributor.name}](${contributor.url})`; } else { str += contributor.name; } } if (contributor.twitter != null) { str += `<br><strong>Twitter</strong>: [@${contributor.twitter}](https://twitter.com/${contributor.twitter})`; } if (contributor.github != null) { str += `<br><strong>Github</strong>: [@${contributor.github}](https://github.com/${contributor.github})`; } if (contributor.role != null) { str += `<br>_${contributor.role}_`; } str += "|"; }); return str; } function generateMaintainersSection(context) { const contributors = getContributorsFromPackage(context.pkg); setSection(context, "maintainers", contributors.length < 1 ? "" : `## Maintainers ` + generateContributorTable(contributors)); } function guessPreferredFundingUrlForOtherDonations(context) { if (context.config.donate.other.fundingUrl != null) { return context.config.donate.other.fundingUrl; } if (context.pkg.funding != null) { if (typeof context.pkg.funding === "string") { return context.pkg.funding; } else if (context.pkg.funding.url != null) { return context.pkg.funding.url; } } return void 0; } function generateBackersSection(context) { let content = ""; if (context.config.donate.other.donors.length > 0) { const preferredFundingUrl = guessPreferredFundingUrlForOtherDonations(context); content += (preferredFundingUrl != null ? `[Become a sponsor/backer](${preferredFundingUrl}) and get your logo listed here. ` : "") + generateContributorTable(context.config.donate.other.donors) + "\n\n"; } if (context.config.donate.openCollective.project != null) { content += `### Open Collective [Become a sponsor/backer](${CONSTANT.openCollectiveDonateUrl(context.config.donate.openCollective.project)}) and get your logo listed here. #### Sponsors ` + formatUrl({ url: CONSTANT.openCollectiveContributorsUrl(context.config.donate.openCollective.project), inner: formatImage({ url: CONSTANT.openCollectiveSponsorsBadgeUrl(context.config.donate.openCollective.project), alt: "Sponsors on Open Collective", width: 500 }) }) + ` #### Backers ` + formatUrl({ url: CONSTANT.openCollectiveContributorsUrl(context.config.donate.openCollective.project), inner: formatImage({ url: CONSTANT.openCollectiveBackersBadgeUrl(context.config.donate.openCollective.project), alt: "Backers on Open Collective" }) }) + "\n\n"; } if (context.config.donate.patreon.userId != null && context.config.donate.patreon.username != null) { content += `### Patreon ` + formatUrl({ url: CONSTANT.patreonDonateUrl(context.config.donate.patreon.userId), inner: formatImage({ url: CONSTANT.patreonBadgeUrl(context.config.donate.patreon.username), alt: "Patrons on Patreon", width: 200 }) }) + "\n\n"; } setSection(context, "backers", context.config.donate.patreon.userId == null && context.config.donate.openCollective.project == null ? "" : `## Backers ` + content); } async function generateLicenseSection(context) { const license = await findLicense(context); const contributors = getContributorsFromPackage(context.pkg); const licenseFilePath = path2.join(context.root, CONSTANT.licenseFilename); const nativeLicenseFilePath = path2.native.normalize(licenseFilePath); setSection( context, "license", license == null || !context.fs.existsSync(nativeLicenseFilePath) ? "" : `## License ${license} \xA9 ${listFormat( contributors.map((contributor) => formatContributor(contributor, "markdown")), "and" )}` ); } export { generateReadme }; //# sourceMappingURL=chunk-C3ACRQH5.js.map