Skip to content

Commit

Permalink
fix(cli): add resource generating invalid react component name (refin…
Browse files Browse the repository at this point in the history
…edev#6226)

Co-authored-by: Ali Emir Şen <senaliemir@gmail.com>
  • Loading branch information
alicanerdurmaz and aliemir committed Aug 5, 2024
1 parent 4e37590 commit 9806a36
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 38 deletions.
14 changes: 14 additions & 0 deletions .changeset/odd-squids-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@refinedev/cli": patch
---

fix: `refine add resource` generating invalid React component name. #6225

`refine add resource blog-posts` command was generating invalid React component name when the resource name contains a hyphen. This issue has been fixed by converting the resource name to PascalCase before generating the React component name.

```diff
- export const Blog-PostsList: React.FC = () => {};
+ export const BlogPostsList: React.FC = () => {};
```

[Resolves #6225](https://github.com/refinedev/refine/issues/6225)
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@npmcli/package-json": "^5.2.0",
"@refinedev/devtools-server": "1.1.34",
"boxen": "^5.1.2",
"camelcase": "^6.2.0",
"cardinal": "^2.1.1",
"center-align": "1.0.1",
"chalk": "^4.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { existsSync, readFileSync, rmdirSync } from "fs-extra";
const srcDirPath = `${__dirname}/../../../..`;

describe("add", () => {
beforeEach(() => {
beforeAll(() => {
// usefull for speed up the tests.
jest.spyOn(console, "log").mockImplementation();

jest.spyOn(testTargetModule, "installInferencer").mockImplementation();
});

Expand Down Expand Up @@ -84,4 +87,76 @@ describe("add", () => {
// cleanup
rmdirSync(reactComponentRootDirPath, { recursive: true });
});

it.each([
{
resourceName: "blog-posts",
folderName: "blog-posts",
componentNamesByActions: {
list: "BlogPostsList",
create: "BlogPostsCreate",
show: "BlogPostsShow",
edit: "BlogPostsEdit",
},
},
{
resourceName: "blog-post",
folderName: "blog-posts",
componentNamesByActions: {
list: "BlogPostList",
create: "BlogPostCreate",
show: "BlogPostShow",
edit: "BlogPostEdit",
},
},
{
resourceName: "product",
folderName: "products",
componentNamesByActions: {
list: "ProductList",
create: "ProductCreate",
show: "ProductShow",
edit: "ProductEdit",
},
},
{
resourceName: "blogPosts",
folderName: "blogposts",
componentNamesByActions: {
list: "BlogPostsList",
create: "BlogPostsCreate",
show: "BlogPostsShow",
edit: "BlogPostsEdit",
},
},
])(
"should generate components and folders for '$resourceName'",
(testCase) => {
jest
.spyOn(utilsProject, "getProjectType")
.mockReturnValue(ProjectTypes.VITE);

jest
.spyOn(testTargetModule, "getCommandRootDir")
.mockReturnValue(srcDirPath);

const actions = ["list", "create", "show", "edit"] as const;
testTargetModule.createResources({ actions: actions.join(",") }, [
testCase.resourceName,
]);

const reactComponentRootDirPath = `${srcDirPath}/pages`;

actions.forEach((action) => {
const componentFilePath = `${reactComponentRootDirPath}/${testCase.folderName}/${action}.tsx`;
const componentContent = readFileSync(componentFilePath, "utf-8");
expect(componentContent).toContain(
`const ${testCase.componentNamesByActions[action]} = () => {`,
);
});

// cleanup
rmdirSync(reactComponentRootDirPath, { recursive: true });
},
);
});
9 changes: 9 additions & 0 deletions packages/cli/src/utils/compile/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
writeFileSync,
unlinkSync,
} from "fs-extra";
import { getComponentNameByResource } from "@utils/resource";

export const compile = (filePath: string, params: any): string => {
const content = readFileSync(filePath);
Expand Down Expand Up @@ -39,6 +40,14 @@ export const compile = (filePath: string, params: any): string => {
return string.charAt(0).toUpperCase() + string.slice(1);
});

Handlebars.registerHelper("getComponentNameByResource", (string) => {
if (!string) {
return;
}

return getComponentNameByResource(string);
});

const template = Handlebars.compile(content.toString());
return template(params);
};
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/src/utils/resource/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ProjectTypes } from "@definitions/projectTypes";
import camelCase from "camelcase";

export const getResourcePath = (
projectType: ProjectTypes,
Expand Down Expand Up @@ -54,3 +55,10 @@ export const getFilesPathByProject = (projectType?: ProjectTypes) => {
return "./src";
}
};

export const getComponentNameByResource = (resource: string): string => {
return camelCase(resource, {
preserveConsecutiveUppercase: true,
pascalCase: true,
});
};
2 changes: 1 addition & 1 deletion packages/cli/templates/resource/components/create.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { {{formatInferencerComponent uiFramework}}Inferencer } from "@refinedev/
import { HeadlessInferencer } from "@refinedev/inferencer/headless";
{{/if}}

export const {{capitalize resource}}Create = () => {
export const {{getComponentNameByResource resource}}Create = () => {
{{#if uiFramework}}
return <{{formatInferencerComponent uiFramework}}Inferencer />;
{{else}}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/resource/components/edit.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { {{formatInferencerComponent uiFramework}}Inferencer } from "@refinedev/
import { HeadlessInferencer } from "@refinedev/inferencer/headless";
{{/if}}

export const {{capitalize resource}}Edit = () => {
export const {{getComponentNameByResource resource}}Edit = () => {
{{#if uiFramework}}
return <{{formatInferencerComponent uiFramework}}Inferencer />;
{{else}}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/resource/components/list.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { {{formatInferencerComponent uiFramework}}Inferencer } from "@refinedev/
import { HeadlessInferencer } from "@refinedev/inferencer/headless";
{{/if}}

export const {{capitalize resource}}List = () => {
export const {{getComponentNameByResource resource}}List = () => {
{{#if uiFramework}}
return <{{formatInferencerComponent uiFramework}}Inferencer />;
{{else}}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/resource/components/show.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { {{formatInferencerComponent uiFramework}}Inferencer } from "@refinedev/
import { HeadlessInferencer } from "@refinedev/inferencer/headless";
{{/if}}

export const {{capitalize resource}}Show = () => {
export const {{getComponentNameByResource resource}}Show = () => {
{{#if uiFramework}}
return <{{formatInferencerComponent uiFramework}}Inferencer />;
{{else}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { {{capitalize resource}}Create } from "@components/{{resourceFolderName}}";
import { {{getComponentNameByResource resource}}Create } from "@components/{{resourceFolderName}}";

export default function {{capitalize resource}}CreatePage() {
return <{{capitalize resource}}Create />;
export default function {{getComponentNameByResource resource}}CreatePage() {
return <{{getComponentNameByResource resource}}Create />;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { {{capitalize resource}}Edit } from "@components/{{resourceFolderName}}";
import { {{getComponentNameByResource resource}}Edit } from "@components/{{resourceFolderName}}";

export default function {{capitalize resource}}EditPage() {
return <{{capitalize resource}}Edit />;
export default function {{getComponentNameByResource resource}}EditPage() {
return <{{getComponentNameByResource resource}}Edit />;
};
6 changes: 3 additions & 3 deletions packages/cli/templates/resource/pages/next/page.tsx.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { {{capitalize resource}}List } from "@components/{{resourceFolderName}}";
import { {{getComponentNameByResource resource}}List } from "@components/{{resourceFolderName}}";

export default function {{capitalize resource}}ListPage() {
return <{{capitalize resource}}List />;
export default function {{getComponentNameByResource resource}}ListPage() {
return <{{getComponentNameByResource resource}}List />;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { {{capitalize resource}}Show } from "@components/{{resourceFolderName}}";
import { {{getComponentNameByResource resource}}Show } from "@components/{{resourceFolderName}}";

export default function {{capitalize resource}}ShowPage() {
return <{{capitalize resource}}Show />;
export default function {{getComponentNameByResource resource}}ShowPage() {
return <{{getComponentNameByResource resource}}Show />;
};
45 changes: 24 additions & 21 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9806a36

Please sign in to comment.