-
Notifications
You must be signed in to change notification settings - Fork 260
Description
In order to provide CDK users with code samples in every language, we automatically translate snippets of TypeScript sample code into other languages.
You can recognize these translated example blocks by them starting with a text similar to the following:
# Example automatically generated. See https://...
This translation is currently experimental, and we'd like you to let us know how this is working out for you. Please comment on this issue if there's something you would like to discuss.
Examples we couldn't compile
We try compiling all the samples before translating them. This is necessary to extract type information that is necessary to render the correct translation of non-TypeScript languages.
However, compilation of sample code requires some setup that we haven't been able to do for all of our code samples yet. That means that many samples are translated without complete type information, and may hence be incorrect. You can recognize them by starting with a comment similar to:
# Example automatically generated without compilation. See https://...
If you encounter issues with some of these samples that are caused by its lack of compilation, we'd love it if you could help out by submitting a Pull Request to make the samples compile! See the following section to figure out what to expect.
Translation mistakes in uncompiled samples
The most common mistake in uncompiled samples is going to be around Structs, which are pure data objects passed to constructors and methods. They are typically called something like FooProps or FooOptions, and in samples they appear something like this:
new SomeClass('param', {
prop1: 'value1',
prop2: 'value2'
})MISTAKE 1: is it a struct or a map?
Mistake 1 the translator may make in translating the preceding code example without having any type information available, is that it can't know whether the argument to new SomeClass is intended to be of type {[key: string]: string} (i.e., a map of string to string), or of type interface SomeClassProps (i.e., a struct).
The caller side for both types looks exactly the same in TypeScript, so the translator can't distinguish between them, and so it is forced to guess.
In most cases uses like this will be structs, so that's what the translator will guess given no other information. However, some classes legitimately take a map as argument (for example, GenericLinuxImage takes a map of region-to-ami), and in those cases the translator will have guessed wrong and produce an incorrect translation.
N.B.: The Java translator will prefer to guess that an untyped value is a map, rather than a struct.
MISTAKE 2: what is the struct's name?
When the translator guesses that something is a struct, it needs to translate it. In a language like Python, structs get translated into keyword arguments and so they don't need names. In other languages like Java and C#, structs get translated into data classes, and you need their name to instantiate them. Unfortunately, the name of the structs doesn't appear in the code sample and since we have no type information we can't look it up.
In those cases, the translator will generate a placeholder name called Struct, with the understanding that you will need to go and look up the actual name when using this code. For example, the C# translator will have translated the above snippet into:
new SomeClass('param', new Struct {
Prop1 = "value1",
Prop2 = "value2"
})
You will need to go and look at the documentation of SomeClass to figure out that new Struct actually needs to be new SomeClassProps, or something to that effect.
How to make samples compile successfully
We'd rather have all samples compile successfully. To achieve that, modules need some boilerplate added to make it possible to compile the examples. Typically, this boilerplate file will just import some names or set up some variables. This is called a fixture.
For example, making our running example compilable would look something like this.
Add a file to the package called rosetta/my-fixture.ts-fixture, and put the following into it:
import { SomeClass } from 'my-library';
/// hereAnd update the example to look like this:
```ts fixture=my-fixture
new SomeClass('param', {
prop1: 'value1',
prop2: 'value2'
})
```
The example code will be inserted into the fixture file at the location marked by /// here, and the resulting complete file should compile.
For more information, see the "Examples" section of aws-cdk's Contribution Guide or the "Fixtures" section of the rosetta tool.
Known Issues
The following are known issues with the translation tool:
Language keywords are not respected: Sometimes TypeScript code uses identifiers which are reserved keywords in other languages. The translated code may copy those identifiers without modification, leading to code that won't compile (example: import aws_cdk.aws_lambda as lambda won't actually work in Python as lambda is a reserved keyword).
Single values are interpreted as code snippets: The @example doc comment directive is used both for code snippets, as well as exemplar values for properties. The translator tries to translate the sample values, which will maul them (example).