UNPKG

ignite-jhipster

Version:

A React Native boilerplate for JHipster apps.

430 lines (401 loc) 16.4 kB
/** * The files portion of the entity generator */ module.exports = async function (generator, igniteContext) { const pluralize = require('pluralize') const fs = require('fs-extra') const { patchInFile } = require('../lib/patch-in-file') const { prettierTransformBatch } = require('../lib/prettier-transform') const { getEntityFormField, getRelationshipFormField } = require('../lib/entity-helpers') const { copyBatch } = require('../lib/copy-batch') const { strings, parameters } = igniteContext const { kebabCase, pascalCase, snakeCase, upperCase, camelCase, isBlank, upperFirst } = strings // eslint-disable-line const name = generator.name const searchEngine = generator.igniteConfig.searchEngine const detox = generator.igniteConfig.detox || (parameters.options.detox && parameters.options.detox !== 'false') 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 const 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' || field.fieldType === 'Instant') { 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 (Object.prototype.hasOwnProperty.call(entityConfig, 'microserviceName')) { props.microservicePath = `services/${entityConfig.microserviceName}/` } 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.toLowerCase()}.json'), } }, get${props.pluralName}: () => { return { ok: true, data: require('../../shared/fixtures/get-${props.pluralName.toLowerCase()}.json'), } }, get${props.name}: (${camelCase(props.name)}Id) => { return { ok: true, data: require('../../shared/fixtures/get-${props.name.toLowerCase()}.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.toLowerCase()}.json') } },` apiMethodsExport += ` search${props.pluralName},` sagaConnections += ` takeLatest(${props.name}Types.${snakeCase(props.name).toUpperCase()}_SEARCH_REQUEST, search${props.pluralName}, api),` } // add methods to api await patchInFile(igniteContext, apiFilePath, { before: 'ignite-jhipster-api-method-needle', insert: apiMethods, }) await patchInFile(igniteContext, apiFilePath, { before: 'ignite-jhipster-api-export-needle', insert: apiMethodsExport, }) await patchInFile(igniteContext, fixtureApiFilePath, { before: 'ignite-jhipster-api-fixture-needle', insert: fixtureApiMethods, }) // import redux in redux/index.js await patchInFile(igniteContext, reduxIndexFilePath, { before: 'ignite-jhipster-redux-store-import-needle', insert: ` ${camelCase(props.pluralName)}: require('../../modules/entities/${props.kebabName}/${props.kebabName}.reducer').reducer,`, }) // import saga/redux in sagas/index.js await patchInFile(igniteContext, sagaIndexFilePath, { before: 'ignite-jhipster-saga-redux-import-needle', insert: `import { ${props.name}Types } from '../../modules/entities/${props.kebabName}/${props.kebabName}.reducer'`, }) await patchInFile(igniteContext, 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'`, }) await patchInFile(igniteContext, sagaIndexFilePath, { before: 'ignite-jhipster-saga-redux-connect-needle', insert: 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.toLowerCase()}.json`, }, { template: `fixtures/entity-get-all.json.ejs`, target: `app/shared/fixtures/get-${props.pluralName.toLowerCase()}.json`, }, { template: `fixtures/entity-update.json.ejs`, target: `app/shared/fixtures/update-${props.name.toLowerCase()}.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.toLowerCase()}.json`, }) } if (props.detox) { entityFiles.push({ template: `entity-e2e-test.js.ejs`, target: `e2e/entities/${props.kebabName}.spec.js`, }) } await 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'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-import-needle', insert: navigationImport, }) const navigationImportDetail = `import ${props.name}EntityDetailScreen from '../modules/entities/${props.kebabName}/${props.kebabName}-entity-detail-screen'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-import-needle', insert: navigationImportDetail, }) const navigationImportEdit = `import ${props.name}EntityEditScreen from '../modules/entities/${props.kebabName}/${props.kebabName}-entity-edit-screen'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-import-needle', insert: navigationImportEdit, }) const upperSnakeCaseName = upperCase(snakeCase(props.name + 'EntityScreen')).replace(/ /g, '_') const upperSnakeCaseNameEdit = upperCase(snakeCase(props.name + 'EntityEditScreen')).replace(/ /g, '_') const upperSnakeCaseNameDetail = upperCase(snakeCase(props.name + 'EntityDetailScreen')).replace(/ /g, '_') // import entity screens to navigation const navigationDeclaration = `export const ${upperSnakeCaseName} = 'nav.${props.name}EntityScreen'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-declaration-needle', insert: navigationDeclaration, }) const navigationDeclarationDetail = `export const ${upperSnakeCaseNameDetail} = 'nav.${props.name}EntityDetailScreen'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-declaration-needle', insert: navigationDeclarationDetail, }) const navigationDeclarationEdit = `export const ${upperSnakeCaseNameEdit} = 'nav.${props.name}EntityEditScreen'` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-declaration-needle', insert: navigationDeclarationEdit, }) const getNavCase = (SCREEN_NAME, component) => `registerComponentWithRedux(${SCREEN_NAME}, ${component})` // add entity screens to navigation await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-registration-needle', insert: getNavCase(upperSnakeCaseName, `${props.name}EntityScreen`), }) await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-registration-needle', insert: getNavCase(upperSnakeCaseNameDetail, `${props.name}EntityDetailScreen`), }) await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-registration-needle', insert: getNavCase(upperSnakeCaseNameEdit, `${props.name}EntityEditScreen`), }) 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, testID: '${camelCase(props.name)}CreateButton', }, ], }, }, }, })` 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, }, }, }, }, })` await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-method-needle', insert: navigationMethodMain, }) await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-method-needle', insert: navigationMethodEdit, }) await patchInFile(igniteContext, navigationRouterFilePath, { before: 'ignite-jhipster-navigation-method-needle', insert: navigationMethodDetail, }) // add entity to entities screen const entityScreenButton = ` <RoundedButton text="${props.name}" onPress={${camelCase( props.name, )}EntityScreen} testID="${camelCase(props.name)}EntityScreenButton" />` await patchInFile(igniteContext, entityScreenFilePath, { before: 'ignite-jhipster-entity-screen-needle', insert: entityScreenButton, }) const entityScreenImport = ` ${camelCase(props.name)}EntityScreen,` await patchInFile(igniteContext, entityScreenFilePath, { before: 'ignite-jhipster-entity-screen-import-needle', insert: entityScreenImport, }) // run prettier on generated files const filesToRunPrettierOn = [ { target: 'app/shared/services/api.js' }, { target: 'app/shared/services/fixture-api.js' }, { target: 'app/shared/sagas/index.js' }, { target: 'app/shared/reducers/index.js' }, { target: 'app/navigation/layouts.js' }, { target: 'app/modules/entities/entities-screen.js' }, ...entityFiles, ] await prettierTransformBatch(filesToRunPrettierOn) }