From 7b2ec05b2ec247de83901e8504f7ba711d6027bb Mon Sep 17 00:00:00 2001 From: Ben Chaimberg Date: Wed, 21 Jul 2021 09:01:26 -0700 Subject: [PATCH] feat(rosetta): hoist declare statements to top-level of document (#2897) `declare` statements allow snippet writers to create a mock variable of a certain type that can be used within a snippet without having to provide a concrete value of that type. This is useful when referencing a type from another module without needing to create an instance of that type, which may be complex. Example: ``` declare const lambdaFunction: lambda.Function; const myResource = ... myResource.grantRead(lambdaFunction); ``` `declare` statements can only exist at the top level of a document, meaning snippets with fixtures may not be able to define a `declare` statement, since the snippet may be embedded into the fixture within a class, function, etc. This feature "hoists" `declare` statements to the top level of the document, similarly to how `import` statements are hoisted currently. --- packages/jsii-rosetta/lib/fixtures.ts | 17 +++++----- packages/jsii-rosetta/test/fixtures.test.ts | 31 +++++++++++++++++++ .../test/rosetta/default.ts-fixture | 1 + 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 packages/jsii-rosetta/test/rosetta/default.ts-fixture diff --git a/packages/jsii-rosetta/lib/fixtures.ts b/packages/jsii-rosetta/lib/fixtures.ts index 91276ca1ed..e87272c2ad 100644 --- a/packages/jsii-rosetta/lib/fixtures.ts +++ b/packages/jsii-rosetta/lib/fixtures.ts @@ -147,13 +147,16 @@ function sidelineImports(source: string): { ScriptKind.TS, ); for (const statement of sourceFile.statements) { - switch (statement.kind) { - case SyntaxKind.ImportDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - imports += statement.getFullText(sourceFile); - break; - default: - statements += statement.getFullText(sourceFile); + if ( + statement.kind === SyntaxKind.ImportDeclaration || + statement.kind === SyntaxKind.ImportEqualsDeclaration || + (statement.kind === SyntaxKind.VariableStatement && + statement.getChildAt(0).getChildAt(0).kind === + SyntaxKind.DeclareKeyword) + ) { + imports += statement.getFullText(sourceFile); + } else { + statements += statement.getFullText(sourceFile); } } diff --git a/packages/jsii-rosetta/test/fixtures.test.ts b/packages/jsii-rosetta/test/fixtures.test.ts index 92e9f9ff7c..d315e86b17 100644 --- a/packages/jsii-rosetta/test/fixtures.test.ts +++ b/packages/jsii-rosetta/test/fixtures.test.ts @@ -16,4 +16,35 @@ describe('fixturize', () => { expect(fixturize(snippet)).toEqual(expect.objectContaining(snippet)); }); + + test('separates imports and declarations', () => { + const source = `import * as ns from 'mod'; +declare const mock: Tpe; +const val = new Cls();`; + const snippet = { + visibleSource: source, + where: 'where', + parameters: { + [SnippetParameters.$PROJECT_DIRECTORY]: 'test', + }, + strict: true, + }; + + const fixturizedSnippet = fixturize(snippet); + + expect(fixturizedSnippet.completeSource) + .toBe(`// Hoisted imports begin after !show marker below +/// !show +import * as ns from 'mod'; +declare const mock: Tpe; +/// !hide +// Hoisted imports ended before !hide marker above +// Code snippet begins after !show marker below +/// !show + +const val = new Cls(); +/// !hide +// Code snippet ended before !hide marker above +`); + }); }); diff --git a/packages/jsii-rosetta/test/rosetta/default.ts-fixture b/packages/jsii-rosetta/test/rosetta/default.ts-fixture new file mode 100644 index 0000000000..acd85cb41b --- /dev/null +++ b/packages/jsii-rosetta/test/rosetta/default.ts-fixture @@ -0,0 +1 @@ +/// here