Skip to content

Commit

Permalink
feat: add fields to api-crud and web-crud generatorsa
Browse files Browse the repository at this point in the history
  • Loading branch information
beeman committed Jan 22, 2024
1 parent 37f8321 commit 52376de
Show file tree
Hide file tree
Showing 38 changed files with 148 additions and 243 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ exports[`api-crud generator should run successfully 1`] = `
"export class AdminCreateCompanyInput {",
"@Field()",
"name!: string;",
"@Field()",
"location!: string;",
"@Field({ nullable: true })",
"phone?: string;",
"}",
],
"isBinary": false,
Expand All @@ -180,6 +184,10 @@ exports[`api-crud generator should run successfully 1`] = `
"export class AdminUpdateCompanyInput {",
"@Field({ nullable: true })",
"name?: string;",
"@Field({ nullable: true })",
"location?: string;",
"@Field({ nullable: true })",
"phone?: string;",
"}",
],
"isBinary": false,
Expand Down Expand Up @@ -214,6 +222,10 @@ exports[`api-crud generator should run successfully 1`] = `
"updatedAt?: Date;",
"@Field()",
"name!: string;",
"@Field()",
"location!: string;",
"@Field({ nullable: true })",
"phone?: string;",
"}",
],
"isBinary": false,
Expand Down Expand Up @@ -1137,6 +1149,8 @@ exports[`api-crud generator should run successfully 1`] = `
"createdAt",
"id",
"name",
"location",
"phone",
"updatedAt",
"}",
"query adminFindManyCompany($input: AdminFindManyCompanyInput!) {",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('api-crud generator', () => {
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace()
await createMockApiApp(tree, options.app)
await apiFeatureGenerator(tree, { app: options.app, model: options.model, name: options.model })
await apiFeatureGenerator(tree, { app: options.app, model: options.model })
})

it('should run successfully', async () => {
Expand Down
1 change: 1 addition & 0 deletions libs/tools/src/generators/api-crud/api-crud-schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface ApiCrudGeneratorSchema {
export interface NormalizedApiCrudSchema extends ApiCrudGeneratorSchema {
label: string
npmScope: string
fields?: PrismaModelField[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export class Test {
createdAt?: Date;
@Field({ nullable: true })
updatedAt?: Date;
@Field()
name!: string;
}
Expand Down
22 changes: 11 additions & 11 deletions libs/tools/src/generators/api-feature/api-feature-generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ApiFeatureGeneratorSchema } from './api-feature-schema'

describe('api-feature generator', () => {
let tree: Tree
const options: ApiFeatureGeneratorSchema = { app: 'api', name: 'test', label: 'name' }
const options: ApiFeatureGeneratorSchema = { app: 'api', label: 'name', model: 'test' }

beforeEach(() => {
tree = createTreeWithEmptyWorkspace()
Expand All @@ -23,12 +23,12 @@ describe('api-feature generator', () => {
await apiFeatureGenerator(tree, options)

libs.forEach((lib) => {
const config = readProjectConfiguration(tree, `${options.app}-${options.name}-${lib}`)
const config = readProjectConfiguration(tree, `${options.app}-${options.model}-${lib}`)
expect(config).toBeDefined()
})

const basePathDataAccess = `libs/${options.app}/${options.name}/data-access/src`
const basePathFeature = `libs/${options.app}/${options.name}/feature/src`
const basePathDataAccess = `libs/${options.app}/${options.model}/data-access/src`
const basePathFeature = `libs/${options.app}/${options.model}/feature/src`

const sourceFilesDataAccess = getRecursiveFileNames({ tree, path: basePathDataAccess })
const sourceFilesFeature = getRecursiveFileNames({ tree, path: basePathFeature })
Expand Down Expand Up @@ -64,12 +64,12 @@ describe('api-feature generator', () => {
await apiFeatureGenerator(tree, { ...options, crud: 'admin,user' })

libs.forEach((lib) => {
const config = readProjectConfiguration(tree, `${options.app}-${options.name}-${lib}`)
const config = readProjectConfiguration(tree, `${options.app}-${options.model}-${lib}`)
expect(config).toBeDefined()
})

const basePathDataAccess = `libs/${options.app}/${options.name}/data-access/src`
const basePathFeature = `libs/${options.app}/${options.name}/feature/src`
const basePathDataAccess = `libs/${options.app}/${options.model}/data-access/src`
const basePathFeature = `libs/${options.app}/${options.model}/feature/src`

const sourceFilesDataAccess = getRecursiveFileNames({ tree, path: basePathDataAccess })
const sourceFilesFeature = getRecursiveFileNames({ tree, path: basePathFeature })
Expand Down Expand Up @@ -118,21 +118,21 @@ describe('api-feature generator', () => {
await apiFeatureGenerator(tree, { ...options, skipUtil: false })

libs.forEach((lib) => {
const config = readProjectConfiguration(tree, `${options.app}-${options.name}-${lib}`)
const config = readProjectConfiguration(tree, `${options.app}-${options.model}-${lib}`)
expect(config).toBeDefined()
})
})

it('should generate the feature with different name', async () => {
const testOptions = { ...options, name: 'company' }
const testOptions = { ...options, model: 'company' }
await createMockApiApp(tree, testOptions.app)

// By default, we generate two libraries: data-access and feature
const libs = ['data-access', 'feature', 'util']
await apiFeatureGenerator(tree, { ...testOptions, skipUtil: false })

libs.forEach((lib) => {
const config = readProjectConfiguration(tree, `${testOptions.app}-${testOptions.name}-${lib}`)
const config = readProjectConfiguration(tree, `${testOptions.app}-${testOptions.model}-${lib}`)
expect(config).toBeDefined()
})
})
Expand All @@ -143,7 +143,7 @@ describe('api-feature generator', () => {
// By default, we generate two libraries: data-access and feature
const libs = ['data-access', 'feature']
const customName = 'custom'
await apiFeatureGenerator(tree, { ...options, name: customName })
await apiFeatureGenerator(tree, { ...options, model: customName })

libs.forEach((lib) => {
const config = readProjectConfiguration(tree, `${options.app}-${customName}-${lib}`)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export type ApiFeatureGeneratorSchema = Partial<Omit<NormalizedApiFeatureSchema, 'crud'>> & {
crud?: string
model: string
}

export interface NormalizedApiFeatureSchema {
app: string
crud: string[]
name: string
label: string
model: string
npmScope: string
Expand Down
9 changes: 0 additions & 9 deletions libs/tools/src/generators/api-feature/api-feature-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@
"title": "",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the feature.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use?"
},
"app": {
"type": "string",
"description": "The name of the application you are adding the feature to.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('web-crud generator', () => {
tree = createTreeWithEmptyWorkspace()

await createMockWebApp(tree, options.app)
await webFeatureGenerator(tree, { app: options.app, model: options.model, name: options.model })
await webFeatureGenerator(tree, { app: options.app, model: options.model })
})

it('should run successfully', async () => {
Expand Down
1 change: 1 addition & 0 deletions libs/tools/src/generators/web-crud/web-crud-schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface WebCrudGeneratorSchema {
export interface NormalizedWebCrudSchema extends WebCrudGeneratorSchema {
label: string
npmScope: string
fields?: PrismaModelField[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export function useUserFindOneTest({ testId }: { testId: string }) {
exports[`web-feature generator should run successfully with crud 9`] = `
"export const AdminTestFeature = lazy(() => import('./lib/admin-test.routes'));
import { lazy } from 'react';
export const UserTestFeature = lazy(() => import('./lib/user-test.routes'));
"
`;
Expand Down Expand Up @@ -686,7 +687,7 @@ export function AdminTestUiCreateForm({
};
const fields: UiFormField<AdminCreateTestInput>[] = [
formFieldText('name', { label: 'Name', required: true }),
formFieldText('name', { label: 'name', required: true }),
];
return (
<UiForm
Expand Down Expand Up @@ -801,7 +802,7 @@ export function AdminTestUiUpdateForm({
};
const fields: UiFormField<AdminUpdateTestInput>[] = [
formFieldText('name', { label: 'Name' }),
formFieldText('name', { label: 'name' }),
];
return (
<UiForm
Expand Down Expand Up @@ -966,7 +967,7 @@ export function UserTestUiCreateForm({
};
const fields: UiFormField<UserCreateTestInput>[] = [
formFieldText('name', { label: 'Name', required: true }),
formFieldText('name', { label: 'name', required: true }),
];
return (
<UiForm
Expand Down Expand Up @@ -1081,7 +1082,7 @@ export function UserTestUiUpdateForm({
};
const fields: UiFormField<UserUpdateTestInput>[] = [
formFieldText('name', { label: 'Name' }),
formFieldText('name', { label: 'name' }),
];
return (
<UiForm
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { Tree } from '@nx/devkit'
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'
import { createMockApiApp } from '../../lib/api/create-mock-api-app'

import { getRecursiveFileNames } from '../../lib/utils/get-recursive-file-names'
import { createMockWebApp, normalizeWebFeatureSchema } from '../../lib/web'
import apiFeatureGenerator from '../api-feature/api-feature-generator'

import { webFeatureGenerator } from './web-feature-generator'
import { type NormalizedWebFeatureSchema, WebFeatureGeneratorSchema } from './web-feature-schema'

describe('web-feature generator', () => {
let tree: Tree
const rawOptions: WebFeatureGeneratorSchema = { app: 'web', name: 'test' }
const rawOptions: WebFeatureGeneratorSchema = { app: 'web', model: 'test' }
let options: NormalizedWebFeatureSchema

beforeEach(async () => {
tree = createTreeWithEmptyWorkspace()
options = normalizeWebFeatureSchema(tree, rawOptions)
await createMockApiApp(tree, 'api')
await apiFeatureGenerator(tree, { app: 'api', crud: 'admin,user', model: 'company' })
await createMockWebApp(tree, options.app)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export type WebFeatureGeneratorSchema = Partial<Omit<NormalizedWebFeatureSchema,
export interface NormalizedWebFeatureSchema {
app: string
crud: string[]
name: string
label: string
model: string
npmScope: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Field, InputType } from '@nestjs/graphql'

@InputType()
export class <%= actor.className %>Create<%= model.className %>Input {
@Field()
<%= label.propertyName %>!: string
<% for (let field of fields){ %>
@Field(<% if(field.optional){ %>{ nullable: true }<% } %>)
<%= field.name %><% if(field.optional){ %>?<% } else { %>!<% } %>: <%= field.type %>
<% } %>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Field, InputType } from '@nestjs/graphql'

@InputType()
export class <%= actor.className %>Update<%= model.className %>Input {
<% for (let field of fields){ %>
@Field({ nullable: true })
<%= label.propertyName %>?: string
<%= field.name %>?: <%= field.type %>
<% } %>
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export class <%= model.className %> {
createdAt?: Date
@Field({ nullable: true })
updatedAt?: Date
@Field()
<%= label.propertyName %>!: string
<% for (let field of fields){ %>
@Field(<% if(field.optional){ %>{ nullable: true }<% } %>)
<%= field.name %><% if(field.optional){ %>?<% } else { %>!<% } %>: <%= field.type %>
<% } %>
}
8 changes: 6 additions & 2 deletions libs/tools/src/lib/api-crud/generate-api-crud.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { generateFiles, getProjects, type ProjectConfiguration, Tree } from '@nx/devkit'
import type { NormalizedApiCrudSchema } from '../../generators/api-crud/api-crud-schema'
import { generateSdkFile } from '../api/generate-sdk-file'
import { addExports } from '../utils/add-export'
import { ensureNxProjectExists } from '../utils/ensure-nx-project-exists'
import { addServiceToClassConstructor } from './add-service-to-class-constructor'
import { addServiceToModuleDecorator } from './add-service-to-module-decorator'
import { generateSdkFile } from './generate-sdk-file'
import { getApiCrudSubstitutions } from './get-api-crud-substitutions'

export function generateApiCrud(tree: Tree, options: NormalizedApiCrudSchema) {
Expand Down Expand Up @@ -71,7 +71,11 @@ export function generateApiCrud(tree: Tree, options: NormalizedApiCrudSchema) {
generateFiles(tree, `${__dirname}/files/feature`, feature.sourceRoot, { ...vars })

// Generate the SDK file
generateSdkFile(tree, options)
generateSdkFile(
tree,
options,
options.fields?.map((f) => f.name.toString()),
)

const e2e = getProjects(tree).get(`${options.app}-e2e`)
if (!e2e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getProjects, names, Tree } from '@nx/devkit'

export function generateSdkFile(tree: Tree, options: { actor: string; model: string; label: string }) {
export function generateSdkFile(tree: Tree, options: { actor: string; model: string }, fields: string[]) {
const project = getProjects(tree).get('sdk')

if (!project) {
Expand All @@ -20,7 +20,7 @@ export function generateSdkFile(tree: Tree, options: { actor: string; model: str

if (!exists) {
// Write the fragment to the file if it doesn't exist.
tree.write(target, sdkTemplateFragment(options.model, options.label))
tree.write(target, sdkTemplateFragment(options.model, fields))
}
const content = tree.read(target)?.toString() ?? ''

Expand All @@ -30,12 +30,12 @@ export function generateSdkFile(tree: Tree, options: { actor: string; model: str
}
}

function sdkTemplateFragment(name: string, label: string) {
function sdkTemplateFragment(name: string, fields: string[]) {
const { className } = names(name)
return `fragment ${className}Details on ${className} {
createdAt
id
${label}
${fields.join('\n ')}
updatedAt
}
`
Expand Down
1 change: 1 addition & 0 deletions libs/tools/src/lib/api-crud/get-api-crud-substitutions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export function getApiCrudSubstitutions(options: NormalizedApiCrudSchema) {
actorFileName: actor.fileName,
app,
appFileName: app.fileName,
fields: options.fields,
label: names(options.label),
model,
modelFileName: model.fileName,
Expand Down
4 changes: 4 additions & 0 deletions libs/tools/src/lib/api-crud/normalize-api-crud-schema.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Tree } from '@nx/devkit'
import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope'
import type { ApiCrudGeneratorSchema, NormalizedApiCrudSchema } from '../../generators/api-crud/api-crud-schema'
import { getPrismaModelFields } from '../prisma/get-prisma-models'

export function normalizeApiCrudSchema(tree: Tree, schema: ApiCrudGeneratorSchema): NormalizedApiCrudSchema {
const npmScope = getNpmScope(tree)
const fields = getPrismaModelFields(tree, schema.model) ?? [{ name: 'name', type: 'string', optional: false }]

return {
app: schema.app ?? 'api',
actor: schema.actor,
label: schema.label ?? 'name',
model: schema.model,
npmScope,
fields,
}
}
Loading

0 comments on commit 52376de

Please sign in to comment.