ignite-jhipster
Version:
A React Native boilerplate for JHipster apps.
431 lines (405 loc) • 16.9 kB
JavaScript
/**
* The files portion of the entity generator
*/
module.exports = async function (generator, igniteContext) {
const semver = require('semver')
const pluralize = require('pluralize')
const fs = require('fs-extra')
const { getEntityFormField, getRelationshipFormField } = require('../lib/entity-helpers')
const { ignite, strings, parameters, print } = igniteContext
const { kebabCase, pascalCase, snakeCase, upperCase, camelCase, isBlank, upperFirst } = strings // eslint-disable-line
let name = generator.name
let searchEngine = generator.igniteConfig.searchEngine
let detox = generator.igniteConfig.detox || parameters.options.detox
const props = {
name: pluralize.singular(name),
searchEngine,
getEntityFormField,
getRelationshipFormField,
pascalCase,
detox,
pluralName: pluralize.plural(name),
kebabName: kebabCase(name)
}
const entityFileName = `${name}.json`
const localEntityFilePath = `.jhipster/${entityFileName}`
let entityContainsDate = false
let entityContainsLocalDate = false
// load the entity config into memory
let entityConfig = await fs.readJson(localEntityFilePath)
entityConfig.fields.forEach((field) => {
field.fieldIsEnum = ![
'String',
'Integer',
'Long',
'Float',
'Double',
'BigDecimal',
'LocalDate',
'Instant',
'ZonedDateTime',
'Boolean',
'byte[]',
'ByteBuffer'
].includes(field.fieldType)
if (field.fieldType === 'LocalDate') {
entityContainsLocalDate = true
}
if (field.fieldType === 'LocalDate' || field.fieldType === 'ZonedDateTime') {
entityContainsDate = true
}
})
// these lists are to prevent double imports when there are multiple relations between the same entity
const alreadyIncludedEntities = []
const uniqueEntityRelationships = []
entityConfig.relationships.forEach((relation) => {
if (relation.relationshipType === 'many-to-one') {
relation.ownerSide = true
}
relation.otherEntityNamePlural = pluralize.plural(relation.otherEntityName)
relation.relationshipNamePlural = pluralize.plural(relation.relationshipName)
if (!alreadyIncludedEntities.includes(relation.otherEntityName)) {
alreadyIncludedEntities.push(relation.otherEntityName)
uniqueEntityRelationships.push(relation)
}
})
entityConfig.uniqueOwnerSideRelationships = uniqueEntityRelationships.filter(relation => relation.ownerSide)
entityConfig.ownerSideRelationships = entityConfig.relationships.filter(relation => relation.ownerSide)
props.entityConfig = entityConfig
props.entityContainsDate = entityContainsDate
props.entityContainsLocalDate = entityContainsLocalDate
props.microservicePath = ''
// if a microservice name is available, set the path prefix in the API paths
if (entityConfig.hasOwnProperty('microserviceName')) {
props.microservicePath = `services/${entityConfig.microserviceName}/`
// check if it's an older JHipster version which does not use the 'services' prefix for microservice
try {
const jhipsterConfig = await fs.readJson(`ignite/yo-rc.json`)
const jhipsterVersion = jhipsterConfig['generator-jhipster'].jhipsterVersion
if (jhipsterVersion && semver.lt(jhipsterVersion, '5.9.0')) {
props.microservicePath = `${entityConfig.microserviceName}/`
} else {
}
} catch (e) {
print.warning(`Couldn't find JHipster version, generating v6 microservice routes`)
}
}
const apiFilePath = `${process.cwd()}/app/shared/services/api.js`
const fixtureApiFilePath = `${process.cwd()}/app/shared/services/fixture-api.js`
const reduxIndexFilePath = `${process.cwd()}/app/shared/reducers/index.js`
const sagaIndexFilePath = `${process.cwd()}/app/shared/sagas/index.js`
const entityScreenFilePath = `${process.cwd()}/app/modules/entities/entities-screen.js`
const navigationRouterFilePath = `${process.cwd()}/app/navigation/layouts.js`
// REDUX AND SAGA SECTION
let apiMethods = `
const get${props.name} = (${camelCase(props.name)}Id) => api.get('${props.microservicePath}api/${kebabCase(props.pluralName)}/' + ${camelCase(props.name)}Id)
const get${props.pluralName} = (options) => api.get('${props.microservicePath}api/${kebabCase(props.pluralName)}', options)
const create${props.name} = (${camelCase(props.name)}) => api.post('${props.microservicePath}api/${kebabCase(props.pluralName)}', ${camelCase(props.name)})
const update${props.name} = (${camelCase(props.name)}) => api.put('${props.microservicePath}api/${kebabCase(props.pluralName)}', ${camelCase(props.name)})
const delete${props.name} = (${camelCase(props.name)}Id) => api.delete('${props.microservicePath}api/${kebabCase(props.pluralName)}/' + ${camelCase(props.name)}Id)`
let fixtureApiMethods = `
update${props.name}: (${camelCase(props.name)}) => {
return {
ok: true,
data: require('../../shared/fixtures/update${props.name}.json')
}
},
get${props.pluralName}: () => {
return {
ok: true,
data: require('../../shared/fixtures/get${props.pluralName}.json')
}
},
get${props.name}: (${camelCase(props.name)}Id) => {
return {
ok: true,
data: require('../../shared/fixtures/get${props.name}.json')
}
},
delete${props.name}: (${camelCase(props.name)}Id) => {
return {
ok: true
}
},`
let apiMethodsExport = `
create${props.name},
update${props.name},
get${props.pluralName},
get${props.name},
delete${props.name},`
let sagaConnections = `
takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_REQUEST, get${props.name}, api),
takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_ALL_REQUEST, get${props.pluralName}, api),
takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_UPDATE_REQUEST, update${props.name}, api),
takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_DELETE_REQUEST, delete${props.name}, api),`
// add searchEngine methods
if (props.searchEngine) {
apiMethods += `
const search${props.pluralName} = (query) => api.get('${props.microservicePath}api/_search/${kebabCase(props.pluralName)}', { query: query })`
fixtureApiMethods += `
search${props.pluralName}: (query) => {
return {
ok: true,
data: require('../../shared/fixtures/search${props.pluralName}.json')
}
},`
apiMethodsExport += `
search${props.pluralName},`
sagaConnections += `
takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_SEARCH_REQUEST, search${props.pluralName}, api),`
}
// add methods to api
ignite.patchInFile(apiFilePath, {
before: 'ignite-jhipster-api-method-needle',
insert: apiMethods,
match: apiMethods
})
ignite.patchInFile(apiFilePath, {
before: 'ignite-jhipster-api-export-needle',
insert: apiMethodsExport,
match: apiMethodsExport
})
ignite.patchInFile(fixtureApiFilePath, {
before: 'ignite-jhipster-api-fixture-needle',
insert: fixtureApiMethods,
match: fixtureApiMethods
})
// import redux in redux/index.js
ignite.patchInFile(reduxIndexFilePath, {
before: 'ignite-jhipster-redux-store-import-needle',
insert: ` ${camelCase(props.pluralName)}: require('../../modules/entities/${props.kebabName}/${props.kebabName}.reducer').reducer,`,
match: ` ${camelCase(props.pluralName)}: require('../../modules/entities/${props.kebabName}/${props.kebabName}.reducer').reducer,`
})
// import saga/redux in sagas/index.js
ignite.patchInFile(sagaIndexFilePath, {
before: 'ignite-jhipster-saga-redux-import-needle',
insert: `import { ${props.name}Types } from '../../modules/entities/${props.kebabName}/${props.kebabName}.reducer'`,
match: `import { ${props.name}Types } from '../../modules/entities/${props.kebabName}/${props.kebabName}.reducer'`
})
ignite.patchInFile(sagaIndexFilePath, {
before: 'ignite-jhipster-saga-method-import-needle',
insert: `import { get${props.name}, get${props.pluralName}, update${props.name}, delete${props.name}${props.searchEngine ? `, search${props.pluralName}` : ''} } from '../../modules/entities/${props.kebabName}/${props.kebabName}.sagas'`,
match: `import { get${props.name}, get${props.pluralName}, update${props.name}, delete${props.name}${props.searchEngine ? `, search${props.pluralName}` : ''} } from '../../modules/entities/${props.kebabName}/${props.kebabName}.sagas'`
})
ignite.patchInFile(sagaIndexFilePath, {
before: 'ignite-jhipster-saga-redux-connect-needle',
insert: sagaConnections,
match: sagaConnections
})
const entityFiles = [
// generate entity saga/redux
{
template: `entity-sagas.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}.sagas.js`
},
{
template: `entity-reducer.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}.reducer.js`
},
// generate entity listing container
{
template: `entity-flatlist.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-screen.js`
},
{
template: `entity-flatlist-style.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-screen-style.js`
},
{
template: `entity-detail-screen.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-detail-screen.js`
},
{
template: `entity-detail-screen-style.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-detail-screen-style.js`
},
{
template: `entity-edit-screen.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-edit-screen.js`
},
{
template: `entity-edit-screen-style.js.ejs`,
target: `app/modules/entities/${props.kebabName}/${props.kebabName}-entity-edit-screen-style.js`
},
// generate entity fixtures
{
template: `fixtures/entity-get.json.ejs`,
target: `app/shared/fixtures/get${props.name}.json`
},
{
template: `fixtures/entity-get-all.json.ejs`,
target: `app/shared/fixtures/get${props.pluralName}.json`
},
{
template: `fixtures/entity-update.json.ejs`,
target: `app/shared/fixtures/update${props.name}.json`
},
// generate entity tests
{
template: `entity-sagas.spec.js.ejs`,
target: `test/spec/modules/entities/${props.kebabName}/${props.kebabName}.sagas.spec.js`
},
{
template: `entity-reducer.spec.js.ejs`,
target: `test/spec/modules/entities/${props.kebabName}/${props.kebabName}.reducer.spec.js`
}
]
if (props.searchEngine) {
entityFiles.push({
template: `fixtures/entity-get-all.json.ejs`,
target: `app/shared/fixtures/search${props.pluralName}.json`
})
}
if (props.detox) {
entityFiles.push({
template: `entity-e2e-test.js.ejs`,
target: `e2e/entities/${props.kebabName}.spec.js`
})
}
await ignite.copyBatch(igniteContext, entityFiles, props, {
directory: `${__dirname}/../../templates/entity`
})
// import entity screens to navigation
const navigationImport = `import ${props.name}EntityScreen from '../modules/entities/${props.kebabName}/${props.kebabName}-entity-screen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-import-needle',
insert: navigationImport,
match: navigationImport
})
const navigationImportDetail = `import ${props.name}EntityDetailScreen from '../modules/entities/${props.kebabName}/${props.kebabName}-entity-detail-screen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-import-needle',
insert: navigationImportDetail,
match: navigationImportDetail
})
const navigationImportEdit = `import ${props.name}EntityEditScreen from '../modules/entities/${props.kebabName}/${props.kebabName}-entity-edit-screen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-import-needle',
insert: navigationImportEdit,
match: navigationImportEdit
})
let upperSnakeCaseName = upperCase(snakeCase(props.name + 'EntityScreen')).replace(/ /g, '_')
let upperSnakeCaseNameEdit = upperCase(snakeCase(props.name + 'EntityEditScreen')).replace(/ /g, '_')
let upperSnakeCaseNameDetail = upperCase(snakeCase(props.name + 'EntityDetailScreen')).replace(/ /g, '_')
// import entity screens to navigation
const navigationDeclaration = `export const ${upperSnakeCaseName} = 'Nav.${props.name}EntityScreen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-declaration-needle',
insert: navigationDeclaration,
match: navigationDeclaration
})
const navigationDeclarationDetail = `export const ${upperSnakeCaseNameDetail} = 'Nav.${props.name}EntityDetailScreen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-declaration-needle',
insert: navigationDeclarationDetail,
match: navigationDeclarationDetail
})
const navigationDeclarationEdit = `export const ${upperSnakeCaseNameEdit} = 'Nav.${props.name}EntityEditScreen'`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-declaration-needle',
insert: navigationDeclarationEdit,
match: navigationDeclarationEdit
})
// add entity screens to navigation
const navigationScreen = ` Navigation.registerComponentWithRedux(${upperSnakeCaseName}, () => ${props.name}EntityScreen, Provider, store)`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-registration-needle',
insert: navigationScreen,
match: navigationScreen
})
const navigationScreenDetail = ` Navigation.registerComponentWithRedux(${upperSnakeCaseNameDetail}, () => ${props.name}EntityDetailScreen, Provider, store)`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-registration-needle',
insert: navigationScreenDetail,
match: navigationScreenDetail
})
const navigationScreenEdit = ` Navigation.registerComponentWithRedux(${upperSnakeCaseNameEdit}, () => ${props.name}EntityEditScreen, Provider, store)`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-registration-needle',
insert: navigationScreenEdit,
match: navigationScreenEdit
})
const navigationMethodMain = `
export const ${camelCase(props.name)}EntityScreen = () => Navigation.push('center', {
component: {
name: ${upperSnakeCaseName},
options: {
topBar: {
title: {
text: '${props.pluralName}',
color: Colors.snow
},
rightButtons: [
{
id: 'createButton',
text: 'Create',
color: Colors.snow
}
]
}
}
}
})`
const navigationMethodDetail = `
export const ${camelCase(props.name)}EntityDetailScreen = (data) => Navigation.push('center', {
component: {
name: ${upperSnakeCaseNameDetail},
passProps: {
data
},
options: {
topBar: {
title: {
text: '${props.pluralName}',
color: Colors.snow
}
}
}
}
})`
const navigationMethodEdit = `
export const ${camelCase(props.name)}EntityEditScreen = (data) => Navigation.push('center', {
component: {
name: ${upperSnakeCaseNameEdit},
passProps: {
data
},
options: {
topBar: {
title: {
text: '${props.pluralName}',
color: Colors.snow
}
}
}
}
})`
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-method-needle',
insert: navigationMethodMain,
match: navigationMethodMain
})
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-method-needle',
insert: navigationMethodEdit,
match: navigationMethodEdit
})
ignite.patchInFile(navigationRouterFilePath, {
before: 'ignite-jhipster-navigation-method-needle',
insert: navigationMethodDetail,
match: navigationMethodDetail
})
// add entity to entities screen
const entityScreenButton = ` <RoundedButton text='${props.name}' onPress={${camelCase(props.name)}EntityScreen} testID='${camelCase(props.name)}EntityScreenButton' />`
ignite.patchInFile(entityScreenFilePath, {
before: 'ignite-jhipster-entity-screen-needle',
insert: entityScreenButton,
match: entityScreenButton
})
const entityScreenImport = ` ${camelCase(props.name)}EntityScreen,`
ignite.patchInFile(entityScreenFilePath, {
before: 'ignite-jhipster-entity-screen-import-needle',
insert: entityScreenImport,
match: entityScreenImport
})
}