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(rosetta): reuse translation results from a cache #3101

Merged
merged 17 commits into from
Nov 2, 2021
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
36 changes: 17 additions & 19 deletions packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
TargetLanguage,
Translation,
enforcesStrictMode,
typeScriptSnippetFromSource,
markDownToXmlDoc,
ApiLocation,
} from 'jsii-rosetta';
import * as xmlbuilder from 'xmlbuilder';

Expand Down Expand Up @@ -44,7 +44,7 @@ export class DotNetDocGenerator {
* Returns
* Remarks (includes examples, links, deprecated)
*/
public emitDocs(obj: spec.Documentable): void {
public emitDocs(obj: spec.Documentable, apiLocation: ApiLocation): void {
const docs = obj.docs;

// The docs may be undefined at the method level but not the parameters level
Expand Down Expand Up @@ -76,7 +76,7 @@ export class DotNetDocGenerator {
// Remarks does not use emitXmlDoc() because the remarks can contain code blocks
// which are fenced with <code> tags, which would be escaped to
// &lt;code&gt; if we used the xml builder.
const remarks = this.renderRemarks(docs);
const remarks = this.renderRemarks(docs, apiLocation);
if (remarks.length > 0) {
this.code.line('/// <remarks>');
remarks.forEach((r) => this.code.line(`/// ${r}`.trimRight()));
Expand All @@ -85,18 +85,21 @@ export class DotNetDocGenerator {

if (docs.example) {
this.code.line('/// <example>');
this.emitXmlDoc('code', this.convertExample(docs.example));
this.emitXmlDoc('code', this.convertExample(docs.example, apiLocation));
this.code.line('/// </example>');
}
}

public emitMarkdownAsRemarks(markdown: string | undefined) {
public emitMarkdownAsRemarks(
markdown: string | undefined,
apiLocation: ApiLocation,
) {
if (!markdown) {
return;
}

const translated = markDownToXmlDoc(
this.convertSamplesInMarkdown(markdown),
this.convertSamplesInMarkdown(markdown, apiLocation),
);
const lines = translated.split('\n');

Expand All @@ -110,12 +113,12 @@ export class DotNetDocGenerator {
/**
* Returns the lines that should go into the <remarks> section
*/
private renderRemarks(docs: spec.Docs): string[] {
private renderRemarks(docs: spec.Docs, apiLocation: ApiLocation): string[] {
const ret: string[] = [];

if (docs.remarks) {
const translated = markDownToXmlDoc(
this.convertSamplesInMarkdown(docs.remarks),
this.convertSamplesInMarkdown(docs.remarks, apiLocation),
);
ret.push(...translated.split('\n'));
ret.push('');
Expand Down Expand Up @@ -161,24 +164,19 @@ export class DotNetDocGenerator {
}
}

private convertExample(example: string): string {
const snippet = typeScriptSnippetFromSource(
private convertExample(example: string, apiLocation: ApiLocation): string {
const translated = this.rosetta.translateExample(
apiLocation,
example,
'example',
enforcesStrictMode(this.assembly),
);
const translated = this.rosetta.translateSnippet(
snippet,
TargetLanguage.CSHARP,
enforcesStrictMode(this.assembly),
);
if (!translated) {
return example;
}
return this.prefixDisclaimer(translated);
}

private convertSamplesInMarkdown(markdown: string): string {
private convertSamplesInMarkdown(markdown: string, api: ApiLocation): string {
return this.rosetta.translateSnippetsInMarkdown(
api,
markdown,
TargetLanguage.CSHARP,
enforcesStrictMode(this.assembly),
Expand Down
78 changes: 63 additions & 15 deletions packages/jsii-pacmak/lib/targets/dotnet/dotnetgenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class DotNetGenerator extends Generator {
this.assembly.name,
jsiiNs,
);
this.emitNamespaceDocs(dotnetNs, submodule);
this.emitNamespaceDocs(dotnetNs, jsiiNs, submodule);
}
}

Expand All @@ -174,7 +174,7 @@ export class DotNetGenerator extends Generator {
const namespace = this.namespaceFor(this.assembly, ifc);
this.openFileIfNeeded(interfaceName, namespace, this.isNested(ifc));

this.dotnetDocGenerator.emitDocs(ifc);
this.dotnetDocGenerator.emitDocs(ifc, { api: 'type', fqn: ifc.fqn });
this.dotnetRuntimeGenerator.emitAttributesForInterface(ifc);

if (implementations.length > 0) {
Expand Down Expand Up @@ -204,7 +204,11 @@ export class DotNetGenerator extends Generator {
}

protected onInterfaceMethod(ifc: spec.InterfaceType, method: spec.Method) {
this.dotnetDocGenerator.emitDocs(method);
this.dotnetDocGenerator.emitDocs(method, {
api: 'member',
fqn: ifc.fqn,
memberName: method.name,
});
this.dotnetRuntimeGenerator.emitAttributesForMethod(ifc, method);
const returnType = method.returns
? this.typeresolver.toDotNetType(method.returns.type)
Expand Down Expand Up @@ -243,7 +247,11 @@ export class DotNetGenerator extends Generator {
}

this.emitNewLineIfNecessary();
this.dotnetDocGenerator.emitDocs(prop);
this.dotnetDocGenerator.emitDocs(prop, {
api: 'member',
fqn: ifc.fqn,
memberName: prop.name,
});
this.dotnetRuntimeGenerator.emitAttributesForProperty(prop);

const propType = this.typeresolver.toDotNetType(prop.type);
Expand Down Expand Up @@ -308,7 +316,11 @@ export class DotNetGenerator extends Generator {

const implementsExpr = ` : ${baseTypeNames.join(', ')}`;

this.dotnetDocGenerator.emitDocs(cls);
this.dotnetDocGenerator.emitDocs(cls, {
api: 'type',
fqn: cls.fqn,
});

this.dotnetRuntimeGenerator.emitAttributesForClass(cls);

this.code.openBlock(
Expand All @@ -320,7 +332,10 @@ export class DotNetGenerator extends Generator {
let parametersBase = '';
const initializer = cls.initializer;
if (initializer) {
this.dotnetDocGenerator.emitDocs(initializer);
this.dotnetDocGenerator.emitDocs(initializer, {
api: 'initializer',
fqn: cls.fqn,
});
this.dotnetRuntimeGenerator.emitDeprecatedAttributeIfNecessary(
initializer,
);
Expand Down Expand Up @@ -452,7 +467,10 @@ export class DotNetGenerator extends Generator {
const namespace = this.namespaceFor(this.assembly, enm);
this.openFileIfNeeded(enumName, namespace, this.isNested(enm));
this.emitNewLineIfNecessary();
this.dotnetDocGenerator.emitDocs(enm);
this.dotnetDocGenerator.emitDocs(enm, {
api: 'type',
fqn: enm.fqn,
});
this.dotnetRuntimeGenerator.emitAttributesForEnum(enm, enumName);
this.code.openBlock(`public enum ${enm.name}`);
}
Expand All @@ -465,7 +483,11 @@ export class DotNetGenerator extends Generator {
}

protected onEnumMember(enm: spec.EnumType, member: spec.EnumMember) {
this.dotnetDocGenerator.emitDocs(member);
this.dotnetDocGenerator.emitDocs(member, {
api: 'member',
fqn: enm.fqn,
memberName: member.name,
});
const enumMemberName = this.nameutils.convertEnumMemberName(member.name);
this.dotnetRuntimeGenerator.emitAttributesForEnumMember(
enumMemberName,
Expand Down Expand Up @@ -544,7 +566,11 @@ export class DotNetGenerator extends Generator {
method,
)})`;

this.dotnetDocGenerator.emitDocs(method);
this.dotnetDocGenerator.emitDocs(method, {
api: 'member',
fqn: cls.fqn,
memberName: method.name,
});
this.dotnetRuntimeGenerator.emitAttributesForMethod(
cls,
method /*, emitForProxyOrDatatype*/,
Expand Down Expand Up @@ -669,7 +695,10 @@ export class DotNetGenerator extends Generator {
this.openFileIfNeeded(name, namespace, isNested);

this.code.line();
this.dotnetDocGenerator.emitDocs(ifc);
this.dotnetDocGenerator.emitDocs(ifc, {
api: 'type',
fqn: ifc.fqn,
});
this.dotnetRuntimeGenerator.emitAttributesForInterfaceProxy(ifc);

const interfaceFqn = this.typeresolver.toNativeFqn(ifc.fqn);
Expand Down Expand Up @@ -758,7 +787,10 @@ export class DotNetGenerator extends Generator {
this.code.line();
}

this.dotnetDocGenerator.emitDocs(ifc);
this.dotnetDocGenerator.emitDocs(ifc, {
api: 'type',
fqn: ifc.fqn,
});
const suffix = `: ${this.typeresolver.toNativeFqn(ifc.fqn)}`;
this.dotnetRuntimeGenerator.emitAttributesForInterfaceDatatype(ifc);
this.code.openBlock(`public class ${name} ${suffix}`);
Expand Down Expand Up @@ -888,7 +920,11 @@ export class DotNetGenerator extends Generator {
const staticKeyWord = prop.static ? 'static ' : '';
const propName = this.nameutils.convertPropertyName(prop.name);

this.dotnetDocGenerator.emitDocs(prop);
this.dotnetDocGenerator.emitDocs(prop, {
api: 'member',
fqn: cls.fqn,
memberName: prop.name,
});
if (prop.optional) {
this.code.line('[JsiiOptional]');
}
Expand Down Expand Up @@ -969,7 +1005,11 @@ export class DotNetGenerator extends Generator {
this.flagFirstMemberWritten(true);
const propType = this.typeresolver.toDotNetType(prop.type);
const isOptional = prop.optional ? '?' : '';
this.dotnetDocGenerator.emitDocs(prop);
this.dotnetDocGenerator.emitDocs(prop, {
api: 'member',
fqn: cls.fqn,
memberName: prop.name,
});
this.dotnetRuntimeGenerator.emitAttributesForProperty(prop);
const access = this.renderAccessLevel(prop);
const propName = this.nameutils.convertPropertyName(prop.name);
Expand Down Expand Up @@ -1086,6 +1126,7 @@ export class DotNetGenerator extends Generator {
private emitAssemblyDocs() {
this.emitNamespaceDocs(
this.assembly.targets!.dotnet!.namespace,
this.assembly.name,
this.assembly,
);
}
Expand All @@ -1102,15 +1143,22 @@ export class DotNetGenerator extends Generator {
* In any case, we need a place to attach the docs where they can be transported around,
* might as well be this method.
*/
private emitNamespaceDocs(namespace: string, docSource: spec.Targetable) {
private emitNamespaceDocs(
namespace: string,
jsiiFqn: string,
docSource: spec.Targetable,
) {
if (!docSource.readme) {
return;
}

const className = 'NamespaceDoc';
this.openFileIfNeeded(className, namespace, false, false);

this.dotnetDocGenerator.emitMarkdownAsRemarks(docSource.readme.markdown);
this.dotnetDocGenerator.emitMarkdownAsRemarks(docSource.readme.markdown, {
api: 'moduleReadme',
moduleFqn: jsiiFqn,
});
this.emitHideAttribute();
// Traditionally this class is made 'internal', but that interacts poorly with DocFX's default filters
// which aren't overridable. So we make it public, but use attributes to hide it from users' IntelliSense,
Expand Down
Loading