Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
florianbgt committed Nov 25, 2024
1 parent 6690287 commit c44e270
Show file tree
Hide file tree
Showing 36 changed files with 994 additions and 1,482 deletions.
93 changes: 93 additions & 0 deletions packages/cli/src/annotationManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Group } from "./dependencyManager/types";
import { LanguagePlugin } from "./languages/types";

class AnnotationManager {
private nanoapiRegex: RegExp;
private commentPrefix: string;
path: string;
method?: string;
group?: string;

constructor(comment: string, languagePlugin: LanguagePlugin) {
this.nanoapiRegex = languagePlugin.annotationRegex;
this.commentPrefix = languagePlugin.commentPrefix;
const { path, method, group } = this.#parsetext(comment);
this.path = path;
this.method = method;
this.group = group;
}

#parsetext(text: string) {
const matches = text.match(this.nanoapiRegex);

if (!matches) {
throw new Error("Could not parse annotation");
}

const methodRegex = /method:([^ ]+)/;
const pathRegex = /path:([^ ]+)/;
const groupRegex = /group:([^ ]+)/;

const pathMatches = text.match(pathRegex);
const methodMatches = text.match(methodRegex);
const groupMatches = text.match(groupRegex);

if (!pathMatches) {
throw new Error("Could not parse path from annotation");
}

const path = pathMatches[1];
const method = methodMatches ? methodMatches[1] : undefined;
const group = groupMatches ? groupMatches[1] : undefined;

return { path, method, group };
}

matchesEndpoint(path: string, method: string | undefined) {
return this.path === path && this.method === method;
}

isInGroup(group: Group) {
// check if annotation has a method (actual endpoint)
if (this.method) {
const endpoint = group.endpoints.find(
(endpoint) =>
endpoint.method === this.method && endpoint.path === this.path,
);

if (endpoint) {
return true;
}

return false;
}

// if annotation has no method, we treat it as a module that contains other endpoints
const endpoints = group.endpoints.filter((endpoint) =>
endpoint.path.startsWith(this.path),
);

if (endpoints.length > 0) {
return true;
}

return false;
}

stringify() {
let annotation = `${this.commentPrefix} @nanoapi`;
if (this.method) {
annotation += ` method:${this.method}`;
}
if (this.path) {
annotation += ` path:${this.path}`;
}
if (this.group) {
annotation += ` group:${this.group}`;
}

return annotation;
}
}

export default AnnotationManager;
3 changes: 2 additions & 1 deletion packages/cli/src/api/scan.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { z } from "zod";
import DependencyTreeManager from "../helper/dependencyTree";
import DependencyTreeManager from "../dependencyManager/dependencyManager";
import { scanSchema } from "./helpers/validation";

export function scan(payload: z.infer<typeof scanSchema>) {
const dependencyTreeManager = new DependencyTreeManager(
payload.entrypointPath,
);
const endpoints = dependencyTreeManager.getEndponts();

return { endpoints };
}
10 changes: 4 additions & 6 deletions packages/cli/src/api/split.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import fs from "fs";
import path from "path";
import DependencyTreeManager from "../helper/dependencyTree";
import DependencyTreeManager from "../dependencyManager/dependencyManager";
import { cleanupOutputDir, createOutputDir } from "../helper/file";
import SplitRunner from "../helper/split";
import SplitRunner from "../splitRunner/splitRunner";
import { splitSchema } from "./helpers/validation";
import { z } from "zod";
import { GroupMap } from "../helper/types";
import { Group } from "../dependencyManager/types";

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

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

// Process each group for splitting
groups.forEach((group, index) => {
console.log(JSON.stringify(dependencyTreeManager.dependencyTree, null, 2));

const splitRunner = new SplitRunner(dependencyTreeManager, group);
const files = splitRunner.run();

Expand Down
68 changes: 29 additions & 39 deletions packages/cli/src/api/sync.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { z } from "zod";
import { syncSchema } from "./helpers/validation";
import fs from "fs";
import {
parseNanoApiAnnotation,
updateCommentFromAnnotation,
} from "../helper/annotations";
import DependencyTreeManager from "../helper/dependencyTree";
import Parser from "tree-sitter";
import { getParserLanguageFromFile } from "../helper/treeSitter";
import { replaceIndexesFromSourceCode } from "../helper/cleanup";
import { getJavascriptAnnotationNodes } from "../helper/languages/javascript/annotations";
import { getTypescriptAnnotationNodes } from "../helper/languages/typescript/annotations";
import DependencyTreeManager from "../dependencyManager/dependencyManager";
import AnnotationManager from "../annotationManager";
import { getLanguagePluginFromFilePath } from "../languages";
import { replaceIndexesFromSourceCode } from "../helper/file";

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

updatedEndpoints.forEach((endpoint) => {
const language = getParserLanguageFromFile(endpoint.filePath);
const parser = new Parser();
parser.setLanguage(language);
const languagePlugin = getLanguagePluginFromFilePath(endpoint.filePath);

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

const tree = parser.parse(sourceCode);
const tree = languagePlugin.parser.parse(sourceCode);

const indexesToReplace: {
startIndex: number;
endIndex: number;
text: string;
}[] = [];

let annotationNodes: Parser.SyntaxNode[];
if (language.name === "javascript") {
annotationNodes = getJavascriptAnnotationNodes(parser, tree.rootNode);
} else if (language.name === "typescript") {
annotationNodes = getTypescriptAnnotationNodes(parser, tree.rootNode);
} else {
throw new Error("Language not supported");
}
const commentNodes = languagePlugin.getCommentNodes(tree.rootNode);

annotationNodes.forEach((node) => {
const annotation = parseNanoApiAnnotation(node.text);
if (
annotation.path === endpoint.path &&
annotation.method === endpoint.method
) {
annotation.group = endpoint.group;
const updatedComment = updateCommentFromAnnotation(
commentNodes.forEach((node) => {
try {
const annotationManager = new AnnotationManager(
node.text,
annotation,
languagePlugin,
);
if (annotationManager.matchesEndpoint(endpoint.path, endpoint.method)) {
annotationManager.group = endpoint.group;
const updatedComment = annotationManager.stringify();

indexesToReplace.push({
startIndex: node.startIndex,
endIndex: node.endIndex,
text: updatedComment,
});
indexesToReplace.push({
startIndex: node.startIndex,
endIndex: node.endIndex,
text: updatedComment,
});
}
} catch {
// Skip if annotation is not valid, we assume it is a regular comment
return;
}
});

sourceCode = replaceIndexesFromSourceCode(sourceCode, indexesToReplace);
const updatedSourceCode = replaceIndexesFromSourceCode(
sourceCode,
indexesToReplace,
);

fs.writeFileSync(endpoint.filePath, sourceCode, "utf-8");
fs.writeFileSync(endpoint.filePath, updatedSourceCode, "utf-8");
});
}
4 changes: 2 additions & 2 deletions packages/cli/src/commands/annotate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "fs";
import DependencyTreeManager from "../helper/dependencyTree";
import DependencyTreeManager from "../dependencyManager/dependencyManager";
import OpenAI from "openai";
import { DependencyTree } from "../helper/types";
import { DependencyTree } from "../dependencyManager/types";

export default async function annotateOpenAICommandHandler(
entrypoint: string, // Path to the entrypoint file
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/commands/split.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import path from "path";
import fs from "fs";
import DependencyTreeManager from "../helper/dependencyTree";
import DependencyTreeManager from "../dependencyManager/dependencyManager";
import { cleanupOutputDir, createOutputDir } from "../helper/file";
import SplitRunner from "../helper/split";
import { GroupMap } from "../helper/types";
import SplitRunner from "../splitRunner/splitRunner";
import { Group } from "../dependencyManager/types";

export default function splitCommandHandler(
entrypointPath: string, // Path to the entrypoint file
outputDir: string, // Path to the output directory
) {
const groupMap: GroupMap = {};
const groupMap: Record<number, Group> = {};

const dependencyTreeManager = new DependencyTreeManager(entrypointPath);

Expand Down
Loading

0 comments on commit c44e270

Please sign in to comment.