Skip to content

Commit 9886b1b

Browse files
devversionjelbourn
authored andcommitted
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
1 parent c54c897 commit 9886b1b

File tree

4 files changed

+62
-19
lines changed

4 files changed

+62
-19
lines changed

.circleci/config.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ jobs:
4747
<<: *post_checkout
4848
- restore_cache:
4949
key: *cache_key
50-
- run: echo "Temporarily disabled until Bazel setup can be fixed"
50+
51+
- run: bazel run @nodejs//:npm install
52+
# TODO(jelbourn): Update this command to run all tests if the Bazel issues have been fixed.
53+
- run: bazel test src/lib/schematics:unit_tests
54+
5155
- save_cache:
5256
key: *cache_key
5357
paths:

src/lib/schematics/utils/ast.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ import {InsertChange} from '@schematics/angular/utility/change';
1313
import {getWorkspace, WorkspaceProject} from '@schematics/angular/utility/config';
1414
import {findModuleFromOptions as internalFindModule} from '@schematics/angular/utility/find-module';
1515
import {getAppModulePath} from '@schematics/angular/utility/ng-ast-utils';
16-
import * as ts from 'typescript';
1716
import {getProjectMainFile} from './project-main-file';
18-
17+
import {ts} from './version-agnostic-typescript';
1918

2019
/** Reads file given path and returns TypeScript source file. */
21-
export function getSourceFile(host: Tree, path: string): ts.SourceFile {
20+
export function getSourceFile(host: Tree, path: string) {
2221
const buffer = host.read(path);
2322
if (!buffer) {
2423
throw new SchematicsException(`Could not find file for path: ${path}`);
@@ -50,8 +49,9 @@ export function addModuleImportToModule(host: Tree, modulePath: string, moduleNa
5049
throw new SchematicsException(`Module not found: ${modulePath}`);
5150
}
5251

53-
// TODO: cast to any, because the types for ts.SourceFile
54-
// aren't compatible with `strictFunctionTypes`.
52+
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
53+
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
54+
// that is a type signature mismatch at compilation which is not valid.
5555
const changes = addImportToModule(moduleSource as any, modulePath, moduleName, src);
5656
const recorder = host.beginUpdate(modulePath);
5757

src/lib/schematics/utils/build-component.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,17 @@ import {buildDefaultPath} from '@schematics/angular/utility/project';
3838
import {validateHtmlSelector, validateName} from '@schematics/angular/utility/validation';
3939
import {readFileSync} from 'fs';
4040
import {dirname, join, resolve} from 'path';
41-
import * as ts from 'typescript';
4241
import {getProjectFromWorkspace} from './get-project';
4342
import {getDefaultComponentOptions} from './schematic-options';
43+
import {ts} from './version-agnostic-typescript';
4444

45-
function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {
45+
function readIntoSourceFile(host: Tree, modulePath: string) {
4646
const text = host.read(modulePath);
4747
if (text === null) {
4848
throw new SchematicsException(`File ${modulePath} does not exist.`);
4949
}
50-
const sourceText = text.toString('utf-8');
5150

52-
return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
51+
return ts.createSourceFile(modulePath, text.toString('utf-8'), ts.ScriptTarget.Latest, true);
5352
}
5453

5554
function addDeclarationToNgModule(options: ComponentOptions): Rule {
@@ -68,9 +67,11 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
6867
const relativePath = buildRelativePath(modulePath, componentPath);
6968
const classifiedName = strings.classify(`${options.name}Component`);
7069

71-
// TODO: cast to any, because the types for ts.SourceFile
72-
// aren't compatible with `strictFunctionTypes`.
73-
const declarationChanges = addDeclarationToModule(source as any,
70+
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
71+
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
72+
// that is a type signature mismatch at compilation which is not valid.
73+
const declarationChanges = addDeclarationToModule(
74+
source as any,
7475
modulePath,
7576
classifiedName,
7677
relativePath);
@@ -88,9 +89,12 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
8889
const source = readIntoSourceFile(host, modulePath);
8990
const exportRecorder = host.beginUpdate(modulePath);
9091

91-
// TODO: cast to any, because the types for ts.SourceFile
92-
// aren't compatible with `strictFunctionTypes`.
93-
const exportChanges = addExportToModule(source as any, modulePath,
92+
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
93+
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
94+
// that is a type signature mismatch at compilation which is not valid.
95+
const exportChanges = addExportToModule(
96+
source as any,
97+
modulePath,
9498
strings.classify(`${options.name}Component`),
9599
relativePath);
96100

@@ -107,10 +111,12 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule {
107111
const source = readIntoSourceFile(host, modulePath);
108112
const entryComponentRecorder = host.beginUpdate(modulePath);
109113

110-
// TODO: cast to any, because the types for ts.SourceFile
111-
// aren't compatible with `strictFunctionTypes`.
114+
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
115+
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
116+
// that is a type signature mismatch at compilation which is not valid.
112117
const entryComponentChanges = addEntryComponentToModule(
113-
source as any, modulePath,
118+
source as any,
119+
modulePath,
114120
strings.classify(`${options.name}Component`),
115121
relativePath);
116122

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/** This is just a type import and won't be generated in the release output. */
10+
import typescript = require('@schematics/angular/node_modules/typescript');
11+
12+
/**
13+
* This is an agnostic re-export of TypeScript. Depending on the context, this module file will
14+
* return the TypeScript version that is being shipped within the `@schematics/angular` package,
15+
* or fall back to the TypeScript version that has been flattened in the node modules.
16+
*
17+
* This is necessary because we parse TypeScript files and pass the resolved AST to the
18+
* `@schematics/angular` package which might have a different TypeScript version installed.
19+
*/
20+
let ts: typeof typescript;
21+
22+
try {
23+
ts = require('@schematics/angular/node_modules/typescript');
24+
} catch {
25+
try {
26+
ts = require('typescript');
27+
} catch {
28+
throw new Error('Error: Could not find TypeScript for the Angular Material schematics. ' +
29+
'Please report an issue on the Angular Material repository.');
30+
}
31+
}
32+
33+
export {ts};

0 commit comments

Comments
 (0)