jsii-rosetta 5.0.4 → 5.0.5-dev.1

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.
Files changed (2) hide show
  1. package/README.md +383 -22
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -2,15 +2,17 @@
2
2
 
3
3
  [![Join the chat at https://cdk.Dev](https://img.shields.io/static/v1?label=Slack&message=cdk.dev&color=brightgreen&logo=slack)](https://cdk.dev)
4
4
  [![All Contributors](https://img.shields.io/github/all-contributors/aws/jsii/main?label=%E2%9C%A8%20All%20Contributors)](#contributors-)
5
- [![Build Status](https://github.com/aws/jsii-compiler/workflows/build/badge.svg)](https://github.com/aws/jsii-compiler/actions?query=workflow%3Abuild+branch%3Amain)
6
- [![npm](https://img.shields.io/npm/v/jsii?logo=npm)](https://www.npmjs.com/package/jsii)
7
- [![docker](https://img.shields.io/badge/docker-jsii%2Fsuperchain-brightgreen?logo=docker)](https://hub.docker.com/r/jsii/superchain)
5
+ [![Build Status](https://github.com/aws/jsii-rosetta/workflows/build/badge.svg)](https://github.com/aws/jsii-rosetta/actions?query=workflow%3Abuild+branch%3Amain)
6
+ [![npm](https://img.shields.io/npm/v/jsii-rosetta?logo=npm)](https://www.npmjs.com/package/jsii-rosetta)
8
7
 
9
8
  ## Overview
10
9
 
11
10
  `jsii-rosetta` translates code samples contained in jsii libraries from TypeScript to supported *jsii* target languages.
12
11
  This is what enables the [AWS Cloud Development Kit][cdk] to deliver polyglot documentation from a single codebase!
13
12
 
13
+ `jsii-rosetta` leverages knowledge about jsii language translation conventions in order to produce translations. It only
14
+ supports a limited set of TypeScript language features (which can be reliably represented in other languages).
15
+
14
16
  [cdk]: https://github.com/aws/aws-cdk
15
17
 
16
18
  ## :question: Documentation
@@ -30,31 +32,390 @@ The jsii toolchain is spread out on multiple repositories:
30
32
  - The jsii runtime libraries for the supported jsii target languages
31
33
  - `1.x` release lines of `jsii` and `jsii-rosetta`
32
34
 
33
- # :book: Blog Posts
35
+ # :gear: Contributing
36
+
37
+ See [CONTRIBUTING](./CONTRIBUTING.md).
34
38
 
35
- Here's a collection of blog posts (in chronological order) related to `jsii`:
39
+ # :school_satchel: Getting Started
36
40
 
37
- - **2020-01-11:** <a id="blog-mbonig" /> [How to Create CDK Constructs][mbonig-2020-01-11], by [Matthew Bonig][@mbonig]
38
- - **2020-05-27:** <a id="blog-floydpink" /> [Generate Python, Java, and .NET software libraries from a TypeScript
39
- source][floydpink-2020-05-27], by [Hari Pachuveetil][@floydpink]
40
- - **2020-12-23:** <a id="blog-romainmuller" /> [How the jsii open source framework meets developers where they are
41
- ][romain-2020-12-23], by [Romain Marcadier][@RomainMuller]
41
+ ## Rosetta for example authors
42
42
 
43
- [mbonig-2020-01-11]: https://www.matthewbonig.com/2020/01/11/creating-constructs/
44
- [floydpink-2020-05-27]:
45
- https://aws.amazon.com/fr/blogs/opensource/generate-python-java-dotnet-software-libraries-from-typescript-source/
46
- [romain-2020-12-23]:
47
- https://aws.amazon.com/blogs/opensource/how-the-jsii-open-source-framework-meets-developers-where-they-are/
48
- [@mbonig]: http://www.matthewbonig.com/
49
- [@floydpink]: https://harimenon.com/
50
- [@romainmuller]: https://github.com/RomainMuller
43
+ This section describes what to pay attention to when writing examples that will be converted
44
+ by Rosetta.
51
45
 
52
- > :information_source: If you wrote blog posts about `jsii` and would like to have them referenced here, do not hesitate
53
- > to file a pull request to add the links here!
46
+ ### Making examples compile
54
47
 
55
- # :gear: Contributing
48
+ The translator can translate both code that completely compiles and typechecks, as well as code that doesn't.
56
49
 
57
- See [CONTRIBUTING](./CONTRIBUTING.md).
50
+ In case of non-compiling samples the translations will be based off of grammatical parsing only. This has the downside
51
+ that we do not have the type information available to the exact thing in all instances. Specifically
52
+ struct types will not be able to be inferred from object literals. Have a look at the following piece of code:
53
+
54
+ ```ts
55
+ someObject.someMethod('foo', {
56
+ bar: 3,
57
+ });
58
+ ```
59
+
60
+ In non-TypeScript languages, it is important to know the type of the second
61
+ argument to the method here. However, without access to the definition of
62
+ `someMethod()`, it's impossible for Rosetta to know the type, and hence
63
+ it cannot translate the example. It is therefore important to include necessary
64
+ imports, variable declarations, etc, to give Rosetta enough information to figure
65
+ out what's going on in this code, and the example should read like this:
66
+
67
+ ```ts
68
+ import * as myLib from 'some-library';
69
+
70
+ declare const someObject: myLib.SomeClass;
71
+
72
+ someObject.someMethod('foo', {
73
+ bar: 3,
74
+ });
75
+ ```
76
+
77
+ ### Enforcing correct examples
78
+
79
+ By default, Rosetta will accept non-compiling examples. If you set
80
+ `jsiiRosetta.strict` to `true` in your `package.json`,
81
+ the Rosetta command will fail if any example contains an error:
82
+
83
+ ```js
84
+ /// package.json
85
+ {
86
+ "jsiiRosetta": {
87
+ "strict": true
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Fixtures
93
+
94
+ To avoid having to repeat common setup every time, code samples can use
95
+ "fixtures": a source template where the example is inserted. A fixture must
96
+ contain the text `/// here` and typically looks like this:
97
+
98
+ ```ts
99
+ const * as module from '@some/dependency';
100
+
101
+ class MyClass {
102
+ constructor() {
103
+ const obj = new MyObject();
104
+
105
+ /// here
106
+ }
107
+ }
108
+ ```
109
+
110
+ The example will be inserted at the location marked as `/// here` and will have
111
+ access to `module`, `obj` and `this`. Any `import` statements found in the
112
+ example will automatically be hoisted at the top of the fixture, where they are
113
+ guaranteed to be syntactically valid.
114
+
115
+ The default file loaded as a fixture is called `rosetta/default.ts-fixture` in
116
+ the package directory (if it exists).
117
+
118
+ Examples can request an alternative fixture by specifying a `fixture` parameter
119
+ as part of the code block fence:
120
+
121
+ ````text
122
+ ```ts fixture=some-fixture
123
+ ````
124
+
125
+ Or opt out of using the default fixture by specifying `nofixture`:
126
+
127
+ ````text
128
+ ```ts nofixture
129
+ ````
130
+
131
+ To specify fixtures in an `@example` block, use an accompanying `@exampleMetadata` tag:
132
+
133
+ ````text
134
+ /**
135
+ * My cool class
136
+ *
137
+ * @exampleMetadata fixture=with-setup
138
+ * @example
139
+ *
140
+ * new MyCoolClass();
141
+ */
142
+ ````
143
+
144
+ ### Dependencies
145
+
146
+ When compiling examples, Rosetta will make sure your package itself and all of
147
+ its `dependencies` and `peerDependencies` are available in the dependency
148
+ closure that your examples will be compiled in.
149
+
150
+ If there are packages you want to use in an example that should *not* be part
151
+ of your package's dependencies, declare them in `jsiiRosetta.exampleDependencies`
152
+ in your `package.json`:
153
+
154
+ ```js
155
+ /// package.json
156
+ {
157
+ "jsiiRosetta": {
158
+ "exampleDependencies": {
159
+ "@some-other/package": "^1.2.3",
160
+ "@yet-another/package": "*",
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ You can also set up a directory with correct dependencies yourself, and pass
167
+ `--directory` when running `jsii-rosetta extract`. We recommend using the
168
+ automatic closure building mechanism and specifying `exampleDependencies` though.
169
+
170
+ ## Rosetta for package publishers
171
+
172
+ This section describes how Rosetta integrates into your build process.
173
+
174
+ ### Extract
175
+
176
+ Rosetta has a number of subcommands. The most important one is `jsii-rosetta extract`.
177
+
178
+ The `jsii-rosetta extract` command will take one or more jsii assemblies,
179
+ extract the snippets from them, will try to compile them with respect to a given
180
+ home directory, and finally store all translations in something called a
181
+ "tablet".
182
+
183
+ A couple of things to note here:
184
+
185
+ * Snippets are always read from the jsii assembly. That means if you make
186
+ changes to examples in source files, you must first re-run `jsii` to
187
+ regenerate the assembly, before re-running `jsii-rosetta extract`.
188
+ * The compilation directory will be used to resolve `import`s. Currently, you
189
+ are responsible for building a directory with the correct `node_modules`
190
+ directories in there so that a TypeScript compilation step will find all
191
+ libraries referenced in the examples. This is especially revelant if your
192
+ examples include libraries that depend on the *current* library: it is not
193
+ uncommon to write examples in library `A` showing how to use it in combination
194
+ with library `B`, where `B` depends on `A`. However, since by definition `B`
195
+ *cannot* be in the set of dependencies of `A`, you must build a directory with
196
+ both `B` and `A` in it somewhere in your filesystem and run Rosetta in that
197
+ directory.
198
+ * "Extract" will compile samples in parallel. The more assemblies you give it
199
+ at the same time, the more efficient of a job it will be able to do.
200
+
201
+ The extract command will write a file named `.jsii.tabl.json` next to every
202
+ assembly, containing translations for all samples found in the assembly. You
203
+ should include this file in your NPM package when you publish, so that
204
+ downstream consumers of the package have access to the translations.
205
+
206
+ An example invocation of `jsii-rosetta extract` looks like this:
207
+
208
+ ```sh
209
+ jsii-rosetta extract --directory some/dir $(find . -name .jsii)
210
+ ```
211
+
212
+ #### Running in parallel
213
+
214
+ Since TypeScript compilation takes a lot of time, much time can be gained by
215
+ using the CPUs in your system effectively. `jsii-rosetta extract` will run the
216
+ compilations in parallel.
217
+
218
+ `jsii-rosetta` will use a number of workers equal to half the number of CPU
219
+ cores, up to a maximum of 16 workers. This default maximum can be overridden by
220
+ setting the `JSII_ROSETTA_MAX_WORKER_COUNT` environment variable.
221
+
222
+ If you get out of memory errors running too many workers, run a command like
223
+ this to raise the memory allowed for your workers:
224
+
225
+ ```sh
226
+ /sbin/sysctl -w vm.max_map_count=2251954
227
+ ```
228
+
229
+ #### Caching
230
+
231
+ Rosetta extract will translate all examples found in `.jsii` and write the
232
+ translations to `.jsii.tabl.json`. From compilation to compilation, many of these
233
+ examples won't have changed. Since TypeScript compilation is a fairly expensive
234
+ process, we would like to avoid doing unnecessary work as much as possible.
235
+
236
+ To that end, rosetta can reuse translations from a cache, and write
237
+ new translations into the same cache:
238
+
239
+ ```sh
240
+ jsii-rosetta extract \
241
+ --directory some/dir \
242
+ --cache cache.json \
243
+ [--trim-cache] \
244
+ $(find . -name .jsii)
245
+ ```
246
+
247
+ The `--trim-cache` flag will remove any old translations from the cache that
248
+ don't exist anymore in any of the given assemblies. This prevents the cache from
249
+ growing endlessly over time (an equivalent `jsii-rosetta trim-cache` command is
250
+ available if your workflow involves running `extract` in multiple distinct
251
+ invocations and want to retain the cache between them).
252
+
253
+ ### Infuse
254
+
255
+ The `jsii-rosetta infuse` command increases the coverage of examples for classes
256
+ in the assembly.
257
+
258
+ It finds classes in the assembly that don't have an example associated with them
259
+ yet (as specified via the `@example` tag in the doc comments), but that are used
260
+ in another example found elsewhere—in either a `README` or an example of another
261
+ class—it will copy the example to all classes involved. This will make sure
262
+ your handwritten examples go as far as possible.
263
+
264
+ Note that in order to do this, `infuse` will *modify* the assemblies it is
265
+ given.
266
+
267
+ `rosetta infuse` depends on the analysis perfomed by `rosetta extract`, and must
268
+ therefore be run after `extract`. It can also be run as part of `extract`, by
269
+ passing the `--infuse` flag:
270
+
271
+ ```sh
272
+ jsii-rosetta extract \
273
+ --directory some/dir \
274
+ --infuse \
275
+ $(find . -name .jsii)
276
+ ```
277
+
278
+ ### Translations and pacmak
279
+
280
+ `jsii-pacmak` will read translation from tablets to substitute translated examples
281
+ into the generated source bindings. `pacmak` will automatically read individual
282
+ `.jsii.tabl.json` files if present, and can additionally also read from a global
283
+ tablet file.
284
+
285
+ When a translation for a code sample cannot be found, `pacmak` can be configured
286
+ to do one of the following:
287
+
288
+ * Leave the sample untranslated (default)
289
+ * Translate the sample in-place (this will slow down generation a lot, and you
290
+ will not have the fine control over the compilation environment that you would
291
+ have if you were to use the `extract` command)
292
+ * Fail
293
+
294
+ Example:
295
+
296
+ ```sh
297
+ jsii-pacmak \
298
+ [--rosetta-tablet=global.json] \
299
+ [--rosetta-unknown-snippets=verbatim|translate|fail]
300
+ ```
301
+
302
+ ### Data flow
303
+
304
+ The diagram below shows how data flows through the jsii tools when used together:
305
+
306
+ ```text
307
+ ┌───────────┐
308
+ │ │
309
+ │ Source ├───┐
310
+ │ │ │ ╔══════════╗ ┌────────────┐ ╔═══════════════╗ ┌──────────┐
311
+ └───────────┘ │ ║ ║ │ │ ║ rosetta ║ │ │
312
+ ├───▶║ jsii ║───▶│ assembly │────▶║ extract ║───▶│ tablet │
313
+ ┌───────────┐ │ ║ ║ │ │ ║ ║ │ │
314
+ │ │ │ ╚══════════╝ └────────────┘ ╚═══════════════╝ └──────────┘
315
+ │ README │───┘ │ │
316
+ │ │ │ │
317
+ └───────────┘ │ ╔═══════════════╗ │
318
+ │ ║ rosetta ║ │
319
+ └──────────▶║ infuse ║◀─────────┘
320
+ ║ ║
321
+ ╚═══════════════╝
322
+
323
+ ┌───────────────────┴───────────────────┐
324
+ │ │
325
+ ▼ ▼
326
+ ┌────────────┐ ┌──────────┐
327
+ │ │ │ │
328
+ │ assembly' │ │ tablet' │
329
+ │ │ │ │
330
+ └────────────┘ └──────────┘
331
+ │ │
332
+ │ │
333
+ │ ▼ ┌─────────────┐
334
+ │ ╔═══════════════╗ ┌┴────────────┐│
335
+ │ ║ ║ │ ││
336
+ └──────────────────────────────▶║ pacmak ║────▶│ packages ││
337
+ ║ ║ │ ├┘
338
+ ╚═══════════════╝ └─────────────┘
339
+ (potentially
340
+ live-translates)
341
+ ```
342
+
343
+ ## Advanced topics
344
+
345
+ ### Hiding code from samples
346
+
347
+ In order to make examples compile, boilerplate code may need to be added that detracts from the example at hand (such as
348
+ variable declarations and imports).
349
+
350
+ This package supports hiding parts of the original source after translation.
351
+
352
+ To mark special locations in the source tree, we can use one of three mechanisms:
353
+
354
+ * Use a `void` expression statement to mark statement locations in the AST.
355
+ * Use the `comma` operator combined with a `void` expression to mark expression locations in the AST.
356
+ * Use special directive comments (`/// !hide`, `/// !show`) to mark locations that span AST nodes. This is less reliable
357
+ (because the source location of translated syntax sometimes will have to be estimated) but the only option if you want
358
+ to mark non-contiguous nodes (such as hide part of a class declaration but show statements inside the constructor).
359
+
360
+ The `void` expression keyword and or the `comma` operator feature are little-used JavaScript features that are reliably
361
+ parsed by TypeScript and do not affect the semantics of the application in which they appear (so the program executes
362
+ the same with or without them).
363
+
364
+ A handy mnemonic for this feature is that you can use it to "send your code into the void".
365
+
366
+ #### Hiding statements
367
+
368
+ Statement hiding looks like this:
369
+
370
+ ```ts
371
+ before(); // will be shown
372
+
373
+ void 0; // start hiding (the argument to 'void' doesn't matter)
374
+ middle(); // will not be shown
375
+ void 'show'; // stop hiding
376
+
377
+ after(); // will be shown again
378
+ ```
379
+
380
+ #### Hiding expressions
381
+
382
+ For hiding expressions, we use `comma` expressions to attach a `void` statement to an expression value without changing
383
+ the meaning of the code.
384
+
385
+ Example:
386
+
387
+ ```ts
388
+ foo(1, 2, (void 1, 3));
389
+ ```
390
+
391
+ Will render as
392
+
393
+ ```ts
394
+ foo(1, 2)
395
+ ```
396
+
397
+ Also supports a visible ellipsis:
398
+
399
+ ```ts
400
+ const x = (void '...', 3);
401
+ ```
402
+
403
+ Renders to:
404
+
405
+ ```ts
406
+ x = ...
407
+ ```
408
+
409
+ #### Hiding across AST nodes
410
+
411
+ Use special comment directives:
412
+
413
+ ```ts
414
+ before();
415
+ /// !hide
416
+ notShown();
417
+ /// !show
418
+ after();
58
419
 
59
420
  ## Contributors ✨
60
421
 
package/package.json CHANGED
@@ -54,7 +54,7 @@
54
54
  "mock-fs": "^5.2.0",
55
55
  "npm-check-updates": "^16",
56
56
  "prettier": "^2.8.7",
57
- "projen": "^0.71.9",
57
+ "projen": "^0.71.15",
58
58
  "tar": "^6.1.13",
59
59
  "ts-jest": "^29.1.0",
60
60
  "ts-node": "^10.9.1"
@@ -67,7 +67,7 @@
67
67
  "commonmark": "^0.30.0",
68
68
  "fast-glob": "^3.2.12",
69
69
  "jsii": "5.0.x",
70
- "semver": "^7.4.0",
70
+ "semver": "^7.5.0",
71
71
  "semver-intersect": "^1.4.0",
72
72
  "stream-json": "^1.7.5",
73
73
  "typescript": "~5.0.4",
@@ -80,7 +80,7 @@
80
80
  "main": "lib/index.js",
81
81
  "license": "Apache-2.0",
82
82
  "homepage": "https://aws.github.io/jsii",
83
- "version": "5.0.4",
83
+ "version": "5.0.5-dev.1",
84
84
  "types": "lib/index.d.ts",
85
85
  "exports": {
86
86
  ".": "./lib/index.js",