refactor(schematics): avoid typescript version conflicts (#12989)

The Angular Material schematics parse TypeScript sources files and pass the AST to the `@schematics/angular` package which defined an explicit dependency on `typescript`. Since we currently just always require the flattened `typescript` dependency (`node_modules/typescript`), there could be either no TypeScript version or a different TypeScript version that causes the AST operations of the `@schematics/angular` utility functions to not work properly (e.g. different `SyntaxKind` ids)

We should primarily try to load the same TypeScript version that has been shipped with the `@schematics/angular`. If that one couldn't be found, fall back to the top level `typescript` version.

Includes workaround for Bazel ts module resolution
This commit is contained in:
Paul Gschwendtner
2018-09-10 16:20:16 +02:00
committed by Jeremy Elbourn
parent c54c89769c
commit 9886b1b198
4 changed files with 62 additions and 19 deletions
+5 -1
View File
@@ -47,7 +47,11 @@ jobs:
<<: *post_checkout
- restore_cache:
key: *cache_key
- run: echo "Temporarily disabled until Bazel setup can be fixed"
- run: bazel run @nodejs//:npm install
# TODO(jelbourn): Update this command to run all tests if the Bazel issues have been fixed.
- run: bazel test src/lib/schematics:unit_tests
- save_cache:
key: *cache_key
paths:
+5 -5
View File
@@ -13,12 +13,11 @@ import {InsertChange} from '@schematics/angular/utility/change';
import {getWorkspace, WorkspaceProject} from '@schematics/angular/utility/config';
import {findModuleFromOptions as internalFindModule} from '@schematics/angular/utility/find-module';
import {getAppModulePath} from '@schematics/angular/utility/ng-ast-utils';
import * as ts from 'typescript';
import {getProjectMainFile} from './project-main-file';
import {ts} from './version-agnostic-typescript';
/** Reads file given path and returns TypeScript source file. */
export function getSourceFile(host: Tree, path: string): ts.SourceFile {
export function getSourceFile(host: Tree, path: string) {
const buffer = host.read(path);
if (!buffer) {
throw new SchematicsException(`Could not find file for path: ${path}`);
@@ -50,8 +49,9 @@ export function addModuleImportToModule(host: Tree, modulePath: string, moduleNa
throw new SchematicsException(`Module not found: ${modulePath}`);
}
// TODO: cast to any, because the types for ts.SourceFile
// aren't compatible with `strictFunctionTypes`.
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
// that is a type signature mismatch at compilation which is not valid.
const changes = addImportToModule(moduleSource as any, modulePath, moduleName, src);
const recorder = host.beginUpdate(modulePath);
+19 -13
View File
@@ -38,18 +38,17 @@ import {buildDefaultPath} from '@schematics/angular/utility/project';
import {validateHtmlSelector, validateName} from '@schematics/angular/utility/validation';
import {readFileSync} from 'fs';
import {dirname, join, resolve} from 'path';
import * as ts from 'typescript';
import {getProjectFromWorkspace} from './get-project';
import {getDefaultComponentOptions} from './schematic-options';
import {ts} from './version-agnostic-typescript';
function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {
function readIntoSourceFile(host: Tree, modulePath: string) {
const text = host.read(modulePath);
if (text === null) {
throw new SchematicsException(`File ${modulePath} does not exist.`);
}
const sourceText = text.toString('utf-8');
return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
return ts.createSourceFile(modulePath, text.toString('utf-8'), ts.ScriptTarget.Latest, true);
}
function addDeclarationToNgModule(options: ComponentOptions): Rule {
@@ -68,9 +67,11 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
const relativePath = buildRelativePath(modulePath, componentPath);
const classifiedName = strings.classify(`${options.name}Component`);
// TODO: cast to any, because the types for ts.SourceFile
// aren't compatible with `strictFunctionTypes`.
const declarationChanges = addDeclarationToModule(source as any,
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
// that is a type signature mismatch at compilation which is not valid.
const declarationChanges = addDeclarationToModule(
source as any,
modulePath,
classifiedName,
relativePath);
@@ -88,9 +89,12 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
const source = readIntoSourceFile(host, modulePath);
const exportRecorder = host.beginUpdate(modulePath);
// TODO: cast to any, because the types for ts.SourceFile
// aren't compatible with `strictFunctionTypes`.
const exportChanges = addExportToModule(source as any, modulePath,
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
// that is a type signature mismatch at compilation which is not valid.
const exportChanges = addExportToModule(
source as any,
modulePath,
strings.classify(`${options.name}Component`),
relativePath);
@@ -107,10 +111,12 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
const source = readIntoSourceFile(host, modulePath);
const entryComponentRecorder = host.beginUpdate(modulePath);
// TODO: cast to any, because the types for ts.SourceFile
// aren't compatible with `strictFunctionTypes`.
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
// that is a type signature mismatch at compilation which is not valid.
const entryComponentChanges = addEntryComponentToModule(
source as any, modulePath,
source as any,
modulePath,
strings.classify(`${options.name}Component`),
relativePath);
@@ -0,0 +1,33 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/** This is just a type import and won't be generated in the release output. */
import typescript = require('@schematics/angular/node_modules/typescript');
/**
* This is an agnostic re-export of TypeScript. Depending on the context, this module file will
* return the TypeScript version that is being shipped within the `@schematics/angular` package,
* or fall back to the TypeScript version that has been flattened in the node modules.
*
* This is necessary because we parse TypeScript files and pass the resolved AST to the
* `@schematics/angular` package which might have a different TypeScript version installed.
*/
let ts: typeof typescript;
try {
ts = require('@schematics/angular/node_modules/typescript');
} catch {
try {
ts = require('typescript');
} catch {
throw new Error('Error: Could not find TypeScript for the Angular Material schematics. ' +
'Please report an issue on the Angular Material repository.');
}
}
export {ts};