From b6e65ddcead5d2397bb3b7a823e6223e359c4e56 Mon Sep 17 00:00:00 2001 From: joeduffy Date: Fri, 13 Jan 2017 12:07:45 -0800 Subject: [PATCH] Mimic TypeScript's logic for export modules This depends on an internal API, and so has been tagged with marapongo/mu#52. --- tools/mujs/lib/compiler/transform.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/mujs/lib/compiler/transform.ts b/tools/mujs/lib/compiler/transform.ts index 517c526b1..069f37b9f 100644 --- a/tools/mujs/lib/compiler/transform.ts +++ b/tools/mujs/lib/compiler/transform.ts @@ -177,8 +177,17 @@ export class Transformer { // Enumerate all source files (each of which is a module in ECMAScript), and transform it. let modules: ast.Modules = {}; for (let sourceFile of this.script.tree!.getSourceFiles()) { - // If the file exists in this script's package list, we will export it as a module. - if (this.script.files.indexOf(sourceFile.fileName) !== -1) { + // TODO[marapongo/mu#52]: to determine whether a SourceFile is part of the current compilation unit or not, + // we must rely on a private TypeScript API, isSourceFileFromExternalLibrary. An alternative would be to + // check to see if the file was loaded from the node_modules/ directory, which is essentially what the + // TypeScript compiler does (except that it has logic for nesting and symbolic links that would be hard to + // emulate). Neither approach is great, however, I prefer to use the API and assert that it exists so we + // match the semantics. Thankfully, the tsserverlib library will contain these, once it is useable. + let isSourceFileFromExternalLibrary = + <((file: ts.SourceFile) => boolean)>(this.script.tree).isSourceFileFromExternalLibrary; + contract.assert(!!isSourceFileFromExternalLibrary, + "Expected internal Program.isSourceFileFromExternalLibrary function to be non-null"); + if (!isSourceFileFromExternalLibrary(sourceFile) && !sourceFile.isDeclarationFile) { let mod: ast.Module = this.transformSourceFile(sourceFile); modules[mod.name.ident] = mod; } @@ -279,10 +288,12 @@ export class Transformer { // TODO(joe): ensure that this dependency exists, to avoid "accidentally" satisfyied name resolution in the // TypeScript compiler; for example, if the package just happens to exist in `node_modules`, etc. let sourceContext: ts.SourceFile = node.getSourceFile(); - // HACK: we are grabbing the sourceContext's resolvedModules property directly, because TypeScript doesn't - // currently offer a convenient way of accessing this information. The (unexported) getResolvedModule function - // almost does this, but not quite, because it doesn't allow us to perform a lookup based on path. + // TODO[marapongo/mu#52]: we are grabbing the sourceContext's resolvedModules property directly, because + // TypeScript doesn't currently offer a convenient way of accessing this information. The (unexported) + // getResolvedModule function almost does this, but not quite, because it doesn't allow us to perform a lookup + // based on path. Ideally we can remove this as soon as the tsserverlibrary is consumable as a module. let candidates = >(sourceContext).resolvedModules; + contract.assert(!!candidates, "Expected internal SourceFile.resolvedModules property to be non-null"); let resolvedModule: ts.ResolvedModuleFull | undefined; for (let candidateName of Object.keys(candidates)) { let candidate: ts.ResolvedModuleFull = candidates[candidateName];