Skip to content

Commit eb1a4ba

Browse files
authored
Merge pull request #515 from code-hike/regex-range
Better regex parsing in annotation range
2 parents c50fed3 + d75d16f commit eb1a4ba

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

.changeset/loud-moons-grow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"codehike": patch
3+
---
4+
5+
Better regex parsing in annotation range
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { expect, test } from "vitest"
2+
import { splitAnnotationsAndCode } from "./extract-annotations.js"
3+
4+
async function t(comment: string) {
5+
const code = `// ${comment} \nvar xyz = "https://example.com"`
6+
const { annotations } = await splitAnnotationsAndCode(code, "javascript", "!")
7+
return annotations[0]
8+
}
9+
10+
test("extracts basic annotation name", async () => {
11+
const annotation = await t("!foo bar")
12+
expect(annotation.name).toEqual("foo")
13+
})
14+
15+
test("extracts name with parentheses range", async () => {
16+
const annotation = await t("!foo(1) bar")
17+
expect(annotation.name).toEqual("foo")
18+
})
19+
20+
test("extracts name with brackets range", async () => {
21+
const annotation = await t("!foo[1] bar")
22+
expect(annotation.name).toEqual("foo")
23+
})
24+
25+
test("extracts name with simple regex", async () => {
26+
const annotation = await t("!foo[/x/] bar")
27+
expect(annotation.name).toEqual("foo")
28+
})
29+
30+
test("extracts name with regex flags", async () => {
31+
const annotation = await t("!foo[/x/gmi] bar")
32+
expect(annotation.name).toEqual("foo")
33+
})
34+
35+
test("extracts name with regex containing brackets", async () => {
36+
const annotation = await t(`!foo[/xyz[a-z]*/g] bar`)
37+
expect(annotation.name).toEqual("foo")
38+
})
39+
40+
test("extracts name with regex containing parentheses", async () => {
41+
const annotation = await t(`!foo(/(xyz[w]*)/g) bar`)
42+
expect(annotation.name).toEqual("foo")
43+
})
44+
45+
test("extracts name with regex containing nested parentheses", async () => {
46+
const annotation = await t(`!foo(/((xyz)[w]*)/g) bar`)
47+
expect(annotation.name).toEqual("foo")
48+
})
49+
50+
test("extracts name with regex containing escaped slashes", async () => {
51+
const annotation = await t(`!foo[/https?:\\/\\//g] bar`)
52+
expect(annotation.name).toEqual("foo")
53+
})
54+
55+
test("extracts name with complex regex pattern", async () => {
56+
const code = `// !tooltip[/#\\[program\\]/] example \n#[program]`
57+
const { annotations } = await splitAnnotationsAndCode(code, "rust", "!")
58+
const annotation = annotations[0]
59+
expect(annotation.name).toEqual("tooltip")
60+
})

packages/codehike/src/code/extract-annotations.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,21 @@ async function extractCommentAnnotations(
2626
annotationPrefix = "!",
2727
) {
2828
const extractor = (comment: string) => {
29-
// const regex = /\s*(!?[\w-]+)?(\([^\)]*\)|\[[^\]]*\])?(.*)$/
29+
const body = "(?:\\\\.|[^\\\\/])+"
30+
const nestedBracketRegex = new RegExp(
31+
`\\s*(${annotationPrefix}?[\\w-]+)?(\\[\\/${body}\\/[a-zA-Z]*\\])(.*)$`,
32+
)
33+
const nestedParenRegex = new RegExp(
34+
`\\s*(${annotationPrefix}?[\\w-]+)?(\\(\\/${body}\\/[a-zA-Z]*\\))(.*)$`,
35+
)
3036
const regex = new RegExp(
3137
`\\s*(${annotationPrefix}?[\\w-]+)?(\\([^\\)]*\\)|\\[[^\\]]*\\])?(.*)$`,
3238
)
3339

34-
const match = comment.match(regex)
40+
const match =
41+
comment.match(nestedBracketRegex) ||
42+
comment.match(nestedParenRegex) ||
43+
comment.match(regex)
3544
if (!match) {
3645
return null
3746
}

0 commit comments

Comments
 (0)