From 8906560c3cadc3bf6a65f1b9abd358cec15199d6 Mon Sep 17 00:00:00 2001 From: Tomer Aberbach Date: Wed, 25 Dec 2024 12:20:06 -0500 Subject: [PATCH] feat: support property comments (#34) (#73) --- src/arbitrary.ts | 16 +++++- src/components.ts | 76 +++++++++++++++----------- src/convert.ts | 4 +- test/index.ts | 10 ++++ test/snapshots/comments/arbitraries.js | 10 ++++ 5 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/arbitrary.ts b/src/arbitrary.ts index 0254570..790eb5f 100644 --- a/src/arbitrary.ts +++ b/src/arbitrary.ts @@ -150,7 +150,14 @@ export const recordArbitrary = ( export type RecordArbitrary = { type: `record` - properties: Map + properties: Map< + string, + { + arbitrary: Arbitrary + comment?: string + required: boolean + } + > } export const intersectionArbitrary = ( @@ -231,7 +238,12 @@ const getArbitraryKey = (arbitrary: Arbitrary): ArbitraryKey => { return keyalesce([ arbitrary.type, ...flatMap( - ([name, { arbitrary, required }]) => [name, arbitrary, required], + ([name, { arbitrary, comment, required }]) => [ + name, + arbitrary, + comment, + required, + ], arbitrary.properties, ), ]) diff --git a/src/components.ts b/src/components.ts index 0b8dfca..472601b 100644 --- a/src/components.ts +++ b/src/components.ts @@ -22,7 +22,7 @@ import { refkey, stc, } from '@alloy-js/core' -import type { Child, Children } from '@alloy-js/core' +import type { Child } from '@alloy-js/core' import type { Arbitrary, ArbitraryNamespace, @@ -572,13 +572,16 @@ const RecordArbitrary = ({ ObjectExpression({ properties: pipe( arbitrary.properties, - map(([name, { arbitrary }]) => [ + map(([name, { arbitrary, comment }]) => [ name, - Arbitrary({ - arbitrary, - sharedArbitraries, - currentStronglyConnectedArbitraries, - }), + { + comment, + value: Arbitrary({ + arbitrary, + sharedArbitraries, + currentStronglyConnectedArbitraries, + }), + }, ]), reduce(toObject()), ), @@ -638,28 +641,15 @@ const RecursiveReferenceArbitrary = ({ const ArrayExpression = ({ values }: { values: Child[] }): Child => code`[${ayJoin(values, { joiner: `, ` })}]` -const Commented = stc( - ({ comment, children }: { comment?: string; children?: Child }) => - ayJoin([comment && Comment({ comment }), children].filter(Boolean), { - joiner: `\n`, - }), -) - -const Comment = ({ comment }: { comment: string }): Child => { - const lines = comment.split(`\n`) - if (lines.length <= 1) { - return code`/** ${comment} */` - } - - return [`/**`, ...lines.map(line => ` * ${line}`), ` */`].join(`\n`) -} - const ObjectExpression = ({ properties, emitEmpty = false, singlePropertyOneLine = false, }: { - properties: Record + properties: Record< + string, + { comment: string | undefined; value: Child } | Child + > emitEmpty?: boolean singlePropertyOneLine?: boolean }): Child => { @@ -674,13 +664,21 @@ const ObjectExpression = ({ const objectProperties = pipe( filteredProperties, - map(([name, value]) => - ts.ObjectProperty({ - name, - // https://github.com/alloy-framework/alloy/issues/42 - value: typeof value === `number` ? String(value) : value, - }), - ), + map(([name, property]) => { + const { comment, value } = + property !== null && + typeof property === `object` && + `comment` in property + ? property + : { value: property } + return Commented({ comment }).children( + ts.ObjectProperty({ + name, + // https://github.com/alloy-framework/alloy/issues/42 + value: typeof value === `number` ? String(value) : value, + }), + ) + }), reduce(toArray()), ) return singlePropertyOneLine && filteredProperties.size === 1 @@ -692,6 +690,22 @@ const ObjectExpression = ({ ` } +const Commented = stc( + ({ comment, children }: { comment?: string; children?: Child }) => + ayJoin([comment && Comment({ comment }), children].filter(Boolean), { + joiner: `\n`, + }), +) + +const Comment = ({ comment }: { comment: string }): Child => { + const lines = comment.split(`\n`) + if (lines.length <= 1) { + return code`/** ${comment} */` + } + + return [`/**`, ...lines.map(line => ` * ${line}`), ` */`].join(`\n`) +} + const CallExpression = ({ name, args, diff --git a/src/convert.ts b/src/convert.ts index 2101bf2..0f94287 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -500,6 +500,7 @@ const convertRecord = ( property.type, mergeConstraints(constraints, getConstraints(program, property)), ) + const comment = getDoc(program, property) return [ name, property.defaultValue @@ -508,9 +509,10 @@ const convertRecord = ( arbitrary, convertValue(property.defaultValue), ]), + comment, required: false, } - : { arbitrary, required: !property.optional }, + : { arbitrary, comment, required: !property.optional }, ] }), reduce(toMap()), diff --git a/test/index.ts b/test/index.ts index e85a93f..5bc95d3 100644 --- a/test/index.ts +++ b/test/index.ts @@ -754,6 +754,7 @@ test.each([ /** Non-shared model comment. */ model SingleLineNonSharedModel { + /** Property comment. */ property: SingleLineSharedModel } @@ -762,11 +763,16 @@ test.each([ * model comment. */ model MultiLineNonSharedModel { + /** + * Property + * comment. + */ property: MultiLineSharedModel } /** Recursive model comment. */ model SingleLineRecursiveModel { + /** Property comment. */ property?: SingleLineRecursiveModel } @@ -775,6 +781,10 @@ test.each([ * model comment. */ model MultiLineRecursiveModel { + /** + * Property + * comment. + */ property?: MultiLineRecursiveModel } diff --git a/test/snapshots/comments/arbitraries.js b/test/snapshots/comments/arbitraries.js index c1330a8..97ceeb8 100644 --- a/test/snapshots/comments/arbitraries.js +++ b/test/snapshots/comments/arbitraries.js @@ -3,6 +3,10 @@ import * as fc from "fast-check"; const group = fc.letrec(tie => ({ MultiLineRecursiveModel: fc.record( { + /** + * Property + * comment. + */ property: tie("MultiLineRecursiveModel"), }, { withDeletedKeys: true }, @@ -17,6 +21,7 @@ export const MultiLineRecursiveModel = group.MultiLineRecursiveModel; const group_2 = fc.letrec(tie => ({ SingleLineRecursiveModel: fc.record( { + /** Property comment. */ property: tie("SingleLineRecursiveModel"), }, { withDeletedKeys: true }, @@ -63,6 +68,7 @@ export const MultiLineNamespace = { /** Non-shared model comment. */ export const SingleLineNonSharedModel = fc.record({ + /** Property comment. */ property: SingleLineSharedModel, }); @@ -71,5 +77,9 @@ export const SingleLineNonSharedModel = fc.record({ * model comment. */ export const MultiLineNonSharedModel = fc.record({ + /** + * Property + * comment. + */ property: MultiLineSharedModel, });