-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VACMS-10355 component generator (#305)
- Loading branch information
Showing
209 changed files
with
1,238 additions
and
219 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,21 @@ | ||
# dependencies & GHA | ||
.github | ||
.next | ||
.yarn | ||
.swc | ||
coverage | ||
node_modules | ||
public | ||
yarn.lock | ||
storybook-static | ||
out | ||
.yarnrc.yml | ||
|
||
# test output | ||
coverage | ||
|
||
# static outputs | ||
public | ||
.next | ||
out | ||
typedocs | ||
storybook-static | ||
packages/*/dist | ||
|
||
# prettier doesn't play well with .hbs format | ||
generator-templates/ |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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,24 @@ | ||
# Next-build generator usage | ||
|
||
Developers contributing to this project can use [plop](https://plopjs.com/) to generate new files in a consistent manner. | ||
|
||
There can be many moving parts that need to be aligned when adding a new data query or content type to next-build. Running `yarn plop` will start a cli tool that handles most of boilerplate, freeing you up to focus on the task at hand. | ||
|
||
Run `yarn plop` to view a list of generators available to this project. | ||
|
||
See `plopfile.js` for specifics of each generator. | ||
|
||
Templates for existing generators can be found inside of `generator-templates`. | ||
|
||
## What is Plop? | ||
|
||
> Plop is what I like to call a "micro-generator framework." Now, I call it that because it is a small tool that gives you a simple way to generate code or any other type of flat text files in a consistent way. You see, we all create structures and patterns in our code (routes, controllers, components, helpers, etc). These patterns change and improve over time so when you need to create a NEW insert-name-of-pattern-here, it's not always easy to locate the files in your codebase that represent the current "best practice." That's where plop saves you. With plop, you have your "best practice" method of creating any given pattern in CODE. Code that can easily be run from the terminal by typing plop. Not only does this save you from hunting around in your codebase for the right files to copy, but it also turns "the right way" into "the easiest way" to make new files. | ||
> If you boil plop down to its core, it is basically glue code between inquirer prompts and handlebar templates. | ||
Helpful documentation: | ||
|
||
- [Plop docs](https://plopjs.com/documentation/) | ||
- [Inquirer options](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md#question) | ||
- [Handlebars](https://github.com/handlebars-lang/handlebars.js?tab=readme-ov-file#usage) | ||
- [Example plopfile](https://github.com/plopjs/plop/blob/main/packages/plop/tests/examples/javascript/plopfile.js) |
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,11 @@ | ||
type {{pascalCase name}}Props = { | ||
title: string | ||
} | ||
|
||
export function {{pascalCase name}}({ title }: {{pascalCase name}}Props) { | ||
return ( | ||
<div> | ||
<p>{title}</p> | ||
</div> | ||
) | ||
} |
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,21 @@ | ||
const { test, expect } = require('../utils/next-test') | ||
|
||
test.describe('{{titleCase name}}', () => { | ||
test('{{titleCase name}} page renders', async ({ | ||
page, | ||
}) => { | ||
await page.goto('/update-this-link') | ||
await expect(page).toHaveURL('/update-this-link') | ||
}) | ||
|
||
test('Should render without a11y errors', async ({ | ||
page, | ||
makeAxeBuilder, | ||
}) => { | ||
await page.goto('/update-this-link') | ||
|
||
const accessibilityScanResults = await makeAxeBuilder().analyze() | ||
|
||
expect(accessibilityScanResults.violations).toEqual([]) | ||
}) | ||
}) |
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,17 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
|
||
import { {{pascalCase name}} } from './index' | ||
|
||
const meta: Meta<typeof {{pascalCase name}}> = { | ||
title: 'Uncategorized/{{pascalCase name}}', | ||
component: {{pascalCase name}}, | ||
} | ||
export default meta | ||
|
||
type Story = StoryObj<typeof {{pascalCase name}}> | ||
|
||
export const Example: Story = { | ||
args: { | ||
title: 'Hello World!' | ||
}, | ||
} |
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,11 @@ | ||
import { render, screen } from '@testing-library/react' | ||
import { {{pascalCase name}} } from './index' | ||
|
||
|
||
describe('{{pascalCase name}} with valid data', () => { | ||
test('renders {{pascalCase name}} component', () => { | ||
render(<{{pascalCase name}} title={'Hello world'} />) | ||
|
||
expect(screen.queryByText(/Hello world/)).toBeInTheDocument() | ||
}) | ||
}) |
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,4 @@ | ||
{ | ||
"note": "Replace this data! The file should contain an example response for the desired query before formatting", | ||
"example": "See src/mocks/newsStory.mock.json for an example response from va.gov-cms's JSON:API" | ||
} |
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,65 @@ | ||
import { QueryData, QueryFormatter, QueryParams } from 'next-drupal-query' | ||
import { drupalClient } from '@/lib/drupal/drupalClient' | ||
import { queries } from '.' | ||
import { Node{{pascalCase name}} } from '@/types/drupal/node' | ||
import { {{pascalCase name}} } from '@/types/formatted/{{pascalCase name}}' | ||
import { ExpandedStaticPropsContext } from '@/lib/drupal/staticProps' | ||
|
||
// Define the query params for fetching node--{{snakeCase name}}. | ||
export const params: QueryParams<null> = () => { | ||
return queries | ||
.getParams() | ||
// uncomment to add referenced entity data to the response | ||
// .addInclude([ | ||
// 'field_media', | ||
// 'field_media.image', | ||
// 'field_administration', | ||
// ]) | ||
} | ||
|
||
// Define the option types for the data loader. | ||
export type {{pascalCase name}}DataOpts = { | ||
id: string | ||
context?: ExpandedStaticPropsContext | ||
} | ||
|
||
// Implement the data loader. | ||
export const data: QueryData<{{pascalCase name}}DataOpts, Node{{pascalCase name}}> = async ( | ||
opts | ||
): Promise<Node{{pascalCase name}}> => { | ||
const entity = opts?.context?.preview | ||
? // need to use getResourceFromContext for unpublished revisions | ||
await drupalClient.getResourceFromContext<Node{{pascalCase name}}>( | ||
'node--{{snakeCase name}}', | ||
opts.context, | ||
{ | ||
params: params().getQueryObject(), | ||
} | ||
) | ||
: // otherwise just lookup by uuid | ||
await drupalClient.getResource<Node{{pascalCase name}}>( | ||
'node--{{snakeCase name}}', | ||
opts.id, | ||
{ | ||
params: params().getQueryObject(), | ||
} | ||
) | ||
|
||
return entity | ||
} | ||
|
||
export const formatter: QueryFormatter<Node{{pascalCase name}}, {{pascalCase name}}> = ( | ||
entity: Node{{pascalCase name}} | ||
) => { | ||
return { | ||
id: entity.id, | ||
entityId: entity.drupal_internal__nid, | ||
entityPath: entity.path.alias, | ||
type: entity.type, | ||
published: entity.status, | ||
moderationState: entity.moderation_state, | ||
title: entity.title, | ||
metatags: entity.metatag, | ||
breadcrumbs: entity.breadcrumbs | ||
} | ||
} |
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,25 @@ | ||
import { {{pascalCase name}} } from '@/types/drupal/node' | ||
import { queries } from '@/data/queries' | ||
import mockData from '@/mocks/{{pascalCase name}}.mock.json' | ||
|
||
const {{pascalCase name}}Mock: {{pascalCase name}} = mockData | ||
|
||
describe('{{pascalCase name}} formatData', () => { | ||
let windowSpy | ||
|
||
beforeEach(() => { | ||
windowSpy = jest.spyOn(window, 'window', 'get') | ||
}) | ||
|
||
afterEach(() => { | ||
windowSpy.mockRestore() | ||
}) | ||
|
||
test('outputs formatted data', () => { | ||
windowSpy.mockImplementation(() => undefined) | ||
|
||
expect( | ||
queries.formatData('node--{{snakeCase name}}', {{pascalCase name}}Mock) | ||
).toMatchSnapshot() | ||
}) | ||
}) |
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 {{pascalCase name}} = { | ||
title: string | ||
} |
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,131 @@ | ||
// Run `yarn plop` to use the generators defined in this file. | ||
// see READMEs/generators.md for more information. | ||
module.exports = function (plop) { | ||
// Create a new component with a test stub and Storybook entry. | ||
plop.setGenerator('Component', { | ||
description: 'New React component', | ||
prompts: [ | ||
{ | ||
type: 'input', | ||
name: 'name', | ||
message: 'Component Name', | ||
}, | ||
], | ||
actions: [ | ||
{ | ||
type: 'add', | ||
path: 'src/templates/components/{{camelCase name}}/index.tsx', | ||
templateFile: 'generator-templates/component/index.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/templates/components/{{camelCase name}}/index.test.tsx', | ||
templateFile: 'generator-templates/component/test.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/templates/components/{{camelCase name}}/{{camelCase name}}.stories.ts', | ||
templateFile: 'generator-templates/component/story.hbs', | ||
}, | ||
], | ||
}) | ||
|
||
// Create a new data query. This defaults to Drupal boilerplate. | ||
// TODO: option for non-drupal data sources. | ||
plop.setGenerator('Query', { | ||
description: 'New Data query', | ||
prompts: [ | ||
{ | ||
type: 'input', | ||
name: 'name', | ||
message: 'Query name please', | ||
}, | ||
], | ||
actions: [ | ||
{ | ||
type: 'add', | ||
path: 'src/data/queries/{{camelCase name}}.ts', | ||
templateFile: 'generator-templates/query/query.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/data/queries/tests/{{camelCase name}}.test.tsx', | ||
templateFile: 'generator-templates/query/test.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/mocks/{{camelCase name}}.mock.json', | ||
templateFile: 'generator-templates/query/mock.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/types/formatted/{{camelCase name}}.ts', | ||
templateFile: 'generator-templates/type/formatted.hbs', | ||
}, | ||
// Strings can be added to print a comment in the terminal. | ||
'You will need to manually import & add your query to src/data/queries/index.ts', | ||
'Be sure to also run `yarn test:u` to update test snapshots for your new query!', | ||
], | ||
}) | ||
|
||
// Generate all files needed to render a new content type from Drupal. | ||
// It also generates an additional test file for E2E testing the page via Playwright. | ||
plop.setGenerator('Content Type', { | ||
description: 'Generate boilerplate for new FE Page based on Content Type', | ||
prompts: [ | ||
{ | ||
type: 'input', | ||
name: 'name', | ||
message: 'Page name please', | ||
}, | ||
], | ||
actions: [ | ||
// Create query files for new Page type. | ||
{ | ||
type: 'add', | ||
path: 'src/data/queries/{{camelCase name}}.ts', | ||
templateFile: 'generator-templates/query/query.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/data/queries/tests/{{camelCase name}}.test.tsx', | ||
templateFile: 'generator-templates/query/test.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/mocks/{{camelCase name}}.mock.json', | ||
templateFile: 'generator-templates/query/mock.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/types/formatted/{{camelCase name}}.ts', | ||
templateFile: 'generator-templates/type/formatted.hbs', | ||
}, | ||
'You will need to manually import & add your query to src/data/queries/index.ts', | ||
'Be sure to also run `yarn test:u` to update test snapshots for your new query!', | ||
// Create react component + test files for new Page type. | ||
{ | ||
type: 'add', | ||
path: 'src/templates/layouts/{{camelCase name}}/index.tsx', | ||
templateFile: 'generator-templates/component/index.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/templates/layouts/{{camelCase name}}/index.test.tsx', | ||
templateFile: 'generator-templates/component/test.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'src/templates/layouts/{{camelCase name}}/{{camelCase name}}.stories.ts', | ||
templateFile: 'generator-templates/component/story.hbs', | ||
}, | ||
{ | ||
type: 'add', | ||
path: 'playwright/tests/{{camelCase name}}.spec.js', | ||
templateFile: 'generator-templates/component/playwright.hbs', | ||
}, | ||
], | ||
}) | ||
|
||
// Add additional generators here | ||
} |
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
Oops, something went wrong.