Skip to content

Commit c19c2ee

Browse files
committed
Initial work on TypeScript compiler in rush-stack-compiler.
1 parent dfe789c commit c19c2ee

File tree

10 files changed

+373
-1
lines changed

10 files changed

+373
-1
lines changed

libraries/node-core-library/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"@types/z-schema": "3.16.31",
2121
"fs-extra": "~5.0.0",
2222
"jju": "~1.3.0",
23-
"z-schema": "~3.18.3"
23+
"z-schema": "~3.18.3",
24+
"colors": "~1.2.1"
2425
},
2526
"devDependencies": {
2627
"tslint-microsoft-contrib": "~5.2.1",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as x from 'colors';
2+
import { ITerminalProvider, Severity } from "./ITerminalProvider";
3+
4+
export class ConsoleTerminalProvider implements ITerminalProvider {
5+
public write(data: string, severity: Severity) {
6+
switch (severity) {
7+
case Severity.error: {
8+
console.error(data);
9+
break;
10+
}
11+
12+
case Severity.warn: {
13+
console.warn(data);
14+
break;
15+
}
16+
17+
case Severity.log:
18+
default: {
19+
console.log(data);
20+
break;
21+
}
22+
}
23+
}
24+
25+
public get width(): number {
26+
return 0;
27+
}
28+
29+
public get supportsColor(): boolean {
30+
x.
31+
}
32+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export enum Severity {
2+
log,
3+
warn,
4+
error
5+
}
6+
7+
export interface ITerminalProvider {
8+
write(data: string, severity: Severity);
9+
supportsColor: boolean;
10+
width: number;
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ITerminalProvider } from "./ITerminalProvider";
2+
3+
export class Terminal {
4+
private _provider;
5+
6+
public constructor(provider: ITerminalProvider) {
7+
this._provider = provider;
8+
}
9+
10+
public write(message: string) {}
11+
public writeWarning(message: string) {}
12+
public writeError(message: string) {}
13+
public writeVerbose(message: string) {}
14+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import * as childProcess from 'child_process';
5+
import * as path from 'path';
6+
import * as os from 'os';
7+
8+
import {
9+
JsonFile,
10+
IPackageJson,
11+
FileSystem,
12+
PackageJsonLookup
13+
} from '@microsoft/node-core-library';
14+
import { Constants } from './Constants';
15+
16+
export interface IBaseCmdTaskConfig {
17+
/**
18+
* Optional list of custom args to pass to the tool
19+
*/
20+
customArgs?: string[];
21+
22+
/**
23+
* The path to the package if the task should override the version of the package.
24+
*/
25+
overridePackagePath?: string;
26+
27+
/**
28+
* The directory in which the tool should be invoked.
29+
*/
30+
buildDirectory?: string;
31+
}
32+
33+
/**
34+
* Options for a CmdTask.
35+
* @public
36+
*/
37+
export interface IBaseTaskOptions<TTaskConfig> {
38+
/**
39+
* The initial config of the task.
40+
*/
41+
initialTaskConfig?: TTaskConfig;
42+
43+
/**
44+
* The name of the package to resolve.
45+
*/
46+
packageName: string;
47+
48+
/**
49+
* The path to the binary to invoke inside the package.
50+
*/
51+
packageBinPath: string;
52+
}
53+
54+
/**
55+
* This base task provides support for finding and then executing a binary in a node package.
56+
*
57+
* @alpha
58+
*/
59+
export abstract class BaseCmdTask<TTaskConfig extends IBaseCmdTaskConfig> {
60+
private static __nodePath: string | undefined; // tslint:disable-line:variable-name
61+
private static get _nodePath(): string | undefined {
62+
if (!BaseCmdTask.__nodePath) {
63+
try {
64+
if (os.platform() === 'win32') {
65+
// We're on Windows
66+
const whereOutput: string = childProcess.execSync('where node', { stdio: [] }).toString();
67+
const lines: string[] = whereOutput.split(os.EOL).filter((line) => !!line);
68+
69+
// take the first result, see https://github.com/Microsoft/web-build-tools/issues/759
70+
BaseCmdTask.__nodePath = lines[0];
71+
} else {
72+
// We aren't on Windows - assume we're on *NIX or Darwin
73+
BaseCmdTask.__nodePath = childProcess.execSync('which node', { stdio: [] }).toString();
74+
}
75+
} catch (e) {
76+
return undefined;
77+
}
78+
79+
BaseCmdTask.__nodePath = BaseCmdTask.__nodePath.trim();
80+
if (!FileSystem.exists(BaseCmdTask.__nodePath)) {
81+
return undefined;
82+
}
83+
}
84+
85+
return BaseCmdTask.__nodePath;
86+
}
87+
88+
protected _constants: Constants;
89+
90+
private _packageName: string;
91+
private _packageBinPath: string;
92+
private _errorHasBeenLogged: boolean;
93+
94+
public static getPackagePath(packageName: string): string | undefined {
95+
const packageJsonPath: string | undefined = BaseCmdTask._getPackageJsonPath(packageName);
96+
return packageJsonPath ? path.dirname(packageJsonPath) : undefined;
97+
}
98+
99+
private static _getPackageJsonPath(packageName: string): string | undefined {
100+
const lookup: PackageJsonLookup = new PackageJsonLookup();
101+
const mainEntryPath: string = require.resolve(packageName);
102+
return lookup.tryGetPackageJsonFilePathFor(mainEntryPath);
103+
}
104+
105+
constructor(constants: Constants, packageName: string, packageBinPath: string) {
106+
this._constants = constants;
107+
}
108+
109+
protected invokeCmd(): Promise<void> {
110+
let packageJsonPath: string | undefined = BaseCmdTask._getPackageJsonPath(this._packageName);
111+
112+
if (!packageJsonPath) {
113+
return Promise.reject(new Error(`Unable to find the package.json file for ${this._packageName}.`));
114+
}
115+
116+
const binaryPackagePath: string = path.dirname(packageJsonPath);
117+
118+
// Print the version
119+
const packageJson: IPackageJson = JsonFile.load(packageJsonPath);
120+
console.log(`${this._packageName} version: ${packageJson.version}`);
121+
122+
const binaryPath: string = path.resolve(binaryPackagePath, this._packageBinPath);
123+
if (!FileSystem.exists(binaryPath)) {
124+
return Promise.reject(new Error(
125+
`The binary is missing. This indicates that ${this._packageName} is not ` +
126+
'installed correctly.'
127+
));
128+
}
129+
130+
return new Promise((resolve: () => void, reject: (error: Error) => void) => {
131+
const nodePath: string | undefined = BaseCmdTask._nodePath;
132+
if (!nodePath) {
133+
reject(new Error('Unable to find node executable'));
134+
return;
135+
}
136+
137+
// Invoke the tool and watch for log messages
138+
const spawnResult: childProcess.ChildProcess = childProcess.spawn(
139+
nodePath,
140+
[binaryPath, ...this._getArgs()],
141+
{
142+
cwd: this._constants.projectFolderPath,
143+
env: process.env,
144+
stdio: 'pipe'
145+
}
146+
);
147+
148+
spawnResult.stdout.on('data', this._onData.bind(this));
149+
spawnResult.stderr.on('data', (data: Buffer) => {
150+
this._errorHasBeenLogged = true;
151+
this._onError(data);
152+
});
153+
154+
spawnResult.on('close', (code) => this._onClose(code, this._errorHasBeenLogged, resolve, reject));
155+
});
156+
}
157+
158+
protected _onData(data: Buffer): void {
159+
console.log(data.toString().trim());
160+
}
161+
162+
protected _onError(data: Buffer): void {
163+
console.error(data.toString().trim());
164+
}
165+
166+
protected _onClose(code: number, hasErrors: boolean, resolve: () => void, reject: (error: Error) => void): void {
167+
if (code !== 0 || hasErrors) {
168+
reject(new Error(`exited with code ${code}`));
169+
} else {
170+
resolve();
171+
}
172+
}
173+
174+
protected _getArgs(): string[] {
175+
return [];
176+
}
177+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import * as path from 'path';
5+
6+
const SRC_FOLDER_NAME: string = 'src';
7+
const LIB_FOLDER_NAME: string = 'lib';
8+
const DIST_FOLDER_NAME: string = 'dist';
9+
10+
export class Constants {
11+
private _projectFolderPath: string;
12+
private _srcFolderPath: string;
13+
private _libFolderPath: string;
14+
private _distFolderPath: string;
15+
16+
public constructor(projectFolderPath: string) {
17+
this._projectFolderPath = projectFolderPath;
18+
}
19+
20+
public get projectFolderPath(): string {
21+
return this._projectFolderPath;
22+
}
23+
24+
public get srcFolderPath(): string {
25+
if (!this._srcFolderPath) {
26+
this._srcFolderPath = path.join(this._projectFolderPath, SRC_FOLDER_NAME);
27+
}
28+
29+
return this._srcFolderPath;
30+
}
31+
32+
public get libFolderPath(): string {
33+
if (!this._libFolderPath) {
34+
this._libFolderPath = path.join(this._projectFolderPath, LIB_FOLDER_NAME);
35+
}
36+
37+
return this._libFolderPath;
38+
}
39+
40+
public get distFolderPath(): string {
41+
if (!this._distFolderPath) {
42+
this._distFolderPath = path.join(this._projectFolderPath, DIST_FOLDER_NAME);
43+
}
44+
45+
return this._distFolderPath;
46+
}
47+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import * as path from 'path';
5+
import {
6+
JsonFile,
7+
FileSystem,
8+
LegacyAdapters
9+
} from '@microsoft/node-core-library';
10+
import * as glob from 'glob';
11+
import * as globEscape from 'glob-escape';
12+
import * as typescript from 'typescript';
13+
import * as decomment from 'decomment';
14+
15+
import {
16+
BaseCmdTask,
17+
IBaseCmdTaskConfig
18+
} from './BaseCmdTask';
19+
import { TsParseConfigHost } from './TsParseConfigHost';
20+
import { Constants } from './Constants';
21+
22+
/**
23+
* @public
24+
*/
25+
export interface ITscCmdTaskConfig extends IBaseCmdTaskConfig {
26+
}
27+
28+
/**
29+
* @alpha
30+
*/
31+
export class TscCmdTask extends BaseCmdTask<ITscCmdTaskConfig> {
32+
constructor(constants: Constants) {
33+
super(
34+
constants,
35+
'typescript',
36+
path.join('bin', 'tsc')
37+
);
38+
}
39+
40+
public loadSchema(): Object {
41+
return JsonFile.load(path.resolve(__dirname, 'schemas', 'tsc-cmd.schema.json'));
42+
}
43+
44+
public invoke(): Promise<void> {
45+
return super.invokeCmd();
46+
}
47+
48+
protected _onData(data: Buffer): void {
49+
// Log lines separately
50+
const dataLines: (string | undefined)[] = data.toString().split('\n');
51+
for (const dataLine of dataLines) {
52+
const trimmedLine: string = (dataLine || '').trim();
53+
if (!!trimmedLine) {
54+
if (trimmedLine.match(/\serror\s/i)) {
55+
// If the line looks like an error, log it as an error
56+
console.error(trimmedLine);
57+
} else {
58+
console.log(trimmedLine);
59+
}
60+
}
61+
}
62+
}
63+
}

stack/rush-stack-compiler/src/index.ts

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"extends": "./includes/tsconfig-node.json",
3+
4+
"compilerOptions": {
5+
"outDir": "lib",
6+
7+
"forceConsistentCasingInFileNames": true,
8+
"jsx": "react",
9+
"declaration": true,
10+
"sourceMap": true,
11+
"inlineSources": true,
12+
"experimentalDecorators": true,
13+
"strictNullChecks": true,
14+
"types": []
15+
},
16+
"include": [
17+
"src/**/*.ts",
18+
"src/**/*.tsx"
19+
],
20+
"exclude": [
21+
"node_modules",
22+
"lib"
23+
]
24+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "./includes/tslint.json"
3+
}

0 commit comments

Comments
 (0)