Skip to content

Commit

Permalink
Merge changes from monorepo
Browse files Browse the repository at this point in the history
  • Loading branch information
ozhanefemeral committed Jul 24, 2024
2 parents 8d72f59 + d99409e commit ebe9ed1
Show file tree
Hide file tree
Showing 17 changed files with 273 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-boats-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ozhanefe/ts-codegenerator": minor
---

add eslint config
5 changes: 5 additions & 0 deletions .changeset/tame-worms-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ozhanefe/ts-codegenerator": minor
---

nextjs support
5 changes: 5 additions & 0 deletions .changeset/warm-pots-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ozhanefe/ts-codegenerator": minor
---

add nextjs parsing/generator features
18 changes: 18 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@repo/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: __dirname,
},
overrides: [
{
files: ["**/*.test.ts", "**/*.test.tsx"],
env: {
jest: true,
},
},
],
};
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# @ozhanefe/ts-codegenerator

## 1.7.0

### Minor Changes

- add eslint config
- nextjs support
- add nextjs parsing/generator features

## 1.6.0

### Minor Changes

- add eslint config
- nextjs support
- add nextjs parsing/generator features

## 1.5.1

### Patch Changes
Expand Down
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
{
"name": "@ozhanefe/ts-codegenerator",
"version": "1.7.0",
"license": "MIT",
"version": "1.5.1",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts --minify --clean",
"release": "pnpm run build && changeset publish",
"lint": "tsc",
"test": "jest"
"lint": "eslint src/**/*.ts",
"test": "jest",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "bun run build && bun run lint && bun run test && changeset publish"
},
"devDependencies": {
"@changesets/cli": "^2.27.7",
"@jest/types": "^29.6.3",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.11",
"jest": "^29.7.0",
"jest-mock-fs": "^1.0.2",
"ts-jest": "^29.2.3",
"ts-node": "^10.9.2",
"tsup": "^8.1.2",
"eslint": "^8.57.0",
"jest": "^29.7.0",
"typescript": "^5.5.3"
},
"peerDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/codebase-scanner.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { scanCodebase } from "../codebase-scanner";
import { CodebaseInfo, FunctionInfo, TypeInfo } from "../types";
import * as path from "path";
import { scanCodebase } from "../codebase-scanner";
import { CodebaseInfo } from "../types";

describe("Codebase Scanner", () => {
it("should scan codebase", () => {
Expand Down
4 changes: 2 additions & 2 deletions src/codebase-scanner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Project, Node, Type, Symbol as TsSymbol } from "ts-morph";
import { FunctionInfo, TypeInfo, CodebaseInfo } from "./types";
import { Node, Project } from "ts-morph";
import { CodebaseInfo, FunctionInfo, TypeInfo } from "./types";

export function scanCodebase(projectPath: string): CodebaseInfo {
const project = new Project();
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ export type {
} from "./types";

export { scanCodebase } from "./codebase-scanner";

export type { NextCodebaseInfo, ServerActionInfo } from "./nextjs";
export { scanNextjsCodebase, generateServerAction } from "./nextjs";
export * as NextJS from "./nextjs";
6 changes: 1 addition & 5 deletions src/module-parser/__tests__/module-parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { Project, SyntaxKind } from "ts-morph";
import {
getFunctionInfoFromNode,
parseFunctionsFromFile,
parseFunctionsFromText,
} from "../parser";
import { getFunctionInfoFromNode, parseFunctionsFromText } from "../parser";

describe("Module Parser", () => {
describe("parseFunctionsFromText", () => {
Expand Down
6 changes: 5 additions & 1 deletion src/module-parser/index.ts
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";
96 changes: 96 additions & 0 deletions src/nextjs/__tests__/nextjs.test.ts
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>"
);
});
});
});
18 changes: 18 additions & 0 deletions src/nextjs/generator.ts
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");
}`;
}
3 changes: 3 additions & 0 deletions src/nextjs/index.ts
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";
48 changes: 48 additions & 0 deletions src/nextjs/scanner.ts
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;
}
9 changes: 9 additions & 0 deletions src/nextjs/types.ts
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[];
}
28 changes: 28 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"target": "es2022",
"verbatimModuleSyntax": false,
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"strict": true,
"noUncheckedIndexedAccess": true,
"moduleResolution": "node",
"module": "ESNext",
"noEmit": true,
"lib": ["es2022", "dom"],
"baseUrl": ".",
"paths": {
"*": ["node_modules/*", "src/*"],
"@/*": ["src/*"]
},
"jsx": "react-jsx",
"types": ["react", "react-dom", "node", "jest"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

{
"compilerOptions": {
"esModuleInterop": true,
Expand Down

0 comments on commit ebe9ed1

Please sign in to comment.