Skip to content

feat: add emoji option #1984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Thanks for your interest in contributing to `create-typescript-app`! 💖
Thanks for your interest in contributing to `create-typescript-app`! 🎁

> After this page, see [DEVELOPMENT.md](./DEVELOPMENT.md) for local development instructions.

Expand Down Expand Up @@ -94,4 +94,4 @@ Please do ping the maintainer who merged your PR if that doesn't happen within 2

If you made it all the way to the end, bravo dear user, we love you.
Please include your favorite emoji in the bottom of your issues and PRs to signal to us that you did in fact read this file and are trying to conform to it as best as possible.
💖 is a good starter if you're not sure which to use.
🎁 is a good starter if you're not sure which to use.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- 👋 Hi, thanks for sending a PR to create-typescript-app! 💖.
<!-- 👋 Hi, thanks for sending a PR to create-typescript-app! 🎁.
Please fill out all fields below and make sure each item is true and [x] checked.
Otherwise we may not be able to review your PR. -->

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ You can read more about `create-typescript-app` and the tooling it supports:
## Development

See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md), then [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md).
Thanks! 💖
Thanks! 🎁

## Contributors

Expand Down
1 change: 1 addition & 0 deletions src/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe("base", () => {
github: "[email protected]",
npm: "[email protected]",
},
emoji: "🎁",
existingLabels: expect.any(Array),
explainer: [
`\`create-typescript-app\` is a one-stop-shop solution to set up a new or existing repository with the latest and greatest TypeScript tooling.`,
Expand Down
16 changes: 13 additions & 3 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { z } from "zod";

import { inputFromOctokit } from "./inputs/inputFromOctokit.js";
import { getExistingLabels } from "./options/getExistingLabels.js";
import { parseEmojiFromDescription } from "./options/parseEmojiFromDescription.js";
import { parsePackageAuthor } from "./options/parsePackageAuthor.js";
import { readAllContributors } from "./options/readAllContributors.js";
import { readDefaultsFromReadme } from "./options/readDefaultsFromReadme.js";
Expand Down Expand Up @@ -53,7 +54,7 @@ export const base = createBase({
.describe("AllContributors contributors to store in .all-contributorsrc"),
description: z
.string()
.default("A very lovely package. Hooray! 💖")
.default("A very lovely package. Hooray!")
.describe("'Sentence case.' description of the repository"),
directory: z.string().describe("Directory to create the repository in"),
documentation: z
Expand All @@ -74,6 +75,10 @@ export const base = createBase({
.describe(
"email address to be listed as the point of contact in docs and packages",
),
emoji: z
.string()
.optional()
.describe("decorative emoji to use in descriptions and docs"),
existingLabels: z
.array(
z.object({
Expand Down Expand Up @@ -196,6 +201,10 @@ export const base = createBase({

// TODO: Make these all use take

const emoji = async () => parseEmojiFromDescription(description);

const description = async () => await readDescription(packageData, readme);

const gitDefaults = tryCatchLazyValueAsync(async () =>
gitUrlParse(await gitRemoteOriginUrl()),
);
Expand Down Expand Up @@ -253,9 +262,10 @@ export const base = createBase({
author,
bin: async () => (await packageData()).bin,
contributors: allContributors,
description: async () => await readDescription(packageData, readme),
description,
documentation,
email,
emoji,
existingLabels,
funding: readFunding,
guide: readGuide,
Expand All @@ -274,7 +284,7 @@ export const base = createBase({
pnpm,
repository,
rulesetId,
...readDefaultsFromReadme(readme, repository),
...readDefaultsFromReadme(emoji, readme, repository),
version,
};
},
Expand Down
2 changes: 1 addition & 1 deletion src/blocks/blockCSpell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ describe("blockCSpell", () => {
"scripts": [
{
"commands": [
"node path/to/cspell-populate-words/bin/index.mjs --words "access" --words "public" --words "description" --words "Test description" --words "directory" --words "." --words "email" --words "github" --words "[email protected]" --words "npm" --words "[email protected]" --words "owner" --words "test-owner" --words "repository" --words "test-repository" --words "title" --words "Test Title"",
"node path/to/cspell-populate-words/bin/index.mjs --words "access" --words "public" --words "description" --words "Test description" --words "directory" --words "." --words "email" --words "github" --words "[email protected]" --words "npm" --words "[email protected]" --words "emoji" --words "💖" --words "owner" --words "test-owner" --words "repository" --words "test-repository" --words "title" --words "Test Title"",
],
"phase": 3,
},
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/blockContributingDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const blockContributingDocs = base.createBlock({
".github": {
"CONTRIBUTING.md": `# Contributing

Thanks for your interest in contributing to \`${options.repository}\`! 💖
Thanks for your interest in contributing to \`${options.repository}\`! ${options.emoji}

> After this page, see [DEVELOPMENT.md](./DEVELOPMENT.md) for local development instructions.

Expand Down Expand Up @@ -105,7 +105,7 @@ Please do ping the maintainer who merged your PR if that doesn't happen within 2

If you made it all the way to the end, bravo dear user, we love you.
Please include your favorite emoji in the bottom of your issues and PRs to signal to us that you did in fact read this file and are trying to conform to it as best as possible.
💖 is a good starter if you're not sure which to use.
${options.emoji} is a good starter if you're not sure which to use.
`,
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/blocks/blockGitHubPRTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const blockGitHubPRTemplate = base.createBlock({
return {
files: {
".github": {
"PULL_REQUEST_TEMPLATE.md": `<!-- 👋 Hi, thanks for sending a PR to ${options.repository}! 💖.
"PULL_REQUEST_TEMPLATE.md": `<!-- 👋 Hi, thanks for sending a PR to ${options.repository}! ${options.emoji}.
Please fill out all fields below and make sure each item is true and [x] checked.
Otherwise we may not be able to review your PR. -->

Expand Down
2 changes: 1 addition & 1 deletion src/blocks/blockREADME.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ${options.usage}
## Development

See [\`.github/CONTRIBUTING.md\`](./.github/CONTRIBUTING.md), then [\`.github/DEVELOPMENT.md\`](./.github/DEVELOPMENT.md).
Thanks! 💖
Thanks! ${options.emoji}
${sections.map((section) => `\n${section}`).join("")}
${notices.length ? `\n${notices.map((notice) => notice.trim()).join("\n\n")}` : ""}`,
},
Expand Down
1 change: 1 addition & 0 deletions src/blocks/options.fakes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const optionsBase = {
github: "[email protected]",
npm: "[email protected]",
},
emoji: "💖",
owner: "test-owner",
repository: "test-repository",
title: "Test Title",
Expand Down
37 changes: 37 additions & 0 deletions src/options/parseEmojiFromDescription.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, expect, it, vi } from "vitest";

import { parseEmojiFromDescription } from "./parseEmojiFromDescription.js";

describe("parseEmojiFromDescription", () => {
it("resolves with undefined when description is undefined", async () => {
const getDescription = vi.fn().mockResolvedValue(undefined);

const actual = await parseEmojiFromDescription(getDescription);

expect(actual).toBe("💖");
});

it("resolves with undefined when the description does not have any emoji", async () => {
const getDescription = () => Promise.resolve("Hello world.");

const actual = await parseEmojiFromDescription(getDescription);

expect(actual).toBe("💖");
});

it("resolves with the emoji when the description has one emoji", async () => {
const getDescription = () => Promise.resolve("Hello. 😊");

const actual = await parseEmojiFromDescription(getDescription);

expect(actual).toBe("😊");
});

it("resolves with the last emoji when the description has multiple emoji", async () => {
const getDescription = () => Promise.resolve("Hello 🌍. 😊");

const actual = await parseEmojiFromDescription(getDescription);

expect(actual).toBe("😊");
});
});
8 changes: 8 additions & 0 deletions src/options/parseEmojiFromDescription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export async function parseEmojiFromDescription(
getDescription: () => Promise<string | undefined>,
) {
return (
(await getDescription())?.match(/\p{Extended_Pictographic}/gu)?.at(-1) ??
"💖"
);
}
23 changes: 23 additions & 0 deletions src/options/readDefaultsFromReadme.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ vi.mock("./getUsageFromReadme.js", () => ({
},
}));

const emoji = () => Promise.resolve("💖");

describe(readDefaultsFromReadme, () => {
describe("explainer", () => {
it("defaults to undefined when it cannot be found", async () => {
const explainer = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(`nothing.`),
() => Promise.resolve(undefined),
).explainer();
Expand All @@ -31,6 +34,7 @@ describe(readDefaultsFromReadme, () => {

it("parses a line after badges", async () => {
const explainer = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
</p>
Expand All @@ -47,6 +51,7 @@ This is my project.

it("parses multiple lines after badges", async () => {
const explainer = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
</p>
Expand All @@ -64,6 +69,7 @@ It is good.

it("parses multiple lines after badges and a logo", async () => {
const explainer = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<p align="center">
Expand Down Expand Up @@ -96,6 +102,7 @@ It is good.
describe("logo", () => {
it("defaults to undefined when it cannot be found", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(`nothing.`),
() => Promise.resolve(undefined),
).logo();
Expand All @@ -105,6 +112,7 @@ It is good.

it("parses when found in an unquoted string", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img src=abc/def.jpg/>`),
Expand All @@ -119,6 +127,7 @@ It is good.

it("parses when found in a single quoted string", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img src='abc/def.jpg'/>`),
Expand All @@ -133,6 +142,7 @@ It is good.

it("parses when found in a double quoted string", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img src="abc/def.jpg"/>`),
Expand All @@ -147,6 +157,7 @@ It is good.

it("includes alt text when it exists in double quotes", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img alt="Project logo: a fancy circle" src="abc/def.jpg"/>`),
Expand All @@ -161,6 +172,7 @@ It is good.

it("includes alt text when it exists in single quotes", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img alt='Project logo: a fancy circle' src='abc/def.jpg'/>`),
Expand All @@ -179,6 +191,7 @@ It is good.
mockReadLogoSizing.mockReturnValueOnce(sizing);

const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<img alt='Project logo: a fancy circle' height='117px' src='abc/def.jpg' width=' 117px'/>`),
Expand All @@ -194,6 +207,7 @@ It is good.

it("parses when found after a badge image", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<a href="#contributors" target="_blank"><img alt="👪 All Contributors: 48" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-48-21bb42.svg" /></a>
Expand All @@ -210,6 +224,7 @@ It is good.

it("parses when found after an h1 and many badge images", async () => {
const logo = await readDefaultsFromReadme(
emoji,
() =>
Promise.resolve(`
<h1 align="center">Create TypeScript App</h1>
Expand Down Expand Up @@ -244,6 +259,7 @@ It is good.
describe("title", () => {
it("defaults to undefined when it cannot be found", async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(`nothing`),
() => Promise.resolve(undefined),
).title();
Expand All @@ -253,6 +269,7 @@ It is good.

it('reads title as markdown from "README.md" when it exists', async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(`# My Awesome Package`),
() => Promise.resolve(undefined),
).title();
Expand All @@ -262,6 +279,7 @@ It is good.

it('reads title as HTML from "README.md" when it exists', async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve('<h1 align="center">My Awesome Package</h1>'),
() => Promise.resolve(undefined),
).title();
Expand All @@ -271,6 +289,7 @@ It is good.

it("converts 'typescript' to 'TypeScript' when parsed from the repository name", async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(""),
() => Promise.resolve("my-typescript-app"),
).title();
Expand All @@ -280,6 +299,7 @@ It is good.

it("converts 'eslint' to 'ESLint' when parsed from the repository name", async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(""),
() => Promise.resolve("my-eslint-plugin"),
).title();
Expand All @@ -289,6 +309,7 @@ It is good.

it("returns undefined when title does not exist", async () => {
const title = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(`Other text.`),
() => Promise.resolve(undefined),
).title();
Expand All @@ -304,6 +325,7 @@ It is good.
mockGetUsageFromReadme.mockReturnValueOnce(existing);

const usage = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(""),
() => Promise.resolve(undefined),
).usage();
Expand All @@ -315,6 +337,7 @@ It is good.
mockGetUsageFromReadme.mockReturnValueOnce(undefined);

const usage = await readDefaultsFromReadme(
emoji,
() => Promise.resolve(""),
() => Promise.resolve("test-repository"),
).usage();
Expand Down
3 changes: 2 additions & 1 deletion src/options/readDefaultsFromReadme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getUsageFromReadme } from "./getUsageFromReadme.js";
import { readLogoSizing } from "./readLogoSizing.js";

export function readDefaultsFromReadme(
emoji: () => Promise<string>,
readme: () => Promise<string>,
repository: () => Promise<string | undefined>,
) {
Expand Down Expand Up @@ -83,7 +84,7 @@ npm i ${await repository()}
\`\`\`ts
import { greet } from "${await repository()}";

greet("Hello, world! 💖");
greet("Hello, world! ${await emoji()}");
\`\`\``
);
},
Expand Down