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
|
import { describe, expect, it } from "vitest";
import { splitTextFiles, textFilePath, textFilePreview } from "./text-file";
const reference = (text: string, streaming = false) =>
splitTextFiles(text, streaming).filter((part) => part.kind === "text-file");
describe("text-file opt-in parser", () => {
it.each([
["[Plan](text-file:notes/plan.md)", "notes/plan.md"],
["[Plan](text-file:/tmp/plan.md)", "/tmp/plan.md"],
["[Plan](<text-file:notes/my plan.md>)", "notes/my plan.md"],
["[Plan](text-file:notes/my%20plan.md)", "notes/my plan.md"],
["[Plan](text-file:notes/100%25.md)", "notes/100%.md"],
["[Plan](text-file:notes/literal%2520.md)", "notes/literal%20.md"],
[String.raw`[Plan](text-file:notes/plan\(1\).md)`, "notes/plan(1).md"],
[String.raw`[Plan](text-file:notes/a\_b.md)`, "notes/a_b.md"],
])("parses %s", (text, path) =>
expect(reference(text)).toEqual([{ kind: "text-file", reference: { label: "Plan", path } }]));
it.each([
"[web](https://example.com)",
"",
"[file](file:///tmp/a.md)",
"see [Plan](text-file:a.md)",
"[Plan](text-file:a.md) suffix",
"`[Plan](text-file:a.md)`",
"```md\n[Plan](text-file:a.md)\n```",
"~~~\n[Plan](text-file:a.md)\n~~~",
" [Plan](text-file:a.md)",
"> [Plan](text-file:a.md)",
"- [Plan](text-file:a.md)",
"[Plan](text-file:a.md",
"[Plan](text-file:",
"[Plan][p]\n\n[p]: text-file:a.md",
'[Plan](text-file:a.md "title")',
"<div data-text-file='a.md'>Plan</div>",
])("does not opt in: %s", (text) => expect(reference(text)).toEqual([]));
it.each([
"file:///tmp/a",
"https://evil/a",
"//host/a",
"~/a",
"~user/a",
"a\\b",
"%00",
"%0a",
"%7f",
"a%5cb",
"%2f%2fhost/a",
"%68ttps://evil/a",
"bad%",
"",
" a",
"a ",
])("rejects unsafe path %s", (path) => expect(textFilePath(`text-file:${path}`)).toBeNull());
it("waits for complete streaming paragraph boundary and keeps settled embeds", () => {
const complete = "[Plan](text-file:a.md)";
for (let i = 0; i <= complete.length; i++)
expect(reference(complete.slice(0, i), true)).toHaveLength(0);
expect(reference(`${complete}\n`, true)).toHaveLength(0);
expect(reference(`${complete}\n\n`, true)).toHaveLength(1);
expect(reference(`${complete}\n\ntail`, true)).toHaveLength(1);
expect(reference(`${complete} suffix`, true)).toHaveLength(0);
expect(reference(complete)).toHaveLength(1);
});
it("bounds per-message document count", () => {
const result = splitTextFiles(
Array.from({ length: 30 }, (_, i) => `[p](text-file:${i}.md)`).join("\n\n"),
);
expect(result.filter((p) => p.kind === "text-file")).toHaveLength(8);
expect(JSON.stringify(result)).toContain("embed limit reached");
});
});
describe("source-line preview", () => {
it.each([1, 6, 12])("does not overlap %i source lines", (n) => {
const text = Array.from({ length: n }, (_, i) => `${i}`).join("\n");
expect(textFilePreview(text, true)).toEqual({ head: text, tail: "", omitted: 0 });
});
it("takes first six and last six source lines, ignoring final newline", () => {
const result = textFilePreview(
`${Array.from({ length: 20 }, (_, i) => `line${i + 1}`).join("\n")}\n`,
true,
);
expect(result).toEqual({
head: "line1\nline2\nline3\nline4\nline5\nline6",
tail: "line15\nline16\nline17\nline18\nline19\nline20",
omitted: 8,
});
});
it("restores top-level fence context at fragment edges", () => {
const text = `\`\`\`js\n${Array.from({ length: 20 }, () => "const x = 1;").join("\n")}\n\`\`\``;
const result = textFilePreview(text, true);
expect(result.head).toMatch(/\n```$/);
expect(result.tail).toMatch(/^```js\n/);
expect(result.tail).toMatch(/\n```$/);
expect(textFilePreview(text, false).tail).not.toMatch(/^```js/);
});
});
describe("text-file parser boundary compatibility", () => {
it("preserves document-wide ordinary reference definitions across embed splits", () => {
const parts = splitTextFiles(
"[before][web]\n\n[Plan](text-file:a.md)\n\n[after][web]\n\n[web]: https://example.com",
);
expect(parts.filter((part) => part.kind === "text-file")).toHaveLength(1);
for (const part of parts) {
if (part.kind === "markdown") expect(part.text).toContain("[web]: https://example.com");
}
});
it.each([
"%C2%85",
"a".repeat(4097),
])("rejects backend-unsupported controls or overlong paths", (path) => {
expect(textFilePath(`text-file:${path}`)).toBeNull();
});
it("accepts encoded filename delimiters without treating them as a URL query/fragment", () => {
expect(textFilePath("text-file:notes/a%23b%3Fc.md")).toBe("notes/a#b?c.md");
});
});
|