mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 13:24:55 +01:00
Match production auto-links and require preserved reply source
Use the existing GFM and issue-reference plugins with the viewer company prefixes. Keep source Markdown mandatory in native receipts and cover bare URLs, known issue keys, foreign plain keys and changed destinations. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
6eba7fffb4
commit
6df66df9d9
9 files changed
+61
-23
No files matched your search
@@ -1,6 +1,8 @@
|
||||
import { fromMarkdown } from "mdast-util-from-markdown";
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { applyCompanyPrefix, extractCompanyPrefixFromPath } from "../../ui/src/lib/company-routes.js";
|
||||
import { parseIssueReferenceFromHref } from "../../ui/src/lib/issue-reference.js";
|
||||
import { parseIssueReferenceFromHref, remarkLinkIssueReferences } from "../../ui/src/lib/issue-reference.js";
|
||||
|
||||
export type ReplyContentPart = { text: string } | { href: string; label?: string; decorated?: boolean };
|
||||
type MarkdownNode = { type: string; value?: string; url?: string; children?: MarkdownNode[] };
|
||||
@@ -31,7 +33,7 @@ function normalized(parts: ReplyContentPart[], pageUrl: string, source = false)
|
||||
* with an issue/document chip. Its exact destination still has to match.
|
||||
* Unsupported Markdown fails closed rather than stripping arbitrary syntax. */
|
||||
export function taskReplyContentMatches(
|
||||
observation: { body: string; content?: ReplyContentPart[]; origin?: string; pageUrl?: string },
|
||||
observation: { body: string; content?: ReplyContentPart[]; origin?: string; pageUrl?: string; knownCompanyPrefixes?: string[] },
|
||||
markdown: string,
|
||||
) {
|
||||
if (observation.content) {
|
||||
@@ -42,19 +44,22 @@ export function taskReplyContentMatches(
|
||||
if (displayed !== observation.body.replace(/\s+/g, " ").trim()) return false;
|
||||
}
|
||||
const parts: ReplyContentPart[] = [];
|
||||
const inlineLabel = (node: MarkdownNode): boolean => ["text", "inlineCode", "strong", "emphasis"].includes(node.type)
|
||||
const inlineLabel = (node: MarkdownNode): boolean => ["text", "inlineCode", "strong", "emphasis", "delete"].includes(node.type)
|
||||
&& (node.children ?? []).every(inlineLabel);
|
||||
const labelText = (node: MarkdownNode): string => node.value ?? (node.children ?? []).map(labelText).join("");
|
||||
function visit(node: MarkdownNode): boolean {
|
||||
if (node.type === "text" || node.type === "inlineCode") { parts.push({ text: node.value ?? "" }); return true; }
|
||||
if (node.type === "break") { parts.push({ text: " " }); return true; }
|
||||
if (node.type === "link" && node.url && (node.children ?? []).every(inlineLabel)) { parts.push({ href: node.url, label: labelText(node) }); return true; }
|
||||
if (!["root", "paragraph", "heading", "blockquote", "list", "listItem", "strong", "emphasis"].includes(node.type)) return false;
|
||||
if (!["root", "paragraph", "heading", "blockquote", "list", "listItem", "strong", "emphasis", "delete"].includes(node.type)) return false;
|
||||
for (const child of node.children ?? []) if (!visit(child)) return false;
|
||||
if (!["strong", "emphasis"].includes(node.type)) parts.push({ text: " " });
|
||||
if (!["strong", "emphasis", "delete"].includes(node.type)) parts.push({ text: " " });
|
||||
return true;
|
||||
}
|
||||
if (!visit(fromMarkdown(markdown) as MarkdownNode)) return false;
|
||||
const parser = unified().use(remarkParse).use(remarkGfm);
|
||||
const tree = parser.runSync(parser.parse(markdown)) as MarkdownNode;
|
||||
remarkLinkIssueReferences({ knownPrefixes: observation.knownCompanyPrefixes })(tree);
|
||||
if (!visit(tree)) return false;
|
||||
const pageUrl = observation.pageUrl ?? observation.origin ?? "https://reply.invalid";
|
||||
const expected = normalized(parts, pageUrl, true);
|
||||
const actual = normalized(observation.content ?? [{ text: observation.body }], pageUrl);
|
||||
|
||||
Reference in new issue
Block a user