Skip to content

Commit

Permalink
feat: externalize config
Browse files Browse the repository at this point in the history
  • Loading branch information
Evyweb committed Sep 23, 2024
1 parent 53d2e8d commit f560a1e
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 65 deletions.
42 changes: 0 additions & 42 deletions bin/next-server-action-scan.ts

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@evyweb/node-script-template",
"name": "@evyweb/next-server-action-scan",
"version": "1.0.0",
"description": "List all your server actions of your NextJS project",
"main": "dist/index.js",
Expand All @@ -9,7 +9,7 @@
"dist/"
],
"bin": {
"next-server-action-scan": "./bin/next-server-action-scan.js"
"next-server-action-scan": "dist/index.js"
},
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
Expand Down
33 changes: 25 additions & 8 deletions specs/extractServerActions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ describe('extractServerActions', () => {
export const serverAction3 = () => console.log('serverAction3');
export const serverAction4 = ServerAction<CreateCharacterActionRequest, CreateCharacterActionResponse>({
request: {
schema: CreateCharacterActionRequest.schema,
},
handler: async ({name}): Promise<CreateCharacterActionResponse> => {
const command = new CreateCharacterCommand(name);
const commandBus = inject<Bus<Command>>(DI.CommandBus);
const newCharacterId = await commandBus.execute<string>(command);
return {newCharacterId};
}
});
export const test = 'nothing';
`);

Expand All @@ -32,9 +46,10 @@ describe('extractServerActions', () => {

// Assert
expect(serverActions).toEqual([
{fileName: 'serverAction.ts', functionName: 'serverAction1'},
{fileName: 'serverAction.ts', functionName: 'serverAction2'},
{fileName: 'serverAction.ts', functionName: 'serverAction3'},
{fileName: '/serverAction.ts', functionName: 'serverAction1'},
{fileName: '/serverAction.ts', functionName: 'serverAction2'},
{fileName: '/serverAction.ts', functionName: 'serverAction3'},
{fileName: '/serverAction.ts', functionName: 'serverAction4'},
]);
});
});
Expand All @@ -43,7 +58,7 @@ describe('extractServerActions', () => {
describe('When functions inside the file has the "use server" directive', () => {
it('should add the functions to the list of server actions', () => {
// Arrange
const sourceFile = project.createSourceFile('serverAction.ts', `
const sourceFile = project.createSourceFile('src/serverAction.ts', `
export function serverAction1() {
"use server";
console.log('serverAction1');
Expand All @@ -61,17 +76,19 @@ describe('extractServerActions', () => {
}
}
export const nothing = () => {};
export const nothing1 = () => {};
export const nothing2 = () => 5;
export const nothing3 = function() {};
`);

// Act
const serverActions = extractServerActions(sourceFile);

// Assert
expect(serverActions).toEqual([
{fileName: 'serverAction.ts', functionName: 'serverAction1'},
{fileName: 'serverAction.ts', functionName: 'serverAction2'},
{fileName: 'serverAction.ts', functionName: 'serverAction3'},
{fileName: '/src/serverAction.ts', functionName: 'serverAction1'},
{fileName: '/src/serverAction.ts', functionName: 'serverAction2'},
{fileName: '/src/serverAction.ts', functionName: 'serverAction3'},
]);
});
});
Expand Down
6 changes: 3 additions & 3 deletions specs/getServerActionsFromSourceFiles.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ describe('getServerActionsFromSourceFiles', () => {

// Assert
expect(result).toEqual([
{fileName: 'firstServerAction.ts', functionName: 'firstServerAction'},
{fileName: 'secondServerAction.ts', functionName: 'secondServerAction'},
{fileName: 'thirdServerAction.tsx', functionName: 'thirdServerAction'},
{fileName: '/firstServerAction.ts', functionName: 'firstServerAction'},
{fileName: '/secondServerAction.ts', functionName: 'secondServerAction'},
{fileName: '/thirdServerAction.tsx', functionName: 'thirdServerAction'},
]);
});
});
25 changes: 16 additions & 9 deletions src/extractServerActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function extractServerActions(sourceFile: SourceFile): ServerAction[] {
return [];
}

const fileName = sourceFile.getBaseName();
const fileName = sourceFile.getFilePath();

const functionNames = hasUseServerDirectiveOnTopOfFile(sourceFile)
? getExportedFunctionNames(sourceFile)
Expand All @@ -24,12 +24,13 @@ export function extractServerActions(sourceFile: SourceFile): ServerAction[] {
}

function isEmptyFile(sourceFile: SourceFile): boolean {
return sourceFile.getStatements().length === 0;
const statements = sourceFile.getStatements();
return statements.length === 0;
}

function hasUseServerDirectiveOnTopOfFile(sourceFile: SourceFile): boolean {
const firstStatement = sourceFile.getStatements()[0];
return isUseServerDirectiveStatement(firstStatement);
const statements = sourceFile.getStatements();
return statements.some(isUseServerDirectiveStatement);
}

function isUseServerDirectiveStatement(statement: Statement): boolean {
Expand All @@ -55,7 +56,7 @@ function getFunctionName(node: Node): string | undefined {

if (Node.isVariableDeclaration(node)) {
const initializer = node.getInitializer();
if (initializer && (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
if (initializer && (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer) || Node.isCallExpression(initializer))) {
return node.getName();
}
}
Expand Down Expand Up @@ -91,12 +92,18 @@ function getFunctionNameIfContainsDirective(node: Node): string | undefined {
function hasUseServerDirectiveInBody(
functionNode: FunctionDeclaration | ArrowFunction | FunctionExpression
): boolean {
const body = functionNode.getBody()!;
const body = functionNode.getBody();

if (!body || !body.isKind(SyntaxKind.Block)) {
return false;
}

const bodyBlock = body.asKind(SyntaxKind.Block)!;
const firstStatement = bodyBlock.getStatements()[0];
return firstStatement ? isUseServerDirectiveStatement(firstStatement) : false;
const statements = bodyBlock.getStatements();

return statements.some(isUseServerDirectiveStatement);
}

function createServerActions(fileName: string, functionNames: string[]): ServerAction[] {
return functionNames.map(functionName => ({fileName, functionName}));
return functionNames.map(functionName => ({ fileName, functionName }));
}
31 changes: 30 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
export * from '../bin/next-server-action-scan';
#!/usr/bin/env node
import { Project } from "ts-morph";
import * as path from "path";
import * as fs from "fs";

import {getServerActionsFromSourceFiles} from "./getServerActionsFromSourceFiles";

function getGlobsFromPackageJson(): string[] {
const packageJsonPath = path.resolve(process.cwd(), "package.json");

if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
return packageJson.nextServerActionScan?.files || [];
}

throw new Error("No package.json found or no file to include defined in nextServerActionScan options.");
}

const filesToScan = getGlobsFromPackageJson();
const project = new Project({
tsConfigFilePath: path.resolve(process.cwd(), "tsconfig.json"),
skipAddingFilesFromTsConfig: true,
});

project.addSourceFilesAtPaths(filesToScan);

const serverActions = getServerActionsFromSourceFiles(project.getSourceFiles());

console.log("Server actions found:");
console.table(serverActions);

0 comments on commit f560a1e

Please sign in to comment.