-
-
Notifications
You must be signed in to change notification settings - Fork 80
/
Copy pathblockREADME.ts
118 lines (97 loc) · 2.72 KB
/
blockREADME.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { z } from "zod";
import { base } from "../base.js";
function printAttributes(attributes: Record<string, number | string>) {
return Object.entries(attributes)
.map(([key, value]) => `${key}="${value}"`)
.sort()
.join(" ");
}
const zBadge = z.object({
alt: z.string(),
comments: z
.object({
after: z.string(),
before: z.string(),
})
.optional(),
href: z.string().optional(),
src: z.string(),
});
type Badge = z.infer<typeof zBadge>;
export const blockREADME = base.createBlock({
about: {
name: "README.md",
},
addons: {
badges: z.array(zBadge).default([]),
notices: z.array(z.string()).default([]),
sections: z.array(z.string()).default([]),
},
produce({ addons, options }) {
const { badges, notices, sections } = addons;
const explainer =
options.documentation.readme.explainer &&
`\n${options.documentation.readme.explainer}\n`;
const logo =
options.logo &&
`\n<img ${printAttributes({ align: "right", ...options.logo })}>\n`;
const suffixes = [
...notices,
options.documentation.readme.footnotes,
].filter((suffix) => typeof suffix === "string");
return {
files: {
"README.md": `<h1 align="center">${options.title}</h1>
<p align="center">${formatDescription(options.description)}</p>
<p align="center">
${formatBadges(badges)}
</p>
${[logo, explainer].filter(Boolean).join("")}
## Usage
${options.documentation.readme.usage}
## Development
See [\`.github/CONTRIBUTING.md\`](./.github/CONTRIBUTING.md), then [\`.github/DEVELOPMENT.md\`](./.github/DEVELOPMENT.md).
Thanks! ${options.emoji}
${[...sections, options.documentation.readme.additional]
.filter(Boolean)
.map((section) => `\n${section}`)
.join("")}
${suffixes.length ? `\n${suffixes.map((suffix) => suffix.trim()).join("\n\n")}` : ""}`,
},
};
},
});
function badgeSorter(a: Badge, b: Badge) {
return removeEmojis(a.alt).localeCompare(removeEmojis(b.alt));
}
function formatBadge(badge: Badge) {
const image = `<img alt="${badge.alt}" src="${badge.src}" />`;
const tagged = badge.href
? `<a href="${badge.href}" target="_blank">${image}</a>`
: image;
const commented = badge.comments
? `${badge.comments.before}${tagged}${badge.comments.after}`
: tagged;
return `\t${commented}`;
}
function formatBadges(badges: Badge[]) {
return [
...badges,
{
alt: "💪 TypeScript: Strict",
src: "https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg",
},
]
.sort(badgeSorter)
.map(formatBadge)
.join("\n");
}
function formatDescription(description: string) {
if (!description.includes(". ")) {
return description;
}
return "\n\t" + description.replaceAll(". ", ".\n\t") + "\n";
}
function removeEmojis(text: string) {
return text.replaceAll(/\p{Emoji}/gu, "").trim();
}