Skip to content

Commit a5bd219

Browse files
authored
fix(rosetta): infuse incorrectly handles compressed assemblies (#3669)
The behavior of `rosetta infuse` was incorrectly handled before. `infuse` would always overwrite the `.jsii` file with the uncompressed assembly. This PR fixes that behavior by detecting whether or not there is a compressed file in the directory, and compressing if that is the case. There are two alternative solutions I considered, primarily because I'm concerned that looking up the location of the compressed assembly can be considered a leaky abstraction: - loading and looking into the contents of `.jsii` again to determine whether or not it is a file redirect. I did not choose this option as it involves additional loading, which will slow things down. - We can expand the `LoadedAssembly` type to include information on whether or not the assembly was originally compressed. Then pass that into the `replaceAssembly()` function. I ultimately decided against this because it would involve changing the function signature of all `loadAssemblyFromXxx` functions. It's both a breaking change, and unnecessary clutter for a single use case. Based on the reasoning above, I think what is included in this PR makes the most sense: expose an independent function, `compressedAssemblyExists`, that returns whether or not there is a file located at `SPEC_FILE_NAME_COMPRESSED`. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
1 parent 6c4b773 commit a5bd219

File tree

3 files changed

+73
-8
lines changed

3 files changed

+73
-8
lines changed

packages/@jsii/spec/src/assembly-utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import {
1414
} from './redirect';
1515
import { validateAssembly } from './validate-assembly';
1616

17+
/**
18+
* Returns true if the SPEC_FILE_NAME_COMPRESSED file exists in the directory.
19+
*/
20+
export function compressedAssemblyExists(directory: string): boolean {
21+
return fs.existsSync(path.join(directory, SPEC_FILE_NAME_COMPRESSED));
22+
}
23+
1724
/**
1825
* Finds the path to the SPEC_FILE_NAME file, which will either
1926
* be the assembly or hold instructions to find the assembly.

packages/jsii-rosetta/lib/jsii/assemblies.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import * as spec from '@jsii/spec';
2-
import { loadAssemblyFromFile, loadAssemblyFromPath, findAssemblyFile, writeAssembly } from '@jsii/spec';
2+
import {
3+
compressedAssemblyExists,
4+
loadAssemblyFromFile,
5+
loadAssemblyFromPath,
6+
findAssemblyFile,
7+
writeAssembly,
8+
} from '@jsii/spec';
39
import * as crypto from 'crypto';
410
import * as fs from 'fs-extra';
511
import * as path from 'path';
@@ -228,14 +234,11 @@ export async function allTypeScriptSnippets(
228234

229235
/**
230236
* Replaces the file where the original assembly file *should* be found with a new assembly file.
237+
* Detects whether or not there is a compressed assembly, and if there is, compresses the new assembly also.
231238
* Recalculates the fingerprint of the assembly to avoid tampering detection.
232239
*/
233-
export function replaceAssembly(
234-
assembly: spec.Assembly,
235-
directory: string,
236-
{ compress = false }: { compress?: boolean } = {},
237-
) {
238-
writeAssembly(directory, _fingerprint(assembly), { compress });
240+
export function replaceAssembly(assembly: spec.Assembly, directory: string) {
241+
writeAssembly(directory, _fingerprint(assembly), { compress: compressedAssemblyExists(directory) });
239242
}
240243

241244
/**

packages/jsii-rosetta/test/commands/infuse.test.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { loadAssemblyFromPath } from '@jsii/spec';
1+
import { loadAssemblyFromPath, SPEC_FILE_NAME, SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec';
22
import * as fs from 'fs-extra';
33
import * as path from 'path';
44

@@ -107,3 +107,58 @@ test('can log to output file', async () => {
107107
expect(stats.isFile()).toBeTruthy();
108108
expect(stats.size).toBeGreaterThan(0);
109109
});
110+
111+
test('preserves the assembly compression if present', async () => {
112+
// Create an assembly in a temp directory
113+
const compAssembly = TestJsiiModule.fromSource(
114+
{
115+
'index.ts': `
116+
export class ClassA {
117+
public someMethod() {
118+
}
119+
}
120+
export class ClassB {
121+
public argumentMethod(args: BeeArgs) {
122+
Array.isArray(args);
123+
}
124+
}
125+
export interface BeeArgs { readonly value: string; readonly nested?: NestedType; }
126+
export interface NestedType { readonly x: number; }
127+
`,
128+
'README.md': DUMMY_README,
129+
},
130+
{
131+
name: 'my_assembly',
132+
jsii: DUMMY_JSII_CONFIG,
133+
},
134+
{
135+
compressAssembly: true,
136+
},
137+
);
138+
139+
// Ensure assembly is compressed
140+
expect(fs.existsSync(path.join(compAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy();
141+
142+
// Create a tabletFile in the same directory
143+
await extractSnippets([compAssembly.moduleDirectory], {
144+
cacheToFile: path.join(compAssembly.moduleDirectory, TABLET_FILE),
145+
includeCompilerDiagnostics: false,
146+
validateAssemblies: false,
147+
});
148+
149+
// Now infuse
150+
await infuse([compAssembly.moduleDirectory]);
151+
152+
// Expect file at SPEC_FILE_NAME to still be a file redirect (not the actual assembly)
153+
expect(fs.readJSONSync(path.join(compAssembly.moduleDirectory, SPEC_FILE_NAME))).toEqual({
154+
schema: 'jsii/file-redirect',
155+
compression: 'gzip',
156+
filename: SPEC_FILE_NAME_COMPRESSED,
157+
});
158+
159+
// Infuse works as expected
160+
const assemblies = loadAssemblies([compAssembly.moduleDirectory], false);
161+
const types = assemblies[0].assembly.types;
162+
expect(types).toBeDefined();
163+
expect(types!['my_assembly.ClassA'].docs?.example).toBeDefined();
164+
});

0 commit comments

Comments
 (0)