-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Next.js Support to ts-codegenerator (#12)
* feat: Add Next.js codebase scanning and server action generation - Add Next.js specific types, scanner, and generator - Update root index.ts to use consistent export strategy * feat: add type support for jest - Add new function `analyzeNextjsSourceFiles` to handle the source files - Update `scanNextjsCodebase` to call `analyzeNextjsSourceFiles` and return the result - Add tests - Update imports - add @next/eslint-plugin-next to next project
- Loading branch information
1 parent
52b694c
commit 6ebd3fc
Showing
11 changed files
with
196 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@ozhanefe/ts-codegenerator": minor | ||
--- | ||
|
||
nextjs support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@ozhanefe/ts-codegenerator": minor | ||
--- | ||
|
||
add nextjs parsing/generator features |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
export { getFunctionInfoFromNode, parseFunctionsFromFile } from "./parser"; | ||
export { | ||
getFunctionInfoFromNode, | ||
parseFunctionsFromFile, | ||
parseFunctionsFromText, | ||
} from "./parser"; | ||
export { getFunctionVariables } from "./utils"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { Project } from "ts-morph"; | ||
import { | ||
analyzeNextjsSourceFiles, | ||
generateServerAction, | ||
ServerActionInfo, | ||
} from "../index"; | ||
|
||
describe("Next.js functionality", () => { | ||
let project: Project; | ||
|
||
beforeEach(() => { | ||
project = new Project({ useInMemoryFileSystem: true }); | ||
}); | ||
|
||
describe("analyzeNextjsSourceFiles", () => { | ||
it("should correctly identify and parse server actions", () => { | ||
const serverActionCode = ` | ||
"use server"; | ||
export async function submitForm(data: FormData) { | ||
// Server action logic | ||
} | ||
export async function deleteItem(id: string) { | ||
// Delete item logic | ||
} | ||
`; | ||
|
||
const sourceFile = project.createSourceFile( | ||
"app/actions.ts", | ||
serverActionCode | ||
); | ||
|
||
const result = analyzeNextjsSourceFiles([sourceFile]); | ||
|
||
expect(result.serverActions).toHaveLength(2); | ||
expect(result.serverActions[0]?.name).toBe("submitForm"); | ||
expect(result.serverActions[1]?.name).toBe("deleteItem"); | ||
}); | ||
|
||
it("should not identify non-server actions", () => { | ||
const regularCode = ` | ||
export function regularFunction() { | ||
// Regular function logic | ||
} | ||
`; | ||
|
||
const sourceFile = project.createSourceFile( | ||
"app/regular.ts", | ||
regularCode | ||
); | ||
|
||
const result = analyzeNextjsSourceFiles([sourceFile]); | ||
|
||
expect(result.serverActions).toHaveLength(0); | ||
}); | ||
}); | ||
|
||
describe("generateServerAction", () => { | ||
it("should generate correct server action code", () => { | ||
const serverActionInfo: ServerActionInfo = { | ||
name: "testAction", | ||
returnType: "Promise<string>", // This could be 'string' or 'Promise<string>', the function should handle both | ||
parameters: [ | ||
{ name: "data", type: "FormData" }, | ||
{ name: "userId", type: "string" }, | ||
], | ||
filePath: "app/actions.ts", | ||
}; | ||
|
||
const generatedCode = generateServerAction(serverActionInfo); | ||
|
||
expect(generatedCode).toContain('"use server";'); | ||
expect(generatedCode).toContain( | ||
"export async function testAction(data: FormData, userId: string): Promise<string>" | ||
); | ||
expect(generatedCode).toContain("// TODO: Implement server action logic"); | ||
expect(generatedCode).toContain('throw new Error("Not implemented");'); | ||
}); | ||
|
||
it("should handle non-Promise return types", () => { | ||
const serverActionInfo: ServerActionInfo = { | ||
name: "testAction", | ||
returnType: "void", | ||
parameters: [], | ||
filePath: "app/actions.ts", | ||
}; | ||
|
||
const generatedCode = generateServerAction(serverActionInfo); | ||
|
||
expect(generatedCode).toContain( | ||
"export async function testAction(): Promise<void>" | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ServerActionInfo } from "./types"; | ||
|
||
export function generateServerAction(info: ServerActionInfo): string { | ||
const parameters = (info.parameters ?? []) | ||
.map((param) => `${param.name}: ${param.type}`) | ||
.join(", "); | ||
|
||
let returnType = info.returnType.replace(/Promise<(.*)>/, "$1"); | ||
|
||
returnType = `Promise<${returnType}>`; | ||
|
||
return `"use server"; | ||
export async function ${info.name}(${parameters}): ${returnType} { | ||
// TODO: Implement server action logic | ||
throw new Error("Not implemented"); | ||
}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export type { NextCodebaseInfo, ServerActionInfo } from "./types"; | ||
export { scanNextjsCodebase, analyzeNextjsSourceFiles } from "./scanner"; | ||
export { generateServerAction } from "./generator"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { Project, SourceFile } from "ts-morph"; | ||
import { ServerActionInfo, NextCodebaseInfo } from "./types"; | ||
|
||
export function scanNextjsCodebase(projectPath: string): NextCodebaseInfo { | ||
const project = new Project(); | ||
project.addSourceFilesAtPaths(`${projectPath}/**/*.ts`); | ||
return analyzeNextjsSourceFiles(project.getSourceFiles()); | ||
} | ||
|
||
export function analyzeNextjsSourceFiles( | ||
sourceFiles: SourceFile[] | ||
): NextCodebaseInfo { | ||
const serverActions: ServerActionInfo[] = []; | ||
|
||
sourceFiles.forEach((sourceFile) => { | ||
if (isServerActionFile(sourceFile)) { | ||
serverActions.push(...extractServerActions(sourceFile)); | ||
} | ||
}); | ||
|
||
return { serverActions }; | ||
} | ||
|
||
function isServerActionFile(sourceFile: SourceFile): boolean { | ||
return sourceFile.getFullText().trim().startsWith('"use server";'); | ||
} | ||
|
||
function extractServerActions(sourceFile: SourceFile): ServerActionInfo[] { | ||
const serverActions: ServerActionInfo[] = []; | ||
|
||
sourceFile.getFunctions().forEach((func) => { | ||
if (func.isAsync()) { | ||
const functionInfo: ServerActionInfo = { | ||
name: func.getName() || "anonymous", | ||
returnType: func.getReturnType().getText(), | ||
parameters: func.getParameters().map((param) => ({ | ||
name: param.getName(), | ||
type: param.getType().getText(), | ||
})), | ||
filePath: sourceFile.getFilePath(), | ||
}; | ||
|
||
serverActions.push(functionInfo); | ||
} | ||
}); | ||
|
||
return serverActions; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FunctionInfo } from "../types"; | ||
|
||
export interface ServerActionInfo extends FunctionInfo { | ||
filePath: string; | ||
} | ||
|
||
export interface NextCodebaseInfo { | ||
serverActions: ServerActionInfo[]; | ||
} |