Skip to content

Commit c44e270

Browse files
committed
wip
1 parent 6690287 commit c44e270

36 files changed

+994
-1482
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Group } from "./dependencyManager/types";
2+
import { LanguagePlugin } from "./languages/types";
3+
4+
class AnnotationManager {
5+
private nanoapiRegex: RegExp;
6+
private commentPrefix: string;
7+
path: string;
8+
method?: string;
9+
group?: string;
10+
11+
constructor(comment: string, languagePlugin: LanguagePlugin) {
12+
this.nanoapiRegex = languagePlugin.annotationRegex;
13+
this.commentPrefix = languagePlugin.commentPrefix;
14+
const { path, method, group } = this.#parsetext(comment);
15+
this.path = path;
16+
this.method = method;
17+
this.group = group;
18+
}
19+
20+
#parsetext(text: string) {
21+
const matches = text.match(this.nanoapiRegex);
22+
23+
if (!matches) {
24+
throw new Error("Could not parse annotation");
25+
}
26+
27+
const methodRegex = /method:([^ ]+)/;
28+
const pathRegex = /path:([^ ]+)/;
29+
const groupRegex = /group:([^ ]+)/;
30+
31+
const pathMatches = text.match(pathRegex);
32+
const methodMatches = text.match(methodRegex);
33+
const groupMatches = text.match(groupRegex);
34+
35+
if (!pathMatches) {
36+
throw new Error("Could not parse path from annotation");
37+
}
38+
39+
const path = pathMatches[1];
40+
const method = methodMatches ? methodMatches[1] : undefined;
41+
const group = groupMatches ? groupMatches[1] : undefined;
42+
43+
return { path, method, group };
44+
}
45+
46+
matchesEndpoint(path: string, method: string | undefined) {
47+
return this.path === path && this.method === method;
48+
}
49+
50+
isInGroup(group: Group) {
51+
// check if annotation has a method (actual endpoint)
52+
if (this.method) {
53+
const endpoint = group.endpoints.find(
54+
(endpoint) =>
55+
endpoint.method === this.method && endpoint.path === this.path,
56+
);
57+
58+
if (endpoint) {
59+
return true;
60+
}
61+
62+
return false;
63+
}
64+
65+
// if annotation has no method, we treat it as a module that contains other endpoints
66+
const endpoints = group.endpoints.filter((endpoint) =>
67+
endpoint.path.startsWith(this.path),
68+
);
69+
70+
if (endpoints.length > 0) {
71+
return true;
72+
}
73+
74+
return false;
75+
}
76+
77+
stringify() {
78+
let annotation = `${this.commentPrefix} @nanoapi`;
79+
if (this.method) {
80+
annotation += ` method:${this.method}`;
81+
}
82+
if (this.path) {
83+
annotation += ` path:${this.path}`;
84+
}
85+
if (this.group) {
86+
annotation += ` group:${this.group}`;
87+
}
88+
89+
return annotation;
90+
}
91+
}
92+
93+
export default AnnotationManager;

packages/cli/src/api/scan.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { z } from "zod";
2-
import DependencyTreeManager from "../helper/dependencyTree";
2+
import DependencyTreeManager from "../dependencyManager/dependencyManager";
33
import { scanSchema } from "./helpers/validation";
44

55
export function scan(payload: z.infer<typeof scanSchema>) {
66
const dependencyTreeManager = new DependencyTreeManager(
77
payload.entrypointPath,
88
);
99
const endpoints = dependencyTreeManager.getEndponts();
10+
1011
return { endpoints };
1112
}

packages/cli/src/api/split.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import fs from "fs";
22
import path from "path";
3-
import DependencyTreeManager from "../helper/dependencyTree";
3+
import DependencyTreeManager from "../dependencyManager/dependencyManager";
44
import { cleanupOutputDir, createOutputDir } from "../helper/file";
5-
import SplitRunner from "../helper/split";
5+
import SplitRunner from "../splitRunner/splitRunner";
66
import { splitSchema } from "./helpers/validation";
77
import { z } from "zod";
8-
import { GroupMap } from "../helper/types";
8+
import { Group } from "../dependencyManager/types";
99

1010
export function split(payload: z.infer<typeof splitSchema>) {
1111
console.time("split command");
12-
const groupMap: GroupMap = {};
12+
const groupMap: Record<number, Group> = {};
1313

1414
// Get the dependency tree
1515
const dependencyTreeManager = new DependencyTreeManager(
@@ -27,8 +27,6 @@ export function split(payload: z.infer<typeof splitSchema>) {
2727

2828
// Process each group for splitting
2929
groups.forEach((group, index) => {
30-
console.log(JSON.stringify(dependencyTreeManager.dependencyTree, null, 2));
31-
3230
const splitRunner = new SplitRunner(dependencyTreeManager, group);
3331
const files = splitRunner.run();
3432

packages/cli/src/api/sync.ts

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import { z } from "zod";
22
import { syncSchema } from "./helpers/validation";
33
import fs from "fs";
4-
import {
5-
parseNanoApiAnnotation,
6-
updateCommentFromAnnotation,
7-
} from "../helper/annotations";
8-
import DependencyTreeManager from "../helper/dependencyTree";
9-
import Parser from "tree-sitter";
10-
import { getParserLanguageFromFile } from "../helper/treeSitter";
11-
import { replaceIndexesFromSourceCode } from "../helper/cleanup";
12-
import { getJavascriptAnnotationNodes } from "../helper/languages/javascript/annotations";
13-
import { getTypescriptAnnotationNodes } from "../helper/languages/typescript/annotations";
4+
import DependencyTreeManager from "../dependencyManager/dependencyManager";
5+
import AnnotationManager from "../annotationManager";
6+
import { getLanguagePluginFromFilePath } from "../languages";
7+
import { replaceIndexesFromSourceCode } from "../helper/file";
148

159
export function sync(payload: z.infer<typeof syncSchema>) {
1610
const dependencyTreeManager = new DependencyTreeManager(
@@ -35,51 +29,47 @@ export function sync(payload: z.infer<typeof syncSchema>) {
3529
});
3630

3731
updatedEndpoints.forEach((endpoint) => {
38-
const language = getParserLanguageFromFile(endpoint.filePath);
39-
const parser = new Parser();
40-
parser.setLanguage(language);
32+
const languagePlugin = getLanguagePluginFromFilePath(endpoint.filePath);
4133

42-
let sourceCode = fs.readFileSync(endpoint.filePath, "utf-8");
34+
const sourceCode = fs.readFileSync(endpoint.filePath, "utf-8");
4335

44-
const tree = parser.parse(sourceCode);
36+
const tree = languagePlugin.parser.parse(sourceCode);
4537

4638
const indexesToReplace: {
4739
startIndex: number;
4840
endIndex: number;
4941
text: string;
5042
}[] = [];
5143

52-
let annotationNodes: Parser.SyntaxNode[];
53-
if (language.name === "javascript") {
54-
annotationNodes = getJavascriptAnnotationNodes(parser, tree.rootNode);
55-
} else if (language.name === "typescript") {
56-
annotationNodes = getTypescriptAnnotationNodes(parser, tree.rootNode);
57-
} else {
58-
throw new Error("Language not supported");
59-
}
44+
const commentNodes = languagePlugin.getCommentNodes(tree.rootNode);
6045

61-
annotationNodes.forEach((node) => {
62-
const annotation = parseNanoApiAnnotation(node.text);
63-
if (
64-
annotation.path === endpoint.path &&
65-
annotation.method === endpoint.method
66-
) {
67-
annotation.group = endpoint.group;
68-
const updatedComment = updateCommentFromAnnotation(
46+
commentNodes.forEach((node) => {
47+
try {
48+
const annotationManager = new AnnotationManager(
6949
node.text,
70-
annotation,
50+
languagePlugin,
7151
);
52+
if (annotationManager.matchesEndpoint(endpoint.path, endpoint.method)) {
53+
annotationManager.group = endpoint.group;
54+
const updatedComment = annotationManager.stringify();
7255

73-
indexesToReplace.push({
74-
startIndex: node.startIndex,
75-
endIndex: node.endIndex,
76-
text: updatedComment,
77-
});
56+
indexesToReplace.push({
57+
startIndex: node.startIndex,
58+
endIndex: node.endIndex,
59+
text: updatedComment,
60+
});
61+
}
62+
} catch {
63+
// Skip if annotation is not valid, we assume it is a regular comment
64+
return;
7865
}
7966
});
8067

81-
sourceCode = replaceIndexesFromSourceCode(sourceCode, indexesToReplace);
68+
const updatedSourceCode = replaceIndexesFromSourceCode(
69+
sourceCode,
70+
indexesToReplace,
71+
);
8272

83-
fs.writeFileSync(endpoint.filePath, sourceCode, "utf-8");
73+
fs.writeFileSync(endpoint.filePath, updatedSourceCode, "utf-8");
8474
});
8575
}

packages/cli/src/commands/annotate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from "fs";
2-
import DependencyTreeManager from "../helper/dependencyTree";
2+
import DependencyTreeManager from "../dependencyManager/dependencyManager";
33
import OpenAI from "openai";
4-
import { DependencyTree } from "../helper/types";
4+
import { DependencyTree } from "../dependencyManager/types";
55

66
export default async function annotateOpenAICommandHandler(
77
entrypoint: string, // Path to the entrypoint file

packages/cli/src/commands/split.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import path from "path";
22
import fs from "fs";
3-
import DependencyTreeManager from "../helper/dependencyTree";
3+
import DependencyTreeManager from "../dependencyManager/dependencyManager";
44
import { cleanupOutputDir, createOutputDir } from "../helper/file";
5-
import SplitRunner from "../helper/split";
6-
import { GroupMap } from "../helper/types";
5+
import SplitRunner from "../splitRunner/splitRunner";
6+
import { Group } from "../dependencyManager/types";
77

88
export default function splitCommandHandler(
99
entrypointPath: string, // Path to the entrypoint file
1010
outputDir: string, // Path to the output directory
1111
) {
12-
const groupMap: GroupMap = {};
12+
const groupMap: Record<number, Group> = {};
1313

1414
const dependencyTreeManager = new DependencyTreeManager(entrypointPath);
1515

0 commit comments

Comments
 (0)