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(cfn2ts): make cfn2ts output TSDoc-compatible docblocks #2000

Merged
merged 2 commits into from
Mar 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tools/awslint/lib/cfn-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function findCfnResources(assembly: reflect.Assembly): CfnResourceSpec[]

// HACK: extract full CFN name from initializer docs
const initializerDoc = (layer1.initializer && layer1.initializer.docs.docs.comment) || '';
const out = /Creates a new ``([^`]+)``/.exec(initializerDoc);
const out = /a new `([^`]+)`/.exec(initializerDoc);
const fullname = out && out[1];
if (!fullname) {
throw new Error('Unable to extract CloudFormation resource name from initializer documentation');
Expand Down
46 changes: 26 additions & 20 deletions tools/cfn2ts/lib/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,8 @@ export default class CodeGenerator {
}
}

private openClass(name: genspec.CodeName, docLink?: string, superClasses?: string, deprecation?: string) {
private openClass(name: genspec.CodeName, superClasses?: string) {
const extendsPostfix = superClasses ? ` extends ${superClasses}` : '';
const before = deprecation ? [ `@deprecated ${deprecation}` ] : [ ];
this.docLink(docLink, ...before);
this.code.openBlock(`export class ${name.className}${extendsPostfix}`);
return name.className;
}
Expand All @@ -120,7 +118,7 @@ export default class CodeGenerator {
if (!spec.Properties || Object.keys(spec.Properties).length === 0) { return; }
const name = genspec.CodeName.forResourceProperties(resourceContext);

this.docLink(spec.Documentation);
this.docLink(spec.Documentation, `Properties for defining a \`${resourceContext.specName!.fqn}\``);
this.code.openBlock(`export interface ${name.className}`);

const conversionTable = this.emitPropsTypeProperties(resourceContext, spec.Properties);
Expand Down Expand Up @@ -172,6 +170,8 @@ export default class CodeGenerator {
private emitResourceType(resourceName: genspec.CodeName, spec: schema.ResourceType, deprecated?: genspec.CodeName): void {
this.beginNamespace(resourceName);

const cfnName = resourceName.specName!.fqn;

//
// Props Bag for this Resource
//
Expand All @@ -185,21 +185,27 @@ export default class CodeGenerator {
`"cloudformation.${resourceName.fqn}" will be deprecated in a future release ` +
`in favor of "${deprecated.fqn}" (see https://github.com/awslabs/aws-cdk/issues/878)`;

this.openClass(resourceName, spec.Documentation, RESOURCE_BASE_CLASS, deprecation);
this.docLink(spec.Documentation, ...[
`A CloudFormation \`${cfnName}\``,
'',
`@cloudformationResource ${cfnName}`,
...(deprecation ? [ `@deprecated ${deprecation}` ] : [ ]),
]);
this.openClass(resourceName, RESOURCE_BASE_CLASS);

//
// Static inspectors.
//

const resourceTypeName = `${JSON.stringify(resourceName.specName!.fqn)}`;
const resourceTypeName = `${JSON.stringify(cfnName)}`;
this.code.line('/**');
this.code.line(` * The CloudFormation resource type name for this resource class.`);
this.code.line(' */');
this.code.line(`public static readonly resourceTypeName = ${resourceTypeName};`);

if (spec.RequiredTransform) {
this.code.line('/**');
this.code.line(' * The ``Transform`` a template must use in order to use this resource');
this.code.line(' * The `Transform` a template must use in order to use this resource');
this.code.line(' */');
this.code.line(`public static readonly requiredTransform = ${JSON.stringify(spec.RequiredTransform)};`);
}
Expand All @@ -216,7 +222,7 @@ export default class CodeGenerator {

this.code.line();

this.docLink(undefined, `@cloudformation_attribute ${attributeName}`);
this.docLink(undefined, `@cloudformationAttribute ${attributeName}`);
const attr = genspec.attributeDefinition(resourceName, attributeName, attributeSpec);

this.code.line(`public readonly ${attr.propertyName}: ${attr.attributeType};`);
Expand All @@ -242,11 +248,11 @@ export default class CodeGenerator {
if (tagEnum !== `${TAG_TYPE}.NotTaggable`) {
this.code.line();
this.code.line('/**');
this.code.line(' * The ``TagManager`` handles setting, removing and formatting tags');
this.code.line(' * The `TagManager` handles setting, removing and formatting tags');
this.code.line(' *');
this.code.line(' * Tags should be managed either passing them as properties during');
this.code.line(' * initiation or by calling methods on this object. If both techniques are');
this.code.line(' * used only the tags from the TagManager will be used. ``Tag`` (aspect)');
this.code.line(' * used only the tags from the TagManager will be used. `Tag` (aspect)');
this.code.line(' * will use the manager.');
this.code.line(' */');
this.code.line(`public readonly tags = new ${TAG_MANAGER}(${tagEnum}, ${resourceTypeName});`);
Expand All @@ -258,11 +264,11 @@ export default class CodeGenerator {

this.code.line();
this.code.line('/**');
this.code.line(` * Creates a new ${quoteCode(resourceName.specName!.fqn)}.`);
this.code.line(` * Create a new ${quoteCode(resourceName.specName!.fqn)}.`);
this.code.line(' *');
this.code.line(` * @param scope scope in which this resource is defined`);
this.code.line(` * @param id scoped id of the resource`);
this.code.line(` * @param props resource properties`);
this.code.line(` * @param scope - scope in which this resource is defined`);
this.code.line(` * @param id - scoped id of the resource`);
this.code.line(` * @param props - resource properties`);
this.code.line(' */');
const optionalProps = spec.Properties && !Object.values(spec.Properties).some(p => p.Required || false);
const propsArgument = propsType ? `, props${optionalProps ? '?' : ''}: ${propsType.className}` : '';
Expand Down Expand Up @@ -362,7 +368,7 @@ export default class CodeGenerator {
this.code.line('/**');
this.code.line(` * Renders the AWS CloudFormation properties of an ${quoteCode(typeName.specName!.fqn)} resource`);
this.code.line(' *');
this.code.line(` * @param properties the TypeScript properties of a ${quoteCode(typeName.className)}`);
this.code.line(` * @param properties - the TypeScript properties of a ${quoteCode(typeName.className)}`);
this.code.line(' *');
this.code.line(` * @returns the AWS CloudFormation properties of an ${quoteCode(typeName.specName!.fqn)} resource.`);
this.code.line(' */');
Expand Down Expand Up @@ -448,7 +454,7 @@ export default class CodeGenerator {
this.code.line('/**');
this.code.line(` * Determine whether the given properties match those of a ${quoteCode(typeName.className)}`);
this.code.line(' *');
this.code.line(` * @param properties the TypeScript properties of a ${quoteCode(typeName.className)}`);
this.code.line(` * @param properties - the TypeScript properties of a ${quoteCode(typeName.className)}`);
this.code.line(' *');
this.code.line(' * @returns the result of the validation.');
this.code.line(' */');
Expand Down Expand Up @@ -622,9 +628,9 @@ export default class CodeGenerator {
private docLink(link: string | undefined, ...before: string[]) {
if (!link && before.length === 0) { return; }
this.code.line('/**');
before.forEach(line => this.code.line(` * ${line}`));
before.forEach(line => this.code.line(` * ${line}`.trimRight()));
if (link) {
this.code.line(` * @link ${link}`);
this.code.line(` * @see ${link}`);
}
this.code.line(' */');
return;
Expand All @@ -639,14 +645,14 @@ export default class CodeGenerator {

/**
* Quotes a code name for inclusion in a JSDoc comment, so it will render properly
* in the Sphinx output.
* in the Markdown output.
*
* @param code a code name to be quoted.
*
* @returns the code name surrounded by double backticks.
*/
function quoteCode(code: string): string {
return '``' + code + '``';
return '`' + code + '`';
}

function tokenizableType(alternatives: string[]) {
Expand Down