Skip to content

Commit b5f5149

Browse files
committed
allow nodes outside match
1 parent 0de3085 commit b5f5149

2 files changed

Lines changed: 90 additions & 2 deletions

File tree

packages/core/src/astgrep.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ export async function astGrepFindFiles(
8181

8282
const pending: Record<string, { root: SgRoot; edits: SgEdit[] }> = {}
8383
const replace = (node: SgNode, text: string) => {
84-
if (!matches.includes(node))
85-
throw new Error("node is not included in the matches")
8684
const edit = node.replace(text)
8785
const root = node.getRoot()
8886
const rootEdits =
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
script({
2+
title: "Generate TypeScript function documentation using AST insertion",
3+
accept: ".ts",
4+
files: "src/cowsay.ts",
5+
parameters: {
6+
applyEdits: {
7+
type: "boolean",
8+
default: false,
9+
description: "If true, the script will not modify the files.",
10+
},
11+
},
12+
})
13+
const { output } = env
14+
const { applyEdits } = env.vars
15+
const file = env.files[0]
16+
17+
// find all exported functions with comments
18+
const sg = await host.astGrep()
19+
const { matches, replace, commitEdits } = await sg.search("ts", file.filename, {
20+
rule: {
21+
kind: "export_statement",
22+
follows: {
23+
kind: "comment",
24+
stopBy: "neighbor",
25+
},
26+
has: {
27+
kind: "function_declaration",
28+
},
29+
},
30+
})
31+
32+
// for each match, generate a docstring for functions not documented
33+
for (const match of matches) {
34+
const comment = match.prev()
35+
36+
const res = await runPrompt(
37+
(_) => {
38+
_.def("FILE", match.getRoot().root().text(), { flex: 1 })
39+
_.def("DOCSTRING", comment.text(), { flex: 10 })
40+
_.def("FUNCTION", match.text(), { flex: 10 })
41+
// this needs more eval-ing
42+
_.$`Update the docstring <DOCSTRING> of function <FUNCTION>.
43+
- If the docstring is up to date, return <NOP>.
44+
- Make sure parameters are documented.
45+
- Be concise. Use technical tone.
46+
- do NOT include types, this is for TypeScript.
47+
- Use docstring syntax.
48+
- Minimize updates to the existing docstring.
49+
50+
The full source of the file is in <FILE> for reference.
51+
The source of the function is in <FUNCTION>.
52+
The current docstring is <DOCSTRING>.
53+
`
54+
},
55+
{
56+
model: "small",
57+
responseType: "text",
58+
flexTokens: 12000,
59+
label: match.child(0).text(),
60+
}
61+
)
62+
// if generation is successful, insert the docs
63+
if (res.error) {
64+
output.warn(res.error.message)
65+
continue
66+
}
67+
68+
if (res.text.includes("<NOP>")) continue
69+
70+
const docs = docify(res.text.trim())
71+
replace(comment, docs)
72+
}
73+
74+
// apply all edits and write to the file
75+
const modified = await commitEdits()
76+
if (applyEdits) {
77+
await workspace.writeFiles(modified)
78+
} else if (modified.length) {
79+
output.diff(file, modified[0])
80+
output.warn(
81+
`edit not applied, use --vars 'applyEdits=true' to apply the edits`
82+
)
83+
}
84+
85+
// normalizes the docstring in case the LLM decides not to generate proper comments
86+
function docify(docs: string) {
87+
if (!/^\/\*\*.*.*\*\/$/s.test(docs))
88+
docs = `/**\n* ${docs.split(/\r?\n/g).join("\n* ")}\n*/`
89+
return docs.replace(/\n+$/, "")
90+
}

0 commit comments

Comments
 (0)