@postxl/generator 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,26 +11,9 @@ const jsdoc_1 = require("../../lib/utils/jsdoc");
11
11
  * Generates types for a given model.
12
12
  */
13
13
  function generateModelTypes({ model, meta }) {
14
- var _a, _b;
14
+ var _a;
15
15
  const idField = model.idField;
16
16
  const imports = imports_1.ImportsGenerator.from(meta.types.filePath);
17
- let hasLinkedItems = false;
18
- for (const relation of (0, fields_1.getRelationFields)(model)) {
19
- if (relation.relationToModel.typeName === model.typeName) {
20
- continue;
21
- }
22
- const refModel = relation.relationToModel;
23
- const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
24
- imports.addImport({
25
- items: [refMeta.types.toBrandedIdTypeFnName],
26
- from: refMeta.types.filePath,
27
- });
28
- imports.addTypeImport({
29
- items: [refModel.brandedIdType, refMeta.types.typeName],
30
- from: refMeta.types.filePath,
31
- });
32
- hasLinkedItems = true;
33
- }
34
17
  for (const f of (0, fields_1.getEnumFields)(model)) {
35
18
  const refEnumMeta = (0, meta_1.getEnumMetadata)({ enumerator: f.enumerator });
36
19
  imports.addTypeImport({
@@ -44,30 +27,33 @@ function generateModelTypes({ model, meta }) {
44
27
  from: schemaMeta.types.dto.path,
45
28
  });
46
29
  const decoderNames = meta.types.zodDecoderFnNames;
30
+ for (const relation of (0, fields_1.getRelationFields)(model)) {
31
+ if (relation.relationToModel.typeName === model.typeName) {
32
+ // NOTE: All type definitions are already present in this file for this model.
33
+ continue;
34
+ }
35
+ const refMeta = (0, meta_1.getModelMetadata)({ model: relation.relationToModel });
36
+ imports.addImport({ from: refMeta.types.filePath, items: [refMeta.types.toBrandedIdTypeFnName] });
37
+ imports.addTypeImport({ from: refMeta.types.filePath, items: [relation.relationToModel.brandedIdType] });
38
+ }
47
39
  return /* ts */ `
48
40
  import { z } from 'zod'
49
41
 
50
42
  ${imports.generate()}
51
43
 
52
- ${(0, jsdoc_1.toJsDocComment)((_b = (_a = model.description) === null || _a === void 0 ? void 0 : _a.split('\n')) !== null && _b !== void 0 ? _b : [])}
44
+ ${(0, jsdoc_1.toJsDocComment)((_a = model.description) === null || _a === void 0 ? void 0 : _a.split('\n'))}
53
45
  export type ${meta.types.typeName} = {
54
46
  ${model.fields
55
- .map((f) => `
56
- ${getFieldComment(f)}
57
- ${f.name}: ${getFieldType(f)}${f.isRequired ? '' : ' | null'}`)
47
+ .map((f) => {
48
+ return `
49
+ ${(0, jsdoc_1.getFieldComment)(f)}
50
+ ${f.name}: ${getFieldType(f)}${f.isRequired ? '' : ' | null'}
51
+ `;
52
+ })
58
53
  .join('\n')}
59
54
  }
60
55
 
61
- ${!hasLinkedItems
62
- ? ``
63
- : `
64
- export type ${meta.types.linkedTypeName} = {
65
- ${model.fields
66
- .map((f) => `
67
- ${getFieldComment(f)}
68
- ${getLinkedFieldType(f)}${f.isRequired ? '' : ' | null'}`)
69
- .join('\n')}
70
- }`}
56
+
71
57
 
72
58
  /**
73
59
  * Branded Id type that should be used to identify an instance of a ${meta.userFriendlyName}.
@@ -95,31 +81,6 @@ export const ${decoderNames.fromDatabase} = z.object({
95
81
  ${model.fields.map((field) => `${field.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field })}`).join(',')}
96
82
  })
97
83
 
98
- /**
99
- * Zod decoder for validating the create input of a ${meta.userFriendlyName}.
100
- */
101
- export const ${decoderNames.createObject} = z.object({
102
- ${model.fields
103
- .filter((f) => !f.attributes.isReadonly)
104
- .map((field) => `${field.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field })}`)
105
- .join(',')}
106
- })
107
-
108
- /**
109
- * Zod decoder for validating the update input of a ${meta.userFriendlyName} .
110
- */
111
- export const ${decoderNames.updateObject} = z.object({
112
- ${model.fields
113
- .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
114
- .map((field) => `${field.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field, allowAnyOptionalField: field.kind !== 'id' })}`)
115
- .join(',')}
116
- })
117
-
118
- /**
119
- * Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
120
- */
121
- export const ${decoderNames.upsertObject} = z.union([${decoderNames.updateObject}, ${decoderNames.createObject}])
122
-
123
84
  /**
124
85
  * Data transfer object for creating a new ${meta.userFriendlyName} instance.
125
86
  */
@@ -137,31 +98,6 @@ export type ${meta.types.dto.upsert} = ${schemaMeta.types.dto.upsert}<${meta.typ
137
98
  `;
138
99
  }
139
100
  exports.generateModelTypes = generateModelTypes;
140
- function getFieldComment(f) {
141
- const examples = getFieldExamples(f);
142
- let comment = '';
143
- if (f.description) {
144
- comment = ` * ${f.description.split('\n').join('\n * ')}\n`;
145
- }
146
- else if (f.kind === 'enum' && f.enumerator.description) {
147
- comment = ` * ${f.enumerator.description.split('\n').join('\n * ')}\n`;
148
- }
149
- if (examples) {
150
- comment += ` * ${examples}\n`;
151
- }
152
- if (comment === '') {
153
- return '';
154
- }
155
- return `
156
- /**
157
- ${comment}*/`;
158
- }
159
- function getFieldExamples(f) {
160
- if (!f.attributes.examples) {
161
- return undefined;
162
- }
163
- return `Examples: ${f.attributes.examples.map((e) => `"${e}"`).join(', ')}`;
164
- }
165
101
  /**
166
102
  * Converts a field to a TypeScript type definition.
167
103
  */
@@ -179,20 +115,3 @@ function getFieldType(f) {
179
115
  throw new types_1.ExhaustiveSwitchCheck(f);
180
116
  }
181
117
  }
182
- /**
183
- * Converts a field to a TypeScript type definition with linked fields.
184
- */
185
- function getLinkedFieldType(f) {
186
- switch (f.kind) {
187
- case 'enum':
188
- return `${f.name}: ${f.typeName}`;
189
- case 'relation':
190
- return `${f.relatedModelBacklinkFieldName}: ${f.relationToModel.typeName}`;
191
- case 'id':
192
- return `${f.name}: ${f.model.brandedIdType}`;
193
- case 'scalar':
194
- return `${f.name}: ${f.tsTypeName}`;
195
- default:
196
- throw new types_1.ExhaustiveSwitchCheck(f);
197
- }
198
- }
@@ -34,6 +34,10 @@ export declare class ExportsGenerator {
34
34
  * NOTE: This should only be used when the generator is a root generator.
35
35
  */
36
36
  exportEverythingFromFile(file: string): ExportsGenerator;
37
+ /**
38
+ * Adds a given file to the collection of files we're exporting a selection from.
39
+ */
40
+ exportSelectionFromPath(from: Types.FilePath, elements: Types.ImportableTypes[]): ExportsGenerator;
37
41
  /**
38
42
  * Returns the TypeScript export statements.
39
43
  */
@@ -8,7 +8,7 @@ const file_1 = require("./utils/file");
8
8
  class ExportsGenerator {
9
9
  constructor({ path, isRoot }) {
10
10
  this._path = path;
11
- this._exports = new Set();
11
+ this._exports = new Map();
12
12
  this.isRoot = isRoot !== null && isRoot !== void 0 ? isRoot : false;
13
13
  }
14
14
  /**
@@ -31,7 +31,7 @@ class ExportsGenerator {
31
31
  throw new Error(`Cannot use "exportEverythingFromPath" on a root generator.`);
32
32
  }
33
33
  const resolvedPath = (0, file_1.getRelativePath)({ from: this._path, to: from });
34
- this._exports.add(resolvedPath);
34
+ this._exports.set(resolvedPath, { kind: 'wildcard' });
35
35
  return this;
36
36
  }
37
37
  /**
@@ -43,18 +43,48 @@ class ExportsGenerator {
43
43
  if (!this.isRoot) {
44
44
  throw new Error(`Cannot use "exportEverythingFromFile" on a non-root generator.`);
45
45
  }
46
- this._exports.add(file);
46
+ this._exports.set(file, { kind: 'wildcard' });
47
+ return this;
48
+ }
49
+ /**
50
+ * Adds a given file to the collection of files we're exporting a selection from.
51
+ */
52
+ exportSelectionFromPath(from, elements) {
53
+ if (this.isRoot) {
54
+ throw new Error(`Cannot use "exportSelectionFromPath" on a root generator.`);
55
+ }
56
+ const resolvedPath = (0, file_1.getRelativePath)({ from: this._path, to: from });
57
+ const _existing = this._exports.get(resolvedPath);
58
+ // NOTE: If we already export everything, we don't need to do anything.
59
+ if ((_existing === null || _existing === void 0 ? void 0 : _existing.kind) === 'wildcard') {
60
+ return this;
61
+ }
62
+ if ((_existing === null || _existing === void 0 ? void 0 : _existing.kind) === 'selection') {
63
+ for (const element of elements) {
64
+ _existing.elements.add(element);
65
+ }
66
+ return this;
67
+ }
68
+ this._exports.set(resolvedPath, { kind: 'selection', elements: new Set(elements) });
47
69
  return this;
48
70
  }
49
71
  /**
50
72
  * Returns the TypeScript export statements.
51
73
  */
52
74
  generate() {
53
- const stetements = [...this._exports.values()]
54
- .sort((a, b) => a.localeCompare(b))
55
- .map((path) => `export * from '${path}'`)
56
- .join('\n');
57
- return stetements;
75
+ const statements = [];
76
+ const exports = Array.from(this._exports.entries()).sort((a, b) => a[0].localeCompare(b[0]));
77
+ for (const [_path, _export] of exports) {
78
+ switch (_export.kind) {
79
+ case 'wildcard':
80
+ statements.push(`export * from '${_path}'`);
81
+ break;
82
+ case 'selection':
83
+ statements.push(`export { ${Array.from(_export.elements).join(', ')} } from '${_path}'`);
84
+ break;
85
+ }
86
+ }
87
+ return statements.join('\n');
58
88
  }
59
89
  }
60
90
  exports.ExportsGenerator = ExportsGenerator;
@@ -107,7 +107,7 @@ export type SchemaMetaData = {
107
107
  */
108
108
  mock: Types.ClassName;
109
109
  };
110
- dispatcherService: {
110
+ dispatcher: {
111
111
  /**
112
112
  * Path to the file containing the dispatcher service class definition.
113
113
  */
@@ -116,6 +116,14 @@ export type SchemaMetaData = {
116
116
  * The name of the dispatcher service class.
117
117
  */
118
118
  class: Types.ClassName;
119
+ /**
120
+ * The name of the interface that indicates a service can dispatch actions.
121
+ */
122
+ interface: Types.ClassName;
123
+ /**
124
+ * The name of a util type that is used to create a dictionary of action payloads and results from the action descriptions.
125
+ */
126
+ actionMethod: Types.TypeName;
119
127
  };
120
128
  };
121
129
  /**
@@ -917,50 +925,17 @@ export type ModelMetaData = {
917
925
  */
918
926
  actionModelDiscriminantName: Types.VariableName;
919
927
  /**
920
- * Name of the model's aggregated action type. (e.g. `Action_Aggregation`)
921
- */
922
- actionName: Types.VariableName;
923
- /**
924
- * Name of the model's aggregated action result type. (e.g. `ActionResult_Aggregation`)
925
- */
926
- actionResultName: Types.VariableName;
927
- /**
928
- * The model's name that is used to build the different action types.
929
- * (e.g. `Aggregation` which will be used to build `Action_Aggregation_Create`)
930
- */
931
- actionNameModelPart: Types.VariableName;
932
- /**
933
- * Name of the function that creates a `create` action for the model (e.g. `createActionAggregationCreate`)
934
- */
935
- createActionFunctionNameCreate: Types.FunctionName;
936
- /**
937
- * Name of the function that creates a `createMany` action for the model (e.g. `createActionAggregationCreateMany`)
938
- */
939
- createActionFunctionNameCreateMany: Types.FunctionName;
940
- /**
941
- * Name of the function that creates a `update` action for the model (e.g. `createActionAggregationUpdate`)
942
- */
943
- createActionFunctionNameUpdate: Types.FunctionName;
944
- /**
945
- * Name of the function that creates a `updateMany` action for the model (e.g. `createActionAggregationUpdateMany`)
946
- */
947
- createActionFunctionNameUpdateMany: Types.FunctionName;
948
- /**
949
- * Name of the function that creates a `upsert` action for the model (e.g. `createActionAggregationUpsert`)
950
- */
951
- createActionFunctionNameUpsert: Types.FunctionName;
952
- /**
953
- * Name of the function that creates a `upsertMany` action for the model (e.g. `createActionAggregationUpsertMany`)
928
+ * The name of the function that decodes a Create object to a fully typed object, e.g. `aggregationCreateDecoder`.
954
929
  */
955
- createActionFunctionNameUpsertMany: Types.FunctionName;
930
+ zodCreateObject: Types.FunctionName;
956
931
  /**
957
- * Name of the function that creates a `delete` action for the model (e.g. `createActionAggregationDelete`)
932
+ * The name of the function that decodes an Update object to a fully typed object, e.g. `aggregationUpdateDecoder`.
958
933
  */
959
- createActionFunctionNameDelete: Types.FunctionName;
934
+ zodUpdateObject: Types.FunctionName;
960
935
  /**
961
- * Name of the function that creates a `deleteMany` action for the model (e.g. `createActionAggregationDeleteMany`)
936
+ * The name of the function that decodes an Upsert object to a fully typed object, e.g. `aggregationUpsertDecoder`.
962
937
  */
963
- createActionFunctionNameDeleteMany: Types.FunctionName;
938
+ zodUpsertObject: Types.FunctionName;
964
939
  };
965
940
  /**
966
941
  * Name by which the business logic service exposes the data service.
@@ -1120,18 +1095,6 @@ export type ModelMetaData = {
1120
1095
  * The name of the function that decodes a source (database) object to a fully typed object, e.g. `aggregationDatabaseDecoder`.
1121
1096
  */
1122
1097
  fromDatabase: Types.FunctionName;
1123
- /**
1124
- * The name of the function that decodes a Create object to a fully typed object, e.g. `aggregationCreateDecoder`.
1125
- */
1126
- createObject: Types.FunctionName;
1127
- /**
1128
- * The name of the function that decodes an Update object to a fully typed object, e.g. `aggregationUpdateDecoder`.
1129
- */
1130
- updateObject: Types.FunctionName;
1131
- /**
1132
- * The name of the function that decodes an Upsert object to a fully typed object, e.g. `aggregationUpsertDecoder`.
1133
- */
1134
- upsertObject: Types.FunctionName;
1135
1098
  };
1136
1099
  /**
1137
1100
  * Type definitions for the different Data Transfer Objects (DTOs).
package/dist/lib/meta.js CHANGED
@@ -86,9 +86,11 @@ function getSchemaMetadata({ config }) {
86
86
  class: Types.toClassName(`ActionExecution`),
87
87
  mock: Types.toClassName(`MockActionExecution`),
88
88
  },
89
- dispatcherService: {
89
+ dispatcher: {
90
90
  filePath: Types.toPath(`${config.paths.actionsPath}dispatcher.service`),
91
91
  class: Types.toClassName(`DispatcherService`),
92
+ interface: Types.toClassName(`IDispatcher`),
93
+ actionMethod: Types.toTypeName(`ActionMethod`),
92
94
  },
93
95
  },
94
96
  businessLogic: {
@@ -335,17 +337,9 @@ function getModelMetadata({ model }) {
335
337
  serviceFileName: Types.toFileName(`${camelCase}.update.service`),
336
338
  serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}update/${camelCase}.update.service`),
337
339
  actionModelDiscriminantName: Types.toVariableName(`${camelCase}`),
338
- actionName: Types.toVariableName(`Action_${PascalCase}`),
339
- actionNameModelPart: Types.toVariableName(`${PascalCase}`),
340
- actionResultName: Types.toVariableName(`ActionResult_${PascalCase}`),
341
- createActionFunctionNameCreate: Types.toFunctionName(`createAction${PascalCase}Create`),
342
- createActionFunctionNameCreateMany: Types.toFunctionName(`createAction${PascalCase}CreateMany`),
343
- createActionFunctionNameUpdate: Types.toFunctionName(`createAction${PascalCase}Update`),
344
- createActionFunctionNameUpdateMany: Types.toFunctionName(`createAction${PascalCase}UpdateMany`),
345
- createActionFunctionNameUpsert: Types.toFunctionName(`createAction${PascalCase}Upsert`),
346
- createActionFunctionNameUpsertMany: Types.toFunctionName(`createAction${PascalCase}UpsertMany`),
347
- createActionFunctionNameDelete: Types.toFunctionName(`createAction${PascalCase}Delete`),
348
- createActionFunctionNameDeleteMany: Types.toFunctionName(`createAction${PascalCase}DeleteMany`),
340
+ zodCreateObject: Types.toFunctionName(`${camelCase}CreateDecoder`),
341
+ zodUpdateObject: Types.toFunctionName(`${camelCase}UpdateDecoder`),
342
+ zodUpsertObject: Types.toFunctionName(`${camelCase}UpsertDecoder`),
349
343
  },
350
344
  dataRepositoryVariableName: Types.toVariableName(`data`),
351
345
  },
@@ -409,9 +403,6 @@ function getModelMetadata({ model }) {
409
403
  zodDecoderFnNames: {
410
404
  id: Types.toFunctionName(`${camelCase}IdDecoder`),
411
405
  fromDatabase: Types.toFunctionName(`${camelCase}DatabaseDecoder`),
412
- createObject: Types.toFunctionName(`${camelCase}CreateDecoder`),
413
- updateObject: Types.toFunctionName(`${camelCase}UpdateDecoder`),
414
- upsertObject: Types.toFunctionName(`${camelCase}UpsertDecoder`),
415
406
  },
416
407
  dto: {
417
408
  create: Types.toTypeName(`${PascalCase}CreateDTO`),
@@ -170,6 +170,10 @@ export type ModelFields = {
170
170
  * All fields of the model
171
171
  */
172
172
  fields: Field[];
173
+ /**
174
+ * A list of models that reference this model in their relations.
175
+ */
176
+ relatedModels: ModelCore[];
173
177
  };
174
178
  /**
175
179
  * A field of a model.
@@ -313,12 +317,12 @@ export type FieldRelation = Prettify<Omit<FieldCore, 'name'> & {
313
317
  */
314
318
  name: Types.FieldName;
315
319
  /**
316
- * Name of the field in the related model that references this model (e.g. `aggregation`).
320
+ * Name of the relation field in the model.
317
321
  *
318
322
  * NOTE: This does not reference the database column name, but the field name
319
323
  * in the model (e.g. not `aggregationId`, but `aggregation`).
320
324
  */
321
- relatedModelBacklinkFieldName: Types.FieldName;
325
+ relationFieldName: Types.FieldName;
322
326
  /**
323
327
  * Name of the unbranded TypeScript type of the field, e.g. string
324
328
  *
@@ -329,7 +333,7 @@ export type FieldRelation = Prettify<Omit<FieldCore, 'name'> & {
329
333
  */
330
334
  unbrandedTypeName: Types.TypeName;
331
335
  /**
332
- * The referenced model
336
+ * The referenced model.
333
337
  */
334
338
  relationToModel: ModelCore;
335
339
  }>;
@@ -343,12 +347,12 @@ export declare const isFieldRelation: (field: Field) => field is Prettify<Omit<F
343
347
  */
344
348
  name: Types.FieldName;
345
349
  /**
346
- * Name of the field in the related model that references this model (e.g. `aggregation`).
350
+ * Name of the relation field in the model.
347
351
  *
348
352
  * NOTE: This does not reference the database column name, but the field name
349
353
  * in the model (e.g. not `aggregationId`, but `aggregation`).
350
354
  */
351
- relatedModelBacklinkFieldName: Types.FieldName;
355
+ relationFieldName: Types.FieldName;
352
356
  /**
353
357
  * Name of the unbranded TypeScript type of the field, e.g. string
354
358
  *
@@ -359,7 +363,7 @@ export declare const isFieldRelation: (field: Field) => field is Prettify<Omit<F
359
363
  */
360
364
  unbrandedTypeName: Types.TypeName;
361
365
  /**
362
- * The referenced model
366
+ * The referenced model.
363
367
  */
364
368
  relationToModel: ModelCore;
365
369
  }>;
@@ -31,7 +31,7 @@ export type DiscriminantName = string & {
31
31
  export declare const toDiscriminantName: (t: string) => DiscriminantName;
32
32
  /**
33
33
  * The name of a model, e.g. "Aggregation".
34
- */
34
+ */
35
35
  export type ModelName = string & {
36
36
  readonly ___type: 'ModelName';
37
37
  };
@@ -67,7 +67,7 @@ export declare const toAnnotatedTypeName: (name: TypeName) => AnnotatedTypeName;
67
67
  export declare const isAnnotatedTypeName: (t: string | AnnotatedTypeName) => t is AnnotatedTypeName;
68
68
  /**
69
69
  * The name of a model field, e.g. "name".
70
- */
70
+ */
71
71
  export type FieldName = string & {
72
72
  readonly ___type: 'FieldName';
73
73
  };
@@ -77,7 +77,7 @@ export type FieldName = string & {
77
77
  export declare const toFieldName: (t: string) => FieldName;
78
78
  /**
79
79
  * The name of an Enum, e.g. "Language".
80
- */
80
+ */
81
81
  export type EnumName = string & {
82
82
  readonly ___type: 'EnumName';
83
83
  };
@@ -87,7 +87,7 @@ export type EnumName = string & {
87
87
  export declare const toEnumName: (t: string) => EnumName;
88
88
  /**
89
89
  * The name of a function (e.g. "toAggregation").
90
- */
90
+ */
91
91
  export type FunctionName = string & {
92
92
  readonly ___type: 'FunctionName';
93
93
  };
@@ -150,7 +150,7 @@ export declare const toPath: (t: string) => FilePath;
150
150
  /**
151
151
  * Branded string values that can be used as import statement values in the generators
152
152
  */
153
- export type ImportableTypes = FunctionName | ClassName | AnnotatedTypeName | VariableName | EnumName;
153
+ export type ImportableTypes = FunctionName | ClassName | TypeName | AnnotatedTypeName | VariableName | EnumName;
154
154
  /**
155
155
  * Branded string values that can be used as paths in import statements
156
156
  */
@@ -1,4 +1,9 @@
1
+ import type { Field } from '../schema/schema';
1
2
  /**
2
3
  * Returns a string of JSDoc comments from an array of lines.
3
4
  */
4
5
  export declare function toJsDocComment(comments: string[] | undefined): string;
6
+ /**
7
+ * Returns a JSDoc comment for a field.
8
+ */
9
+ export declare function getFieldComment(f: Field): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toJsDocComment = void 0;
3
+ exports.getFieldComment = exports.toJsDocComment = void 0;
4
4
  /**
5
5
  * Returns a string of JSDoc comments from an array of lines.
6
6
  */
@@ -14,3 +14,24 @@ function toJsDocComment(comments) {
14
14
  .join('')} \n */`;
15
15
  }
16
16
  exports.toJsDocComment = toJsDocComment;
17
+ /**
18
+ * Returns a JSDoc comment for a field.
19
+ */
20
+ function getFieldComment(f) {
21
+ const lines = [];
22
+ if (f.description) {
23
+ lines.push(...f.description.split('\n'));
24
+ }
25
+ else if (f.kind === 'enum' && f.enumerator.description) {
26
+ lines.push(...f.enumerator.description.split('\n'));
27
+ }
28
+ const _examples = f.attributes.examples;
29
+ if (_examples) {
30
+ lines.push(`Examples: ${_examples.map((e) => `"${e}"`).join(', ')}`);
31
+ }
32
+ if (lines.length === 0) {
33
+ return '';
34
+ }
35
+ return toJsDocComment(lines);
36
+ }
37
+ exports.getFieldComment = getFieldComment;