@coldtea/pr-lens-cli 0.9.0 → 0.10.0
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.
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +25 -6
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/comment.d.ts +1 -1
- package/dist/commands/comment.d.ts.map +1 -1
- package/dist/commands/comment.js +16 -2
- package/dist/commands/comment.js.map +1 -1
- package/dist/commands/render.d.ts +1 -1
- package/dist/commands/render.d.ts.map +1 -1
- package/dist/commands/render.js +9 -4
- package/dist/commands/render.js.map +1 -1
- package/dist/comment.d.ts +4 -0
- package/dist/comment.d.ts.map +1 -1
- package/dist/comment.js +193 -33
- package/dist/comment.js.map +1 -1
- package/dist/config-file.d.ts +7 -2
- package/dist/config-file.d.ts.map +1 -1
- package/dist/config-file.js +14 -2
- package/dist/config-file.js.map +1 -1
- package/dist/git.d.ts +17 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +37 -2
- package/dist/git.js.map +1 -1
- package/dist/skill-content.generated.d.ts +1 -1
- package/dist/skill-content.generated.d.ts.map +1 -1
- package/dist/skill-content.generated.js +1 -1
- package/dist/skill-content.generated.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +3 -3
- package/src/commands/analyze.ts +30 -6
- package/src/commands/comment.ts +18 -2
- package/src/commands/render.ts +18 -5
- package/src/comment.ts +249 -34
- package/src/config-file.ts +14 -2
- package/src/git.ts +38 -3
- package/src/skill-content.generated.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,eAAO,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,eAAO,MAAM,KAAK,QAwB+D,CAAC;AA8BlF,eAAO,MAAM,cAAc,SACnB,SAAS,MAAM,EAAE,YACb,QAAQ,OACb,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACtC,OAAO,CAAC,IAAI,CAuJd,CAAC"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { LENSES } from "@coldtea/pr-lens-schema";
|
|
1
|
+
import { LENSES, PROVIDERS } from "@coldtea/pr-lens-schema";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { parseOptions, readBoolean, readInt, readList, readString } from "../args.js";
|
|
4
4
|
import { discoverConfig, loadConfig } from "../config-file.js";
|
|
5
5
|
import { PrLensCliError, usageError } from "../errors.js";
|
|
6
6
|
import { extractGraph } from "../extract.js";
|
|
7
|
-
import { collectDiff, mergeBase, parseRepoSlug, remoteSlug, repositoryRoot, resolveCommit } from "../git.js";
|
|
7
|
+
import { collectDiff, mergeBase, parseRepoSlug, pullRequestUrl, remoteSlug, repositoryRoot, resolveCommit } from "../git.js";
|
|
8
8
|
import { writeJsonFile } from "../io.js";
|
|
9
9
|
import { buildExtractionPrompt, SYSTEM_PROMPT } from "../prompt.js";
|
|
10
10
|
import { completeJson, isProviderId, PROVIDER_IDS, resolveProvider } from "../providers/index.js";
|
|
@@ -33,6 +33,8 @@ environment, and the diff goes straight to the provider you name.
|
|
|
33
33
|
--pr <number> pull request number, recorded in provenance
|
|
34
34
|
--repo-slug <owner/name> override the slug read from the git remote
|
|
35
35
|
--remote <name> remote to read the slug from (default origin)
|
|
36
|
+
--forge <name> github | gitlab | bitbucket — where the repository is
|
|
37
|
+
hosted (default read from the remote host)
|
|
36
38
|
--max-diff-bytes <n> truncate the diff sent to the model (default ${DEFAULT_MAX_DIFF_BYTES})
|
|
37
39
|
--max-output-tokens <n> room for the answer (default ${DEFAULT_MAX_OUTPUT_TOKENS})
|
|
38
40
|
--dry-run report what would be sent, and send nothing
|
|
@@ -46,6 +48,15 @@ const readLenses = (values) => {
|
|
|
46
48
|
throw usageError(`unknown lens ${unknown.join(", ")}`, `known lenses: ${LENSES.join(", ")}`);
|
|
47
49
|
return LENSES.filter((lens) => requested.includes(lens));
|
|
48
50
|
};
|
|
51
|
+
const readForge = (values) => {
|
|
52
|
+
const forge = readString(values.forge, "forge");
|
|
53
|
+
if (forge === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
const known = PROVIDERS.find((provider) => provider === forge);
|
|
56
|
+
if (known === undefined)
|
|
57
|
+
throw usageError(`unknown forge ${JSON.stringify(forge)}`, `known forges: ${PROVIDERS.join(", ")}`);
|
|
58
|
+
return known;
|
|
59
|
+
};
|
|
49
60
|
const readProviderId = (values) => {
|
|
50
61
|
const id = readString(values.provider, "provider") ?? "gemini";
|
|
51
62
|
if (!isProviderId(id))
|
|
@@ -67,6 +78,7 @@ export const analyzeCommand = async (args, terminal, env) => {
|
|
|
67
78
|
pr: { type: "string" },
|
|
68
79
|
"repo-slug": { type: "string" },
|
|
69
80
|
remote: { type: "string" },
|
|
81
|
+
forge: { type: "string" },
|
|
70
82
|
"max-diff-bytes": { type: "string" },
|
|
71
83
|
"max-output-tokens": { type: "string" },
|
|
72
84
|
"dry-run": { type: "boolean" },
|
|
@@ -81,11 +93,18 @@ export const analyzeCommand = async (args, terminal, env) => {
|
|
|
81
93
|
const head = readString(values.head, "head") ?? "HEAD";
|
|
82
94
|
const maxDiffBytes = readInt(values["max-diff-bytes"], "max-diff-bytes", DEFAULT_MAX_DIFF_BYTES);
|
|
83
95
|
const slugOption = readString(values["repo-slug"], "repo-slug");
|
|
84
|
-
const
|
|
96
|
+
const detected = slugOption === undefined
|
|
85
97
|
? await remoteSlug(repo, readString(values.remote, "remote") ?? "origin")
|
|
86
98
|
: parseRepoSlug(slugOption);
|
|
87
|
-
if (
|
|
99
|
+
if (detected === undefined)
|
|
88
100
|
throw new PrLensCliError("REPOSITORY_UNKNOWN", "cannot tell which repository this is", "pass --repo-slug owner/name, or add a git remote the CLI can read");
|
|
101
|
+
const forge = readForge(values);
|
|
102
|
+
// An owner/name slug carries no host, and parseRepoSlug fills in
|
|
103
|
+
// github.com — which a non-GitHub forge would then dress in the wrong
|
|
104
|
+
// URLs. Refusing beats a permalink that 404s in the reader's face.
|
|
105
|
+
if (forge !== undefined && forge !== "github" && slugOption !== undefined)
|
|
106
|
+
throw usageError(`--forge ${forge} cannot be combined with --repo-slug`, "an owner/name slug names no host; let the CLI read the git remote, which carries one");
|
|
107
|
+
const slug = forge === undefined ? detected : { ...detected, provider: forge };
|
|
89
108
|
const configPath = readString(values.config, "config");
|
|
90
109
|
const configured = readBoolean(values["no-config"])
|
|
91
110
|
? undefined
|
|
@@ -125,9 +144,9 @@ export const analyzeCommand = async (args, terminal, env) => {
|
|
|
125
144
|
const pr = values.pr === undefined ? undefined : readInt(values.pr, "pr", 0);
|
|
126
145
|
const pullRequest = pr === undefined
|
|
127
146
|
? undefined
|
|
128
|
-
: { number: pr, url:
|
|
147
|
+
: { number: pr, url: pullRequestUrl(slug, pr) };
|
|
129
148
|
const provenance = {
|
|
130
|
-
repo: slug,
|
|
149
|
+
repo: { owner: slug.owner, name: slug.name, host: slug.host },
|
|
131
150
|
base: { sha: comparedAgainst, ref: baseCommit.ref },
|
|
132
151
|
head: { sha: headCommit.sha, ref: headCommit.ref },
|
|
133
152
|
...(pullRequest === undefined ? {} : { pullRequest }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Terminal } from "../terminal.js";
|
|
2
|
-
export declare const USAGE = "pr-lens comment --graph <graph.json> --manifest <manifest.json> [options]\n\nComposes the pull request comment: the diagrams as light/dark <picture> pairs,\nthe headline numbers, and the drill-down tree. It posts nothing \u2014 the markdown\ngoes to stdout, or to a file, for whatever does the posting.\n\n --graph <file> the document that was rendered \u2014 the one the render\n wrote beside the manifest, not the one it read\n --manifest <file> what the render produced (required)\n --asset-base-url <url> where the rendered SVGs are published, when the\n manifest records local paths\n --config <file> read 'branding' from a repository config\n --no-branding leave off the PR Lens footer\n --print-marker print the hidden marker that identifies the\n comment, and nothing else\n -o, --out <file> write the markdown here instead of stdout";
|
|
2
|
+
export declare const USAGE = "pr-lens comment --graph <graph.json> --manifest <manifest.json> [options]\n\nComposes the pull request comment: the diagrams as light/dark <picture> pairs,\nthe headline numbers, and the drill-down tree. It posts nothing \u2014 the markdown\ngoes to stdout, or to a file, for whatever does the posting.\n\n --graph <file> the document that was rendered \u2014 the one the render\n wrote beside the manifest, not the one it read\n --manifest <file> what the render produced (required)\n --asset-base-url <url> where the rendered SVGs are published, when the\n manifest records local paths\n --config <file> read 'branding' from a repository config\n --no-branding leave off the PR Lens footer\n --target <forge> github | gitlab | bitbucket \u2014 who renders the\n comment (default github). GitLab gets no <picture>\n pair; Bitbucket gets plain markdown, no HTML\n --print-marker print the hidden marker that identifies the\n comment, and nothing else\n -o, --out <file> write the markdown here instead of stdout";
|
|
3
3
|
export declare const commentCommand: (args: readonly string[], terminal: Terminal) => Promise<void>;
|
|
4
4
|
//# sourceMappingURL=comment.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,eAAO,MAAM,KAAK,0uCAkBsD,CAAC;AAUzE,eAAO,MAAM,cAAc,SAAgB,SAAS,MAAM,EAAE,YAAY,QAAQ,KAAG,OAAO,CAAC,IAAI,CAsD9F,CAAC"}
|
package/dist/commands/comment.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { graphContentHash } from "@coldtea/pr-lens-renderer";
|
|
2
|
+
import { PROVIDERS } from "@coldtea/pr-lens-schema";
|
|
2
3
|
import { parseOptions, readBoolean, readString } from "../args.js";
|
|
3
|
-
import {
|
|
4
|
+
import { commentMarker, composeComment } from "../comment.js";
|
|
4
5
|
import { loadConfig } from "../config-file.js";
|
|
5
6
|
import { readGraphDoc, readRenderManifest } from "../document.js";
|
|
6
7
|
import { usageError } from "../errors.js";
|
|
@@ -18,9 +19,19 @@ goes to stdout, or to a file, for whatever does the posting.
|
|
|
18
19
|
manifest records local paths
|
|
19
20
|
--config <file> read 'branding' from a repository config
|
|
20
21
|
--no-branding leave off the PR Lens footer
|
|
22
|
+
--target <forge> github | gitlab | bitbucket — who renders the
|
|
23
|
+
comment (default github). GitLab gets no <picture>
|
|
24
|
+
pair; Bitbucket gets plain markdown, no HTML
|
|
21
25
|
--print-marker print the hidden marker that identifies the
|
|
22
26
|
comment, and nothing else
|
|
23
27
|
-o, --out <file> write the markdown here instead of stdout`;
|
|
28
|
+
const readTarget = (values) => {
|
|
29
|
+
const target = readString(values.target, "target") ?? "github";
|
|
30
|
+
const known = PROVIDERS.find((provider) => provider === target);
|
|
31
|
+
if (known === undefined)
|
|
32
|
+
throw usageError(`unknown target ${JSON.stringify(target)}`, `known targets: ${PROVIDERS.join(", ")}`);
|
|
33
|
+
return known;
|
|
34
|
+
};
|
|
24
35
|
export const commentCommand = async (args, terminal) => {
|
|
25
36
|
const { values, positionals } = parseOptions(args, {
|
|
26
37
|
graph: { type: "string" },
|
|
@@ -28,13 +39,15 @@ export const commentCommand = async (args, terminal) => {
|
|
|
28
39
|
"asset-base-url": { type: "string" },
|
|
29
40
|
config: { type: "string" },
|
|
30
41
|
"no-branding": { type: "boolean" },
|
|
42
|
+
target: { type: "string" },
|
|
31
43
|
"print-marker": { type: "boolean" },
|
|
32
44
|
out: { type: "string", short: "o" },
|
|
33
45
|
});
|
|
34
46
|
if (positionals.length > 0)
|
|
35
47
|
throw usageError(`comment takes no positional arguments, got ${positionals.join(" ")}`);
|
|
48
|
+
const target = readTarget(values);
|
|
36
49
|
if (readBoolean(values["print-marker"])) {
|
|
37
|
-
terminal.out(
|
|
50
|
+
terminal.out(commentMarker(target));
|
|
38
51
|
return;
|
|
39
52
|
}
|
|
40
53
|
const graphPath = readString(values.graph, "graph");
|
|
@@ -52,6 +65,7 @@ export const commentCommand = async (args, terminal) => {
|
|
|
52
65
|
manifest,
|
|
53
66
|
assetBaseUrl: readString(values["asset-base-url"], "asset-base-url"),
|
|
54
67
|
branding: readBoolean(values["no-branding"]) ? false : (configured?.config.branding ?? true),
|
|
68
|
+
target,
|
|
55
69
|
});
|
|
56
70
|
const out = readString(values.out, "out");
|
|
57
71
|
if (out === undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Terminal } from "../terminal.js";
|
|
2
|
-
export declare const USAGE = "pr-lens render <graph.json> [options]\n\nDraws the document as self-contained SVGs \u2014 one per drill-down section per\nlens, in light and dark \u2014 and writes the manifest describing them. A document\nwith no sections gets one diagram per lens it declares.\n\n -o, --out <dir> where the SVGs, the document and the manifest go\n (default .pr-lens/<title>/, one directory per drawing)\n --theme <theme> light | dark | both (default both)\n --config <file> corrections to draw with (default the repository's, if any)\n --no-config ignore the repository's corrections";
|
|
2
|
+
export declare const USAGE = "pr-lens render <graph.json> [options]\n\nDraws the document as self-contained SVGs \u2014 one per drill-down section per\nlens, in light and dark \u2014 and writes the manifest describing them. A document\nwith no sections gets one diagram per lens it declares.\n\n -o, --out <dir> where the SVGs, the document and the manifest go\n (default .pr-lens/<title>/, one directory per drawing)\n --theme <theme> light | dark | both | neutral (default both)\n neutral is the single self-contained render for a\n surface that shows one image: GitLab and Bitbucket\n --config <file> corrections to draw with (default the repository's, if any)\n --no-config ignore the repository's corrections";
|
|
3
3
|
export declare const renderCommand: (args: readonly string[], terminal: Terminal) => Promise<void>;
|
|
4
4
|
//# sourceMappingURL=render.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAoB/C,eAAO,MAAM,KAAK,8wBAYyC,CAAC;AAkC5D,eAAO,MAAM,aAAa,SAAgB,SAAS,MAAM,EAAE,YAAY,QAAQ,KAAG,OAAO,CAAC,IAAI,CA8D7F,CAAC"}
|
package/dist/commands/render.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyCorrections, PrLensRenderError, renderAll,
|
|
1
|
+
import { applyCorrections, PrLensRenderError, renderAll, THEME_PAIR, } from "@coldtea/pr-lens-renderer";
|
|
2
2
|
import { safeParseGraphDoc } from "@coldtea/pr-lens-schema";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { expectOne, parseOptions, readBoolean, readString } from "../args.js";
|
|
@@ -31,7 +31,9 @@ with no sections gets one diagram per lens it declares.
|
|
|
31
31
|
|
|
32
32
|
-o, --out <dir> where the SVGs, the document and the manifest go
|
|
33
33
|
(default ${WORKSPACE_DIR}/<title>/, one directory per drawing)
|
|
34
|
-
--theme <theme> light | dark | both (default both)
|
|
34
|
+
--theme <theme> light | dark | both | neutral (default both)
|
|
35
|
+
neutral is the single self-contained render for a
|
|
36
|
+
surface that shows one image: GitLab and Bitbucket
|
|
35
37
|
--config <file> corrections to draw with (default the repository's, if any)
|
|
36
38
|
--no-config ignore the repository's corrections`;
|
|
37
39
|
const readThemes = (value) => {
|
|
@@ -39,11 +41,14 @@ const readThemes = (value) => {
|
|
|
39
41
|
switch (theme) {
|
|
40
42
|
case "light":
|
|
41
43
|
case "dark":
|
|
44
|
+
// A surface that shows one image wants this one instead of the pair, not
|
|
45
|
+
// as well as it — so it is a choice of --theme, never an addition to both.
|
|
46
|
+
case "neutral":
|
|
42
47
|
return [theme];
|
|
43
48
|
case "both":
|
|
44
|
-
return
|
|
49
|
+
return THEME_PAIR;
|
|
45
50
|
default:
|
|
46
|
-
throw usageError(`--theme takes light, dark or
|
|
51
|
+
throw usageError(`--theme takes light, dark, both or neutral, got ${JSON.stringify(theme)}`);
|
|
47
52
|
}
|
|
48
53
|
};
|
|
49
54
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"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"}
|
package/dist/comment.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Provider } from "@coldtea/pr-lens-schema";
|
|
1
2
|
import type { GraphDoc, RenderManifest } from "@coldtea/pr-lens-schema";
|
|
2
3
|
/**
|
|
3
4
|
* How the comment is recognised on a second run, so a pull request keeps one
|
|
@@ -5,12 +6,15 @@ import type { GraphDoc, RenderManifest } from "@coldtea/pr-lens-schema";
|
|
|
5
6
|
* this string: a marker that drifts orphans every comment already posted.
|
|
6
7
|
*/
|
|
7
8
|
export declare const COMMENT_MARKER = "<!-- pr-lens -->";
|
|
9
|
+
export declare const commentMarker: (target: Provider) => string;
|
|
8
10
|
export type CommentOptions = {
|
|
9
11
|
graph: GraphDoc;
|
|
10
12
|
manifest: RenderManifest;
|
|
11
13
|
/** Prefix for assets the manifest records as local paths, e.g. a raw content URL. */
|
|
12
14
|
assetBaseUrl: string | undefined;
|
|
13
15
|
branding: boolean;
|
|
16
|
+
/** Which forge will render the comment. Defaults to GitHub, today's output. */
|
|
17
|
+
target?: Provider;
|
|
14
18
|
};
|
|
15
19
|
export declare const composeComment: (options: CommentOptions) => string;
|
|
16
20
|
//# sourceMappingURL=comment.d.ts.map
|
package/dist/comment.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../src/comment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../src/comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,QAAQ,EAAqB,cAAc,EAAQ,MAAM,yBAAyB,CAAC;AAGjG;;;;GAIG;AACH,eAAO,MAAM,cAAc,qBAAqB,CAAC;AASjD,eAAO,MAAM,aAAa,WAAY,QAAQ,KAAG,MAUhD,CAAC;AAKF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,qFAAqF;IACrF,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAwUF,eAAO,MAAM,cAAc,YAAa,cAAc,KAAG,MA6BxD,CAAC"}
|
package/dist/comment.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertNever } from "@coldtea/pr-lens-schema";
|
|
1
|
+
import { assertNever, surfaceFor, } from "@coldtea/pr-lens-schema";
|
|
2
2
|
import { PrLensCliError } from "./errors.js";
|
|
3
3
|
/**
|
|
4
4
|
* How the comment is recognised on a second run, so a pull request keeps one
|
|
@@ -6,6 +6,23 @@ import { PrLensCliError } from "./errors.js";
|
|
|
6
6
|
* this string: a marker that drifts orphans every comment already posted.
|
|
7
7
|
*/
|
|
8
8
|
export const COMMENT_MARKER = "<!-- pr-lens -->";
|
|
9
|
+
/**
|
|
10
|
+
* Bitbucket renders no HTML, and an HTML comment there risks appearing as
|
|
11
|
+
* text. A link-reference definition is the markdown-native invisible line:
|
|
12
|
+
* consumed by the renderer, still greppable in the source.
|
|
13
|
+
*/
|
|
14
|
+
const BITBUCKET_COMMENT_MARKER = "[pr-lens]: #pr-lens";
|
|
15
|
+
export const commentMarker = (target) => {
|
|
16
|
+
switch (target) {
|
|
17
|
+
case "github":
|
|
18
|
+
case "gitlab":
|
|
19
|
+
return COMMENT_MARKER;
|
|
20
|
+
case "bitbucket":
|
|
21
|
+
return BITBUCKET_COMMENT_MARKER;
|
|
22
|
+
default:
|
|
23
|
+
return assertNever(target, "Unhandled provider");
|
|
24
|
+
}
|
|
25
|
+
};
|
|
9
26
|
const PROJECT_URL = "https://github.com/coldteadotai/pr-lens";
|
|
10
27
|
const COLDTEA_URL = "https://coldtea.ai";
|
|
11
28
|
const escape = (value) => value
|
|
@@ -13,22 +30,62 @@ const escape = (value) => value
|
|
|
13
30
|
.replaceAll("<", "<")
|
|
14
31
|
.replaceAll(">", ">")
|
|
15
32
|
.replaceAll('"', """);
|
|
33
|
+
/**
|
|
34
|
+
* Which characters, at the start of a rendered word, a forge turns into a
|
|
35
|
+
* notification or a cross-link after markdown has run. GitHub reads @ and #;
|
|
36
|
+
* GitLab additionally reads ! (merge requests), ~ (labels), % (milestones),
|
|
37
|
+
* $ (snippets) and & (epics). The guard is a zero-width space after the
|
|
38
|
+
* sigil, so a diff's say-so never pages a person or links an issue.
|
|
39
|
+
*/
|
|
40
|
+
const sigilsFor = (dialect) => {
|
|
41
|
+
switch (dialect) {
|
|
42
|
+
case "gfm":
|
|
43
|
+
return /([@#])(?=[\w-])/g;
|
|
44
|
+
// The lookahead runs on the escaped string, so a quoted reference like
|
|
45
|
+
// ~"multi word" appears as ~"… — matched as the entity.
|
|
46
|
+
case "glfm":
|
|
47
|
+
return /([@#!~%$])(?=[\w-]|")/g;
|
|
48
|
+
default:
|
|
49
|
+
return assertNever(dialect, "Unhandled dialect");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
16
52
|
/**
|
|
17
53
|
* Model-authored prose, rendered as the words it is.
|
|
18
54
|
*
|
|
19
55
|
* Every string in the document was written by a model reading a diff, and a
|
|
20
56
|
* pull request can carry whatever text an author likes into that diff. So
|
|
21
|
-
* none of it may reach
|
|
22
|
-
* job, because markdown would still turn `[Security update](http://…)`
|
|
23
|
-
* link that looks like ours. Each string therefore lands inside an
|
|
24
|
-
* element — inside one, markdown is not parsed at all — on a single
|
|
25
|
-
* a blank line cannot end the block and let the rest through.
|
|
57
|
+
* none of it may reach the forge as markup: escaping the HTML is only half
|
|
58
|
+
* the job, because markdown would still turn `[Security update](http://…)`
|
|
59
|
+
* into a link that looks like ours. Each string therefore lands inside an
|
|
60
|
+
* HTML element — inside one, markdown is not parsed at all — on a single
|
|
61
|
+
* line, so a blank line cannot end the block and let the rest through.
|
|
26
62
|
*
|
|
27
|
-
* The zero-width space after
|
|
28
|
-
* after markdown, on the rendered text, and would otherwise notify a
|
|
29
|
-
* or cross-link an issue on the say-so of a diff.
|
|
63
|
+
* The zero-width space after a reference sigil is the last piece: those are
|
|
64
|
+
* matched after markdown, on the rendered text, and would otherwise notify a
|
|
65
|
+
* person or cross-link an issue on the say-so of a diff. GitLab's & becomes
|
|
66
|
+
* & during escaping, so its guard runs on the entity.
|
|
30
67
|
*/
|
|
31
|
-
const text = (value) =>
|
|
68
|
+
const text = (value, dialect) => {
|
|
69
|
+
const guarded = escape(value.replace(/\s+/g, " ").trim()).replace(sigilsFor(dialect), "$1​");
|
|
70
|
+
return dialect === "glfm" ? guarded.replace(/&(?=[\w-]|")/g, "&​") : guarded;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The same job for a forge that renders no HTML: there is no element to hide
|
|
74
|
+
* inside, so every character Python-Markdown can act on is backslash-escaped
|
|
75
|
+
* instead — its documented escapable set. What that set cannot cover is
|
|
76
|
+
* broken with a zero-width space instead: doubled tildes (strikethrough via
|
|
77
|
+
* the del extension), reference sigils, and an opening `<`, which is not
|
|
78
|
+
* escapable and would otherwise hand a raw tag to whatever HTML subset the
|
|
79
|
+
* forge's renderer lets through. An entity would risk rendering as text on
|
|
80
|
+
* a forge that escapes ampersands, so the space is the literal character.
|
|
81
|
+
*/
|
|
82
|
+
const proseMd = (value) => value
|
|
83
|
+
.replace(/\s+/g, " ")
|
|
84
|
+
.trim()
|
|
85
|
+
.replace(/[\\`*_{}[\]()>#+\-.!]/g, "\\$&")
|
|
86
|
+
.replace(/~~/g, "~\u200B~")
|
|
87
|
+
.replace(/<(?=[A-Za-z/!?])/g, "<\u200B")
|
|
88
|
+
.replace(/([@#])(?=[\w-])/g, "$1\u200B");
|
|
32
89
|
const href = (asset, assetBaseUrl) => {
|
|
33
90
|
if (asset.url !== undefined)
|
|
34
91
|
return asset.url;
|
|
@@ -36,31 +93,52 @@ const href = (asset, assetBaseUrl) => {
|
|
|
36
93
|
throw new PrLensCliError("USAGE", `asset '${asset.id}' is a local file, so the comment has nowhere to point`, "pass --asset-base-url with the location the rendered SVGs are published at");
|
|
37
94
|
return `${assetBaseUrl.replace(/\/+$/, "")}/${asset.path.replace(/^\/+/, "")}`;
|
|
38
95
|
};
|
|
96
|
+
/** A bare markdown destination: the characters that would end or nest it are percent-encoded. */
|
|
97
|
+
const hrefMd = (asset, assetBaseUrl) => href(asset, assetBaseUrl).replace(/[<>() ]/g, (found) => `%${found.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`);
|
|
98
|
+
const EMPTY_PAIR = { light: undefined, dark: undefined, neutral: undefined };
|
|
39
99
|
const pairsByLens = (assets) => {
|
|
40
100
|
const pairs = new Map();
|
|
41
101
|
for (const asset of assets) {
|
|
42
|
-
const pair = pairs.get(asset.lens) ??
|
|
102
|
+
const pair = pairs.get(asset.lens) ?? EMPTY_PAIR;
|
|
43
103
|
pairs.set(asset.lens, { ...pair, [asset.theme]: asset });
|
|
44
104
|
}
|
|
45
105
|
return pairs;
|
|
46
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* The one asset a single-image surface shows.
|
|
109
|
+
*
|
|
110
|
+
* `neutral` first, because it is the render made for exactly this and reads
|
|
111
|
+
* on a light page and a dark one alike. Falling back to a half of the pair is
|
|
112
|
+
* for a manifest rendered before neutral existed, or one rendered `--theme
|
|
113
|
+
* light` by hand: better a diagram tuned for the wrong ground than no
|
|
114
|
+
* diagram, but it is a fallback and not the intent.
|
|
115
|
+
*/
|
|
116
|
+
const single = (pair) => pair.neutral ?? pair.light ?? pair.dark;
|
|
47
117
|
/**
|
|
48
118
|
* A `<picture>` is what makes one comment readable in both GitHub themes: the
|
|
49
119
|
* dark source is swapped in by the browser, with the light asset as the `img`
|
|
50
120
|
* every other reader — email, mobile, an old client — falls back to.
|
|
51
121
|
*
|
|
122
|
+
* GitLab strips `picture` and `source`, so there one image stands alone
|
|
123
|
+
* rather than trusting a sanitizer to unwrap gracefully — and that image is
|
|
124
|
+
* the neutral render, which reads on either ground, instead of a half of the
|
|
125
|
+
* pair that reads well on one.
|
|
126
|
+
*
|
|
52
127
|
* The whole thing is a link to the image itself, because a comment column is
|
|
53
128
|
* about 830 pixels wide and a diagram of a system with several lanes is
|
|
54
129
|
* several times that. It arrives scaled to fit, which is right for scanning,
|
|
55
130
|
* and one click gives a reader the size the labels were drawn at.
|
|
56
131
|
*/
|
|
57
|
-
const picture = (pair, alt, assetBaseUrl) => {
|
|
58
|
-
|
|
59
|
-
|
|
132
|
+
const picture = (pair, alt, assetBaseUrl, surface) => {
|
|
133
|
+
// A paired surface shows the light half as the `img` every non-swapping
|
|
134
|
+
// client falls back to; a single-image surface shows the neutral render.
|
|
135
|
+
const paired = surface.themeStrategy === "pair" && pair.light !== undefined && pair.dark !== undefined;
|
|
136
|
+
const shownAsset = paired ? pair.light : single(pair);
|
|
137
|
+
if (shownAsset === undefined)
|
|
60
138
|
return "";
|
|
61
|
-
const source = escape(href(
|
|
62
|
-
const image = `<img alt="${text(alt)}" src="${source}" width="${
|
|
63
|
-
const shown =
|
|
139
|
+
const source = escape(href(shownAsset, assetBaseUrl));
|
|
140
|
+
const image = `<img alt="${text(alt, surface.dialect)}" src="${source}" width="${shownAsset.width}">`;
|
|
141
|
+
const shown = !paired || pair.dark === undefined
|
|
64
142
|
? image
|
|
65
143
|
: [
|
|
66
144
|
"<picture>",
|
|
@@ -80,11 +158,11 @@ const lensLabel = (lens) => {
|
|
|
80
158
|
return assertNever(lens, "Unhandled lens");
|
|
81
159
|
}
|
|
82
160
|
};
|
|
83
|
-
const
|
|
161
|
+
const statChips = (graph) => {
|
|
84
162
|
const { stats } = graph;
|
|
85
163
|
if (stats === undefined)
|
|
86
|
-
return
|
|
87
|
-
|
|
164
|
+
return [];
|
|
165
|
+
return [
|
|
88
166
|
stats.filesChanged === undefined
|
|
89
167
|
? undefined
|
|
90
168
|
: `${stats.filesChanged} ${stats.filesChanged === 1 ? "file" : "files"}`,
|
|
@@ -92,19 +170,24 @@ const statsLine = (graph) => {
|
|
|
92
170
|
stats.deletions === undefined ? undefined : `−${stats.deletions}`,
|
|
93
171
|
...stats.chips.map((chip) => `${chip.label} ${chip.value}`),
|
|
94
172
|
].filter((chip) => chip !== undefined);
|
|
95
|
-
return `<p>${chips.map((chip) => `<code>${text(chip)}</code>`).join(" · ")}</p>`;
|
|
96
173
|
};
|
|
97
|
-
const
|
|
174
|
+
const statsLine = (graph, surface) => {
|
|
175
|
+
const chips = statChips(graph);
|
|
176
|
+
if (chips.length === 0)
|
|
177
|
+
return "";
|
|
178
|
+
return `<p>${chips.map((chip) => `<code>${text(chip, surface.dialect)}</code>`).join(" · ")}</p>`;
|
|
179
|
+
};
|
|
180
|
+
const viewSection = (view, assets, assetBaseUrl, surface) => {
|
|
98
181
|
const own = assets.get(view.id) ?? [];
|
|
99
182
|
const pair = pairsByLens(own).get(view.lens);
|
|
100
183
|
const body = [
|
|
101
|
-
view.summary === undefined ? "" : `<p>${text(view.summary)}</p>`,
|
|
102
|
-
pair === undefined ? "" : picture(pair, view.title, assetBaseUrl),
|
|
103
|
-
...view.children.map((child) => viewSection(child, assets, assetBaseUrl)),
|
|
184
|
+
view.summary === undefined ? "" : `<p>${text(view.summary, surface.dialect)}</p>`,
|
|
185
|
+
pair === undefined ? "" : picture(pair, view.title, assetBaseUrl, surface),
|
|
186
|
+
...view.children.map((child) => viewSection(child, assets, assetBaseUrl, surface)),
|
|
104
187
|
].filter((part) => part !== "");
|
|
105
188
|
return [
|
|
106
189
|
`<details${view.defaultOpen ? " open" : ""}>`,
|
|
107
|
-
`<summary><b>${text(view.title)}</b></summary>`,
|
|
190
|
+
`<summary><b>${text(view.title, surface.dialect)}</b></summary>`,
|
|
108
191
|
"",
|
|
109
192
|
...body.flatMap((part) => [part, ""]),
|
|
110
193
|
"</details>",
|
|
@@ -120,24 +203,30 @@ const byView = (manifest) => {
|
|
|
120
203
|
}
|
|
121
204
|
return grouped;
|
|
122
205
|
};
|
|
123
|
-
|
|
206
|
+
const composeHtml = (options, surface, marker, keptViews) => {
|
|
124
207
|
const { graph, manifest, assetBaseUrl, branding } = options;
|
|
125
208
|
const assets = byView(manifest);
|
|
126
209
|
const roots = pairsByLens(assets.get(ROOT) ?? []);
|
|
127
210
|
const diagrams = graph.lenses.flatMap((lens) => {
|
|
128
211
|
const pair = roots.get(lens);
|
|
129
|
-
return pair === undefined
|
|
212
|
+
return pair === undefined
|
|
213
|
+
? []
|
|
214
|
+
: [picture(pair, `${graph.title} — ${lensLabel(lens)}`, assetBaseUrl, surface)];
|
|
130
215
|
});
|
|
216
|
+
const omitted = graph.views.length - keptViews;
|
|
131
217
|
const footer = branding
|
|
132
218
|
? `<sub>◈ Rendered by <a href="${PROJECT_URL}">PR Lens</a> · from the team behind <a href="${COLDTEA_URL}">Coldtea</a></sub>`
|
|
133
219
|
: "";
|
|
134
220
|
return [
|
|
135
|
-
|
|
136
|
-
`<h3>${text(graph.title)}</h3>`,
|
|
137
|
-
graph.summary === undefined ? "" : `<p>${text(graph.summary)}</p>`,
|
|
138
|
-
statsLine(graph),
|
|
221
|
+
marker,
|
|
222
|
+
`<h3>${text(graph.title, surface.dialect)}</h3>`,
|
|
223
|
+
graph.summary === undefined ? "" : `<p>${text(graph.summary, surface.dialect)}</p>`,
|
|
224
|
+
statsLine(graph, surface),
|
|
139
225
|
...diagrams,
|
|
140
|
-
...graph.views.map((view) => viewSection(view, assets, assetBaseUrl)),
|
|
226
|
+
...graph.views.slice(0, keptViews).map((view) => viewSection(view, assets, assetBaseUrl, surface)),
|
|
227
|
+
omitted === 0
|
|
228
|
+
? ""
|
|
229
|
+
: `<sub>${omitted} drill-down ${omitted === 1 ? "section" : "sections"} did not fit this comment.</sub>`,
|
|
141
230
|
footer === "" ? "" : "---",
|
|
142
231
|
footer,
|
|
143
232
|
]
|
|
@@ -145,4 +234,75 @@ export const composeComment = (options) => {
|
|
|
145
234
|
.join("\n\n")
|
|
146
235
|
.concat("\n");
|
|
147
236
|
};
|
|
237
|
+
const diagramMd = (pair, alt, assetBaseUrl) => {
|
|
238
|
+
// With no HTML there is no theme pairing at all, so the neutral render is
|
|
239
|
+
// the only one that serves a reader whichever theme they are in.
|
|
240
|
+
const shown = single(pair);
|
|
241
|
+
if (shown === undefined)
|
|
242
|
+
return "";
|
|
243
|
+
const source = hrefMd(shown, assetBaseUrl);
|
|
244
|
+
return `[](${source})`;
|
|
245
|
+
};
|
|
246
|
+
/** The drill-down tree flattened: with no collapsible to nest in, order carries the hierarchy. */
|
|
247
|
+
const viewSectionsMd = (views, assets, assetBaseUrl) => views.flatMap((view) => {
|
|
248
|
+
const pair = pairsByLens(assets.get(view.id) ?? []).get(view.lens);
|
|
249
|
+
return [
|
|
250
|
+
`**${proseMd(view.title)}**`,
|
|
251
|
+
...(view.summary === undefined ? [] : [proseMd(view.summary)]),
|
|
252
|
+
...(pair === undefined ? [] : [diagramMd(pair, view.title, assetBaseUrl)]),
|
|
253
|
+
...viewSectionsMd(view.children, assets, assetBaseUrl),
|
|
254
|
+
];
|
|
255
|
+
});
|
|
256
|
+
const composeMarkdown = (options, marker, keptViews) => {
|
|
257
|
+
const { graph, manifest, assetBaseUrl, branding } = options;
|
|
258
|
+
const assets = byView(manifest);
|
|
259
|
+
const roots = pairsByLens(assets.get(ROOT) ?? []);
|
|
260
|
+
const diagrams = graph.lenses.flatMap((lens) => {
|
|
261
|
+
const pair = roots.get(lens);
|
|
262
|
+
return pair === undefined ? [] : [diagramMd(pair, `${graph.title} — ${lensLabel(lens)}`, assetBaseUrl)];
|
|
263
|
+
});
|
|
264
|
+
const chips = statChips(graph);
|
|
265
|
+
const omitted = graph.views.length - keptViews;
|
|
266
|
+
return [
|
|
267
|
+
marker,
|
|
268
|
+
`### ${proseMd(graph.title)}`,
|
|
269
|
+
graph.summary === undefined ? "" : proseMd(graph.summary),
|
|
270
|
+
chips.length === 0 ? "" : chips.map((chip) => proseMd(chip)).join(" · "),
|
|
271
|
+
...diagrams,
|
|
272
|
+
...viewSectionsMd(graph.views.slice(0, keptViews), assets, assetBaseUrl),
|
|
273
|
+
omitted === 0
|
|
274
|
+
? ""
|
|
275
|
+
: `*${omitted} drill-down ${omitted === 1 ? "section" : "sections"} did not fit this comment.*`,
|
|
276
|
+
branding
|
|
277
|
+
? `*Rendered by [PR Lens](${PROJECT_URL}) · from the team behind [Coldtea](${COLDTEA_URL})*`
|
|
278
|
+
: "",
|
|
279
|
+
]
|
|
280
|
+
.filter((block) => block !== "")
|
|
281
|
+
.join("\n\n")
|
|
282
|
+
.concat("\n");
|
|
283
|
+
};
|
|
284
|
+
export const composeComment = (options) => {
|
|
285
|
+
const target = options.target ?? "github";
|
|
286
|
+
const surface = surfaceFor(target);
|
|
287
|
+
const marker = commentMarker(target);
|
|
288
|
+
const compose = (keptViews) => {
|
|
289
|
+
switch (surface.dialect) {
|
|
290
|
+
case "gfm":
|
|
291
|
+
case "glfm":
|
|
292
|
+
return composeHtml(options, { dialect: surface.dialect, themeStrategy: surface.themeStrategy }, marker, keptViews);
|
|
293
|
+
case "python-markdown":
|
|
294
|
+
return composeMarkdown(options, marker, keptViews);
|
|
295
|
+
default:
|
|
296
|
+
return assertNever(surface.dialect, "Unhandled dialect");
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
// A body over the forge's limit would be rejected outright, so trailing
|
|
300
|
+
// drill-down sections are shed until it fits: the headline, the numbers and
|
|
301
|
+
// the root diagrams are worth more than the deepest view.
|
|
302
|
+
for (let keptViews = options.graph.views.length;; keptViews -= 1) {
|
|
303
|
+
const body = compose(keptViews);
|
|
304
|
+
if (body.length <= surface.maxChars || keptViews === 0)
|
|
305
|
+
return body;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
148
308
|
//# sourceMappingURL=comment.js.map
|