create-typescript-app 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +2 -2
  2. package/lib/base.d.ts +6 -6
  3. package/lib/base.js +120 -99
  4. package/lib/blocks/blockESLintNode.js +2 -9
  5. package/lib/constants.d.ts +8 -0
  6. package/lib/constants.js +9 -0
  7. package/lib/data/packageData.d.ts +1 -1
  8. package/lib/inputs/inputFromOctokit.js +1 -0
  9. package/lib/options/readAuthor.d.ts +7 -0
  10. package/lib/options/readAuthor.js +6 -0
  11. package/lib/options/readEmailFromCodeOfConduct.d.ts +5 -0
  12. package/lib/options/readEmailFromCodeOfConduct.js +10 -0
  13. package/lib/options/readEmailFromGit.d.ts +5 -0
  14. package/lib/options/readEmailFromGit.js +7 -0
  15. package/lib/options/readEmailFromNpm.d.ts +7 -0
  16. package/lib/options/readEmailFromNpm.js +6 -0
  17. package/lib/options/readEmails.d.ts +1 -6
  18. package/lib/options/readEmails.js +3 -8
  19. package/lib/options/readEmoji.d.ts +3 -0
  20. package/lib/options/{parseEmojiFromDescription.js → readEmoji.js} +2 -2
  21. package/lib/options/readExistingLabels.d.ts +9 -0
  22. package/lib/options/{getExistingLabels.js → readExistingLabels.js} +3 -2
  23. package/lib/options/readExplainer.d.ts +3 -0
  24. package/lib/options/readExplainer.js +12 -0
  25. package/lib/options/readFunding.d.ts +3 -1
  26. package/lib/options/readFunding.js +6 -6
  27. package/lib/options/readGitDefaults.d.ts +5 -0
  28. package/lib/options/readGitDefaults.js +12 -0
  29. package/lib/options/readGuide.d.ts +3 -1
  30. package/lib/options/readGuide.js +8 -3
  31. package/lib/options/readLogo.d.ts +8 -0
  32. package/lib/options/readLogo.js +19 -0
  33. package/lib/options/readNode.d.ts +8 -0
  34. package/lib/options/readNode.js +12 -0
  35. package/lib/options/readNpmDefaults.d.ts +6 -0
  36. package/lib/options/readNpmDefaults.js +9 -0
  37. package/lib/options/readOwner.d.ts +8 -0
  38. package/lib/options/readOwner.js +9 -0
  39. package/lib/options/readPackageAuthor.d.ts +8 -0
  40. package/lib/options/{parsePackageAuthor.js → readPackageAuthor.js} +3 -2
  41. package/lib/options/readPackageData.d.ts +5 -1
  42. package/lib/options/readPackageData.js +7 -3
  43. package/lib/options/readPackageDataFull.d.ts +6 -0
  44. package/lib/options/readPackageDataFull.js +9 -0
  45. package/lib/options/readRepository.d.ts +9 -0
  46. package/lib/options/readRepository.js +6 -0
  47. package/lib/options/readRulesetId.d.ts +5 -0
  48. package/lib/options/readRulesetId.js +16 -0
  49. package/lib/options/readTitle.d.ts +3 -0
  50. package/lib/options/readTitle.js +13 -0
  51. package/lib/options/readUsage.d.ts +3 -0
  52. package/lib/options/readUsage.js +14 -0
  53. package/lib/options/readUsageFromReadme.d.ts +3 -0
  54. package/lib/options/{getUsageFromReadme.js → readUsageFromReadme.js} +2 -2
  55. package/lib/utils/swallowErrorAsync.d.ts +3 -0
  56. package/lib/utils/swallowErrorAsync.js +10 -0
  57. package/package.json +1 -1
  58. package/lib/options/getExistingLabels.d.ts +0 -9
  59. package/lib/options/getUsageFromReadme.d.ts +0 -3
  60. package/lib/options/parseEmojiFromDescription.d.ts +0 -3
  61. package/lib/options/parsePackageAuthor.d.ts +0 -8
  62. package/lib/options/readDefaultsFromReadme.d.ts +0 -13
  63. package/lib/options/readDefaultsFromReadme.js +0 -57
  64. package/lib/options/readGitHubEmail.d.ts +0 -3
  65. package/lib/options/readGitHubEmail.js +0 -11
  66. package/lib/utils/tryCatchAsync.d.ts +0 -3
  67. package/lib/utils/tryCatchAsync.js +0 -10
  68. package/lib/utils/tryCatchLazyValueAsync.d.ts +0 -3
  69. package/lib/utils/tryCatchLazyValueAsync.js +0 -8
package/README.md CHANGED
@@ -48,8 +48,8 @@ You can read more about the supported runtime modes in their docs pages:
48
48
  You can read more about `create-typescript-app` and the tooling it supports:
49
49
 
50
50
  1. [**Blocks**](./docs/Blocks.md): a breakdown of all the pieces this template can set up.
51
- 2. [**Options**](./docs/Options.md): granular options to customize how the template is run.
52
- 3. [**FAQs**](./docs/FAQs.md): frequently asked questions
51
+ 2. [**CLI**](./docs/CLI.md): providing granular options to customize how the template is run.
52
+ 3. [**FAQs**](./docs/FAQs.md): frequently asked questions and troubleshooting
53
53
 
54
54
  > [!NOTE]
55
55
  > This template is early stage, opinionated, and not endorsed by the TypeScript team.
package/lib/base.d.ts CHANGED
@@ -9,16 +9,16 @@ declare const zContributor: z.ZodObject<{
9
9
  name: z.ZodString;
10
10
  profile: z.ZodString;
11
11
  }, "strip", z.ZodTypeAny, {
12
+ name: string;
12
13
  avatar_url: string;
13
14
  contributions: string[];
14
15
  login: string;
15
- name: string;
16
16
  profile: string;
17
17
  }, {
18
+ name: string;
18
19
  avatar_url: string;
19
20
  contributions: string[];
20
21
  login: string;
21
- name: string;
22
22
  profile: string;
23
23
  }>;
24
24
  type Contributor = z.infer<typeof zContributor>;
@@ -33,16 +33,16 @@ declare const base: bingo_stratum.Base<{
33
33
  name: z.ZodString;
34
34
  profile: z.ZodString;
35
35
  }, "strip", z.ZodTypeAny, {
36
+ name: string;
36
37
  avatar_url: string;
37
38
  contributions: string[];
38
39
  login: string;
39
- name: string;
40
40
  profile: string;
41
41
  }, {
42
+ name: string;
42
43
  avatar_url: string;
43
44
  contributions: string[];
44
45
  login: string;
45
- name: string;
46
46
  profile: string;
47
47
  }>, "many">>;
48
48
  description: z.ZodDefault<z.ZodString>;
@@ -84,11 +84,11 @@ declare const base: bingo_stratum.Base<{
84
84
  href: z.ZodString;
85
85
  title: z.ZodString;
86
86
  }, "strip", z.ZodTypeAny, {
87
- href: string;
88
87
  title: string;
89
- }, {
90
88
  href: string;
89
+ }, {
91
90
  title: string;
91
+ href: string;
92
92
  }>>;
93
93
  keywords: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
94
94
  logo: z.ZodOptional<z.ZodObject<{
package/lib/base.js CHANGED
@@ -1,28 +1,35 @@
1
1
  import { createBase } from "bingo-stratum";
2
- import { execaCommand } from "execa";
3
- import gitRemoteOriginUrl from "git-remote-origin-url";
4
- import gitUrlParse from "git-url-parse";
5
2
  import { inputFromFile } from "input-from-file";
6
3
  import { inputFromScript } from "input-from-script";
7
4
  import lazyValue from "lazy-value";
8
- import npmUser from "npm-user";
9
5
  import { z } from "zod";
10
- import { inputFromOctokit } from "./inputs/inputFromOctokit.js";
11
- import { getExistingLabels } from "./options/getExistingLabels.js";
12
- import { parseEmojiFromDescription } from "./options/parseEmojiFromDescription.js";
13
- import { parsePackageAuthor } from "./options/parsePackageAuthor.js";
14
6
  import { readAllContributors } from "./options/readAllContributors.js";
15
- import { readDefaultsFromReadme } from "./options/readDefaultsFromReadme.js";
7
+ import { readAuthor } from "./options/readAuthor.js";
16
8
  import { readDescription } from "./options/readDescription.js";
17
9
  import { readDocumentation } from "./options/readDocumentation.js";
10
+ import { readEmailFromCodeOfConduct } from "./options/readEmailFromCodeOfConduct.js";
11
+ import { readEmailFromGit } from "./options/readEmailFromGit.js";
12
+ import { readEmailFromNpm } from "./options/readEmailFromNpm.js";
18
13
  import { readEmails } from "./options/readEmails.js";
14
+ import { readEmoji } from "./options/readEmoji.js";
15
+ import { readExistingLabels } from "./options/readExistingLabels.js";
16
+ import { readExplainer } from "./options/readExplainer.js";
19
17
  import { readFileSafe } from "./options/readFileSafe.js";
20
18
  import { readFunding } from "./options/readFunding.js";
19
+ import { readGitDefaults } from "./options/readGitDefaults.js";
21
20
  import { readGuide } from "./options/readGuide.js";
21
+ import { readLogo } from "./options/readLogo.js";
22
+ import { readNode } from "./options/readNode.js";
23
+ import { readNpmDefaults } from "./options/readNpmDefaults.js";
24
+ import { readOwner } from "./options/readOwner.js";
25
+ import { readPackageAuthor } from "./options/readPackageAuthor.js";
22
26
  import { readPackageData } from "./options/readPackageData.js";
27
+ import { readPackageDataFull } from "./options/readPackageDataFull.js";
23
28
  import { readPnpm } from "./options/readPnpm.js";
24
- import { swallowError } from "./utils/swallowError.js";
25
- import { tryCatchLazyValueAsync } from "./utils/tryCatchLazyValueAsync.js";
29
+ import { readRepository } from "./options/readRepository.js";
30
+ import { readRulesetId } from "./options/readRulesetId.js";
31
+ import { readTitle } from "./options/readTitle.js";
32
+ import { readUsage } from "./options/readUsage.js";
26
33
  const zContributor = z.object({
27
34
  avatar_url: z.string(),
28
35
  contributions: z.array(z.string()),
@@ -73,13 +80,13 @@ const base = createBase({
73
80
  src: z.string(),
74
81
  width: z.number().optional()
75
82
  }).optional().describe(
76
- "local image file in the repository to display near the top of the README.md"
83
+ "local image file and alt text to display near the top of the README.md"
77
84
  ),
78
85
  node: z.object({
79
86
  minimum: z.string(),
80
87
  pinned: z.string().optional()
81
- }).optional().describe("node.js engine version(s) to pin and require a minimum of"),
82
- owner: z.string().describe("GitHub organization or user the repository is underneath"),
88
+ }).optional().describe("Node.js engine version(s) to pin and require a minimum of"),
89
+ owner: z.string().describe("organization or user owning the repository"),
83
90
  packageData: z.object({
84
91
  dependencies: z.record(z.string(), z.string()).optional(),
85
92
  devDependencies: z.record(z.string(), z.string()).optional(),
@@ -89,100 +96,114 @@ const base = createBase({
89
96
  repository: z.string().describe("'kebab-case' or 'PascalCase' title of the repository"),
90
97
  rulesetId: z.string().optional().describe("GitHub branch ruleset ID for main branch protections"),
91
98
  title: z.string().describe("'Title Case' title for the repository"),
92
- usage: z.string().optional().describe("markdown docs to put in README.md under the ## Usage heading"),
99
+ usage: z.string().optional().describe("Markdown docs to put in README.md under the ## Usage heading"),
93
100
  version: z.string().optional().describe("package version to publish as and store in `package.json`")
94
101
  },
95
102
  prepare({ options, take }) {
96
- const allContributors = lazyValue(async () => readAllContributors(take));
97
- const documentation = lazyValue(async () => readDocumentation(take));
98
- const nvmrc = lazyValue(
103
+ const getAllContributors = lazyValue(
104
+ async () => await readAllContributors(take)
105
+ );
106
+ const getAuthor = lazyValue(
107
+ async () => await readAuthor(getPackageAuthor, getNpmDefaults, options.owner)
108
+ );
109
+ const getBin = lazyValue(async () => (await getPackageDataFull()).bin);
110
+ const getEmoji = lazyValue(async () => await readEmoji(getDescription));
111
+ const getDescription = lazyValue(
112
+ async () => await readDescription(getPackageDataFull, getReadme)
113
+ );
114
+ const getDocumentation = lazyValue(
115
+ async () => await readDocumentation(take)
116
+ );
117
+ const getEmail = lazyValue(
118
+ async () => await readEmails(
119
+ getEmailFromCodeOfConduct,
120
+ getEmailFromGit,
121
+ getEmailFromNpm
122
+ )
123
+ );
124
+ const getEmailFromCodeOfConduct = lazyValue(
125
+ async () => await readEmailFromCodeOfConduct(take)
126
+ );
127
+ const getEmailFromGit = lazyValue(async () => await readEmailFromGit(take));
128
+ const getEmailFromNpm = lazyValue(
129
+ async () => await readEmailFromNpm(getNpmDefaults, getPackageAuthor)
130
+ );
131
+ const getExistingLabels = lazyValue(
132
+ async () => await readExistingLabels(take, getOwner, getRepository)
133
+ );
134
+ const getExplainer = lazyValue(async () => await readExplainer(getReadme));
135
+ const getFunding = lazyValue(async () => await readFunding(take));
136
+ const getGitDefaults = lazyValue(async () => await readGitDefaults());
137
+ const getGuide = lazyValue(async () => await readGuide(take));
138
+ const getLogo = lazyValue(async () => await readLogo(getReadme));
139
+ const getPackageData = lazyValue(
140
+ async () => await readPackageData(getPackageDataFull)
141
+ );
142
+ const getPackageDataFull = lazyValue(
143
+ async () => await readPackageDataFull(take)
144
+ );
145
+ const getNode = lazyValue(
146
+ async () => await readNode(getNvmrc, getPackageDataFull)
147
+ );
148
+ const getNpmDefaults = lazyValue(
149
+ async () => await readNpmDefaults(getNpmWhoami)
150
+ );
151
+ const getNpmWhoami = lazyValue(
152
+ async () => await take(inputFromScript, { command: "npm whoami --offline" })
153
+ );
154
+ const getNvmrc = lazyValue(
99
155
  async () => await take(inputFromFile, {
100
156
  filePath: ".nvmrc"
101
157
  })
102
158
  );
103
- const existingLabels = lazyValue(
104
- async () => getExistingLabels(take, await owner(), await repository())
105
- );
106
- const githubCliUser = lazyValue(async () => {
107
- return swallowError(
108
- await take(inputFromScript, {
109
- command: "gh config get user -h github.com"
110
- })
111
- )?.stdout?.toString();
112
- });
113
- const readme = lazyValue(async () => await readFileSafe("README.md", ""));
114
- const rulesetId = lazyValue(async () => {
115
- const rulesets = await take(inputFromOctokit, {
116
- endpoint: "GET /repos/{owner}/{repo}/rulesets",
117
- options: {
118
- owner: await owner(),
119
- repo: await repository()
120
- }
121
- });
122
- return rulesets?.find(
123
- (ruleset) => ruleset.name === "Branch protection for main"
124
- )?.id;
125
- });
126
- const emoji = async () => parseEmojiFromDescription(description);
127
- const description = async () => await readDescription(packageData, readme);
128
- const gitDefaults = tryCatchLazyValueAsync(
129
- async () => gitUrlParse(await gitRemoteOriginUrl())
130
- );
131
- const npmDefaults = tryCatchLazyValueAsync(async () => {
132
- const whoami = (await execaCommand(`npm whoami`)).stdout;
133
- return whoami ? await npmUser(whoami) : void 0;
134
- });
135
- const packageData = lazyValue(readPackageData);
136
- const packageAuthor = lazyValue(
137
- async () => parsePackageAuthor(await packageData())
138
- );
139
- const author = lazyValue(
140
- async () => (await packageAuthor()).author ?? (await npmDefaults())?.name ?? options.owner
141
- );
142
- const node = lazyValue(async () => {
143
- const { engines } = await packageData();
144
- return {
145
- minimum: (engines?.node && /[\d+.]+/.exec(engines.node))?.[0] ?? "18.3.0",
146
- pinned: swallowError(await nvmrc())?.trim() ?? "20.18.0"
147
- };
148
- });
149
- const pnpm = lazyValue(async () => readPnpm(packageData));
150
- const version = lazyValue(async () => (await packageData()).version);
151
- const owner = lazyValue(
152
- async () => (await gitDefaults())?.organization ?? (await packageAuthor()).author ?? await githubCliUser()
153
- );
154
- const repository = lazyValue(
155
- async () => options.repository ?? (await gitDefaults())?.name ?? (await packageData()).name ?? options.directory
156
- );
157
- const email = lazyValue(async () => readEmails(npmDefaults, packageAuthor));
159
+ const getOwner = lazyValue(
160
+ async () => await readOwner(take, getGitDefaults, getPackageAuthor)
161
+ );
162
+ const getPackageAuthor = lazyValue(
163
+ async () => await readPackageAuthor(getPackageDataFull)
164
+ );
165
+ const getPnpm = lazyValue(async () => await readPnpm(getPackageDataFull));
166
+ const getReadme = lazyValue(
167
+ async () => await readFileSafe("README.md", "")
168
+ );
169
+ const getRepository = lazyValue(
170
+ async () => await readRepository(getGitDefaults, getPackageDataFull, options)
171
+ );
172
+ const getRulesetId = lazyValue(
173
+ async () => await readRulesetId(take, getOwner, getRepository)
174
+ );
175
+ const getTitle = lazyValue(
176
+ async () => await readTitle(getReadme, getRepository)
177
+ );
178
+ const getUsage = lazyValue(
179
+ async () => await readUsage(getEmoji, getReadme, getRepository)
180
+ );
181
+ const getVersion = lazyValue(
182
+ async () => (await getPackageDataFull()).version
183
+ );
158
184
  return {
159
185
  access: "public",
160
- author,
161
- bin: async () => (await packageData()).bin,
162
- contributors: allContributors,
163
- description,
164
- documentation,
165
- email,
166
- emoji,
167
- existingLabels,
168
- funding: readFunding,
169
- guide: readGuide,
170
- login: author,
171
- node,
172
- owner,
173
- packageData: async () => {
174
- const original = await packageData();
175
- return {
176
- dependencies: original.dependencies,
177
- devDependencies: original.devDependencies,
178
- scripts: original.scripts
179
- };
180
- },
181
- pnpm,
182
- repository,
183
- rulesetId,
184
- ...readDefaultsFromReadme(emoji, readme, repository),
185
- version
186
+ author: getAuthor,
187
+ bin: getBin,
188
+ contributors: getAllContributors,
189
+ description: getDescription,
190
+ documentation: getDocumentation,
191
+ email: getEmail,
192
+ emoji: getEmoji,
193
+ existingLabels: getExistingLabels,
194
+ explainer: getExplainer,
195
+ funding: getFunding,
196
+ guide: getGuide,
197
+ logo: getLogo,
198
+ node: getNode,
199
+ owner: getOwner,
200
+ packageData: getPackageData,
201
+ pnpm: getPnpm,
202
+ repository: getRepository,
203
+ rulesetId: getRulesetId,
204
+ title: getTitle,
205
+ usage: getUsage,
206
+ version: getVersion
186
207
  };
187
208
  }
188
209
  });
@@ -4,7 +4,7 @@ const blockESLintNode = base.createBlock({
4
4
  about: {
5
5
  name: "ESLint Node Plugin"
6
6
  },
7
- produce({ options }) {
7
+ produce() {
8
8
  return {
9
9
  addons: [
10
10
  blockESLint({
@@ -13,14 +13,7 @@ const blockESLintNode = base.createBlock({
13
13
  {
14
14
  extends: ["tseslint.configs.disableTypeChecked"],
15
15
  files: ["**/*.md/*.ts"],
16
- ...options.usage?.includes(`from "${options.repository}`) && {
17
- rules: {
18
- "n/no-missing-import": [
19
- "error",
20
- { allowModules: [options.repository] }
21
- ]
22
- }
23
- }
16
+ rules: { "n/no-missing-import": "off" }
24
17
  }
25
18
  ],
26
19
  imports: [{ source: "eslint-plugin-n", specifier: "n" }]
@@ -0,0 +1,8 @@
1
+ declare const defaults: {
2
+ node: {
3
+ minimum: string;
4
+ pinned: string;
5
+ };
6
+ };
7
+
8
+ export { defaults };
@@ -0,0 +1,9 @@
1
+ const defaults = {
2
+ node: {
3
+ minimum: "18.3.0",
4
+ pinned: "20.18.0"
5
+ }
6
+ };
7
+ export {
8
+ defaults
9
+ };
@@ -1,5 +1,5 @@
1
1
  var name = "create-typescript-app";
2
- var version = "2.5.0";
2
+ var version = "2.6.0";
3
3
  var description = "Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. 🎁";
4
4
  var repository = {
5
5
  type: "git",
@@ -14,6 +14,7 @@ const inputFromOctokit = createInput({
14
14
  headers: {
15
15
  "X-GitHub-Api-Version": "2022-11-28"
16
16
  },
17
+ request: { retries: 0 },
17
18
  ...args.options
18
19
  });
19
20
  return response.data;
@@ -0,0 +1,7 @@
1
+ declare function readAuthor(getPackageAuthor: () => Promise<{
2
+ author?: string;
3
+ }>, getNpmDefaults: () => Promise<undefined | {
4
+ name?: string;
5
+ }>, owner: string | undefined): Promise<string | undefined>;
6
+
7
+ export { readAuthor };
@@ -0,0 +1,6 @@
1
+ async function readAuthor(getPackageAuthor, getNpmDefaults, owner) {
2
+ return (await getPackageAuthor()).author ?? (await getNpmDefaults())?.name ?? owner;
3
+ }
4
+ export {
5
+ readAuthor
6
+ };
@@ -0,0 +1,5 @@
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readEmailFromCodeOfConduct(take: TakeInput): Promise<string | undefined>;
4
+
5
+ export { readEmailFromCodeOfConduct };
@@ -0,0 +1,10 @@
1
+ import { inputFromFile } from "input-from-file";
2
+ async function readEmailFromCodeOfConduct(take) {
3
+ const codeOfConduct = await take(inputFromFile, {
4
+ filePath: ".github/CODE_OF_CONDUCT.md"
5
+ });
6
+ return typeof codeOfConduct === "string" && codeOfConduct.includes("Contributor Covenant Code of Conduct") ? /for enforcement at[\r\n]+(.+)\.[\r\n]+All/.exec(codeOfConduct)?.[1] : void 0;
7
+ }
8
+ export {
9
+ readEmailFromCodeOfConduct
10
+ };
@@ -0,0 +1,5 @@
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readEmailFromGit(take: TakeInput): Promise<string | undefined>;
4
+
5
+ export { readEmailFromGit };
@@ -0,0 +1,7 @@
1
+ import { inputFromScript } from "input-from-script";
2
+ async function readEmailFromGit(take) {
3
+ return (await take(inputFromScript, { command: "git config --get user.email" })).stdout?.toString();
4
+ }
5
+ export {
6
+ readEmailFromGit
7
+ };
@@ -0,0 +1,7 @@
1
+ import { UserInfo } from 'npm-user';
2
+
3
+ declare function readEmailFromNpm(getNpmDefaults: () => Promise<undefined | UserInfo>, getPackageAuthor: () => Promise<{
4
+ email: string | undefined;
5
+ }>): Promise<string | undefined>;
6
+
7
+ export { readEmailFromNpm };
@@ -0,0 +1,6 @@
1
+ async function readEmailFromNpm(getNpmDefaults, getPackageAuthor) {
2
+ return (await getNpmDefaults())?.email ?? (await getPackageAuthor()).email;
3
+ }
4
+ export {
5
+ readEmailFromNpm
6
+ };
@@ -1,9 +1,4 @@
1
- import { UserInfo } from 'npm-user';
2
-
3
- declare function readEmails(npmDefaults: () => Promise<undefined | UserInfo>, packageAuthor: () => Promise<{
4
- author: string | undefined;
5
- email: string | undefined;
6
- }>): Promise<{
1
+ declare function readEmails(getEmailFromCodeOfConduct: () => Promise<string | undefined>, getEmailFromGit: () => Promise<string | undefined>, getEmailFromNpm: () => Promise<string | undefined>): Promise<{
7
2
  github: string;
8
3
  npm: string;
9
4
  } | undefined>;
@@ -1,11 +1,6 @@
1
- import { $ } from "execa";
2
- import { tryCatchAsync } from "../utils/tryCatchAsync.js";
3
- import { readGitHubEmail } from "./readGitHubEmail.js";
4
- async function readEmails(npmDefaults, packageAuthor) {
5
- const github = await readGitHubEmail() ?? await tryCatchAsync(
6
- async () => (await $`git config --get user.email`).stdout
7
- );
8
- const npm = ((await npmDefaults())?.email ?? (await packageAuthor()).email) || github;
1
+ async function readEmails(getEmailFromCodeOfConduct, getEmailFromGit, getEmailFromNpm) {
2
+ const github = await getEmailFromCodeOfConduct() ?? await getEmailFromGit();
3
+ const npm = await getEmailFromNpm() ?? github;
9
4
  return npm ? { github: github || npm, npm } : void 0;
10
5
  }
11
6
  export {
@@ -0,0 +1,3 @@
1
+ declare function readEmoji(getDescription: () => Promise<string | undefined>): Promise<string>;
2
+
3
+ export { readEmoji };
@@ -1,6 +1,6 @@
1
- async function parseEmojiFromDescription(getDescription) {
1
+ async function readEmoji(getDescription) {
2
2
  return (await getDescription())?.match(/\p{Extended_Pictographic}/gu)?.at(-1) ?? "\u{1F496}";
3
3
  }
4
4
  export {
5
- parseEmojiFromDescription
5
+ readEmoji
6
6
  };
@@ -0,0 +1,9 @@
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readExistingLabels(take: TakeInput, getOwner: () => Promise<string | undefined>, getRepository: () => Promise<string | undefined>): Promise<{
4
+ color: string;
5
+ description: string;
6
+ name: string;
7
+ }[]>;
8
+
9
+ export { readExistingLabels };
@@ -1,6 +1,7 @@
1
1
  import { githubDefaultLabels } from "github-default-labels";
2
2
  import { inputFromOctokit } from "../inputs/inputFromOctokit.js";
3
- async function getExistingLabels(take, owner, repository) {
3
+ async function readExistingLabels(take, getOwner, getRepository) {
4
+ const [owner, repository] = await Promise.all([getOwner(), getRepository()]);
4
5
  const existingLabelsActual = owner && repository && await take(inputFromOctokit, {
5
6
  endpoint: "GET /repos/{owner}/{repo}/labels",
6
7
  options: {
@@ -18,5 +19,5 @@ async function getExistingLabels(take, owner, repository) {
18
19
  return githubDefaultLabels;
19
20
  }
20
21
  export {
21
- getExistingLabels
22
+ readExistingLabels
22
23
  };
@@ -0,0 +1,3 @@
1
+ declare function readExplainer(getReadme: () => Promise<string>): Promise<string[] | undefined>;
2
+
3
+ export { readExplainer };
@@ -0,0 +1,12 @@
1
+ async function readExplainer(getReadme) {
2
+ const readme = await getReadme();
3
+ const indexOfH2 = readme.indexOf("##");
4
+ if (indexOfH2 === -1) {
5
+ return void 0;
6
+ }
7
+ const lastTag = readme.slice(0, indexOfH2).lastIndexOf(">");
8
+ return readme.slice(lastTag + 1, indexOfH2).split("\n").map((line) => line.trim()).filter(Boolean);
9
+ }
10
+ export {
11
+ readExplainer
12
+ };
@@ -1,3 +1,5 @@
1
- declare function readFunding(): Promise<string | undefined>;
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readFunding(take: TakeInput): Promise<string | undefined>;
2
4
 
3
5
  export { readFunding };
@@ -1,9 +1,9 @@
1
- import fs from "node:fs/promises";
2
- import { tryCatchAsync } from "../utils/tryCatchAsync.js";
3
- async function readFunding() {
4
- return await tryCatchAsync(
5
- async () => (await fs.readFile(".github/FUNDING.yml")).toString().split(":")[1]?.trim()
6
- );
1
+ import { inputFromFile } from "input-from-file";
2
+ import { swallowError } from "../utils/swallowError.js";
3
+ async function readFunding(take) {
4
+ return swallowError(
5
+ await take(inputFromFile, { filePath: ".github/FUNDING.yml" })
6
+ )?.split(":")[1]?.trim();
7
7
  }
8
8
  export {
9
9
  readFunding
@@ -0,0 +1,5 @@
1
+ import gitUrlParse from 'git-url-parse';
2
+
3
+ declare function readGitDefaults(): Promise<gitUrlParse.GitUrl | undefined>;
4
+
5
+ export { readGitDefaults };
@@ -0,0 +1,12 @@
1
+ import gitRemoteOriginUrl from "git-remote-origin-url";
2
+ import gitUrlParse from "git-url-parse";
3
+ async function readGitDefaults() {
4
+ try {
5
+ return gitUrlParse(await gitRemoteOriginUrl());
6
+ } catch {
7
+ return void 0;
8
+ }
9
+ }
10
+ export {
11
+ readGitDefaults
12
+ };
@@ -1,4 +1,6 @@
1
- declare function readGuide(): Promise<{
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readGuide(take: TakeInput): Promise<{
2
4
  href: string;
3
5
  title: string;
4
6
  } | undefined>;
@@ -1,6 +1,11 @@
1
- import { readFileSafe } from "./readFileSafe.js";
2
- async function readGuide() {
3
- const development = await readFileSafe(".github/DEVELOPMENT.md", "");
1
+ import { inputFromFile } from "input-from-file";
2
+ async function readGuide(take) {
3
+ const development = await take(inputFromFile, {
4
+ filePath: ".github/DEVELOPMENT.md"
5
+ });
6
+ if (development instanceof Error) {
7
+ return void 0;
8
+ }
4
9
  const tag = /> .*guided walkthrough, see \[((?!\[).+)\]\((.+)\)/i.exec(
5
10
  development
6
11
  );
@@ -0,0 +1,8 @@
1
+ declare function readLogo(getReadme: () => Promise<string>): Promise<{
2
+ height?: number;
3
+ width?: number;
4
+ alt: string;
5
+ src: string;
6
+ } | undefined>;
7
+
8
+ export { readLogo };
@@ -0,0 +1,19 @@
1
+ import { readLogoSizing } from "./readLogoSizing.js";
2
+ async function readLogo(getReadme) {
3
+ const tag = /\n<img.+src=.+>/.exec(await getReadme())?.[0];
4
+ if (!tag) {
5
+ return void 0;
6
+ }
7
+ const src = /src\s*=(.+)['"/]>/.exec(tag)?.[1]?.split(/\s*\w+=/)[0].replaceAll(/^['"]|['"]$/g, "");
8
+ if (!src) {
9
+ return void 0;
10
+ }
11
+ return {
12
+ alt: /alt=['"](.+)['"]\s*src=/.exec(tag)?.[1].split(/['"]?\s*\w+=/)[0] ?? "Project logo",
13
+ src,
14
+ ...readLogoSizing(src)
15
+ };
16
+ }
17
+ export {
18
+ readLogo
19
+ };
@@ -0,0 +1,8 @@
1
+ import { PartialPackageData } from '../types.js';
2
+
3
+ declare function readNode(getNvmrc: () => Promise<Error | string>, getPackageDataFull: () => Promise<PartialPackageData>): Promise<{
4
+ minimum: string;
5
+ pinned: string;
6
+ }>;
7
+
8
+ export { readNode };
@@ -0,0 +1,12 @@
1
+ import { defaults } from "../constants.js";
2
+ import { swallowError } from "../utils/swallowError.js";
3
+ async function readNode(getNvmrc, getPackageDataFull) {
4
+ const { engines } = await getPackageDataFull();
5
+ return {
6
+ minimum: (engines?.node && /[\d+.]+/.exec(engines.node))?.[0] ?? defaults.node.minimum,
7
+ pinned: swallowError(await getNvmrc())?.trim() || defaults.node.pinned
8
+ };
9
+ }
10
+ export {
11
+ readNode
12
+ };
@@ -0,0 +1,6 @@
1
+ import * as npm_user from 'npm-user';
2
+ import { ExecaError, Result } from 'execa';
3
+
4
+ declare function readNpmDefaults(getNpmWhoami: () => Promise<ExecaError | Result | undefined>): Promise<npm_user.UserInfo | undefined>;
5
+
6
+ export { readNpmDefaults };
@@ -0,0 +1,9 @@
1
+ import npmUser from "npm-user";
2
+ import { swallowErrorAsync } from "../utils/swallowErrorAsync.js";
3
+ async function readNpmDefaults(getNpmWhoami) {
4
+ const whoami = await getNpmWhoami();
5
+ return typeof whoami?.stdout === "string" ? await swallowErrorAsync(npmUser(whoami.stdout)) : void 0;
6
+ }
7
+ export {
8
+ readNpmDefaults
9
+ };
@@ -0,0 +1,8 @@
1
+ import { TakeInput } from 'bingo';
2
+ import { GitUrl } from 'git-url-parse';
3
+
4
+ declare function readOwner(take: TakeInput, getGitDefaults: () => Promise<GitUrl | undefined>, getPackageAuthor: () => Promise<{
5
+ author?: string;
6
+ }>): Promise<string | undefined>;
7
+
8
+ export { readOwner };
@@ -0,0 +1,9 @@
1
+ import { inputFromScript } from "input-from-script";
2
+ async function readOwner(take, getGitDefaults, getPackageAuthor) {
3
+ return (await getGitDefaults())?.organization ?? (await getPackageAuthor()).author ?? (await take(inputFromScript, {
4
+ command: "gh config get user -h github.com"
5
+ })).stdout?.toString();
6
+ }
7
+ export {
8
+ readOwner
9
+ };
@@ -0,0 +1,8 @@
1
+ import { PartialPackageData } from '../types.js';
2
+
3
+ declare function readPackageAuthor(getPackageDataFull: () => Promise<PartialPackageData>): Promise<{
4
+ author: string | undefined;
5
+ email: string | undefined;
6
+ }>;
7
+
8
+ export { readPackageAuthor };
@@ -1,5 +1,6 @@
1
1
  import parse from "parse-author";
2
- function parsePackageAuthor(packageData) {
2
+ async function readPackageAuthor(getPackageDataFull) {
3
+ const packageData = await getPackageDataFull();
3
4
  let packageAuthor;
4
5
  let packageEmail;
5
6
  if (typeof packageData.author === "string") {
@@ -16,5 +17,5 @@ function parsePackageAuthor(packageData) {
16
17
  };
17
18
  }
18
19
  export {
19
- parsePackageAuthor
20
+ readPackageAuthor
20
21
  };
@@ -1,5 +1,9 @@
1
1
  import { PartialPackageData } from '../types.js';
2
2
 
3
- declare function readPackageData(): Promise<PartialPackageData>;
3
+ declare function readPackageData(getPackageDataFull: () => Promise<PartialPackageData>): Promise<{
4
+ dependencies: Record<string, string> | undefined;
5
+ devDependencies: Record<string, string> | undefined;
6
+ scripts: Record<string, string> | undefined;
7
+ }>;
4
8
 
5
9
  export { readPackageData };
@@ -1,6 +1,10 @@
1
- import { readFileSafe } from "./readFileSafe.js";
2
- async function readPackageData() {
3
- return JSON.parse(await readFileSafe("./package.json", "{}")) ?? {};
1
+ async function readPackageData(getPackageDataFull) {
2
+ const original = await getPackageDataFull();
3
+ return {
4
+ dependencies: original.dependencies,
5
+ devDependencies: original.devDependencies,
6
+ scripts: original.scripts
7
+ };
4
8
  }
5
9
  export {
6
10
  readPackageData
@@ -0,0 +1,6 @@
1
+ import { TakeInput } from 'bingo';
2
+ import { PartialPackageData } from '../types.js';
3
+
4
+ declare function readPackageDataFull(take: TakeInput): Promise<PartialPackageData>;
5
+
6
+ export { readPackageDataFull };
@@ -0,0 +1,9 @@
1
+ import { inputFromFileJSON } from "input-from-file-json";
2
+ async function readPackageDataFull(take) {
3
+ return await take(inputFromFileJSON, {
4
+ filePath: "./package.json"
5
+ }) ?? {};
6
+ }
7
+ export {
8
+ readPackageDataFull
9
+ };
@@ -0,0 +1,9 @@
1
+ import { GitUrl } from 'git-url-parse';
2
+ import { PartialPackageData } from '../types.js';
3
+
4
+ declare function readRepository(getGitDefaults: () => Promise<GitUrl | undefined>, getPackageDataFull: () => Promise<PartialPackageData>, options: {
5
+ directory?: string;
6
+ repository?: string;
7
+ }): Promise<string | undefined>;
8
+
9
+ export { readRepository };
@@ -0,0 +1,6 @@
1
+ async function readRepository(getGitDefaults, getPackageDataFull, options) {
2
+ return options.repository ?? (await getGitDefaults())?.name ?? (await getPackageDataFull()).name ?? options.directory;
3
+ }
4
+ export {
5
+ readRepository
6
+ };
@@ -0,0 +1,5 @@
1
+ import { TakeInput } from 'bingo';
2
+
3
+ declare function readRulesetId(take: TakeInput, getOwner: () => Promise<string | undefined>, getRepository: () => Promise<string | undefined>): Promise<string | undefined>;
4
+
5
+ export { readRulesetId };
@@ -0,0 +1,16 @@
1
+ import { inputFromOctokit } from "../inputs/inputFromOctokit.js";
2
+ async function readRulesetId(take, getOwner, getRepository) {
3
+ const rulesets = await take(inputFromOctokit, {
4
+ endpoint: "GET /repos/{owner}/{repo}/rulesets",
5
+ options: {
6
+ owner: await getOwner(),
7
+ repo: await getRepository()
8
+ }
9
+ });
10
+ return rulesets?.find(
11
+ (ruleset) => ruleset.name === "Branch protection for main"
12
+ )?.id;
13
+ }
14
+ export {
15
+ readRulesetId
16
+ };
@@ -0,0 +1,3 @@
1
+ declare function readTitle(getReadme: () => Promise<string>, getRepository: () => Promise<string | undefined>): Promise<string | undefined>;
2
+
3
+ export { readTitle };
@@ -0,0 +1,13 @@
1
+ import { titleCase } from "title-case";
2
+ async function readTitle(getReadme, getRepository) {
3
+ const text = await getReadme();
4
+ const fromText = (/^<h1\s+align="center">(.+)<\/h1>/.exec(text) ?? /^# (.+)/.exec(text))?.[1];
5
+ if (fromText) {
6
+ return fromText;
7
+ }
8
+ const repositoryValue = await getRepository();
9
+ return repositoryValue && titleCase(repositoryValue).replaceAll("Eslint", "ESLint").replaceAll("Typescript", "TypeScript").replaceAll("-", " ");
10
+ }
11
+ export {
12
+ readTitle
13
+ };
@@ -0,0 +1,3 @@
1
+ declare function readUsage(getEmoji: () => Promise<string>, getReadme: () => Promise<string>, getRepository: () => Promise<string | undefined>): Promise<string>;
2
+
3
+ export { readUsage };
@@ -0,0 +1,14 @@
1
+ import { readUsageFromReadme } from "./readUsageFromReadme.js";
2
+ async function readUsage(getEmoji, getReadme, getRepository) {
3
+ return readUsageFromReadme(await getReadme()) ?? `\`\`\`shell
4
+ npm i ${await getRepository()}
5
+ \`\`\`
6
+ \`\`\`ts
7
+ import { greet } from "${await getRepository()}";
8
+
9
+ greet("Hello, world! ${await getEmoji()}");
10
+ \`\`\``;
11
+ }
12
+ export {
13
+ readUsage
14
+ };
@@ -0,0 +1,3 @@
1
+ declare function readUsageFromReadme(readme: string): string | undefined;
2
+
3
+ export { readUsageFromReadme };
@@ -1,6 +1,6 @@
1
1
  const startDevelopment = "## Development";
2
2
  const startUsage = "## Usage";
3
- function getUsageFromReadme(readme) {
3
+ function readUsageFromReadme(readme) {
4
4
  const indexOfUsage = readme.indexOf(startUsage);
5
5
  if (indexOfUsage === -1) {
6
6
  return void 0;
@@ -16,5 +16,5 @@ function getUsageFromReadme(readme) {
16
16
  return usage ? usage : void 0;
17
17
  }
18
18
  export {
19
- getUsageFromReadme
19
+ readUsageFromReadme
20
20
  };
@@ -0,0 +1,3 @@
1
+ declare function swallowErrorAsync<T>(task: Promise<T>): Promise<T | undefined>;
2
+
3
+ export { swallowErrorAsync };
@@ -0,0 +1,10 @@
1
+ async function swallowErrorAsync(task) {
2
+ try {
3
+ return await task;
4
+ } catch {
5
+ return void 0;
6
+ }
7
+ }
8
+ export {
9
+ swallowErrorAsync
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-typescript-app",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. 🎁",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,9 +0,0 @@
1
- import { TakeInput } from 'bingo';
2
-
3
- declare function getExistingLabels(take: TakeInput, owner: string | undefined, repository: string | undefined): Promise<{
4
- color: string;
5
- description: string;
6
- name: string;
7
- }[]>;
8
-
9
- export { getExistingLabels };
@@ -1,3 +0,0 @@
1
- declare function getUsageFromReadme(readme: string): string | undefined;
2
-
3
- export { getUsageFromReadme };
@@ -1,3 +0,0 @@
1
- declare function parseEmojiFromDescription(getDescription: () => Promise<string | undefined>): Promise<string>;
2
-
3
- export { parseEmojiFromDescription };
@@ -1,8 +0,0 @@
1
- import { PartialPackageData } from '../types.js';
2
-
3
- declare function parsePackageAuthor(packageData: PartialPackageData): {
4
- author: string | undefined;
5
- email: string | undefined;
6
- };
7
-
8
- export { parsePackageAuthor };
@@ -1,13 +0,0 @@
1
- declare function readDefaultsFromReadme(emoji: () => Promise<string>, readme: () => Promise<string>, repository: () => Promise<string | undefined>): {
2
- explainer: () => Promise<string[] | undefined>;
3
- logo: () => Promise<{
4
- height?: number;
5
- width?: number;
6
- alt: string;
7
- src: string;
8
- } | undefined>;
9
- title: () => Promise<string | undefined>;
10
- usage: () => Promise<string>;
11
- };
12
-
13
- export { readDefaultsFromReadme };
@@ -1,57 +0,0 @@
1
- import lazyValue from "lazy-value";
2
- import { titleCase } from "title-case";
3
- import { getUsageFromReadme } from "./getUsageFromReadme.js";
4
- import { readLogoSizing } from "./readLogoSizing.js";
5
- function readDefaultsFromReadme(emoji, readme, repository) {
6
- const imageTag = lazyValue(
7
- async () => /\n<img.+src=.+>/.exec(await readme())?.[0]
8
- );
9
- return {
10
- explainer: async () => {
11
- const readmeText = await readme();
12
- const indexOfH2 = readmeText.indexOf("##");
13
- if (indexOfH2 === -1) {
14
- return void 0;
15
- }
16
- const lastTag = readmeText.slice(0, indexOfH2).lastIndexOf(">");
17
- return readmeText.slice(lastTag + 1, indexOfH2).split("\n").map((line) => line.trim()).filter(Boolean);
18
- },
19
- logo: async () => {
20
- const tag = await imageTag();
21
- if (!tag) {
22
- return void 0;
23
- }
24
- const src = /src\s*=(.+)['"/]>/.exec(tag)?.[1]?.split(/\s*\w+=/)[0].replaceAll(/^['"]|['"]$/g, "");
25
- if (!src) {
26
- return void 0;
27
- }
28
- return {
29
- alt: /alt=['"](.+)['"]\s*src=/.exec(tag)?.[1].split(/['"]?\s*\w+=/)[0] ?? "Project logo",
30
- src,
31
- ...readLogoSizing(src)
32
- };
33
- },
34
- title: async () => {
35
- const text = await readme();
36
- const fromText = (/^<h1\s+align="center">(.+)<\/h1>/.exec(text) ?? /^# (.+)/.exec(text))?.[1];
37
- if (fromText) {
38
- return fromText;
39
- }
40
- const repositoryValue = await repository();
41
- return repositoryValue && titleCase(repositoryValue).replaceAll("Eslint", "ESLint").replaceAll("Typescript", "TypeScript").replaceAll("-", " ");
42
- },
43
- usage: async () => {
44
- return getUsageFromReadme(await readme()) ?? `\`\`\`shell
45
- npm i ${await repository()}
46
- \`\`\`
47
- \`\`\`ts
48
- import { greet } from "${await repository()}";
49
-
50
- greet("Hello, world! ${await emoji()}");
51
- \`\`\``;
52
- }
53
- };
54
- }
55
- export {
56
- readDefaultsFromReadme
57
- };
@@ -1,3 +0,0 @@
1
- declare function readGitHubEmail(): Promise<string | undefined>;
2
-
3
- export { readGitHubEmail };
@@ -1,11 +0,0 @@
1
- import { readFileSafe } from "./readFileSafe.js";
2
- async function readGitHubEmail() {
3
- const codeOfConduct = await readFileSafe(".github/CODE_OF_CONDUCT.md", "");
4
- if (!codeOfConduct.includes("Contributor Covenant Code of Conduct")) {
5
- return void 0;
6
- }
7
- return /for enforcement at[\r\n]+(.+)\.[\r\n]+All/.exec(codeOfConduct)?.[1];
8
- }
9
- export {
10
- readGitHubEmail
11
- };
@@ -1,3 +0,0 @@
1
- declare function tryCatchAsync<T>(get: () => Promise<T>): Promise<T | undefined>;
2
-
3
- export { tryCatchAsync };
@@ -1,10 +0,0 @@
1
- async function tryCatchAsync(get) {
2
- try {
3
- return await get();
4
- } catch {
5
- return void 0;
6
- }
7
- }
8
- export {
9
- tryCatchAsync
10
- };
@@ -1,3 +0,0 @@
1
- declare function tryCatchLazyValueAsync<T>(get: () => Promise<T>): () => Promise<T | undefined>;
2
-
3
- export { tryCatchLazyValueAsync };
@@ -1,8 +0,0 @@
1
- import lazyValue from "lazy-value";
2
- import { tryCatchAsync } from "./tryCatchAsync.js";
3
- function tryCatchLazyValueAsync(get) {
4
- return lazyValue(async () => await tryCatchAsync(get));
5
- }
6
- export {
7
- tryCatchLazyValueAsync
8
- };