Skip to content
This repository has been archived by the owner on Jan 13, 2023. It is now read-only.

Added the ability to generate/scaffold a React.FunctionComponent #300

Merged
merged 11 commits into from
Jan 16, 2020
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
},
"scripts": {
"format": "npm-run-all format:*",
"format:js": "prettier --write {.,**}/*.js",
"format:json": "prettier --write {.,**}/*.json",
"format:md": "prettier --write {.,**}/*.md",
"format:ts": "prettier --write {.,**}/*.{ts,tsx}",
"format:js": "prettier --write '{.,**}/*.js'",
"format:json": "prettier --write '{.,**}/*.json'",
"format:md": "prettier --write '{.,**}/*.md'",
"format:ts": "prettier --write '{.,**}/*.{ts,tsx}'",
"lint": "eslint src test --ext .ts --fix",
"test": "yarn build && jest --runInBand && yarn lint && yarn clean",
"watch": "jest --runInBand --watch",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ To keep your React Native app updated:

To keep your Ignite Bowser based app updated:

- [ignite-bowser-difff-purge](https://github.com/nirre7/ignite-bowser-diff-purge) To help you see the diffs between versions
- [ignite-bowser-diff-purge](https://github.com/nirre7/ignite-bowser-diff-purge) To help you see the diffs between versions

## TypeScript

Expand Down
55 changes: 48 additions & 7 deletions src/commands/generate/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { GluegunToolbox } from "gluegun"
export const description = "Generates a component, supporting files, and a storybook test."
export const run = async function(toolbox: GluegunToolbox) {
// grab some features
const { parameters, strings, print, ignite, patching, filesystem } = toolbox
const { pascalCase, isBlank } = strings
const { parameters, strings, print, ignite, patching, filesystem, prompt } = toolbox
const { pascalCase, camelCase, isBlank } = strings

// validation
if (isBlank(parameters.first)) {
Expand All @@ -13,21 +13,62 @@ export const run = async function(toolbox: GluegunToolbox) {
return
}

let componentType
if (!parameters.options["function-component"] && !parameters.options["stateless-function"]) {
const componentTypes = [
{
name: "functionComponent",
message: "React.FunctionComponent, aka \"hooks component\"",
},
{
name: "statelessFunction",
message: "Stateless function, aka the \"classic\" ignite-bowser component",
},
]

const { component } = await prompt.ask([
{
name: "component",
message: "Which type of component do you want to generate?",
type: "select",
choices: componentTypes,
},
])
componentType = component
}

const name = parameters.first
const pascalName = pascalCase(name)
const camelCaseName = camelCase(name)
const props = { name, pascalName, camelCaseName }

const props = { name, pascalName }
const jobs = [
{
template: 'component.tsx.ejs',
target: `app/components/${name}/${name}.tsx`
},
{
template: 'component.story.tsx.ejs',
target: `app/components/${name}/${name}.story.tsx`
},
{
template: 'styles.ts.ejs',
target: `app/components/${name}/${name}.styles.ts`
}
]

if (componentType === "functionComponent" || parameters.options["function-component"]) {
jobs.push(
{
template: 'function-component.tsx.ejs',
target: `app/components/${name}/${name}.tsx`
}
)
} else if (componentType === "statelessFunction" || parameters.options["stateless-function"]) {
jobs.push(
{
template: 'component.tsx.ejs',
target: `app/components/${name}/${name}.tsx`
}
)
}

await ignite.copyBatch(toolbox, jobs, props)

// patch the barrel export file
Expand Down
1 change: 1 addition & 0 deletions templates/component.tsx.ejs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react"
import { View, ViewStyle } from "react-native"
import { Text } from "../"
import { <%= props.camelCaseName %>Styles as styles } from "./<%= props.name %>.styles"

export interface <%= props.pascalName %>Props {
/**
Expand Down
23 changes: 23 additions & 0 deletions templates/function-component.tsx.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as React from "react"
import { View } from "react-native"
import { useObserver } from "mobx-react-lite"
import { Text } from "../"
import { useStores } from "../../models/root-store"
import { <%= props.camelCaseName %>Styles as styles } from "./<%= props.name %>.styles"

export interface <%= props.pascalName %>Props {}

/**
* React.FunctionComponent for your hook(s) needs
*
* Component description here for TypeScript tips.
*/
export const <%= props.pascalName %>: React.FunctionComponent<<%= props.pascalName %>Props> = props => {
// const { someStore } = useStores()

return useObserver(() => (
<View style={styles.WRAPPER}>
<Text>Hi Func</Text>
</View>
))
}
7 changes: 7 additions & 0 deletions templates/styles.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ViewStyle } from "react-native"

export const <%= props.camelCaseName %>Styles = {
WRAPPER: {
justifyContent: 'center'
} as ViewStyle
}
23 changes: 16 additions & 7 deletions test/generators-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,22 @@ describe("a generated app", () => {
)
})

test("generates a component", async () => {
const simpleComponent = "Simple"
await execa(IGNITE, ["g", "component", simpleComponent], { preferLocal: false })
expect(jetpack.exists(`app/components/${simpleComponent}/${simpleComponent}.tsx`)).toBe("file")
expect(jetpack.exists(`app/components/${simpleComponent}/${simpleComponent}.story.tsx`)).toBe(
"file",
)
test("generates a stateless function", async () => {
const statelessFunction = "Stateless"
await execa(IGNITE, ["g", "component", statelessFunction, "--stateless-function"], { preferLocal: false })
expect(jetpack.exists(`app/components/${statelessFunction}/${statelessFunction}.tsx`)).toBe("file")
expect(jetpack.exists(`app/components/${statelessFunction}/${statelessFunction}.story.tsx`)).toBe("file")
expect(jetpack.exists(`app/components/${statelessFunction}/${statelessFunction}.styles.ts`)).toBe("file")
const lint = await execa("npm", ["-s", "run", "lint"])
expect(lint.stderr).toBe("")
})

test("generates a function component", async () => {
const functionComponent = "FunctionComponent"
await execa(IGNITE, ["g", "component", functionComponent, "--function-component"], { preferLocal: false })
expect(jetpack.exists(`app/components/${functionComponent}/${functionComponent}.tsx`)).toBe("file")
expect(jetpack.exists(`app/components/${functionComponent}/${functionComponent}.story.tsx`)).toBe("file")
expect(jetpack.exists(`app/components/${functionComponent}/${functionComponent}.styles.ts`)).toBe("file")
const lint = await execa("npm", ["-s", "run", "lint"])
expect(lint.stderr).toBe("")
})
Expand Down