Skip to content

Commit

Permalink
feat(settings): allow disable jsdoc guide (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Aug 30, 2021
1 parent 01daf38 commit 9418649
Show file tree
Hide file tree
Showing 14 changed files with 480 additions and 278 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"prepublishOnly": "yarn build"
},
"devDependencies": {
"@homer0/prettier-plugin-jsdoc": "^4.0.1",
"@homer0/prettier-plugin-jsdoc": "^4.0.5",
"@prisma-labs/prettier-config": "0.1.0",
"@prisma/client": "2.30.0",
"@prisma/sdk": "2.30.0",
Expand Down
33 changes: 33 additions & 0 deletions src/generator/gentime/settingsSingleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,36 @@ export namespace Gentime {
* @default 'Int'
*/
projectIdIntToGraphQL?: 'ID' | 'Int'
// TODO once fixed https://github.com/homer0/packages/issues/21
// use @default tag in this JSDoc block
/**
* Nexus Prisma will project your Prisma schema field/model/enum documentation into JSDoc of the generated Nexus Prisma API.
*
* This setting controls what Nexus Prisma should do when you have not written documentation in your Prisma Schema for a field/model/enum.
*
* The following modes are as follows:
*
* 1. `none`
*
* In this mode, no default JSDoc will be written.
*
* 2. `guide`
*
* In this mode, guide content into your JSDoc that looks something like the following:
*
* ```
* * ### ️⚠️ You have not writen documentation for ${thisItem}
*
* * Replace this default advisory JSDoc with your own documentation about ${thisItem}
* * by documenting it in your Prisma schema. For example:
* * ...
* * ...
* * ...
* ```
*
* The default is `guide`.
*/
jsdocPropagationDefault?: 'none' | 'guide'
// TODO add some examples
/**
* Should Prisma Schema docs propagate as docs?
Expand Down Expand Up @@ -63,6 +93,9 @@ export namespace Gentime {
projectIdIntToGraphQL: {
initial: () => 'Int',
},
jsdocPropagationDefault: {
initial: () => 'guide',
},
docPropagation: {
shorthand: (enabled) => ({
GraphQLDocs: enabled,
Expand Down
123 changes: 77 additions & 46 deletions src/generator/helpers/JSDocTemplates.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import { DMMF } from '@prisma/client/runtime'
import dedent from 'dindist'
import { PrismaDocumentation } from '../../lib/prisma-documnetation'
import { Gentime } from '../gentime/settingsSingleton'

type JSDoc = string

type FieldModelParams = {
field: DMMF.Field
model: DMMF.Model
settings: Gentime.Settings
}

const jsdocIndent = ' '
const jsdocEmptyLine = `\n${jsdocIndent}*\n`

/**
* Enum
*/

export function jsDocForEnum(enum_: DMMF.DatamodelEnum): JSDoc {
return dedent`
/**
${enumIntro(enum_)}
*
${nodeDocumentation({ enum: enum_ })}
*
* Contains these members: ${enum_.values.map((value) => value.name).join(', ')}
*
${enumExample(enum_)}
*/
`
export function jsDocForEnum(params: { enum: DMMF.DatamodelEnum; settings: Gentime.Settings }): JSDoc {
const sections = [
enumIntro(params.enum),
nodeDocumentation({
enum: params.enum,
settings: params.settings,
}),
`* Contains these members: ${params.enum.values.map((value) => value.name).join(', ')}`,
enumExample(params.enum),
]
const jsdoc = jsDocBookends(joinSections(sections))
return jsdoc
}

function enumIntro(enum_: DMMF.DatamodelEnum): string {
Expand All @@ -44,7 +49,7 @@ function enumExample(enum_: DMMF.DatamodelEnum): string {
`
}

function enumMissingDoc(enum_: DMMF.DatamodelEnum): string {
function enumMissingDocGuide(enum_: DMMF.DatamodelEnum): string {
return dedent`
${missingDocsIntro({ kind: 'enum', enum: enum_ })}
*
Expand All @@ -63,16 +68,10 @@ function enumMissingDoc(enum_: DMMF.DatamodelEnum): string {
* Model
*/

export function jsDocForModel(model: DMMF.Model): JSDoc {
return dedent`
/**
${modelIntro(model)}
*
${nodeDocumentation({ model })}
*
${modelExample(model)}
*/
`
export function jsDocForModel(params: { model: DMMF.Model; settings: Gentime.Settings }): JSDoc {
const sections = [modelIntro(params.model), nodeDocumentation(params), modelExample(params.model)]
const jsdoc = jsDocBookends(joinSections(sections))
return jsdoc
}

function modelIntro(model: DMMF.Model): string {
Expand All @@ -82,8 +81,11 @@ function modelIntro(model: DMMF.Model): string {
}

const nodeDocumentation = (
params: { model: DMMF.Model } | { model: DMMF.Model; field: DMMF.Field } | { enum: DMMF.DatamodelEnum }
): string | undefined => {
params:
| { settings: Gentime.Settings; model: DMMF.Model }
| { settings: Gentime.Settings; model: DMMF.Model; field: DMMF.Field }
| { settings: Gentime.Settings; enum: DMMF.DatamodelEnum }
): string | null => {
const documentation =
'field' in params
? params.field.documentation
Expand All @@ -93,18 +95,28 @@ const nodeDocumentation = (
? params.enum.documentation
: null

const doc = documentation
? `* ${PrismaDocumentation.format(documentation)}`
: 'field' in params
? fieldMissingDoc({ field: params.field, model: params.model })
: 'model' in params
? modelMissingDoc(params.model)
: enumMissingDoc(params.enum)
if (documentation) {
return dedent`
* ${PrismaDocumentation.format(documentation)}
`
}

if (params.settings.data.jsdocPropagationDefault === 'guide') {
return 'field' in params
? fieldMissingDocGuide({
field: params.field,
model: params.model,
settings: params.settings,
})
: 'model' in params
? modelMissingDocGuide(params.model)
: enumMissingDocGuide(params.enum)
}

return doc
return null
}

function modelMissingDoc(model: DMMF.Model): string {
function modelMissingDocGuide(model: DMMF.Model): string {
// TODO once https://stackoverflow.com/questions/61893953/how-to-escape-symbol-in-jsdoc-for-vscode
// is resolved then we can write better examples below like: id String @id
return dedent`
Expand Down Expand Up @@ -142,16 +154,10 @@ function modelExample(model: DMMF.Model): string {
* Field
*/

export function jsDocForField({ field, model }: FieldModelParams): JSDoc {
return dedent`
/**
${fieldIntro({ field, model })}
*
${nodeDocumentation({ field, model })}
*
${fieldExample({ field, model })}
*/
`
export function jsDocForField(params: FieldModelParams): JSDoc {
const sections = [fieldIntro(params), nodeDocumentation(params), fieldExample(params)]
const jsdoc = jsDocBookends(joinSections(sections))
return jsdoc
}

function fieldIntro({ model, field }: FieldModelParams): string {
Expand All @@ -160,7 +166,7 @@ function fieldIntro({ model, field }: FieldModelParams): string {
`
}

function fieldMissingDoc({ model, field }: FieldModelParams): string {
function fieldMissingDocGuide({ model, field }: FieldModelParams): string {
return dedent`
${missingDocsIntro({ kind: 'model', model })}
* \`\`\`prisma
Expand Down Expand Up @@ -210,8 +216,33 @@ function missingDocsIntro(
*
* Replace this default advisory JSDoc with your own documentation about ${thisItem}
* by documenting it in your Prisma schema. For example:
*
`
}

const missingDocsOutro = `* Learn more about documentation comments in Prisma schema files [here](https://www.prisma.io/docs/concepts/components/prisma-schema#comments).`

/**
* Convert a list of JSDoc sections into a single unified JSDoc section.
*
* Each joined section is separated by an empty line.
*
* Each section being joined is expected to handle its own JSDoc "spine" (e.g. `* some content here`).
*/
const joinSections = (sections: (string | null)[]) => {
return sections.filter((section) => section !== null).join(jsdocEmptyLine + jsdocIndent)
}

const jsDocBookends = (content: string) => {
const start = `/**`
const end = '*/'
const body = prefixBlock(jsdocIndent, content)

return `${start}\n${body}\n${jsdocIndent}${end}`
}

const prefixBlock = (prefix: string, content: string): string => {
return content
.split('\n')
.map((_) => `${prefix}${_.trim()}`)
.join('\n')
}
6 changes: 3 additions & 3 deletions src/generator/models/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export function renderTypeScriptDeclarationForDocumentModels(
}

function renderTypeScriptDeclarationForEnum(enum_: DMMF.DatamodelEnum, settings: Gentime.Settings): string {
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForEnum(enum_) + '\n' : ''
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForEnum({ enum: enum_, settings }) + '\n' : ''
const description = renderPrismaNodeDocumentationToDescription({ settings, node: enum_ })

return dedent`
Expand All @@ -173,7 +173,7 @@ function renderTypeScriptDeclarationForEnum(enum_: DMMF.DatamodelEnum, settings:
}

function renderTypeScriptDeclarationForModel(model: DMMF.Model, settings: Gentime.Settings): string {
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForModel(model) + '\n' : ''
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForModel({ model, settings }) + '\n' : ''
const description = renderPrismaNodeDocumentationToDescription({ settings, node: model })

return dedent`
Expand Down Expand Up @@ -209,7 +209,7 @@ function renderTypeScriptDeclarationForField({
model: DMMF.Model
settings: Gentime.Settings
}): string {
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForField({ field, model }) + '\n' : ''
const jsdoc = settings.data.docPropagation.JSDoc ? jsDocForField({ field, model, settings }) + '\n' : ''
const description = renderPrismaNodeDocumentationToDescription({ settings, node: field })
return dedent`
${jsdoc}${field.name}: {
Expand Down
13 changes: 12 additions & 1 deletion tests/__helpers__/testers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,19 @@ type IntegrationTestParams = IntegrationTestSpec & {
/**
* Test that the given Prisma schema generates the expected generated source code.
*/
export function testGeneratedModules(params: { databaseSchema: string; description: string }) {
export function testGeneratedModules(params: {
description: string
databaseSchema: string
/**
* The gentime settings to use.
*/
settings?: Gentime.SettingsInput
}) {
it(params.description, async () => {
Gentime.settings.reset()
if (params.settings) {
Gentime.settings.change(params.settings)
}
const { indexdts } = await generateModules(params.databaseSchema)
expect(indexdts).toMatchSnapshot('index.d.ts')
})
Expand Down
Loading

1 comment on commit 9418649

@vercel
Copy link

@vercel vercel bot commented on 9418649 Aug 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.