Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add JSDoc style comment support to Typescript generator #621

Merged
merged 14 commits into from
Mar 9, 2022
2 changes: 2 additions & 0 deletions docs/presets.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Each language has different model types, which results in different implementabl

Below is a custom preset written for TypeScript language, which adds a description to each interface's property and to the model itself as a JavaScript comment.

You can find the full preset at [typescript/presets/DescriptionPreset.ts](../src/generators/typescript/presets/DescriptionPreset.ts)

```ts
import { TypeScriptGenerator } from '@asyncapi/modelina';

Expand Down
62 changes: 62 additions & 0 deletions src/generators/typescript/presets/DescriptionPreset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { CommonModel } from '../../../models';
import { TypeScriptPreset } from '../TypeScriptPreset';
import { TypeScriptRenderer } from '../TypeScriptRenderer';

const renderDescription = ({
renderer,
content,
item,
}: {
renderer: TypeScriptRenderer;
content: string;
item: CommonModel;
}): string => {
const desc = item.getFromOriginalInput('description')?.trim();
const examples = item.getFromOriginalInput('examples');
const formattedExamples = `@example ${
examples?.join ? examples.join(', ') : examples
}`;

if (desc || examples) {
const doc = renderer.renderComments(
`${desc || ''}\n${examples ? formattedExamples : ''}`.trim()
);
return `${doc}\n${content}`;
}

return content;
};

/**
* Preset which adds descriptions
*
* @implements {TypeScriptPreset}
*/
export const TS_DESCRIPTION_PRESET: TypeScriptPreset = {
class: {
self({ renderer, model, content }) {
return renderDescription({ renderer, content, item: model });
},
property({ renderer, property, content }) {
return renderDescription({ renderer, content, item: property });
}
},
interface: {
self({ renderer, model, content }) {
return renderDescription({ renderer, content, item: model });
},
property({ renderer, property, content }) {
return renderDescription({ renderer, content, item: property });
}
},
type: {
self({ renderer, model, content }) {
return renderDescription({ renderer, content, item: model });
},
},
enum: {
self({ renderer, model, content }) {
return renderDescription({ renderer, content, item: model });
},
},
};
1 change: 1 addition & 0 deletions src/generators/typescript/presets/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './CommonPreset';
export * from './DescriptionPreset';
47 changes: 47 additions & 0 deletions test/generators/typescript/preset/DescriptionPreset.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {TS_DESCRIPTION_PRESET, TypeScriptGenerator} from '../../../../src';

const doc = {
$id: 'Test',
type: 'object',
additionalProperties: true,
required: ['string prop'],
description: 'Main Description',
properties: {
'string prop': { type: 'string' },
numberProp: {
type: 'number',
description: 'Description',
examples: 'Example',
},
objectProp: {
type: 'object',
$id: 'NestedTest',
properties: { stringProp: { type: 'string' } },
examples: ['Example 1', 'Example 2'],
},
},
};

describe('Description generation', () => {
let generator: TypeScriptGenerator;
beforeEach(() => {
generator = new TypeScriptGenerator({
presets: [TS_DESCRIPTION_PRESET],
});
});

test('should render example function for model', async () => {
const inputModel = await generator.process(doc);
const testModel = inputModel.models['Test'];
const nestedTestModel = inputModel.models['NestedTest'];

const testClass = await generator.renderClass(testModel, inputModel);
const nestedTestClass = await generator.renderClass(
nestedTestModel,
inputModel
);

expect(testClass.result).toMatchSnapshot();
expect(nestedTestClass.result).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Description generation should render example function for model 1`] = `
"/**
* Main Description
*/
class Test {
private _stringProp: string;
/**
* Description
* @example Example
*/
private _numberProp?: number;
private _objectProp?: NestedTest;
private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;

constructor(input: {
stringProp: string,
numberProp?: number,
objectProp?: NestedTest,
}) {
this._stringProp = input.stringProp;
this._numberProp = input.numberProp;
this._objectProp = input.objectProp;
}

get stringProp(): string { return this._stringProp; }
set stringProp(stringProp: string) { this._stringProp = stringProp; }

get numberProp(): number | undefined { return this._numberProp; }
set numberProp(numberProp: number | undefined) { this._numberProp = numberProp; }

get objectProp(): NestedTest | undefined { return this._objectProp; }
set objectProp(objectProp: NestedTest | undefined) { this._objectProp = objectProp; }

get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
}"
`;

exports[`Description generation should render example function for model 2`] = `
"/**
* @example Example 1, Example 2
*/
class NestedTest {
private _stringProp?: string;
private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;

constructor(input: {
stringProp?: string,
}) {
this._stringProp = input.stringProp;
}

get stringProp(): string | undefined { return this._stringProp; }
set stringProp(stringProp: string | undefined) { this._stringProp = stringProp; }

get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
}"
`;