Skip to content

Commit

Permalink
split js from ts
Browse files Browse the repository at this point in the history
  • Loading branch information
florianbgt committed Nov 7, 2024
1 parent a710574 commit a648125
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 60 deletions.
13 changes: 11 additions & 2 deletions packages/cli/src/api/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
import Parser from "tree-sitter";
import { getParserLanguageFromFile } from "../helper/treeSitter";
import { replaceIndexesFromSourceCode } from "../helper/cleanup";
import { getAnnotationNodes } from "../helper/languages/javascript/annotations";
import { getJavascriptAnnotationNodes } from "../helper/languages/javascript/annotations";
import { getTypescriptAnnotationNodes } from "../helper/languages/typescript/annotations";

export function sync(payload: z.infer<typeof syncSchema>) {
const tree = getDependencyTree(payload.entrypointPath);
Expand Down Expand Up @@ -49,7 +50,15 @@ export function sync(payload: z.infer<typeof syncSchema>) {
text: string;
}[] = [];

const annotationNodes = getAnnotationNodes(parser, tree.rootNode);
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");
}

annotationNodes.forEach((node) => {
const annotation = parseNanoApiAnnotation(node.text);
if (
Expand Down
60 changes: 47 additions & 13 deletions packages/cli/src/helper/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import { Group } from "./types";
import { getParserLanguageFromFile } from "./treeSitter";
import { getJavascriptExports } from "./languages/javascript/exports";
import assert from "assert";
import {
cleanupTypescriptAnnotations,
cleanupTypescriptInvalidImports,
cleanupUnusedTypescriptImports,
} from "./languages/typescript/cleanup";
import { getTypescriptExports } from "./languages/typescript/exports";
import { getTypescriptImports } from "./languages/typescript/imports";

export function cleanupAnnotations(
filePath: string,
Expand All @@ -23,8 +30,10 @@ export function cleanupAnnotations(

let updatedSourceCode: string;

if (["javascript", "typescript"].includes(language.name)) {
if (language.name === "javascript") {
updatedSourceCode = cleanupJavascriptAnnotations(parser, sourceCode, group);
} else if (language.name === "typescript") {
updatedSourceCode = cleanupTypescriptAnnotations(parser, sourceCode, group);
} else {
throw new Error(`Unsupported language: ${language.language}`);
}
Expand All @@ -48,9 +57,12 @@ export function getExportMap(files: { path: string; sourceCode: string }[]) {
const parser = new Parser();
parser.setLanguage(language);

if (["javascript", "typescript"].includes(language.name)) {
if (language.name === "javascript") {
const exports = getJavascriptExports(parser, file.sourceCode);
exportIdentifiersMap.set(file.path, exports);
} else if (language.name === "typescript") {
const exports = getTypescriptExports(parser, file.sourceCode);
exportIdentifiersMap.set(file.path, exports);
} else {
throw new Error(`Unsupported language: ${language.language}`);
}
Expand Down Expand Up @@ -79,13 +91,20 @@ export function cleanupInvalidImports(

let updatedSourceCode: string = sourceCode;

if (["javascript", "typescript"].includes(language.name)) {
if (language.name === "javascript") {
updatedSourceCode = cleanupJavascriptInvalidImports(
parser,
filePath,
sourceCode,
exportIdentifiersMap,
);
} else if (language.name === "typescript") {
updatedSourceCode = cleanupTypescriptInvalidImports(
parser,
filePath,
sourceCode,
exportIdentifiersMap,
);
} else {
throw new Error(`Unsupported language: ${language.language}`);
}
Expand All @@ -99,8 +118,10 @@ export function cleanupUnusedImports(filePath: string, sourceCode: string) {
parser.setLanguage(language);

let updatedSourceCode: string;
if (["javascript", "typescript"].includes(language.name)) {
if (language.name === "javascript") {
updatedSourceCode = cleanupUnusedJavascriptImports(parser, sourceCode);
} else if (language.name === "typescript") {
updatedSourceCode = cleanupUnusedTypescriptImports(parser, sourceCode);
} else {
throw new Error(`Unsupported language: ${language.language}`);
}
Expand All @@ -126,23 +147,36 @@ export function cleanupUnusedFiles(
const parser = new Parser();
parser.setLanguage(language);

if (["javascript", "typescript"].includes(language.name)) {
let dependencies = getJavascriptImports(
let dependencies: {
node: Parser.SyntaxNode;
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
}[];
if (language.name === "javascript") {
dependencies = getJavascriptImports(
parser,
parser.parse(file.sourceCode).rootNode,
);
// Only keep files dependencies
dependencies = dependencies.filter((dep) => dep.source.startsWith("."));
} else if (language.name === "typescript") {
dependencies = getTypescriptImports(
parser,
parser.parse(file.sourceCode).rootNode,
);
// Only keep files dependencies
dependencies = dependencies.filter((dep) => dep.source.startsWith("."));

dependencies.forEach((dep) => {
const resolvedPath = resolveFilePath(dep.source, file.path);
if (resolvedPath) {
filesToKeep.add(resolvedPath);
}
});
} else {
throw new Error(`Unsupported language: ${language.language}`);
}

dependencies.forEach((dep) => {
const resolvedPath = resolveFilePath(dep.source, file.path);
if (resolvedPath) {
filesToKeep.add(resolvedPath);
}
});
});

const previousFilesLength = files.length;
Expand Down
38 changes: 24 additions & 14 deletions packages/cli/src/helper/dependencyTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { DependencyTree, Group } from "./types";
import { Endpoint } from "./types";
import { getParserLanguageFromFile } from "./treeSitter";
import { parseNanoApiAnnotation } from "./annotations";
import { getAnnotationNodes } from "./languages/javascript/annotations";
import { getJavascriptAnnotationNodes } from "./languages/javascript/annotations";
import { getJavascriptImports } from "./languages/javascript/imports";
import { getTypescriptImports } from "./languages/typescript/imports";

export function getDependencyTree(filePath: string): DependencyTree {
const sourceCode = fs.readFileSync(filePath, "utf8");
Expand All @@ -23,23 +24,29 @@ export function getDependencyTree(filePath: string): DependencyTree {
const parser = new Parser();
parser.setLanguage(language);

if (["javascript", "typescript"].includes(language.name)) {
let imports = getJavascriptImports(
parser,
parser.parse(sourceCode).rootNode,
);
let imports: {
node: Parser.SyntaxNode;
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
}[];
if (language.name === "javascript") {
imports = getJavascriptImports(parser, parser.parse(sourceCode).rootNode);
imports = imports.filter((importPath) => importPath.source.startsWith("."));
} else if (language.name === "typescript") {
imports = getTypescriptImports(parser, parser.parse(sourceCode).rootNode);
imports = imports.filter((importPath) => importPath.source.startsWith("."));

imports.forEach((importPath) => {
const resolvedPath = resolveFilePath(importPath.source, filePath);
if (resolvedPath && fs.existsSync(resolvedPath)) {
dependencyTree.children.push(getDependencyTree(resolvedPath));
}
});
} else {
throw new Error(`Unsupported language: ${language.name}`);
}

imports.forEach((importPath) => {
const resolvedPath = resolveFilePath(importPath.source, filePath);
if (resolvedPath && fs.existsSync(resolvedPath)) {
dependencyTree.children.push(getDependencyTree(resolvedPath));
}
});

return dependencyTree;
}

Expand Down Expand Up @@ -74,7 +81,10 @@ export function getEndpontsFromTree(
return uniqueFilePaths;
}

const annotationNodes = getAnnotationNodes(parser, parsedTree.rootNode);
const annotationNodes = getJavascriptAnnotationNodes(
parser,
parsedTree.rootNode,
);
annotationNodes.forEach((node) => {
const annotation = parseNanoApiAnnotation(node.text);

Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/helper/languages/javascript/annotations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import Parser from "tree-sitter";

export function getAnnotationNodes(parser: Parser, node: Parser.SyntaxNode) {
export function getJavascriptAnnotationNodes(
parser: Parser,
node: Parser.SyntaxNode,
) {
const commentQuery = new Parser.Query(
parser.getLanguage(),
`
Expand Down
88 changes: 63 additions & 25 deletions packages/cli/src/helper/languages/javascript/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,27 @@ import {
getJavascriptImportIdentifierUsage,
} from "./imports";
import { removeIndexesFromSourceCode } from "../../cleanup";
import { getAnnotationNodes } from "./annotations";
import { getJavascriptAnnotationNodes } from "./annotations";
import { resolveFilePath } from "../../file";
import { getTypescriptAnnotationNodes } from "../typescript/annotations";
import {
getTypescriptImportIdentifierUsage,
getTypescriptImports,
} from "../typescript/imports";

export function cleanupJavascriptAnnotations(
parser: Parser,
sourceCode: string,
groupToKeep: Group,
isTypescript = false,
): string {
const tree = parser.parse(sourceCode);

const indexesToRemove: { startIndex: number; endIndex: number }[] = [];

const annotationNodes = getAnnotationNodes(parser, tree.rootNode);
const annotationNodes = isTypescript
? getTypescriptAnnotationNodes(parser, tree.rootNode)
: getJavascriptAnnotationNodes(parser, tree.rootNode);

annotationNodes.forEach((node) => {
const annotation = parseNanoApiAnnotation(node.text);
Expand Down Expand Up @@ -65,12 +73,15 @@ export function cleanupJavascriptInvalidImports(
defaultExport?: Parser.SyntaxNode;
}
>,
isTypescript = false,
) {
const indexesToRemove: { startIndex: number; endIndex: number }[] = [];

const tree = parser.parse(sourceCode);

const depImports = getJavascriptImports(parser, tree.rootNode);
const depImports = isTypescript
? getTypescriptImports(parser, tree.rootNode)
: getJavascriptImports(parser, tree.rootNode);
// check if identifier exists in the imported file (as an export)
depImports.forEach((depImport) => {
// check if the import is a file, do not process external dependencies
Expand All @@ -86,11 +97,17 @@ export function cleanupJavascriptInvalidImports(
}

if (depImport.importIdentifier && !exportsForFile.defaultExport) {
let usages = getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
);
let usages = isTypescript
? getTypescriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
)
: getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
);
usages = usages.filter((usage) => {
return usage.id !== depImport.importIdentifier?.id;
});
Expand All @@ -114,11 +131,17 @@ export function cleanupJavascriptInvalidImports(
namedExport.identifierNode.text === importSpecifier.text,
)
) {
let usages = getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
);
let usages = isTypescript
? getTypescriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
)
: getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
);
usages = usages.filter((usage) => {
return usage.id !== depImport.importIdentifier?.id;
});
Expand Down Expand Up @@ -149,21 +172,30 @@ export function cleanupJavascriptInvalidImports(
export function cleanupUnusedJavascriptImports(
parser: Parser,
sourceCode: string,
isTypescript = false,
) {
const tree = parser.parse(sourceCode);

const imports = getJavascriptImports(parser, tree.rootNode);
const imports = isTypescript
? getTypescriptImports(parser, tree.rootNode)
: getJavascriptImports(parser, tree.rootNode);

const indexesToRemove: { startIndex: number; endIndex: number }[] = [];

imports.forEach((depImport) => {
const importSpecifierToRemove: Parser.SyntaxNode[] = [];
depImport.importSpecifierIdentifiers.forEach((importSpecifier) => {
let usages = getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
);
let usages = isTypescript
? getTypescriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
)
: getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
importSpecifier,
);
usages = usages.filter((usage) => {
return usage.id !== importSpecifier.id;
});
Expand All @@ -175,11 +207,17 @@ export function cleanupUnusedJavascriptImports(

let removeDefaultImport = false;
if (depImport.importIdentifier) {
let usages = getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
);
let usages = isTypescript
? getTypescriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
)
: getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.importIdentifier,
);
usages = usages.filter((usage) => {
return usage.id !== depImport.importIdentifier?.id;
});
Expand All @@ -192,7 +230,7 @@ export function cleanupUnusedJavascriptImports(
if (
importSpecifierToRemove.length ===
depImport.importSpecifierIdentifiers.length &&
removeDefaultImport
(removeDefaultImport || !depImport.importIdentifier)
) {
indexesToRemove.push({
startIndex: depImport.node.startIndex,
Expand Down
Loading

0 comments on commit a648125

Please sign in to comment.