Skip to content

Commit

Permalink
feat: plop and generators set up (#5)
Browse files Browse the repository at this point in the history
Co-authored-by: Jérémy Fumeron <jeremy.fumeron@ubisoft.com>
  • Loading branch information
JFeremy and Jérémy Fumeron committed Sep 12, 2023
1 parent 911693e commit 8ab9af1
Show file tree
Hide file tree
Showing 40 changed files with 1,128 additions and 35 deletions.
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
node_modules
out
styled-system
public
public
plop-templates
CHANGELOG.md
4 changes: 3 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.next
node_modules
out
styled-system
styled-system
plop-templates
CHANGELOG.md
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
- [‼️ Prerequisites](#-prerequisites)
- [🧪 Running Tests](#-running-tests)
- [🏃 Run Locally](#-run-locally)
- [⚙️ Generate elements](#-generate-elements)
- [📃 Page](#📃-page)
- [✏️ Component](#✏️-component)
- [🎨 UI](#🎨-ui)
- [🚢 DEPLOY TO NETLIFY](#🚢-deploy-to-netlify)
- [🧭 ROADMAP](#-roadmap)
- [🔗 REFERENCES & LINKS](#-references--links)
Expand Down Expand Up @@ -108,6 +112,94 @@ Start the server
yarn start
```

### ⚙️ Generate elements

#### 📃 Page

This script will generate all content for a new page

```bash
yarn generate // choose 📃 Page
> Page name ? // Enter the name of the page (it will be the URL path)
> Page path after [lang] ? // for example for an subpage cv under about-me, enter about-me/
```

Example
```bash
λ yarn generate
yarn run v1.22.19
$ plop
? [PLOP] Please choose a generator. 📃 Page - Create a page
? Page name ? cv
? Page path after [lang] ? about-me/
✔ ++ \src\app\[lang]\about-me\cv\page.tsx
✔ ++ \src\app\[lang]\about-me\cv\__tests__\page.test.tsx
✔ ++ \public\locales\pages\cv.page.ts
✔ _+ \public\locales\pages\index.ts
✔ _+ \public\locales\pages\index.ts
✔ ++ \public\locales\metadatas\cv.metadata.ts
✔ _+ \public\locales\metadatas\index.ts
✔ _+ \public\locales\metadatas\index.ts
Done in 13.43s.
```

---

#### ✏️ Component

This script will generate all content for a new component

```bash
yarn generate // choose ✏️ Component
> Component name ? // Enter the name of the component
> Component required a dedicated translation ? // Your component will have his own translation and not import by another component or page
> Component required a dedicated behavior ? // Your component need a dedicated behavior like a hook to split it between render and features
> Is a client Component ? // Your component will be generated in the client interface
```

Example
```bash
λ yarn generate
yarn run v1.22.19
$ plop
? [PLOP] Please choose a generator. ✏️ Component - Create a reusable component
? Component name ? Footer
? Component required a dedicated translation ? Yes
? Component required a dedicated behavior ? Yes
? Is a client Component ? Yes
✔ ++ \src\components\footer\index.tsx
✔ ++ \src\components\footer\__tests__\index.test.tsx
✔ ++ \src\components\footer\behavior.tsx
✔ ++ \src\components\footer\__tests__\behavior.test.tsx
✔ ++ \public\locales\components\footer.component.ts
✔ _+ \public\locales\components\index.ts
✔ _+ \public\locales\components\index.ts
Done in 15.58s.
```

---

#### 🎨 UI

This script will generate all content for a new UI element like button design or link ...

```bash
yarn generate // choose 🎨 UI
> UI element name ? // Enter the name of the ui element
```

Example
```bash
λ yarn generate
yarn run v1.22.19
$ plop
? [PLOP] Please choose a generator. 🎨 UI - Create a reusable UI element
? UI element name ? link
✔ ++ \src\ui\link\index.tsx
✔ ++ \src\ui\link\design.tsx
Done in 7.54s.
```

## 🚢 DEPLOY TO NETLIFY

Clone this repository on own GitHub account and deploy to Netlify:
Expand Down
5 changes: 3 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ const config = {
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
prefix: '<rootDir>/src/',
}),
modulePathIgnorePatterns: [
collectCoverage: true,
coveragePathIgnorePatterns: [
'src/app/_styles/',
'src/interfaces/',
'src/ui/',
'src/middleware.ts',
],
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts', 'src/**/*.tsx'],
coverageThreshold: {
global: {
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
"license": "MIT",
"private": false,
"scripts": {
"clean": "rimraf .next .swc out coverage",
"clean:all": "yarn clean && rimraf node_modules yarn.lock",
"setup": "yarn install --immutable --immutable-cache --frozen-lockfile",
"prepare": "panda codegen && husky install",
"dev": "next",
"build": "next build",
"postbuild": "next-sitemap",
"start": "next start",
"clean": "rimraf .next .swc out coverage",
"clean:all": "yarn clean && rimraf node_modules yarn.lock",
"lint": "next lint",
"lint:fix": "eslint src --fix && yarn format",
"lint:strict": "eslint --max-warnings=0 src",
Expand All @@ -24,7 +24,8 @@
"test": "jest",
"test:snap-update": "yarn test -u",
"test:watch": "jest --watchAll",
"synchro": "git checkout main && git pull"
"synchro": "git checkout main && git pull",
"generate": "plop"
},
"config": {
"commitizen": {
Expand Down Expand Up @@ -97,6 +98,7 @@
"lint-staged": "^14.x",
"next-sitemap": "^4.x",
"node-fetch": "^3.3.2",
"plop": "^4.x",
"prettier": "^3.x",
"react-test-renderer": "^18.x",
"rimraf": "^5.x",
Expand Down
37 changes: 37 additions & 0 deletions plop-templates/component/behavior.test.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { act, renderHook } from '@testing-library/react';

import use{{pascalCase name}}Behavior from '../behavior';

describe('use{{pascalCase name}}Behavior', () => {
it('should initialize count with the provided initialCount', () => {
const { result } = renderHook(() =>
use{{pascalCase name}}Behavior({ initialCount: 5 }),
);

expect(result.current.count).toBe(5);
});

it('should increment count when increment function is called', () => {
const { result } = renderHook(() =>
use{{pascalCase name}}Behavior({ initialCount: 0 }),
);

act(() => {
result.current.increment();
});

expect(result.current.count).toBe(1);
});

it('should decrement count when decrement function is called', () => {
const { result } = renderHook(() =>
use{{pascalCase name}}Behavior({ initialCount: 3 }),
);

act(() => {
result.current.decrement();
});

expect(result.current.count).toBe(2);
});
});
25 changes: 25 additions & 0 deletions plop-templates/component/behavior.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

import { useState } from 'react';

interface {{pascalCase name}}BehaviorProps {
readonly initialCount: number;
}

const use{{pascalCase name}}Behavior = ({
initialCount,
}: {{pascalCase name}}BehaviorProps) => {
const [count, setCount] = useState(initialCount);

const increment = () => {
setCount(count + 1);
};

const decrement = () => {
setCount(count - 1);
};

return { count, increment, decrement };
};

export default use{{pascalCase name}}Behavior;
16 changes: 16 additions & 0 deletions plop-templates/component/component.test.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { render } from '@testing-library/react';

import {{pascalCase name}} from '..';

describe('{{pascalCase name}}', () => {
it('renders without error', () => {

});

it('component matches snapshot', async () => {
const view = render(
<{{pascalCase name}} />,
);
expect(view.container).toMatchSnapshot();
});
});
49 changes: 49 additions & 0 deletions plop-templates/component/component.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{{#if isClient}}
'use client';

{{/if}}
import React from 'react';

{{#if hasBehavior}}
import use{{pascalCase name}}Behavior from './behavior';
{{/if}}

{{#if hasTranslation}}
import { TLocale } from '@/interfaces';
import { getComponentsTranslation } from '@/utils/translate';

interface {{pascalCase name}}Props {
readonly lang: TLocale;
}
const {{pascalCase name}} = ({ lang }: {{pascalCase name}}Props): React.JSX.Element => {
const { {{camelCase name}}: t{{pascalCase name}} } = getComponentsTranslation(lang, ['{{camelCase name}}']);
{{#if hasBehavior}}
const { tochange } = use{{pascalCase name}}Behavior;
{{/if}}

return (
<div>
{t{{pascalCase name}}['label']}
</div>
);
};
{{else}}
{{#if hasBehavior}}
const {{pascalCase name}} = (): React.JSX.Element => {
const { tochange } = use{{pascalCase name}}Behavior;
return (
<div>
{{pascalCase name}}
</div>
);
};
{{else}}
const {{pascalCase name}} = (): React.JSX.Element => (
<div>
{{pascalCase name}}
</div>
);
{{/if}}
{{/if}}

export default {{pascalCase name}};
8 changes: 8 additions & 0 deletions plop-templates/component/translation.ts.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TLangContent } from '@/interfaces/langs.interface';

export const {{camelCase name}}: TLangContent = {
label: {
en: '🛑 {{camelCase name}} TO CHANGE 🛑',
fr: '🛑 {{camelCase name}} TO CHANGE 🛑',
},
};
61 changes: 61 additions & 0 deletions plop-templates/page/page.test.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { render } from '@testing-library/react';

import {
getComponentsTranslation,
getMetadataPageTranslation,
getPageTranslation,
} from '@/utils/translate';

import {{pascalCase name}}, { generateMetadata, generateStaticParams } from '../page';

jest.mock('@/utils/translate', () => ({
getPageTranslation: jest.fn(),
getComponentsTranslation: jest.fn(),
getMetadataPageTranslation: jest.fn(),
}));



describe('{{pascalCase name}}', () => {
describe('Page', () => {
it('component matches snapshot', async () => {
const view = render(
<{{pascalCase name}} params={ { lang: 'fr' } }/>,
);
expect(view.container).toMatchSnapshot();
});
});


describe('generateStaticParams', () => {
it('should generate static params for all available locales', async () => {
const staticParams = await generateStaticParams();
expect(staticParams).toHaveLength(2);
expect(staticParams).toEqual(
expect.arrayContaining([{ lang: 'en' }, { lang: 'fr' }]),
);
});
});


describe('generateMetadata', () => {
it('should generate metadata for locale', async () => {
const mockMTranslationData = {
title: 'Lorem ipsum dolor sit amet.',
description:
'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illo architecto mollitia blanditiis, accusantium quibusdam possimus officia eligendi eveniet nostrum iure.',
};

(getMetadataPageTranslation as jest.Mock).mockReturnValue(
mockMTranslationData,
);

const metadata = await generateMetadata({ params: { lang: 'en' } });
expect(metadata).toEqual(mockMTranslationData);
expect(getMetadataPageTranslation as jest.Mock).toHaveBeenCalledWith(
'en',
'{{camelCase name}}',
);
});
});
});
Loading

0 comments on commit 8ab9af1

Please sign in to comment.