Skip to content

Commit 7b199aa

Browse files
committed
feat: safe MD output
1 parent 7117af6 commit 7b199aa

6 files changed

Lines changed: 203 additions & 30 deletions

File tree

packages/github-action/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
"execa": "^9.6.0",
4141
"hast-util-to-html": "^9.0.5",
4242
"hastscript": "^9.0.1",
43-
"p-map": "^7.0.3"
43+
"mdast-util-to-markdown": "^2.1.2",
44+
"p-map": "^7.0.3",
45+
"unist-builder": "^4.0.0"
4446
},
4547
"devDependencies": {
4648
"@todone/internal-build": "workspace:*",

packages/github-action/src/lib/create-issues.ts

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import * as core from "@actions/core";
22
import * as github from "@actions/github";
33
import dedent from "dedent";
4+
import { toHtml } from "hast-util-to-html";
5+
import { h } from "hastscript";
6+
import { toMarkdown } from "mdast-util-to-markdown";
47
import pMap from "p-map";
8+
import { u } from "unist-builder";
59
import { reconcile } from "./reconciler";
6-
import { ExpiredResult, partition } from "./util";
10+
import { ExpiredResult, formatDate, partition } from "./util";
711

812
const TODONE_LABEL = "todone";
913

@@ -12,31 +16,88 @@ export const generateIssue = async ({
1216
}: ExpiredResult) => {
1317
const urlString = url.toString();
1418
const title = `TODO: ${result.title ?? urlString}`;
15-
const body = dedent`
16-
The following TODO has expired${result.expirationDate ? ` as of ${result.expirationDate.toDateString()}` : ""}:
1719

18-
~~~
19-
${[result.title, urlString].filter(Boolean).join("\n")}
20-
~~~
21-
22-
It is present in the following files:
23-
24-
${(
25-
await pMap(
26-
matches,
27-
async (match) =>
28-
`- ${(await match.file.getUrl(match.position.line)) || `${match.file.location}:${match.position.line}:${match.position.column}`}`,
29-
{ concurrency: 1 },
30-
)
31-
).join("\n")}
32-
33-
---
34-
35-
This issue has been automatically created by ${"`todone`"}.
36-
37-
<!-- Please do not edit this comment, it is automatically generated by todone. -->
38-
<!-- todone ${urlString} -->
39-
`;
20+
const body = toMarkdown(
21+
u("root", [
22+
u("paragraph", [
23+
u("text", "The following TODO has expired"),
24+
...(result.expirationDate
25+
? [
26+
u("text", ` as of `),
27+
u(
28+
"html",
29+
toHtml(
30+
h(
31+
"time",
32+
{ datetime: result.expirationDate.toISOString() },
33+
formatDate(result.expirationDate),
34+
),
35+
),
36+
),
37+
]
38+
: []),
39+
u("text", ":"),
40+
]),
41+
42+
u("list", [
43+
u("listItem", [
44+
u("paragraph", [
45+
...(result.title
46+
? [
47+
u("link", { url: urlString }, [u("text", result.title)]),
48+
u("break"),
49+
]
50+
: []),
51+
u("link", { url: urlString }, [u("text", urlString)]),
52+
]),
53+
]),
54+
]),
55+
56+
u("paragraph", [u("text", "It is present in the following files:")]),
57+
58+
u(
59+
"list",
60+
await pMap(
61+
matches,
62+
async (match) => {
63+
const fileUrl = await match.file.getUrl(match.position.line);
64+
65+
return u("listItem", [
66+
u("paragraph", [
67+
fileUrl
68+
? u("link", { url: fileUrl }, [u("text", fileUrl)])
69+
: u(
70+
"text",
71+
`${match.file.location}:${match.position.line}:${match.position.column}`,
72+
),
73+
]),
74+
]);
75+
},
76+
{ concurrency: 1 },
77+
),
78+
),
79+
80+
u("thematicBreak", []),
81+
82+
u("paragraph", [
83+
u("text", "This issue has been automatically created by "),
84+
u("inlineCode", { value: "todone" }),
85+
u("text", "."),
86+
]),
87+
88+
u(
89+
"html",
90+
toHtml([
91+
u(
92+
"comment",
93+
"Please do not edit this comment, it is automatically generated by todone.",
94+
),
95+
u("text", "\n"),
96+
u("comment", `todone ${urlString}`),
97+
]),
98+
),
99+
]),
100+
);
40101

41102
return { id: urlString, title, body };
42103
};

packages/github-action/src/lib/logger.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as core from "@actions/core";
22
import { AnalysisItem } from "@todone/core";
33
import { GitHubFile } from "./files";
4+
import { formatDate } from "./util";
45

56
export const makeDebugLogger = () => (item: AnalysisItem<GitHubFile>) =>
67
core.debug("Found: " + JSON.stringify(item, null, 2));
@@ -17,7 +18,9 @@ export const makeResultLogger =
1718
? [
1819
result.title || "No title",
1920
result.isExpired ? "Expired" : "Not expired",
20-
result.expirationDate?.toDateString() || "No expiration date",
21+
result.expirationDate
22+
? formatDate(result.expirationDate)
23+
: "No expiration date",
2124
]
2225
: ["No plugin responded"];
2326

packages/github-action/src/lib/summary.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as core from "@actions/core";
22
import { toHtml } from "hast-util-to-html";
33
import { h } from "hastscript";
44
import pMap from "p-map";
5-
import { Result } from "./util";
5+
import { formatDate, Result } from "./util";
66

77
type Row = [file: string, url: string, expired: string, expirationDate: string];
88

@@ -33,7 +33,9 @@ export const makeSummary = async (items: Result[]) => {
3333
toHtml(h("a", { href: resultUrl }, resultUrl)),
3434
result ? (result.isExpired ? "❗" : "⌛") : "",
3535
result
36-
? result.expirationDate?.toDateString() || "No expiration date"
36+
? result.expirationDate
37+
? formatDate(result.expirationDate)
38+
: "No expiration date"
3739
: "",
3840
] as const;
3941
},

packages/github-action/src/lib/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ export const isExpiredResult = (
3131
item: AnalysisItem<GitHubFile>,
3232
): item is ExpiredResult =>
3333
Boolean(isResult(item) && item.result.result?.isExpired);
34+
35+
export const formatDate = (date: Date) =>
36+
date.toISOString().replace(/T.*$/, "");

yarn.lock

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,10 +1026,12 @@ __metadata:
10261026
execa: "npm:^9.6.0"
10271027
hast-util-to-html: "npm:^9.0.5"
10281028
hastscript: "npm:^9.0.1"
1029+
mdast-util-to-markdown: "npm:^2.1.2"
10291030
p-map: "npm:^7.0.3"
10301031
tsdown: "npm:^0.13.3"
10311032
type-fest: "npm:^4.41.0"
10321033
typescript: "npm:~5.9.2"
1034+
unist-builder: "npm:^4.0.0"
10331035
languageName: unknown
10341036
linkType: soft
10351037

@@ -1545,6 +1547,13 @@ __metadata:
15451547
languageName: node
15461548
linkType: hard
15471549

1550+
"character-entities@npm:^2.0.0":
1551+
version: 2.0.2
1552+
resolution: "character-entities@npm:2.0.2"
1553+
checksum: 10/c8dd1f4bf1a92fccf7d2fad9673660a88b37854557d30f6076c32fedfb92d1420208298829ff1d3b6b4fa1c7012e8326c45e7f5c3ed1e9a09ec177593c521b2f
1554+
languageName: node
1555+
linkType: hard
1556+
15481557
"chokidar@npm:^4.0.3":
15491558
version: 4.0.3
15501559
resolution: "chokidar@npm:4.0.3"
@@ -1708,6 +1717,15 @@ __metadata:
17081717
languageName: node
17091718
linkType: hard
17101719

1720+
"decode-named-character-reference@npm:^1.0.0":
1721+
version: 1.2.0
1722+
resolution: "decode-named-character-reference@npm:1.2.0"
1723+
dependencies:
1724+
character-entities: "npm:^2.0.0"
1725+
checksum: 10/f26b23046c1a137c0b41fa51e3ce07ba8364640322c742a31570999784abc8572fc24cb108a76b14ff72ddb75d35aad3d14b10d7743639112145a2664b9d1864
1726+
languageName: node
1727+
linkType: hard
1728+
17111729
"dedent@npm:^1.6.0":
17121730
version: 1.6.0
17131731
resolution: "dedent@npm:1.6.0"
@@ -2583,6 +2601,13 @@ __metadata:
25832601
languageName: node
25842602
linkType: hard
25852603

2604+
"longest-streak@npm:^3.0.0":
2605+
version: 3.1.0
2606+
resolution: "longest-streak@npm:3.1.0"
2607+
checksum: 10/d7f952ed004cbdb5c8bcfc4f7f5c3d65449e6c5a9e9be4505a656e3df5a57ee125f284286b4bf8ecea0c21a7b3bf2b8f9001ad506c319b9815ad6a63a47d0fd0
2608+
languageName: node
2609+
linkType: hard
2610+
25862611
"lunr@npm:^2.3.9":
25872612
version: 2.3.9
25882613
resolution: "lunr@npm:2.3.9"
@@ -2613,6 +2638,16 @@ __metadata:
26132638
languageName: node
26142639
linkType: hard
26152640

2641+
"mdast-util-phrasing@npm:^4.0.0":
2642+
version: 4.1.0
2643+
resolution: "mdast-util-phrasing@npm:4.1.0"
2644+
dependencies:
2645+
"@types/mdast": "npm:^4.0.0"
2646+
unist-util-is: "npm:^6.0.0"
2647+
checksum: 10/3a97533e8ad104a422f8bebb34b3dde4f17167b8ed3a721cf9263c7416bd3447d2364e6d012a594aada40cac9e949db28a060bb71a982231693609034ed5324e
2648+
languageName: node
2649+
linkType: hard
2650+
26162651
"mdast-util-to-hast@npm:^13.0.0":
26172652
version: 13.2.0
26182653
resolution: "mdast-util-to-hast@npm:13.2.0"
@@ -2630,6 +2665,32 @@ __metadata:
26302665
languageName: node
26312666
linkType: hard
26322667

2668+
"mdast-util-to-markdown@npm:^2.1.2":
2669+
version: 2.1.2
2670+
resolution: "mdast-util-to-markdown@npm:2.1.2"
2671+
dependencies:
2672+
"@types/mdast": "npm:^4.0.0"
2673+
"@types/unist": "npm:^3.0.0"
2674+
longest-streak: "npm:^3.0.0"
2675+
mdast-util-phrasing: "npm:^4.0.0"
2676+
mdast-util-to-string: "npm:^4.0.0"
2677+
micromark-util-classify-character: "npm:^2.0.0"
2678+
micromark-util-decode-string: "npm:^2.0.0"
2679+
unist-util-visit: "npm:^5.0.0"
2680+
zwitch: "npm:^2.0.0"
2681+
checksum: 10/ab494a32f1ec90f0a502970b403b1847a10f3ba635adddb66ce70994cc47b4924c6c05078ddd29a8c2c5c9bc8c0bcc20e5fc1ef0fcb9b0cb9c0589a000817f1c
2682+
languageName: node
2683+
linkType: hard
2684+
2685+
"mdast-util-to-string@npm:^4.0.0":
2686+
version: 4.0.0
2687+
resolution: "mdast-util-to-string@npm:4.0.0"
2688+
dependencies:
2689+
"@types/mdast": "npm:^4.0.0"
2690+
checksum: 10/f4a5dbb9ea03521d7d3e26a9ba5652a1d6fbd55706dddd2155427517085688830e0ecd3f12418cfd40892640886eb39a4034c3c967d85e01e2fa64cfb53cff05
2691+
languageName: node
2692+
linkType: hard
2693+
26332694
"mdurl@npm:^2.0.0":
26342695
version: 2.0.0
26352696
resolution: "mdurl@npm:2.0.0"
@@ -2654,6 +2715,38 @@ __metadata:
26542715
languageName: node
26552716
linkType: hard
26562717

2718+
"micromark-util-classify-character@npm:^2.0.0":
2719+
version: 2.0.1
2720+
resolution: "micromark-util-classify-character@npm:2.0.1"
2721+
dependencies:
2722+
micromark-util-character: "npm:^2.0.0"
2723+
micromark-util-symbol: "npm:^2.0.0"
2724+
micromark-util-types: "npm:^2.0.0"
2725+
checksum: 10/4d8bbe3a6dbf69ac0fc43516866b5bab019fe3f4568edc525d4feaaaf78423fa54e6b6732b5bccbeed924455279a3758ffc9556954aafb903982598a95a02704
2726+
languageName: node
2727+
linkType: hard
2728+
2729+
"micromark-util-decode-numeric-character-reference@npm:^2.0.0":
2730+
version: 2.0.2
2731+
resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2"
2732+
dependencies:
2733+
micromark-util-symbol: "npm:^2.0.0"
2734+
checksum: 10/ee11c8bde51e250e302050474c4a2adca094bca05c69f6cdd241af12df285c48c88d19ee6e022b9728281c280be16328904adca994605680c43af56019f4b0b6
2735+
languageName: node
2736+
linkType: hard
2737+
2738+
"micromark-util-decode-string@npm:^2.0.0":
2739+
version: 2.0.1
2740+
resolution: "micromark-util-decode-string@npm:2.0.1"
2741+
dependencies:
2742+
decode-named-character-reference: "npm:^1.0.0"
2743+
micromark-util-character: "npm:^2.0.0"
2744+
micromark-util-decode-numeric-character-reference: "npm:^2.0.0"
2745+
micromark-util-symbol: "npm:^2.0.0"
2746+
checksum: 10/2f517e4c613609445db4b9a17f8c77832f55fb341620a8fd598f083c1227027485d601c2021c2f8f9883210b8671e7b3990f0c6feeecd49a136475465808c380
2747+
languageName: node
2748+
linkType: hard
2749+
26572750
"micromark-util-encode@npm:^2.0.0":
26582751
version: 2.0.1
26592752
resolution: "micromark-util-encode@npm:2.0.1"
@@ -3783,6 +3876,15 @@ __metadata:
37833876
languageName: node
37843877
linkType: hard
37853878

3879+
"unist-builder@npm:^4.0.0":
3880+
version: 4.0.0
3881+
resolution: "unist-builder@npm:4.0.0"
3882+
dependencies:
3883+
"@types/unist": "npm:^3.0.0"
3884+
checksum: 10/4657177eb71eaa45f53e8a8c8b453f60be8e3b1e6b736a2bb1272cc9ccafb98018e43bb4e853a9f35c5030d4e6f7d27d392af2c82d57d9f91e02a760c857d61f
3885+
languageName: node
3886+
linkType: hard
3887+
37863888
"unist-util-is@npm:^6.0.0":
37873889
version: 6.0.0
37883890
resolution: "unist-util-is@npm:6.0.0"
@@ -4001,7 +4103,7 @@ __metadata:
40014103
languageName: node
40024104
linkType: hard
40034105

4004-
"zwitch@npm:^2.0.4":
4106+
"zwitch@npm:^2.0.0, zwitch@npm:^2.0.4":
40054107
version: 2.0.4
40064108
resolution: "zwitch@npm:2.0.4"
40074109
checksum: 10/f22ec5fc2d5f02c423c93d35cdfa83573a3a3bd98c66b927c368ea4d0e7252a500df2a90a6b45522be536a96a73404393c958e945fdba95e6832c200791702b6

0 commit comments

Comments
 (0)