From f371c9066d1d46ce88ece507ece0917c39005672 Mon Sep 17 00:00:00 2001 From: Chuck Jazdzewski Date: Wed, 6 Apr 2016 16:10:45 -0700 Subject: [PATCH] build(broccoli): Clean-up TypeScript build The TypeScript parser now only references files that are in broccoli trees. Closes #7941 --- tools/broccoli/broccoli-typescript.ts | 65 +++++++++------------------ tools/broccoli/trees/browser_tree.ts | 7 ++- tools/broccoli/trees/node_tree.ts | 29 +++++++++--- 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/tools/broccoli/broccoli-typescript.ts b/tools/broccoli/broccoli-typescript.ts index 3c1e9b03e7..f97bcbc6b9 100644 --- a/tools/broccoli/broccoli-typescript.ts +++ b/tools/broccoli/broccoli-typescript.ts @@ -58,7 +58,6 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin { private genInternalTypings: boolean = false; static includeExtensions = ['.ts']; - static excludeExtensions = ['.d.ts']; constructor(public inputPath: string, public cachePath: string, public options) { if (options.rootFilePaths) { @@ -83,11 +82,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin { this.genInternalTypings = false; } - // TODO: the above turns rootDir set to './' into an empty string - looks like a tsc bug - // check back when we upgrade to 1.7.x - if (this.tsOpts.rootDir === '') { - this.tsOpts.rootDir = './'; - } + this.tsOpts.rootDir = inputPath; this.tsOpts.outDir = this.cachePath; this.tsServiceHost = new CustomLanguageServiceHost(this.tsOpts, this.rootFilePaths, @@ -331,7 +326,9 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost { } - getScriptFileNames(): string[] { return this.fileNames; } + getScriptFileNames(): string[] { + return this.fileNames.map(f => path.join(this.treeInputPath, f)); + } getScriptVersion(fileName: string): string { @@ -339,46 +336,24 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost { } - /** - * This method is called quite a bit to lookup 3 kinds of paths: - * 1/ files in the fileRegistry - * - these are the files in our project that we are watching for changes - * - in the future we could add caching for these files and invalidate the cache when - * the file is changed lazily during lookup - * 2/ .d.ts and library files not in the fileRegistry - * - these are not our files, they come from tsd or typescript itself - * - these files change only rarely but since we need them very rarely, it's not worth the - * cache invalidation hassle to cache them - * 3/ bogus paths that typescript compiler tries to lookup during import resolution - * - these paths are tricky to cache since files come and go and paths that was bogus in the - * past might not be bogus later - * - * In the initial experiments the impact of this caching was insignificant (single digit %) and - * not worth the potential issues with stale cache records. - */ getScriptSnapshot(tsFilePath: string): ts.IScriptSnapshot { - let absoluteTsFilePath; + // TypeScript seems to request lots of bogus paths during import path lookup and resolution, + // so we we just return undefined when the path is not correct. - if (tsFilePath == this.defaultLibFilePath || path.isAbsolute(tsFilePath)) { - absoluteTsFilePath = tsFilePath; - } else if (this.compilerOptions.moduleResolution === ts.ModuleResolutionKind.NodeJs && - tsFilePath.match(/^node_modules/)) { - absoluteTsFilePath = path.resolve(tsFilePath); - } else if (tsFilePath.match(/^rxjs/)) { - absoluteTsFilePath = path.resolve('node_modules', tsFilePath); - } else if (tsFilePath.match(/^node_modules/)) { - absoluteTsFilePath = path.resolve('node_modules/../', tsFilePath); - } else { - absoluteTsFilePath = path.join(this.treeInputPath, tsFilePath); - } - - - if (!fs.existsSync(absoluteTsFilePath)) { - // TypeScript seems to request lots of bogus paths during import path lookup and resolution, - // so we we just return undefined when the path is not correct. + // Ensure it is in the input tree or a lib.d.ts file. + if (!startsWith(tsFilePath, this.treeInputPath) && !tsFilePath.match(/\/lib(\..*)*.d\.ts$/)) { + if (fs.existsSync(tsFilePath)) { + console.log('Rejecting', tsFilePath, '. File is not in the input tree.'); + } return undefined; } - return ts.ScriptSnapshot.fromString(fs.readFileSync(absoluteTsFilePath, FS_OPTS)); + + // Ensure it exists + if (!fs.existsSync(tsFilePath)) { + return undefined; + } + + return ts.ScriptSnapshot.fromString(fs.readFileSync(tsFilePath, FS_OPTS)); } @@ -402,6 +377,10 @@ function clone(object: T): T { return result; } +function startsWith(str: string, substring: string): boolean { + return str.substring(0, substring.length) === substring; +} + function endsWith(str: string, substring: string): boolean { return str.indexOf(substring, str.length - substring.length) !== -1; } diff --git a/tools/broccoli/trees/browser_tree.ts b/tools/broccoli/trees/browser_tree.ts index 7021eae316..4f36a8bb93 100644 --- a/tools/broccoli/trees/browser_tree.ts +++ b/tools/broccoli/trees/browser_tree.ts @@ -113,13 +113,18 @@ module.exports = function makeBrowserTree(options, destinationPath) { {include: ['**/**'], exclude: ['e2e_test/**'], destDir: '/benchpress/'}); } + let externalTypings = + new Funnel('node_modules', {include: ['rxjs/**/*.d.ts', 'zone.js/**/*.d.ts']}); + + var modulesTree = mergeTrees([ angular2Tree, benchmarksTree, benchmarksExternalTree, payloadTestsTree, playgroundTree, - benchpressTree + benchpressTree, + externalTypings, ]); var es6PolyfillTypings = diff --git a/tools/broccoli/trees/node_tree.ts b/tools/broccoli/trees/node_tree.ts index 5df590a57a..a58a34daed 100644 --- a/tools/broccoli/trees/node_tree.ts +++ b/tools/broccoli/trees/node_tree.ts @@ -30,20 +30,28 @@ module.exports = function makeNodeTree(projects, destinationPath) { 'angular2/src/upgrade/**', 'angular2/upgrade.ts', 'angular2/platform/testing/**', + 'angular2/manual_typings/**', + 'angular2/typings/**' ] }); - let ambientTypings = [ + let externalTypings = [ 'angular2/typings/hammerjs/hammerjs.d.ts', 'angular2/typings/node/node.d.ts', - 'node_modules/zone.js/dist/zone.js.d.ts', 'angular2/manual_typings/globals.d.ts', 'angular2/typings/es6-collections/es6-collections.d.ts', 'angular2/typings/es6-promise/es6-promise.d.ts' ]; + let externalTypingsTree = new Funnel('modules', {files: externalTypings}); + + let packageTypings = + new Funnel('node_modules', {include: ['rxjs/**/*.d.ts', 'zone.js/**/*.d.ts']}); + + let compileSrcContext = mergeTrees([srcTree, externalTypingsTree, packageTypings]); + // Compile the sources and generate the @internal .d.ts - let compiledSrcTreeWithInternals = compileTree(srcTree, true, ambientTypings); + let compiledSrcTreeWithInternals = compileTree(compileSrcContext, true, []); var testTree = new Funnel('modules', { include: [ @@ -71,6 +79,8 @@ module.exports = function makeNodeTree(projects, destinationPath) { 'angular2/test/platform/xhr_impl_spec.ts', 'angular2/test/platform/browser/**/*.ts', 'angular2/test/common/forms/**', + 'angular2/manual_typings/**', + 'angular2/typings/**', // we call browser's bootstrap 'angular2/test/router/route_config/route_config_spec.ts', @@ -92,12 +102,17 @@ module.exports = function makeNodeTree(projects, destinationPath) { let srcPrivateDeclarations = new Funnel(compiledSrcTreeWithInternals, {srcDir: INTERNAL_TYPINGS_PATH}); - testTree = mergeTrees([testTree, srcPrivateDeclarations]); - - let compiledTestTree = compileTree(testTree, false, ambientTypings.concat([ + let testAmbients = [ 'angular2/typings/jasmine/jasmine.d.ts', 'angular2/typings/angular-protractor/angular-protractor.d.ts', - ])); + 'angular2/typings/selenium-webdriver/selenium-webdriver.d.ts' + ]; + let testAmbientsTree = new Funnel('modules', {files: testAmbients}); + + testTree = mergeTrees( + [testTree, srcPrivateDeclarations, testAmbientsTree, externalTypingsTree, packageTypings]); + + let compiledTestTree = compileTree(testTree, false, []); // Merge the compiled sources and tests let compiledSrcTree =