Skip to content

Commit

Permalink
fix(jsii): selective exports declarations are ignored
Browse files Browse the repository at this point in the history
When specific symbols are exported from a module using the
*ExportDeclaration* syntax:

```ts
export { Foo } from './foo';
```

Those declarations would not be processed at all, because they lack the
`ts.ModifierFlags.Export` modifier (which is to be expected from a
declaration that **is** an export statement).

Added the necessary code (and a test) to ensure these statements are
correctly detected, and the exported symbols are correctly processed
into the output assembly.

Fixes #1818
  • Loading branch information
RomainMuller committed Jul 29, 2020
1 parent 7a74bdb commit 5e6452e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
17 changes: 17 additions & 0 deletions packages/jsii/lib/assembler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,23 @@ export class Assembler implements Emitter {
return allTypes;
}

if (ts.isExportSpecifier(node)) {
// This is what happens when one does `export { Symbol } from "./location";`
// ExportSpecifier: ~~~~~~

const resolvedSymbol = this._typeChecker.getExportSpecifierLocalTargetSymbol(
node,
);
if (!resolvedSymbol) {
// A grammar error, compilation will already have failed
return [];
}
return this._visitNode(
resolvedSymbol.valueDeclaration ?? resolvedSymbol.declarations[0],
context,
);
}

if ((ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) === 0) {
return [];
}
Expand Down
18 changes: 14 additions & 4 deletions packages/jsii/lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,28 @@ import { loadProjectInfo, ProjectInfo } from './project-info';
* Compile a piece of source and return the JSII assembly for it
*
* Only usable for trivial cases and tests.
*
* @param source can either be a single `string` (the content of `index.ts`), or
* a map of fileName to content, which *must* include `index.ts`.
*/
export async function sourceToAssemblyHelper(
source: string,
source: string | { 'index.ts': string; [name: string]: string },
cb?: (obj: PackageInfo) => void,
): Promise<spec.Assembly> {
if (typeof source === 'string') {
source = { 'index.ts': source };
}

// Easiest way to get the source into the compiler is to write it to disk somewhere.
// I guess we could make an in-memory compiler host but that seems like work...
return inTempDir(async () => {
const fileName = 'index.ts';
await fs.writeFile(fileName, source, { encoding: 'utf-8' });
await Promise.all(
Object.entries(source).map(([fileName, content]) =>
fs.writeFile(fileName, content, { encoding: 'utf-8' }),
),
);
const compiler = new Compiler({
projectInfo: await makeProjectInfo(fileName, cb),
projectInfo: await makeProjectInfo('index.ts', cb),
});
const emitResult = await compiler.emit();

Expand Down
16 changes: 16 additions & 0 deletions packages/jsii/test/export-specifier.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { sourceToAssemblyHelper } from '../lib';

test('export { Foo } from "./foo"', async () => {
const assembly = await sourceToAssemblyHelper({
'index.ts': 'export { Foo } from "./foo";',
'foo.ts': 'export class Foo { private constructor() {} }',
});

expect(assembly.types?.['testpkg.Foo']).toEqual({
assembly: 'testpkg',
fqn: 'testpkg.Foo',
kind: 'class',
locationInModule: { filename: 'foo.ts', line: 1 },
name: 'Foo',
});
});

0 comments on commit 5e6452e

Please sign in to comment.