mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-22 17:22:47 +00:00
fix(markdown): bare prose paths need an extension, line suffix or depth
Slash-separated English pairs were recognized as file links in prose. Require stronger path intent there while preserving the existing inline-code recognition rule.
This commit is contained in:
@@ -444,14 +444,20 @@ it.each([
|
|||||||
it.each([
|
it.each([
|
||||||
"src/index.ts",
|
"src/index.ts",
|
||||||
"README.md",
|
"README.md",
|
||||||
"packages/app",
|
|
||||||
"./scripts/run",
|
"./scripts/run",
|
||||||
|
"./x/y",
|
||||||
|
"../x/y",
|
||||||
|
"/x/y",
|
||||||
|
"a/b/c",
|
||||||
|
String.raw`C:\Users\x`,
|
||||||
|
"src/index.ts:12:3",
|
||||||
|
"src/run:12",
|
||||||
|
"src/run:12:3",
|
||||||
|
"src/run:12-20",
|
||||||
"~/dev/paseo",
|
"~/dev/paseo",
|
||||||
String.raw`C:\Users\x\file.txt`,
|
String.raw`C:\Users\x\file.txt`,
|
||||||
"file.ts:12",
|
"file.ts:12",
|
||||||
"file.ts:12-20",
|
"file.ts:12-20",
|
||||||
"123/file",
|
|
||||||
"src/123",
|
|
||||||
"123.ts",
|
"123.ts",
|
||||||
"FILE.TS",
|
"FILE.TS",
|
||||||
"https://example.com/path",
|
"https://example.com/path",
|
||||||
@@ -463,6 +469,20 @@ it.each([
|
|||||||
expect(linkRecognition.inlineCode.test(token)).toBe(true);
|
expect(linkRecognition.inlineCode.test(token)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
"before/after",
|
||||||
|
"and/or",
|
||||||
|
"input/output",
|
||||||
|
"read/write",
|
||||||
|
"packages/app",
|
||||||
|
"123/file",
|
||||||
|
"src/123",
|
||||||
|
])("requires stronger path intent in prose while preserving inline code: %s", (token) => {
|
||||||
|
const { linkRecognition } = prepareMarkdownSource(`Compare ${token}, then continue.`);
|
||||||
|
expect([...`Compare ${token}, then continue.`.matchAll(linkRecognition.text)]).toEqual([]);
|
||||||
|
expect(linkRecognition.inlineCode.test(token)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps prose and inline-code recognition enabled through the native regex adapter", () => {
|
it("keeps prose and inline-code recognition enabled through the native regex adapter", () => {
|
||||||
const { linkRecognition } = prepareMarkdownSource("3/4 src/index.ts");
|
const { linkRecognition } = prepareMarkdownSource("3/4 src/index.ts");
|
||||||
const native = toNativeLinkRecognition(linkRecognition);
|
const native = toNativeLinkRecognition(linkRecognition);
|
||||||
|
|||||||
@@ -16,20 +16,31 @@ const LINE_SUFFIX = String.raw`(?::\d+(?::\d+)?(?:-\d+(?::\d+)?)?)?`;
|
|||||||
const FILE_EXTENSIONS = [...ASSISTANT_FILE_EXTENSIONS]
|
const FILE_EXTENSIONS = [...ASSISTANT_FILE_EXTENSIONS]
|
||||||
.map((extension) => extension.replace(/[a-z]/g, (letter) => `[${letter}${letter.toUpperCase()}]`))
|
.map((extension) => extension.replace(/[a-z]/g, (letter) => `[${letter}${letter.toUpperCase()}]`))
|
||||||
.join("|");
|
.join("|");
|
||||||
const SEPARATED_PATH = String.raw`(?:[A-Za-z]:[\\/]|\.{0,2}\/|~\/)?(?=${PATH_CHARACTER}*(?:[\\/]${PATH_CHARACTER}*)*${PATH_LETTER})${PATH_SEGMENT}(?:[\\/]${PATH_SEGMENT})+`;
|
const PATH_PREFIX = String.raw`(?:[A-Za-z]:[\\/]|\.{0,2}\/|~\/)`;
|
||||||
|
const HAS_PATH_LETTER = String.raw`(?=${PATH_CHARACTER}*(?:[\\/]${PATH_CHARACTER}*)*${PATH_LETTER})`;
|
||||||
|
const SEPARATED_PATH = String.raw`${PATH_SEGMENT}(?:[\\/]${PATH_SEGMENT})+`;
|
||||||
const FILE_NAME = String.raw`${PATH_SEGMENT}\.(?:${FILE_EXTENSIONS})`;
|
const FILE_NAME = String.raw`${PATH_SEGMENT}\.(?:${FILE_EXTENSIONS})`;
|
||||||
// The native adapter mistakes a literal + in lookbehind for a quantifier; use its hex escape.
|
// Bare prose paths need a known extension, a line suffix, or at least two separators.
|
||||||
const FILE_PATTERN = new RegExp(
|
const PROSE_PATH = String.raw`(?:${PATH_PREFIX}${HAS_PATH_LETTER}${SEPARATED_PATH}|${HAS_PATH_LETTER}(?:${PATH_SEGMENT}(?:[\\/]${PATH_SEGMENT})*[\\/]${FILE_NAME}|${PATH_SEGMENT}(?:[\\/]${PATH_SEGMENT}){2,}|${SEPARATED_PATH}(?=:)))`;
|
||||||
String.raw`(?:https?://[^\s<>]+|(?<![a-zA-Z0-9\u0080-\uFFFF_@.%\x2b~:/\\-])(?:${SEPARATED_PATH}|${FILE_NAME})${LINE_SUFFIX}(?![a-zA-Z0-9\u0080-\uFFFF_@%+:/\\-]|\.${PATH_CHARACTER}))`,
|
const INLINE_CODE_PATH = String.raw`${PATH_PREFIX}?${HAS_PATH_LETTER}${SEPARATED_PATH}`;
|
||||||
"g",
|
|
||||||
);
|
function createFilePattern(path: string): RegExp {
|
||||||
|
// The native adapter mistakes a literal + in lookbehind for a quantifier; use its hex escape.
|
||||||
|
return new RegExp(
|
||||||
|
String.raw`(?:https?://[^\s<>]+|(?<![a-zA-Z0-9\u0080-\uFFFF_@.%\x2b~:/\\-])(?:${path}|${FILE_NAME})${LINE_SUFFIX}(?![a-zA-Z0-9\u0080-\uFFFF_@%+:/\\-]|\.${PATH_CHARACTER}))`,
|
||||||
|
"g",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FILE_PATTERN = createFilePattern(PROSE_PATH);
|
||||||
|
const INLINE_CODE_FILE_PATTERN = createFilePattern(INLINE_CODE_PATH);
|
||||||
|
|
||||||
function linkMetadata() {
|
function linkMetadata() {
|
||||||
return {
|
return {
|
||||||
linkRecognition: {
|
linkRecognition: {
|
||||||
text: FILE_PATTERN,
|
text: FILE_PATTERN,
|
||||||
inlineCode: new RegExp(
|
inlineCode: new RegExp(
|
||||||
String.raw`^(?:${FILE_PATTERN.source})(?:\(\d+(?:,\d+)?(?:-\d+(?:,\d+)?)?\)| lines? \d+(?:-\d+)?)?$`,
|
String.raw`^(?:${INLINE_CODE_FILE_PATTERN.source})(?:\(\d+(?:,\d+)?(?:-\d+(?:,\d+)?)?\)| lines? \d+(?:-\d+)?)?$`,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
linkSource: markdownLinkSource,
|
linkSource: markdownLinkSource,
|
||||||
|
|||||||
Reference in New Issue
Block a user