Skip to content

Commit 81b28b5

Browse files
authored
Merge pull request microsoft#919 from Microsoft/ianc/autoresolve-rsc
[rush-stack] Automatically resolve rush-stack-compiler from tsconfig
2 parents a4ff60d + 572cd9a commit 81b28b5

5 files changed

Lines changed: 108 additions & 70 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/gulp-core-build-typescript",
5+
"comment": "Update the way rush-stack-compiler is resolved. Now it's resolved by looking at the \"extends\" properties of tsconfig.json",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@microsoft/gulp-core-build-typescript",
10+
"email": "iclanton@users.noreply.github.com"
11+
}

core-build/gulp-core-build-typescript/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
"decomment": "~0.9.1",
2020
"glob": "~7.0.5",
2121
"glob-escape": "~0.0.1",
22-
"resolve": "~1.8.1"
22+
"resolve": "1.8.1"
2323
},
2424
"devDependencies": {
2525
"@microsoft/api-extractor": "6.1.0",
2626
"@microsoft/rush-stack-compiler": "0.4.1",
2727
"@microsoft/node-library-build": "6.0.2",
2828
"@types/glob": "5.0.30",
29-
"@types/resolve": "0.0.8",
3029
"gulp": "~3.9.1",
31-
"typescript": "~3.0.3"
30+
"typescript": "~3.0.3",
31+
"@types/resolve": "0.0.8"
3232
}
3333
}

core-build/gulp-core-build-typescript/src/RSCTask.ts

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,62 +6,49 @@ import * as resolve from 'resolve';
66

77
import {
88
JsonFile,
9-
IPackageJson
9+
IPackageJson,
10+
FileSystem,
11+
PackageJsonLookup,
12+
Terminal
1013
} from '@microsoft/node-core-library';
1114
import { GulpTask } from '@microsoft/gulp-core-build';
1215
import * as RushStackCompiler from '@microsoft/rush-stack-compiler';
1316
import { GCBTerminalProvider } from './GCBTerminalProvider';
1417

1518
export interface IRSCTaskConfig extends Object {
1619
buildDirectory: string;
20+
}
1721

18-
/**
19-
* This is the name of the rush-stack-compiler package, or the name of the package that
20-
* extends the configuration of rush-stack-compiler. This defaults to "\@microsoft/rush-stack-compiler"
21-
*/
22-
rushStackCompilerPackageName?: string;
22+
interface ITsconfig {
23+
extends?: string;
2324
}
2425

2526
export abstract class RSCTask<TTaskConfig extends IRSCTaskConfig> extends GulpTask<TTaskConfig> {
27+
private static _rushStackCompilerPackagePathCache: Map<string, string> = new Map<string, string>();
28+
private static __packageJsonLookup: PackageJsonLookup | undefined; // tslint:disable-line:variable-name
29+
private static get _packageJsonLookup(): PackageJsonLookup {
30+
if (!RSCTask.__packageJsonLookup) {
31+
RSCTask.__packageJsonLookup = new PackageJsonLookup();
32+
}
33+
34+
return RSCTask.__packageJsonLookup;
35+
}
36+
2637
protected _terminalProvider: GCBTerminalProvider = new GCBTerminalProvider(this);
38+
protected _terminal: Terminal = new Terminal(this._terminalProvider);
2739

2840
protected _rushStackCompiler: typeof RushStackCompiler;
2941

30-
private __rushStackCompilerPackagePath: string | undefined; // tslint:disable-line:variable-name
3142
private get _rushStackCompilerPackagePath(): string {
32-
if (!this.__rushStackCompilerPackagePath) {
33-
try {
34-
this.__rushStackCompilerPackagePath = resolve.sync(
35-
this.taskConfig.rushStackCompilerPackageName!,
36-
{
37-
basedir: this.buildConfig.rootPath,
38-
packageFilter: (pkg: IPackageJson) => {
39-
pkg.main = 'package.json';
40-
return pkg;
41-
}
42-
}
43-
);
44-
45-
if (!this.__rushStackCompilerPackagePath) {
46-
throw new Error();
47-
}
48-
49-
this.__rushStackCompilerPackagePath = path.dirname(this.__rushStackCompilerPackagePath);
50-
} catch (e) {
51-
throw new Error(`Unable to find "${this.taskConfig.rushStackCompilerPackageName}" package.`);
52-
}
43+
if (!RSCTask._rushStackCompilerPackagePathCache.has(this.buildFolder)) {
44+
const projectTsconfigPath: string = path.join(this.buildFolder, 'tsconfig.json');
45+
RSCTask._rushStackCompilerPackagePathCache.set(
46+
this.buildFolder,
47+
this._resolveRushStackCompilerFromTsconfig(projectTsconfigPath)
48+
);
5349
}
5450

55-
return this.__rushStackCompilerPackagePath;
56-
}
57-
58-
constructor(name: string, options: Partial<TTaskConfig>) {
59-
super(name,
60-
{
61-
rushStackCompilerPackageName: '@microsoft/rush-stack-compiler',
62-
...(options as any) // tslint:disable-line:no-any - TS is complaining about the spread operator here
63-
}
64-
);
51+
return RSCTask._rushStackCompilerPackagePathCache.get(this.buildFolder)!;
6552
}
6653

6754
protected initializeRushStackCompiler(): void {
@@ -70,9 +57,7 @@ export abstract class RSCTask<TTaskConfig extends IRSCTaskConfig> extends GulpTa
7057
);
7158
const main: string | undefined = compilerPackageJson.main;
7259
if (!main) {
73-
throw new Error(
74-
`Compiler package "${this.taskConfig.rushStackCompilerPackageName}" does not have a "main" entry.`
75-
);
60+
throw new Error('Compiler package does not have a "main" entry.');
7661
}
7762

7863
this._rushStackCompiler = require(path.join(this._rushStackCompilerPackagePath, main));
@@ -81,4 +66,72 @@ export abstract class RSCTask<TTaskConfig extends IRSCTaskConfig> extends GulpTa
8166
protected get buildFolder(): string {
8267
return this.taskConfig.buildDirectory || this.buildConfig.rootPath;
8368
}
69+
70+
private _resolveRushStackCompilerFromTsconfig(tsconfigPath: string): string {
71+
this._terminal.writeVerboseLine(`Examining ${tsconfigPath}`);
72+
73+
// First, see if the package we're in is rush-stack-compiler
74+
const packageJsonPath: string | undefined = RSCTask._packageJsonLookup.tryGetPackageJsonFilePathFor(tsconfigPath);
75+
if (packageJsonPath) {
76+
const packageJson: IPackageJson = JsonFile.load(packageJsonPath);
77+
if (packageJson.name === '@microsoft/rush-stack-compiler') {
78+
const packagePath: string = path.dirname(packageJsonPath);
79+
this._terminal.writeVerboseLine(`Found rush-stack compiler at ${packagePath}/`);
80+
return packagePath;
81+
}
82+
}
83+
84+
if (!FileSystem.exists(tsconfigPath)) {
85+
throw new Error(`tsconfig.json file (${tsconfigPath}) does not exist.`);
86+
}
87+
88+
let tsconfig: ITsconfig;
89+
try {
90+
tsconfig = JsonFile.load(tsconfigPath);
91+
} catch (e) {
92+
throw new Error(`Error parsing tsconfig.json ${tsconfigPath}: ${e}`);
93+
}
94+
95+
if (!tsconfig.extends) {
96+
throw new Error(
97+
'Rush Stack determines your TypeScript compiler by following the "extends" field in your tsconfig.json ' +
98+
'file, until it reaches a package folder that depends on @microsoft/rush-stack-compiler. This lookup ' +
99+
`failed when it reached this file: ${tsconfigPath}`
100+
);
101+
}
102+
103+
let baseTsconfigPath: string;
104+
let extendsPathKind: string;
105+
if (path.isAbsolute(tsconfig.extends)) {
106+
// Absolute path
107+
baseTsconfigPath = tsconfig.extends;
108+
extendsPathKind = 'an absolute path';
109+
} else if (tsconfig.extends.match(/^\./)) {
110+
// Relative path
111+
baseTsconfigPath = path.resolve(path.dirname(tsconfigPath), tsconfig.extends);
112+
extendsPathKind = 'a relative path';
113+
} else {
114+
// Package path
115+
baseTsconfigPath = resolve.sync(
116+
tsconfig.extends,
117+
{
118+
basedir: this.buildConfig.rootPath,
119+
packageFilter: (pkg: IPackageJson) => {
120+
return {
121+
...pkg,
122+
main: 'package.json'
123+
};
124+
}
125+
}
126+
);
127+
extendsPathKind = 'a package path';
128+
}
129+
130+
this._terminal.writeVerboseLine(
131+
`Found tsconfig.extends property ${tsconfig.extends}. It appears ` +
132+
`to be ${extendsPathKind}. Resolved to ${baseTsconfigPath}`
133+
);
134+
135+
return this._resolveRushStackCompilerFromTsconfig(baseTsconfigPath);
136+
}
84137
}

core-build/gulp-core-build-typescript/src/schemas/tsc-cmd.schema.json

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@
1111
"description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.",
1212
"type": "string"
1313
},
14-
"overridePackagePath": {
15-
"description": "The path to the typescript compiler package to use.",
16-
"type": "string"
17-
},
1814
"staticMatch": {
1915
"description": "Glob matches for files to be passed through the build",
2016
"type": "array",
@@ -24,15 +20,6 @@
2420
},
2521
"minItems": 1
2622
},
27-
"customArgs": {
28-
"description": "Optional list of custom args to pass to \"tsc\"",
29-
"type": "array",
30-
"items": {
31-
"type": "string",
32-
"minLength": 1
33-
},
34-
"minItems": 1
35-
},
3623
"buildDirectory": {
3724
"description": "The directory in which the typescript compiler should be invoked.",
3825
"type": "string"

core-build/gulp-core-build-typescript/src/schemas/tslint-cmd.schema.json

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,6 @@
1111
"description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.",
1212
"type": "string"
1313
},
14-
"overridePackagePath": {
15-
"description": "The path to the typescript compiler package to use.",
16-
"type": "string"
17-
},
18-
"customArgs": {
19-
"description": "Optional list of custom args to pass to \"tslint\"",
20-
"type": "array",
21-
"items": {
22-
"type": "string",
23-
"minLength": 1
24-
},
25-
"minItems": 1
26-
},
2714
"buildDirectory": {
2815
"description": "The directory in which tslint should be invoked.",
2916
"type": "string"

0 commit comments

Comments
 (0)