jsii-rosetta 5.9.16-dev.4 → 5.9.19

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 (40) hide show
  1. package/README.md +14 -0
  2. package/lib/commands/extract.d.ts +6 -0
  3. package/lib/commands/extract.js +16 -3
  4. package/lib/commands/extract.js.map +1 -1
  5. package/lib/commands/infuse.js +1 -1
  6. package/lib/commands/infuse.js.map +1 -1
  7. package/lib/commands/transliterate.d.ts +6 -0
  8. package/lib/commands/transliterate.js +1 -0
  9. package/lib/commands/transliterate.js.map +1 -1
  10. package/lib/languages/python.js +16 -7
  11. package/lib/languages/python.js.map +1 -1
  12. package/lib/logging.d.ts +3 -3
  13. package/lib/logging.js +14 -6
  14. package/lib/logging.js.map +1 -1
  15. package/lib/main.js +15 -0
  16. package/lib/main.js.map +1 -1
  17. package/lib/o-tree.d.ts +20 -6
  18. package/lib/o-tree.js +45 -4
  19. package/lib/o-tree.js.map +1 -1
  20. package/lib/renderer.d.ts +1 -1
  21. package/lib/renderer.js +1 -1
  22. package/lib/renderer.js.map +1 -1
  23. package/lib/rosetta-reader.js +2 -2
  24. package/lib/rosetta-reader.js.map +1 -1
  25. package/lib/rosetta-translator.d.ts +6 -0
  26. package/lib/rosetta-translator.js +3 -5
  27. package/lib/rosetta-translator.js.map +1 -1
  28. package/lib/translate.d.ts +73 -27
  29. package/lib/translate.js +142 -56
  30. package/lib/translate.js.map +1 -1
  31. package/lib/translate_all.d.ts +1 -1
  32. package/lib/translate_all.js +12 -4
  33. package/lib/translate_all.js.map +1 -1
  34. package/lib/translate_all_worker.d.ts +4 -0
  35. package/lib/translate_all_worker.js +22 -1
  36. package/lib/translate_all_worker.js.map +1 -1
  37. package/lib/typescript/ts-compiler.d.ts +9 -2
  38. package/lib/typescript/ts-compiler.js +42 -25
  39. package/lib/typescript/ts-compiler.js.map +1 -1
  40. package/package.json +6 -6
package/README.md CHANGED
@@ -263,6 +263,20 @@ growing endlessly over time (an equivalent `jsii-rosetta trim-cache` command is
263
263
  available if your workflow involves running `extract` in multiple distinct
264
264
  invocations and want to retain the cache between them).
265
265
 
266
+ ##### Dirty Translations
267
+
268
+ When reusing translations from cache, Rosetta checks if cached translations are still valid.
269
+ A translation becomes "dirty" (and is dropped from cache) when:
270
+
271
+ - **Changed sources**: The TypeScript source code has been modified since the translation was cached.
272
+ - **Changed translator version**: The translator for one or more target languages has been updated to a new version.
273
+ This is a rare occurrence that may happen when upgrading from an older version of Rosetta.
274
+ - **Changed types**: The types referenced by the snippet have changed and consequently any translation might have to be updated.
275
+ This is detected using type fingerprinting.
276
+ - **Non-compiling**: The cached translation didn't compile, but `--compile` mode is enabled.
277
+
278
+ Dirty translations are dropped and re-translated.
279
+
266
280
  ### Infuse
267
281
 
268
282
  The `jsii-rosetta infuse` command increases the coverage of examples for classes
@@ -73,6 +73,12 @@ export interface ExtractOptions {
73
73
  * @default true
74
74
  */
75
75
  readonly cleanup?: boolean;
76
+ /**
77
+ * Batch size for compiling snippets together
78
+ *
79
+ * @default undefined (no batching)
80
+ */
81
+ readonly batchSize?: number;
76
82
  }
77
83
  export declare function extractAndInfuse(assemblyLocations: string[], options: ExtractOptions): Promise<ExtractResult>;
78
84
  /**
@@ -50,9 +50,21 @@ async function extractSnippets(assemblyLocations, options = {}) {
50
50
  }
51
51
  translator.addTabletsToCache(...Object.values(await (0, assemblies_1.loadAllDefaultTablets)(assemblies)));
52
52
  if (translator.hasCache()) {
53
- const { translations, remaining } = translator.readFromCache(snippets, true, options.includeCompilerDiagnostics);
54
- logging.info(`Reused ${translations.length} translations from cache`);
55
- snippets = remaining;
53
+ const cache = translator.readFromCache(snippets, true, options.includeCompilerDiagnostics);
54
+ logging.info(`Reused ${cache.dirtyCount === 0 ? 'all ' : ''}${cache.translations.length} translations from cache`);
55
+ if (cache.dirtyCount) {
56
+ const dirt = {
57
+ 'non-compiling': cache.dirtyDidntCompile,
58
+ 'changed sources': cache.dirtySourceCount,
59
+ 'changed translator version': cache.dirtyTranslatorCount,
60
+ 'changed types': cache.dirtyTypesCount,
61
+ };
62
+ logging.info(`Dropped ${cache.dirtyCount} translations (${Object.entries(dirt)
63
+ .filter(([_, count]) => !!count)
64
+ .map(([desc, count]) => `${count} ${desc}`)
65
+ .join(', ')})`);
66
+ }
67
+ snippets = cache.remaining;
56
68
  }
57
69
  const diagnostics = [];
58
70
  if (snippets.length > 0) {
@@ -61,6 +73,7 @@ async function extractSnippets(assemblyLocations, options = {}) {
61
73
  const result = await translator.translateAll(snippets, {
62
74
  compilationDirectory: options.compilationDirectory,
63
75
  cleanup: options.cleanup,
76
+ batchSize: options.batchSize,
64
77
  });
65
78
  const delta = (Date.now() - startTime) / 1000;
66
79
  logging.info(`Translated ${snippets.length} snippets in ${delta} seconds (${(delta / snippets.length).toPrecision(3)}s/snippet)`);
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\n\nimport { infuse } from './infuse';\nimport {\n loadAssemblies,\n allTypeScriptSnippets,\n loadAllDefaultTablets,\n compressedTabletExists,\n} from '../jsii/assemblies';\nimport * as logging from '../logging';\nimport { RosettaTranslator, RosettaTranslatorOptions } from '../rosetta-translator';\nimport { TypeScriptSnippet, SnippetParameters } from '../snippet';\nimport { snippetKey } from '../tablets/key';\nimport { LanguageTablet, DEFAULT_TABLET_NAME, DEFAULT_TABLET_NAME_COMPRESSED } from '../tablets/tablets';\nimport { RosettaDiagnostic } from '../translate';\nimport { groupBy, isDefined } from '../util';\n\nexport interface ExtractResult {\n diagnostics: RosettaDiagnostic[];\n tablet: LanguageTablet;\n}\n\nexport interface ExtractOptions {\n readonly includeCompilerDiagnostics?: boolean;\n readonly validateAssemblies?: boolean;\n readonly only?: string[];\n\n /**\n * A tablet file to be loaded and used as a source for caching\n */\n readonly cacheFromFile?: string;\n\n /**\n * A tablet file to append translated snippets to\n */\n readonly cacheToFile?: string;\n\n /**\n * Trim cache to only contain translations found in the current assemblies\n *\n * @default false\n */\n readonly trimCache?: boolean;\n\n /**\n * Write translations to implicit tablets (`.jsii.tabl.json`)\n *\n * @default true\n */\n readonly writeToImplicitTablets?: boolean;\n\n /**\n * What directory to compile the samples in\n *\n * @default - Rosetta manages the compilation directory\n * @deprecated Samples declare their own dependencies instead\n */\n readonly compilationDirectory?: string;\n\n /**\n * Make a translator (just for testing)\n */\n readonly translatorFactory?: (opts: RosettaTranslatorOptions) => RosettaTranslator;\n\n /**\n * Turn on 'loose mode' or not\n *\n * Loose mode ignores failures during fixturizing, and undoes 'strict mode' for\n * diagnostics.\n *\n * @default false\n */\n readonly loose?: boolean;\n\n /**\n * Accept dirty translations from the cache\n *\n * @default false\n */\n readonly allowDirtyTranslations?: boolean;\n\n /**\n * Compress the implicit tablet files.\n *\n * @default - preserves the original compression status of each individual implicit tablet file.\n */\n readonly compressTablet?: boolean;\n\n /**\n * Compress the cacheToFile tablet.\n *\n * @default false\n */\n readonly compressCacheToFile?: boolean;\n\n /**\n * Cleanup temporary directories\n *\n * @default true\n */\n readonly cleanup?: boolean;\n}\n\nexport async function extractAndInfuse(assemblyLocations: string[], options: ExtractOptions): Promise<ExtractResult> {\n const result = await extractSnippets(assemblyLocations, options);\n await infuse(assemblyLocations, {\n cacheFromFile: options.cacheFromFile,\n cacheToFile: options.cacheToFile,\n compressCacheToFile: options.compressCacheToFile,\n });\n return result;\n}\n\n/**\n * Extract all samples from the given assemblies into a tablet\n */\nexport async function extractSnippets(\n assemblyLocations: readonly string[],\n options: ExtractOptions = {},\n): Promise<ExtractResult> {\n const only = options.only ?? [];\n\n logging.info(`Loading ${assemblyLocations.length} assemblies`);\n const assemblies = loadAssemblies(assemblyLocations, options.validateAssemblies ?? false);\n\n let snippets = Array.from(await allTypeScriptSnippets(assemblies, options.loose));\n if (only.length > 0) {\n snippets = filterSnippets(snippets, only);\n }\n\n // Map every assembly to a list of snippets, so that we know what implicit\n // tablet to write the translations to later on.\n const snippetsPerAssembly = groupBy(\n snippets.map((s) => ({ key: snippetKey(s), location: projectDirectory(s) })),\n (x) => x.location,\n );\n\n const translatorOptions: RosettaTranslatorOptions = {\n includeCompilerDiagnostics: options.includeCompilerDiagnostics ?? false,\n assemblies: assemblies.map((a) => a.assembly),\n allowDirtyTranslations: options.allowDirtyTranslations,\n };\n\n const translator = options.translatorFactory\n ? options.translatorFactory(translatorOptions)\n : new RosettaTranslator(translatorOptions);\n\n // Prime the snippet cache with:\n // - Cache source file\n // - Default tablets found next to each assembly\n if (options.cacheFromFile) {\n await translator.addToCache(options.cacheFromFile);\n }\n translator.addTabletsToCache(...Object.values(await loadAllDefaultTablets(assemblies)));\n\n if (translator.hasCache()) {\n const { translations, remaining } = translator.readFromCache(snippets, true, options.includeCompilerDiagnostics);\n logging.info(`Reused ${translations.length} translations from cache`);\n snippets = remaining;\n }\n\n const diagnostics = [];\n if (snippets.length > 0) {\n logging.info('Translating');\n const startTime = Date.now();\n\n const result = await translator.translateAll(snippets, {\n compilationDirectory: options.compilationDirectory,\n cleanup: options.cleanup,\n });\n\n const delta = (Date.now() - startTime) / 1000;\n logging.info(\n `Translated ${snippets.length} snippets in ${delta} seconds (${(delta / snippets.length).toPrecision(\n 3,\n )}s/snippet)`,\n );\n diagnostics.push(...result.diagnostics);\n } else {\n logging.info('Nothing left to translate');\n }\n\n // Save to individual tablet files\n if (options.writeToImplicitTablets ?? true) {\n await Promise.all(\n Object.entries(snippetsPerAssembly).map(async ([location, snips]) => {\n // Compress the implicit tablet if explicitly asked to, otherwise compress only if the original tablet was compressed.\n const compressedTablet = options.compressTablet ?? compressedTabletExists(location);\n\n const asmTabletFile = path.join(\n location,\n compressedTablet ? DEFAULT_TABLET_NAME_COMPRESSED : DEFAULT_TABLET_NAME,\n );\n logging.debug(`Writing ${snips.length} translations to ${asmTabletFile}`);\n const translations = snips.map(({ key }) => translator.tablet.tryGetSnippet(key)).filter(isDefined);\n\n const asmTablet = new LanguageTablet();\n asmTablet.addSnippets(...translations);\n await asmTablet.save(asmTabletFile, compressedTablet);\n }),\n );\n }\n\n // optionally append to the output file\n if (options.cacheToFile) {\n logging.info(`Adding translations to ${options.cacheToFile}`);\n const output = options.trimCache\n ? new LanguageTablet()\n : await LanguageTablet.fromOptionalFile(options.cacheToFile);\n output.addTablets(translator.tablet);\n await output.save(options.cacheToFile, options.compressCacheToFile);\n }\n\n return { diagnostics, tablet: translator.tablet };\n}\n\n/**\n * Only yield the snippets whose id exists in a whitelist\n */\nfunction filterSnippets(ts: TypeScriptSnippet[], includeIds: string[]) {\n return ts.filter((t) => includeIds.includes(snippetKey(t)));\n}\n\nfunction projectDirectory(ts: TypeScriptSnippet) {\n const dir = ts.parameters?.[SnippetParameters.$PROJECT_DIRECTORY];\n if (!dir) {\n throw new Error(`Snippet does not have associated project directory: ${JSON.stringify(ts.location)}`);\n }\n return dir;\n}\n"]}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\n\nimport { infuse } from './infuse';\nimport {\n loadAssemblies,\n allTypeScriptSnippets,\n loadAllDefaultTablets,\n compressedTabletExists,\n} from '../jsii/assemblies';\nimport * as logging from '../logging';\nimport { RosettaTranslator, RosettaTranslatorOptions } from '../rosetta-translator';\nimport { TypeScriptSnippet, SnippetParameters } from '../snippet';\nimport { snippetKey } from '../tablets/key';\nimport { LanguageTablet, DEFAULT_TABLET_NAME, DEFAULT_TABLET_NAME_COMPRESSED } from '../tablets/tablets';\nimport { RosettaDiagnostic } from '../translate';\nimport { groupBy, isDefined } from '../util';\n\nexport interface ExtractResult {\n diagnostics: RosettaDiagnostic[];\n tablet: LanguageTablet;\n}\n\nexport interface ExtractOptions {\n readonly includeCompilerDiagnostics?: boolean;\n readonly validateAssemblies?: boolean;\n readonly only?: string[];\n\n /**\n * A tablet file to be loaded and used as a source for caching\n */\n readonly cacheFromFile?: string;\n\n /**\n * A tablet file to append translated snippets to\n */\n readonly cacheToFile?: string;\n\n /**\n * Trim cache to only contain translations found in the current assemblies\n *\n * @default false\n */\n readonly trimCache?: boolean;\n\n /**\n * Write translations to implicit tablets (`.jsii.tabl.json`)\n *\n * @default true\n */\n readonly writeToImplicitTablets?: boolean;\n\n /**\n * What directory to compile the samples in\n *\n * @default - Rosetta manages the compilation directory\n * @deprecated Samples declare their own dependencies instead\n */\n readonly compilationDirectory?: string;\n\n /**\n * Make a translator (just for testing)\n */\n readonly translatorFactory?: (opts: RosettaTranslatorOptions) => RosettaTranslator;\n\n /**\n * Turn on 'loose mode' or not\n *\n * Loose mode ignores failures during fixturizing, and undoes 'strict mode' for\n * diagnostics.\n *\n * @default false\n */\n readonly loose?: boolean;\n\n /**\n * Accept dirty translations from the cache\n *\n * @default false\n */\n readonly allowDirtyTranslations?: boolean;\n\n /**\n * Compress the implicit tablet files.\n *\n * @default - preserves the original compression status of each individual implicit tablet file.\n */\n readonly compressTablet?: boolean;\n\n /**\n * Compress the cacheToFile tablet.\n *\n * @default false\n */\n readonly compressCacheToFile?: boolean;\n\n /**\n * Cleanup temporary directories\n *\n * @default true\n */\n readonly cleanup?: boolean;\n\n /**\n * Batch size for compiling snippets together\n *\n * @default undefined (no batching)\n */\n readonly batchSize?: number;\n}\n\nexport async function extractAndInfuse(assemblyLocations: string[], options: ExtractOptions): Promise<ExtractResult> {\n const result = await extractSnippets(assemblyLocations, options);\n await infuse(assemblyLocations, {\n cacheFromFile: options.cacheFromFile,\n cacheToFile: options.cacheToFile,\n compressCacheToFile: options.compressCacheToFile,\n });\n return result;\n}\n\n/**\n * Extract all samples from the given assemblies into a tablet\n */\nexport async function extractSnippets(\n assemblyLocations: readonly string[],\n options: ExtractOptions = {},\n): Promise<ExtractResult> {\n const only = options.only ?? [];\n\n logging.info(`Loading ${assemblyLocations.length} assemblies`);\n const assemblies = loadAssemblies(assemblyLocations, options.validateAssemblies ?? false);\n\n let snippets = Array.from(await allTypeScriptSnippets(assemblies, options.loose));\n if (only.length > 0) {\n snippets = filterSnippets(snippets, only);\n }\n\n // Map every assembly to a list of snippets, so that we know what implicit\n // tablet to write the translations to later on.\n const snippetsPerAssembly = groupBy(\n snippets.map((s) => ({ key: snippetKey(s), location: projectDirectory(s) })),\n (x) => x.location,\n );\n\n const translatorOptions: RosettaTranslatorOptions = {\n includeCompilerDiagnostics: options.includeCompilerDiagnostics ?? false,\n assemblies: assemblies.map((a) => a.assembly),\n allowDirtyTranslations: options.allowDirtyTranslations,\n };\n\n const translator = options.translatorFactory\n ? options.translatorFactory(translatorOptions)\n : new RosettaTranslator(translatorOptions);\n\n // Prime the snippet cache with:\n // - Cache source file\n // - Default tablets found next to each assembly\n if (options.cacheFromFile) {\n await translator.addToCache(options.cacheFromFile);\n }\n translator.addTabletsToCache(...Object.values(await loadAllDefaultTablets(assemblies)));\n\n if (translator.hasCache()) {\n const cache = translator.readFromCache(snippets, true, options.includeCompilerDiagnostics);\n logging.info(`Reused ${cache.dirtyCount === 0 ? 'all ' : ''}${cache.translations.length} translations from cache`);\n if (cache.dirtyCount) {\n const dirt = {\n 'non-compiling': cache.dirtyDidntCompile,\n 'changed sources': cache.dirtySourceCount,\n 'changed translator version': cache.dirtyTranslatorCount,\n 'changed types': cache.dirtyTypesCount,\n };\n logging.info(\n `Dropped ${cache.dirtyCount} translations (${Object.entries(dirt)\n .filter(([_, count]) => !!count)\n .map(([desc, count]) => `${count} ${desc}`)\n .join(', ')})`,\n );\n }\n\n snippets = cache.remaining;\n }\n\n const diagnostics = [];\n if (snippets.length > 0) {\n logging.info('Translating');\n const startTime = Date.now();\n\n const result = await translator.translateAll(snippets, {\n compilationDirectory: options.compilationDirectory,\n cleanup: options.cleanup,\n batchSize: options.batchSize,\n });\n\n const delta = (Date.now() - startTime) / 1000;\n logging.info(\n `Translated ${snippets.length} snippets in ${delta} seconds (${(delta / snippets.length).toPrecision(\n 3,\n )}s/snippet)`,\n );\n diagnostics.push(...result.diagnostics);\n } else {\n logging.info('Nothing left to translate');\n }\n\n // Save to individual tablet files\n if (options.writeToImplicitTablets ?? true) {\n await Promise.all(\n Object.entries(snippetsPerAssembly).map(async ([location, snips]) => {\n // Compress the implicit tablet if explicitly asked to, otherwise compress only if the original tablet was compressed.\n const compressedTablet = options.compressTablet ?? compressedTabletExists(location);\n\n const asmTabletFile = path.join(\n location,\n compressedTablet ? DEFAULT_TABLET_NAME_COMPRESSED : DEFAULT_TABLET_NAME,\n );\n logging.debug(`Writing ${snips.length} translations to ${asmTabletFile}`);\n const translations = snips.map(({ key }) => translator.tablet.tryGetSnippet(key)).filter(isDefined);\n\n const asmTablet = new LanguageTablet();\n asmTablet.addSnippets(...translations);\n await asmTablet.save(asmTabletFile, compressedTablet);\n }),\n );\n }\n\n // optionally append to the output file\n if (options.cacheToFile) {\n logging.info(`Adding translations to ${options.cacheToFile}`);\n const output = options.trimCache\n ? new LanguageTablet()\n : await LanguageTablet.fromOptionalFile(options.cacheToFile);\n output.addTablets(translator.tablet);\n await output.save(options.cacheToFile, options.compressCacheToFile);\n }\n\n return { diagnostics, tablet: translator.tablet };\n}\n\n/**\n * Only yield the snippets whose id exists in a whitelist\n */\nfunction filterSnippets(ts: TypeScriptSnippet[], includeIds: string[]) {\n return ts.filter((t) => includeIds.includes(snippetKey(t)));\n}\n\nfunction projectDirectory(ts: TypeScriptSnippet) {\n const dir = ts.parameters?.[SnippetParameters.$PROJECT_DIRECTORY];\n if (!dir) {\n throw new Error(`Snippet does not have associated project directory: ${JSON.stringify(ts.location)}`);\n }\n return dir;\n}\n"]}
@@ -165,7 +165,7 @@ function insertExample(example, original, type, tablets) {
165
165
  };
166
166
  }
167
167
  for (const tablet of tablets) {
168
- tablet.addSnippet(example.withLocation({
168
+ tablet.addSnippets(example.withLocation({
169
169
  api: { api: 'type', fqn: type.fqn },
170
170
  field: { field: 'example' },
171
171
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"infuse.js","sourceRoot":"","sources":["../../src/commands/infuse.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as spec from '@jsii/spec';\nimport { replaceAssembly } from '@jsii/spec';\n\nimport { loadAssemblies, loadAllDefaultTablets, LoadedAssembly, allTypeScriptSnippets } from '../jsii/assemblies';\nimport { renderMetadataline, TypeScriptSnippet } from '../snippet';\nimport { SnippetSelector, mean, meanLength, shortest, longest } from '../snippet-selectors';\nimport { snippetKey } from '../tablets/key';\nimport {\n LanguageTablet,\n TranslatedSnippet,\n DEFAULT_TABLET_NAME,\n DEFAULT_TABLET_NAME_COMPRESSED,\n} from '../tablets/tablets';\nimport { isDefined, mkDict, indexBy } from '../util';\n\nexport interface InfuseResult {\n readonly coverageResults: Record<string, InfuseTypes>;\n}\n\nexport interface InfuseTypes {\n readonly types: number;\n readonly typesWithInsertedExamples: number;\n}\n\nexport interface InfuseOptions {\n readonly logFile?: string;\n\n /**\n * Where to read additional translations\n */\n readonly cacheFromFile?: string;\n\n /**\n * In addition to the implicit tablets, also write all added examples to this additional output tablet\n */\n readonly cacheToFile?: string;\n\n /**\n * Compress the cacheToFile\n */\n readonly compressCacheToFile?: boolean;\n}\n\nexport const DEFAULT_INFUSION_RESULTS_NAME = 'infusion-results.html';\n\nconst ADDITIONAL_SELECTORS: Record<string, SnippetSelector> = { meanLength, shortest, longest };\n\nclass DefaultRecord<A> {\n public readonly index: Record<string, A[]> = {};\n\n public add(key: string, value: A) {\n if (!this.index[key]) {\n this.index[key] = [];\n }\n this.index[key].push(value);\n }\n}\n\n/**\n * Infuse will analyze the snippets in a set of tablets, and update the assembly to add\n * examples to types that don't have any yet, based on snippets that use the given type.\n */\nexport async function infuse(assemblyLocations: string[], options?: InfuseOptions): Promise<InfuseResult> {\n let stream: fs.WriteStream | undefined = undefined;\n if (options?.logFile) {\n // Create stream for html file and insert some styling\n stream = fs.createWriteStream(options.logFile, { encoding: 'utf-8' });\n startFile(stream);\n }\n\n // Load tablet file and assemblies\n const assemblies = loadAssemblies(assemblyLocations, false);\n const defaultTablets = await loadAllDefaultTablets(assemblies);\n\n const availableTranslations = new LanguageTablet();\n if (options?.cacheFromFile) {\n availableTranslations.addTablet(await LanguageTablet.fromOptionalFile(options.cacheFromFile));\n }\n availableTranslations.addTablets(...Object.values(defaultTablets));\n\n const { translationsByFqn, originalsByKey } = await availableSnippetsPerFqn(assemblies, availableTranslations);\n\n const additionalOutputTablet = options?.cacheToFile\n ? await LanguageTablet.fromOptionalFile(options?.cacheToFile)\n : new LanguageTablet();\n\n const coverageResults = mkDict(\n await Promise.all(\n assemblies.map(async ({ assembly, directory }) => {\n stream?.write(`<h1>${assembly.name}</h1>\\n`);\n\n const implicitTablet = defaultTablets[directory];\n const implicitTabletFile = path.join(\n directory,\n implicitTablet.compressedSource ? DEFAULT_TABLET_NAME_COMPRESSED : DEFAULT_TABLET_NAME,\n );\n if (!implicitTablet) {\n throw new Error(`No tablet found for ${directory}`);\n }\n\n let insertedExamples = 0;\n const filteredTypes = filterForTypesWithoutExamples(assembly.types ?? {});\n for (const [typeFqn, type] of Object.entries(filteredTypes)) {\n const available = translationsByFqn[typeFqn];\n if (!available) {\n continue;\n }\n\n const example = pickBestExample(typeFqn, available, stream);\n const original = originalsByKey[example.key];\n insertExample(example, original, type, [implicitTablet, additionalOutputTablet]);\n insertedExamples++;\n }\n\n if (insertedExamples > 0) {\n // Save the updated assembly and implicit tablets\n // eslint-disable-next-line no-await-in-loop\n await Promise.all([\n replaceAssembly(assembly, directory),\n implicitTablet.save(implicitTabletFile, implicitTablet.compressedSource),\n ]);\n }\n\n return [\n directory,\n {\n types: Object.keys(filteredTypes).length,\n typesWithInsertedExamples: insertedExamples,\n } as InfuseTypes,\n ] as const;\n }),\n ),\n );\n\n stream?.close();\n\n // If we copied examples onto different types, we'll also have inserted new snippets\n // with different keys into the tablet. We must now write the updated tablet somewhere.\n if (options?.cacheToFile) {\n await additionalOutputTablet.save(options.cacheToFile, options.compressCacheToFile);\n }\n\n return {\n coverageResults: coverageResults,\n };\n}\n\nfunction pickBestExample(typeFqn: string, choices: TranslatedSnippet[], logStream?: fs.WriteStream) {\n const meanResult = mean(choices);\n if (logStream) {\n const selected = Object.entries(ADDITIONAL_SELECTORS).map(([name, fn]) => [name, fn(choices)] as const);\n const selectedFromSelector = {\n ...makeDict(selected),\n mean: meanResult,\n };\n logOutput(logStream, typeFqn, createHtmlEntry(selectedFromSelector));\n }\n return meanResult;\n}\n\nfunction startFile(stream: fs.WriteStream) {\n stream.write('<style>\\n');\n stream.write('h2 { color: blue; clear: both; }\\n');\n stream.write('h1 { color: red; clear: both; }\\n');\n stream.write(\n 'div { float: left; height: 31em; width: 22em; overflow: auto; margin: 1em; background-color: #ddd; }\\n',\n );\n stream.write(\n 'pre { float: left; height: 30em; width: 25em; overflow: auto; padding: 0.5em; background-color: #ddd; }\\n',\n );\n stream.write('</style>\\n');\n}\n\nfunction createHtmlEntry(results: Record<string, TranslatedSnippet>): Record<string, string[]> {\n const entry = new DefaultRecord<string>();\n for (const [key, value] of Object.entries(results)) {\n entry.add(value.originalSource.source, key);\n }\n return entry.index;\n}\n\nfunction logOutput(stream: fs.WriteStream | undefined, typeFqn: string, algorithmMap: Record<string, string[]>) {\n stream?.write(`<h2>${typeFqn}</h2>\\n`);\n for (const [key, value] of Object.entries(algorithmMap)) {\n stream?.write(`<div class=\"snippet\"><h3>${value.toString()}</h3>\\n<pre>${key}</pre>\\n</div>\\n`);\n }\n for (let i = 0; i < 4 - Object.keys(algorithmMap).length; i++) {\n stream?.write('<div class=\"padding\"></div>\\n');\n }\n}\n\nfunction filterForTypesWithoutExamples(types: { [fqn: string]: spec.Type }): Record<string, spec.Type> {\n const filteredTypes: Record<string, spec.Type> = {};\n for (const [typeFqn, type] of Object.entries(types)) {\n // Ignore Interfaces that contain only properties\n if (type.kind === spec.TypeKind.Interface && !type.datatype) {\n continue;\n }\n // Already has example\n if (type.docs?.example !== undefined) {\n continue;\n }\n filteredTypes[typeFqn] = type;\n }\n return filteredTypes;\n}\n\n/**\n * Insert an example into the docs of a type, and insert it back into the tablet under a new key\n */\nfunction insertExample(\n example: TranslatedSnippet,\n original: TypeScriptSnippet | undefined,\n type: spec.Type,\n tablets: LanguageTablet[],\n): void {\n const parameters = {\n ...original?.parameters,\n infused: '',\n };\n // exampleMetadata should always be nonempty since we always have a parameter.\n const exampleMetadata = renderMetadataline(parameters) ?? '';\n\n if (type.docs) {\n type.docs.example = example.originalSource.source;\n type.docs.custom = { ...type.docs.custom, exampleMetadata };\n } else {\n type.docs = {\n example: example.originalSource.source,\n custom: { exampleMetadata },\n };\n }\n\n for (const tablet of tablets) {\n tablet.addSnippet(\n example.withLocation({\n api: { api: 'type', fqn: type.fqn },\n field: { field: 'example' },\n }),\n );\n }\n}\n\n/**\n * Return a map of FQN -> snippet keys that exercise that FQN.\n *\n * For a snippet to qualify, it must both:\n *\n * a) be current (i.e.: exist in the input assemblies)\n * b) have been analyzed (i.e.: exist in one of the translated tablets)\n *\n * Returns a map of fqns to a list of keys that represent snippets that include the fqn.\n */\nasync function availableSnippetsPerFqn(asms: readonly LoadedAssembly[], translationsTablet: LanguageTablet) {\n const ret = new DefaultRecord<TranslatedSnippet>();\n\n const originalsByKey = indexBy(await allTypeScriptSnippets(asms), snippetKey);\n\n const translations = Object.keys(originalsByKey)\n .map((key) => translationsTablet.tryGetSnippet(key))\n .filter(isDefined);\n\n for (const trans of translations) {\n for (const fqn of trans.snippet.fqnsReferenced ?? []) {\n ret.add(fqn, trans);\n }\n }\n\n return { originalsByKey, translationsByFqn: ret.index };\n}\n\nfunction makeDict<A>(xs: Array<readonly [string, A]>): Record<string, A> {\n const ret: Record<string, A> = {};\n for (const [str, a] of xs) {\n ret[str] = a;\n }\n return ret;\n}\n"]}
1
+ {"version":3,"file":"infuse.js","sourceRoot":"","sources":["../../src/commands/infuse.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as spec from '@jsii/spec';\nimport { replaceAssembly } from '@jsii/spec';\n\nimport { loadAssemblies, loadAllDefaultTablets, LoadedAssembly, allTypeScriptSnippets } from '../jsii/assemblies';\nimport { renderMetadataline, TypeScriptSnippet } from '../snippet';\nimport { SnippetSelector, mean, meanLength, shortest, longest } from '../snippet-selectors';\nimport { snippetKey } from '../tablets/key';\nimport {\n LanguageTablet,\n TranslatedSnippet,\n DEFAULT_TABLET_NAME,\n DEFAULT_TABLET_NAME_COMPRESSED,\n} from '../tablets/tablets';\nimport { isDefined, mkDict, indexBy } from '../util';\n\nexport interface InfuseResult {\n readonly coverageResults: Record<string, InfuseTypes>;\n}\n\nexport interface InfuseTypes {\n readonly types: number;\n readonly typesWithInsertedExamples: number;\n}\n\nexport interface InfuseOptions {\n readonly logFile?: string;\n\n /**\n * Where to read additional translations\n */\n readonly cacheFromFile?: string;\n\n /**\n * In addition to the implicit tablets, also write all added examples to this additional output tablet\n */\n readonly cacheToFile?: string;\n\n /**\n * Compress the cacheToFile\n */\n readonly compressCacheToFile?: boolean;\n}\n\nexport const DEFAULT_INFUSION_RESULTS_NAME = 'infusion-results.html';\n\nconst ADDITIONAL_SELECTORS: Record<string, SnippetSelector> = { meanLength, shortest, longest };\n\nclass DefaultRecord<A> {\n public readonly index: Record<string, A[]> = {};\n\n public add(key: string, value: A) {\n if (!this.index[key]) {\n this.index[key] = [];\n }\n this.index[key].push(value);\n }\n}\n\n/**\n * Infuse will analyze the snippets in a set of tablets, and update the assembly to add\n * examples to types that don't have any yet, based on snippets that use the given type.\n */\nexport async function infuse(assemblyLocations: string[], options?: InfuseOptions): Promise<InfuseResult> {\n let stream: fs.WriteStream | undefined = undefined;\n if (options?.logFile) {\n // Create stream for html file and insert some styling\n stream = fs.createWriteStream(options.logFile, { encoding: 'utf-8' });\n startFile(stream);\n }\n\n // Load tablet file and assemblies\n const assemblies = loadAssemblies(assemblyLocations, false);\n const defaultTablets = await loadAllDefaultTablets(assemblies);\n\n const availableTranslations = new LanguageTablet();\n if (options?.cacheFromFile) {\n availableTranslations.addTablet(await LanguageTablet.fromOptionalFile(options.cacheFromFile));\n }\n availableTranslations.addTablets(...Object.values(defaultTablets));\n\n const { translationsByFqn, originalsByKey } = await availableSnippetsPerFqn(assemblies, availableTranslations);\n\n const additionalOutputTablet = options?.cacheToFile\n ? await LanguageTablet.fromOptionalFile(options?.cacheToFile)\n : new LanguageTablet();\n\n const coverageResults = mkDict(\n await Promise.all(\n assemblies.map(async ({ assembly, directory }) => {\n stream?.write(`<h1>${assembly.name}</h1>\\n`);\n\n const implicitTablet = defaultTablets[directory];\n const implicitTabletFile = path.join(\n directory,\n implicitTablet.compressedSource ? DEFAULT_TABLET_NAME_COMPRESSED : DEFAULT_TABLET_NAME,\n );\n if (!implicitTablet) {\n throw new Error(`No tablet found for ${directory}`);\n }\n\n let insertedExamples = 0;\n const filteredTypes = filterForTypesWithoutExamples(assembly.types ?? {});\n for (const [typeFqn, type] of Object.entries(filteredTypes)) {\n const available = translationsByFqn[typeFqn];\n if (!available) {\n continue;\n }\n\n const example = pickBestExample(typeFqn, available, stream);\n const original = originalsByKey[example.key];\n insertExample(example, original, type, [implicitTablet, additionalOutputTablet]);\n insertedExamples++;\n }\n\n if (insertedExamples > 0) {\n // Save the updated assembly and implicit tablets\n // eslint-disable-next-line no-await-in-loop\n await Promise.all([\n replaceAssembly(assembly, directory),\n implicitTablet.save(implicitTabletFile, implicitTablet.compressedSource),\n ]);\n }\n\n return [\n directory,\n {\n types: Object.keys(filteredTypes).length,\n typesWithInsertedExamples: insertedExamples,\n } as InfuseTypes,\n ] as const;\n }),\n ),\n );\n\n stream?.close();\n\n // If we copied examples onto different types, we'll also have inserted new snippets\n // with different keys into the tablet. We must now write the updated tablet somewhere.\n if (options?.cacheToFile) {\n await additionalOutputTablet.save(options.cacheToFile, options.compressCacheToFile);\n }\n\n return {\n coverageResults: coverageResults,\n };\n}\n\nfunction pickBestExample(typeFqn: string, choices: TranslatedSnippet[], logStream?: fs.WriteStream) {\n const meanResult = mean(choices);\n if (logStream) {\n const selected = Object.entries(ADDITIONAL_SELECTORS).map(([name, fn]) => [name, fn(choices)] as const);\n const selectedFromSelector = {\n ...makeDict(selected),\n mean: meanResult,\n };\n logOutput(logStream, typeFqn, createHtmlEntry(selectedFromSelector));\n }\n return meanResult;\n}\n\nfunction startFile(stream: fs.WriteStream) {\n stream.write('<style>\\n');\n stream.write('h2 { color: blue; clear: both; }\\n');\n stream.write('h1 { color: red; clear: both; }\\n');\n stream.write(\n 'div { float: left; height: 31em; width: 22em; overflow: auto; margin: 1em; background-color: #ddd; }\\n',\n );\n stream.write(\n 'pre { float: left; height: 30em; width: 25em; overflow: auto; padding: 0.5em; background-color: #ddd; }\\n',\n );\n stream.write('</style>\\n');\n}\n\nfunction createHtmlEntry(results: Record<string, TranslatedSnippet>): Record<string, string[]> {\n const entry = new DefaultRecord<string>();\n for (const [key, value] of Object.entries(results)) {\n entry.add(value.originalSource.source, key);\n }\n return entry.index;\n}\n\nfunction logOutput(stream: fs.WriteStream | undefined, typeFqn: string, algorithmMap: Record<string, string[]>) {\n stream?.write(`<h2>${typeFqn}</h2>\\n`);\n for (const [key, value] of Object.entries(algorithmMap)) {\n stream?.write(`<div class=\"snippet\"><h3>${value.toString()}</h3>\\n<pre>${key}</pre>\\n</div>\\n`);\n }\n for (let i = 0; i < 4 - Object.keys(algorithmMap).length; i++) {\n stream?.write('<div class=\"padding\"></div>\\n');\n }\n}\n\nfunction filterForTypesWithoutExamples(types: { [fqn: string]: spec.Type }): Record<string, spec.Type> {\n const filteredTypes: Record<string, spec.Type> = {};\n for (const [typeFqn, type] of Object.entries(types)) {\n // Ignore Interfaces that contain only properties\n if (type.kind === spec.TypeKind.Interface && !type.datatype) {\n continue;\n }\n // Already has example\n if (type.docs?.example !== undefined) {\n continue;\n }\n filteredTypes[typeFqn] = type;\n }\n return filteredTypes;\n}\n\n/**\n * Insert an example into the docs of a type, and insert it back into the tablet under a new key\n */\nfunction insertExample(\n example: TranslatedSnippet,\n original: TypeScriptSnippet | undefined,\n type: spec.Type,\n tablets: LanguageTablet[],\n): void {\n const parameters = {\n ...original?.parameters,\n infused: '',\n };\n // exampleMetadata should always be nonempty since we always have a parameter.\n const exampleMetadata = renderMetadataline(parameters) ?? '';\n\n if (type.docs) {\n type.docs.example = example.originalSource.source;\n type.docs.custom = { ...type.docs.custom, exampleMetadata };\n } else {\n type.docs = {\n example: example.originalSource.source,\n custom: { exampleMetadata },\n };\n }\n\n for (const tablet of tablets) {\n tablet.addSnippets(\n example.withLocation({\n api: { api: 'type', fqn: type.fqn },\n field: { field: 'example' },\n }),\n );\n }\n}\n\n/**\n * Return a map of FQN -> snippet keys that exercise that FQN.\n *\n * For a snippet to qualify, it must both:\n *\n * a) be current (i.e.: exist in the input assemblies)\n * b) have been analyzed (i.e.: exist in one of the translated tablets)\n *\n * Returns a map of fqns to a list of keys that represent snippets that include the fqn.\n */\nasync function availableSnippetsPerFqn(asms: readonly LoadedAssembly[], translationsTablet: LanguageTablet) {\n const ret = new DefaultRecord<TranslatedSnippet>();\n\n const originalsByKey = indexBy(await allTypeScriptSnippets(asms), snippetKey);\n\n const translations = Object.keys(originalsByKey)\n .map((key) => translationsTablet.tryGetSnippet(key))\n .filter(isDefined);\n\n for (const trans of translations) {\n for (const fqn of trans.snippet.fqnsReferenced ?? []) {\n ret.add(fqn, trans);\n }\n }\n\n return { originalsByKey, translationsByFqn: ret.index };\n}\n\nfunction makeDict<A>(xs: Array<readonly [string, A]>): Record<string, A> {\n const ret: Record<string, A> = {};\n for (const [str, a] of xs) {\n ret[str] = a;\n }\n return ret;\n}\n"]}
@@ -33,6 +33,12 @@ export interface TransliterateAssemblyOptions {
33
33
  * @default UnknownSnippetMode.FAIL
34
34
  */
35
35
  readonly unknownSnippets?: UnknownSnippetMode;
36
+ /**
37
+ * Batch size for compiling snippets together
38
+ *
39
+ * @default undefined (no batching)
40
+ */
41
+ readonly batchSize?: number;
36
42
  }
37
43
  /**
38
44
  * Prepares transliterated versions of the designated assemblies into the
@@ -34,6 +34,7 @@ async function transliterateAssembly(assemblyLocations, targetLanguages, options
34
34
  cacheFromFile: options.tablet,
35
35
  writeToImplicitTablets: false,
36
36
  allowDirtyTranslations: true,
37
+ batchSize: options.batchSize,
37
38
  });
38
39
  // Now do a regular "tablet reader" cycle, expecting everything to be translated already,
39
40
  // and therefore it doesn't matter that we do this all in a single-threaded loop.
@@ -1 +1 @@
1
- {"version":3,"file":"transliterate.js","sourceRoot":"","sources":["../../src/commands/transliterate.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind, loadAssemblyFromPath } from '@jsii/spec';\n\nimport { extractSnippets } from './extract';\nimport { SUPPORTED_ASSEMBLY_FEATURES } from '../jsii/assemblies';\nimport { TargetLanguage } from '../languages';\nimport { targetName } from '../languages/target-language';\nimport { debug } from '../logging';\nimport { RosettaTabletReader, UnknownSnippetMode } from '../rosetta-reader';\nimport { typeScriptSnippetFromVisibleSource, ApiLocation } from '../snippet';\nimport { Mutable } from '../util';\n\nexport interface TransliterateAssemblyOptions {\n /**\n * Whether to ignore any missing fixture files or literate markdown documents\n * referenced by the assembly, instead of failing.\n *\n * @default false\n */\n readonly loose?: boolean;\n\n /**\n * Whether transliteration should fail upon failing to compile an example that\n * required live transliteration.\n *\n * @default false\n */\n readonly strict?: boolean;\n\n /**\n * A pre-build translation tablet (as produced by `jsii-rosetta extract`).\n *\n * @default - Only the default tablet (`.jsii.tabl.json`) files will be used.\n */\n readonly tablet?: string;\n\n /**\n * A directory to output translated assemblies to\n *\n * @default - assembly location\n */\n readonly outdir?: string;\n\n /**\n * Whether or not to live-convert samples\n *\n * @default UnknownSnippetMode.FAIL\n */\n readonly unknownSnippets?: UnknownSnippetMode;\n}\n\n/**\n * Prepares transliterated versions of the designated assemblies into the\n * selected target languages.\n *\n * @param assemblyLocations the directories which contain assemblies to\n * transliterate.\n * @param targetLanguages the languages into which to transliterate.\n * @param tabletLocation an optional Rosetta tablet file to source\n * pre-transliterated snippets from.\n *\n * @experimental\n */\nexport async function transliterateAssembly(\n assemblyLocations: readonly string[],\n targetLanguages: readonly TargetLanguage[],\n options: TransliterateAssemblyOptions = {},\n): Promise<void> {\n // Start by doing an 'extract' for all these assemblies\n //\n // This will locate all examples that haven't been translated yet and translate\n // them. Importantly: it will translate them in parallel, which is going to improve\n // performance a lot. We ignore diagnostics.\n const { tablet } = await extractSnippets(assemblyLocations, {\n includeCompilerDiagnostics: true,\n loose: options.loose,\n cacheFromFile: options.tablet,\n writeToImplicitTablets: false,\n allowDirtyTranslations: true,\n });\n\n // Now do a regular \"tablet reader\" cycle, expecting everything to be translated already,\n // and therefore it doesn't matter that we do this all in a single-threaded loop.\n const rosetta = new RosettaTabletReader({\n unknownSnippets: options?.unknownSnippets ?? UnknownSnippetMode.FAIL,\n targetLanguages,\n prefixDisclaimer: true,\n });\n // Put in the same caching tablet here\n if (options.tablet) {\n await rosetta.loadTabletFromFile(options.tablet);\n }\n // Any fresh translations we just came up with\n rosetta.addTablet(tablet);\n\n const assemblies = await loadAssemblies(assemblyLocations, rosetta);\n\n for (const [location, loadAssembly] of assemblies.entries()) {\n for (const language of targetLanguages) {\n const now = new Date().getTime();\n const result = loadAssembly();\n\n if (result.targets?.[targetName(language)] == null) {\n // This language is not supported by the assembly, so we skip it...\n continue;\n }\n\n if (result.readme?.markdown) {\n result.readme.markdown = rosetta.translateSnippetsInMarkdown(\n { api: 'moduleReadme', moduleFqn: result.name },\n result.readme.markdown,\n language,\n true /* strict */,\n );\n }\n for (const type of Object.values(result.types ?? {})) {\n transliterateType(type, rosetta, language);\n }\n // eslint-disable-next-line no-await-in-loop\n await fs.writeFile(\n resolve(options?.outdir ?? location, `${SPEC_FILE_NAME}.${language}`),\n JSON.stringify(result, null, 2),\n );\n const then = new Date().getTime();\n debug(`Done transliterating ${result.name}@${result.version} to ${language} after ${then - now} milliseconds`);\n }\n }\n\n rosetta.printDiagnostics(process.stderr, process.stderr.isTTY);\n if (rosetta.hasErrors && options.strict) {\n throw new Error('Strict mode is enabled and some examples failed compilation!');\n }\n}\n\n/**\n * Given a set of directories containing `.jsii` assemblies, load all the\n * assemblies into the provided `Rosetta` instance and return a map of\n * directories to assembly-loading functions (the function re-loads the original\n * assembly from disk on each invocation).\n *\n * @param directories the assembly-containing directories to traverse.\n * @param rosetta the `Rosetta` instance in which to load assemblies.\n *\n * @returns a map of directories to a function that loads the `.jsii` assembly\n * contained therein from disk.\n */\nasync function loadAssemblies(\n directories: readonly string[],\n rosetta: RosettaTabletReader,\n): Promise<ReadonlyMap<string, AssemblyLoader>> {\n const result = new Map<string, AssemblyLoader>();\n\n for (const directory of directories) {\n const loader = () => loadAssemblyFromPath(directory, false, SUPPORTED_ASSEMBLY_FEATURES);\n // eslint-disable-next-line no-await-in-loop\n await rosetta.addAssembly(loader(), directory);\n result.set(directory, loader);\n }\n\n return result;\n}\n\ntype AssemblyLoader = () => Mutable<Assembly>;\n\nfunction transliterateType(type: Type, rosetta: RosettaTabletReader, language: TargetLanguage): void {\n transliterateDocs({ api: 'type', fqn: type.fqn }, type.docs);\n switch (type.kind) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore 7029\n case TypeKind.Class:\n if (type.initializer) {\n transliterateDocs({ api: 'initializer', fqn: type.fqn }, type.initializer.docs);\n }\n\n // fallthrough\n case TypeKind.Interface:\n for (const method of type.methods ?? []) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: method.name }, method.docs);\n for (const parameter of method.parameters ?? []) {\n transliterateDocs(\n { api: 'parameter', fqn: type.fqn, methodName: method.name, parameterName: parameter.name },\n parameter.docs,\n );\n }\n }\n for (const property of type.properties ?? []) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: property.name }, property.docs);\n }\n break;\n\n case TypeKind.Enum:\n for (const member of type.members) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: member.name }, member.docs);\n }\n break;\n\n default:\n throw new Error(`Unsupported type kind: ${(type as any).kind}`);\n }\n\n function transliterateDocs(api: ApiLocation, docs: Docs | undefined) {\n if (docs?.remarks) {\n docs.remarks = rosetta.translateSnippetsInMarkdown(api, docs.remarks, language, true /* strict */);\n }\n\n if (docs?.example) {\n const location = { api, field: { field: 'example' } } as const;\n const snippet = typeScriptSnippetFromVisibleSource(docs.example, location, true /* strict */);\n const translation = rosetta.translateSnippet(snippet, language);\n if (translation != null) {\n docs.example = translation.source;\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"transliterate.js","sourceRoot":"","sources":["../../src/commands/transliterate.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind, loadAssemblyFromPath } from '@jsii/spec';\n\nimport { extractSnippets } from './extract';\nimport { SUPPORTED_ASSEMBLY_FEATURES } from '../jsii/assemblies';\nimport { TargetLanguage } from '../languages';\nimport { targetName } from '../languages/target-language';\nimport { debug } from '../logging';\nimport { RosettaTabletReader, UnknownSnippetMode } from '../rosetta-reader';\nimport { typeScriptSnippetFromVisibleSource, ApiLocation } from '../snippet';\nimport { Mutable } from '../util';\n\nexport interface TransliterateAssemblyOptions {\n /**\n * Whether to ignore any missing fixture files or literate markdown documents\n * referenced by the assembly, instead of failing.\n *\n * @default false\n */\n readonly loose?: boolean;\n\n /**\n * Whether transliteration should fail upon failing to compile an example that\n * required live transliteration.\n *\n * @default false\n */\n readonly strict?: boolean;\n\n /**\n * A pre-build translation tablet (as produced by `jsii-rosetta extract`).\n *\n * @default - Only the default tablet (`.jsii.tabl.json`) files will be used.\n */\n readonly tablet?: string;\n\n /**\n * A directory to output translated assemblies to\n *\n * @default - assembly location\n */\n readonly outdir?: string;\n\n /**\n * Whether or not to live-convert samples\n *\n * @default UnknownSnippetMode.FAIL\n */\n readonly unknownSnippets?: UnknownSnippetMode;\n\n /**\n * Batch size for compiling snippets together\n *\n * @default undefined (no batching)\n */\n readonly batchSize?: number;\n}\n\n/**\n * Prepares transliterated versions of the designated assemblies into the\n * selected target languages.\n *\n * @param assemblyLocations the directories which contain assemblies to\n * transliterate.\n * @param targetLanguages the languages into which to transliterate.\n * @param tabletLocation an optional Rosetta tablet file to source\n * pre-transliterated snippets from.\n *\n * @experimental\n */\nexport async function transliterateAssembly(\n assemblyLocations: readonly string[],\n targetLanguages: readonly TargetLanguage[],\n options: TransliterateAssemblyOptions = {},\n): Promise<void> {\n // Start by doing an 'extract' for all these assemblies\n //\n // This will locate all examples that haven't been translated yet and translate\n // them. Importantly: it will translate them in parallel, which is going to improve\n // performance a lot. We ignore diagnostics.\n const { tablet } = await extractSnippets(assemblyLocations, {\n includeCompilerDiagnostics: true,\n loose: options.loose,\n cacheFromFile: options.tablet,\n writeToImplicitTablets: false,\n allowDirtyTranslations: true,\n batchSize: options.batchSize,\n });\n\n // Now do a regular \"tablet reader\" cycle, expecting everything to be translated already,\n // and therefore it doesn't matter that we do this all in a single-threaded loop.\n const rosetta = new RosettaTabletReader({\n unknownSnippets: options?.unknownSnippets ?? UnknownSnippetMode.FAIL,\n targetLanguages,\n prefixDisclaimer: true,\n });\n // Put in the same caching tablet here\n if (options.tablet) {\n await rosetta.loadTabletFromFile(options.tablet);\n }\n // Any fresh translations we just came up with\n rosetta.addTablet(tablet);\n\n const assemblies = await loadAssemblies(assemblyLocations, rosetta);\n\n for (const [location, loadAssembly] of assemblies.entries()) {\n for (const language of targetLanguages) {\n const now = new Date().getTime();\n const result = loadAssembly();\n\n if (result.targets?.[targetName(language)] == null) {\n // This language is not supported by the assembly, so we skip it...\n continue;\n }\n\n if (result.readme?.markdown) {\n result.readme.markdown = rosetta.translateSnippetsInMarkdown(\n { api: 'moduleReadme', moduleFqn: result.name },\n result.readme.markdown,\n language,\n true /* strict */,\n );\n }\n for (const type of Object.values(result.types ?? {})) {\n transliterateType(type, rosetta, language);\n }\n // eslint-disable-next-line no-await-in-loop\n await fs.writeFile(\n resolve(options?.outdir ?? location, `${SPEC_FILE_NAME}.${language}`),\n JSON.stringify(result, null, 2),\n );\n const then = new Date().getTime();\n debug(`Done transliterating ${result.name}@${result.version} to ${language} after ${then - now} milliseconds`);\n }\n }\n\n rosetta.printDiagnostics(process.stderr, process.stderr.isTTY);\n if (rosetta.hasErrors && options.strict) {\n throw new Error('Strict mode is enabled and some examples failed compilation!');\n }\n}\n\n/**\n * Given a set of directories containing `.jsii` assemblies, load all the\n * assemblies into the provided `Rosetta` instance and return a map of\n * directories to assembly-loading functions (the function re-loads the original\n * assembly from disk on each invocation).\n *\n * @param directories the assembly-containing directories to traverse.\n * @param rosetta the `Rosetta` instance in which to load assemblies.\n *\n * @returns a map of directories to a function that loads the `.jsii` assembly\n * contained therein from disk.\n */\nasync function loadAssemblies(\n directories: readonly string[],\n rosetta: RosettaTabletReader,\n): Promise<ReadonlyMap<string, AssemblyLoader>> {\n const result = new Map<string, AssemblyLoader>();\n\n for (const directory of directories) {\n const loader = () => loadAssemblyFromPath(directory, false, SUPPORTED_ASSEMBLY_FEATURES);\n // eslint-disable-next-line no-await-in-loop\n await rosetta.addAssembly(loader(), directory);\n result.set(directory, loader);\n }\n\n return result;\n}\n\ntype AssemblyLoader = () => Mutable<Assembly>;\n\nfunction transliterateType(type: Type, rosetta: RosettaTabletReader, language: TargetLanguage): void {\n transliterateDocs({ api: 'type', fqn: type.fqn }, type.docs);\n switch (type.kind) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore 7029\n case TypeKind.Class:\n if (type.initializer) {\n transliterateDocs({ api: 'initializer', fqn: type.fqn }, type.initializer.docs);\n }\n\n // fallthrough\n case TypeKind.Interface:\n for (const method of type.methods ?? []) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: method.name }, method.docs);\n for (const parameter of method.parameters ?? []) {\n transliterateDocs(\n { api: 'parameter', fqn: type.fqn, methodName: method.name, parameterName: parameter.name },\n parameter.docs,\n );\n }\n }\n for (const property of type.properties ?? []) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: property.name }, property.docs);\n }\n break;\n\n case TypeKind.Enum:\n for (const member of type.members) {\n transliterateDocs({ api: 'member', fqn: type.fqn, memberName: member.name }, member.docs);\n }\n break;\n\n default:\n throw new Error(`Unsupported type kind: ${(type as any).kind}`);\n }\n\n function transliterateDocs(api: ApiLocation, docs: Docs | undefined) {\n if (docs?.remarks) {\n docs.remarks = rosetta.translateSnippetsInMarkdown(api, docs.remarks, language, true /* strict */);\n }\n\n if (docs?.example) {\n const location = { api, field: { field: 'example' } } as const;\n const snippet = typeScriptSnippetFromVisibleSource(docs.example, location, true /* strict */);\n const translation = rosetta.translateSnippet(snippet, language);\n if (translation != null) {\n docs.example = translation.source;\n }\n }\n }\n}\n"]}
@@ -240,7 +240,7 @@ class PythonVisitor extends default_1.DefaultVisitor {
240
240
  // We know it's a struct we can DEFINITELY inline the args for
241
241
  return this.renderObjectLiteralExpression('', '', true, node, context);
242
242
  }
243
- const structName = structType.kind === 'struct' ? this.importedNameForType(structType.jsiiSym) : structType.type.symbol.name;
243
+ const structName = structType.kind === 'struct' ? this.importedNameForType(structType.jsiiSym, node) : structType.type.symbol.name;
244
244
  return this.renderObjectLiteralExpression(`${structName}(`, ')', true, node, context);
245
245
  }
246
246
  keyValueObjectLiteralExpression(node, context) {
@@ -512,7 +512,7 @@ class PythonVisitor extends default_1.DefaultVisitor {
512
512
  /**
513
513
  * Find the import for the FQNs submodule, and return it and the rest of the name
514
514
  */
515
- importedNameForType(jsiiSym) {
515
+ importedNameForType(jsiiSym, node) {
516
516
  // Look for an existing import that contains this symbol
517
517
  for (const imp of this.imports) {
518
518
  if (jsiiSym.fqn.startsWith(`${imp.importedFqn}.`)) {
@@ -523,15 +523,24 @@ class PythonVisitor extends default_1.DefaultVisitor {
523
523
  // Otherwise look up the Python name of this symbol (but not for fake imports from tests)
524
524
  const pythonName = findPythonName(jsiiSym);
525
525
  if (!jsiiSym.fqn.startsWith('fake_jsii.') && pythonName) {
526
- this.syntheticImportsToAdd.push(pythonName);
526
+ this.syntheticImportsToAdd.push([pythonName, node]);
527
527
  }
528
528
  return (0, jsii_utils_1.simpleName)(jsiiSym.fqn);
529
529
  }
530
530
  renderSyntheticImports() {
531
- const grouped = (0, util_1.groupBy)(this.syntheticImportsToAdd, jsii_utils_1.namespaceName);
532
- return Object.entries(grouped).map(([namespaceFqn, fqns]) => {
533
- const simpleNames = fqns.map(jsii_utils_1.simpleName);
534
- return `from ${namespaceFqn} import ${simpleNames.join(', ')}\n`;
531
+ const grouped = (0, util_1.groupBy)(this.syntheticImportsToAdd, ([fqn]) => (0, jsii_utils_1.namespaceName)(fqn));
532
+ return Object.entries(grouped).map(([namespaceFqn, entries]) => {
533
+ // Create an OTree for each imported name with its causing node's span
534
+ const nameOTrees = entries.map(([fqn, node]) => {
535
+ const tree = new o_tree_1.OTree([(0, jsii_utils_1.simpleName)(fqn)]);
536
+ tree.setSpan(node.getStart(), node.getEnd());
537
+ return tree;
538
+ });
539
+ // Use ChildVisibilityOTree so the import only renders if at least one name is visible
540
+ return new o_tree_1.ChildVisibilityOTree([`from ${namespaceFqn} import `], nameOTrees, {
541
+ separator: ', ',
542
+ suffix: '\n',
543
+ });
535
544
  });
536
545
  }
537
546
  }