Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes <johannes.rieken@gmail.com>2022-05-05 12:35:33 +0300
committerJohannes <johannes.rieken@gmail.com>2022-05-05 12:35:33 +0300
commitc13d581bcec2c5dbebe7e51a4988a46c50899f0e (patch)
tree7be7550c8e5ced92971cd821de702b10ca9caee6
parent63076cfe1013c9d29972a9ddfdb749e29640a07e (diff)
move gulp-tsb into the `build/lib` remove as dependency
-rw-r--r--build/gulpfile.extensions.js2
-rw-r--r--build/lib/compilation.js2
-rw-r--r--build/lib/compilation.ts2
-rw-r--r--build/lib/tsb/builder.js491
-rw-r--r--build/lib/tsb/builder.ts616
-rw-r--r--build/lib/tsb/index.js89
-rw-r--r--build/lib/tsb/index.ts118
-rw-r--r--build/lib/tsb/utils.js124
-rw-r--r--build/lib/tsb/utils.ts140
-rw-r--r--build/lib/typings/gulp-tsb.d.ts18
-rw-r--r--extensions/vscode-colorize-tests/test/colorize-fixtures/test.js20
-rw-r--r--extensions/vscode-colorize-tests/test/colorize-results/test_js.json38
-rw-r--r--package.json1
-rw-r--r--yarn.lock10
14 files changed, 1622 insertions, 49 deletions
diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js
index 8e05d03d295..ba2606861fd 100644
--- a/build/gulpfile.extensions.js
+++ b/build/gulpfile.extensions.js
@@ -102,7 +102,7 @@ const tasks = compilations.map(function (tsconfigFile) {
function createPipeline(build, emitError) {
const nlsDev = require('vscode-nls-dev');
- const tsb = require('gulp-tsb');
+ const tsb = require('./lib/tsb');
const sourcemaps = require('gulp-sourcemaps');
const reporter = createReporter('extensions');
diff --git a/build/lib/compilation.js b/build/lib/compilation.js
index 1841795cefd..db489e01f9d 100644
--- a/build/lib/compilation.js
+++ b/build/lib/compilation.js
@@ -35,7 +35,7 @@ function getTypeScriptCompilerOptions(src) {
return options;
}
function createCompile(src, build, emitError) {
- const tsb = require('gulp-tsb');
+ const tsb = require('./tsb');
const sourcemaps = require('gulp-sourcemaps');
const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json');
const overrideOptions = { ...getTypeScriptCompilerOptions(src), inlineSources: Boolean(build) };
diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts
index 1325f89fd04..d40b6139cc0 100644
--- a/build/lib/compilation.ts
+++ b/build/lib/compilation.ts
@@ -40,7 +40,7 @@ function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions {
}
function createCompile(src: string, build: boolean, emitError?: boolean) {
- const tsb = require('gulp-tsb') as typeof import('gulp-tsb');
+ const tsb = require('./tsb') as typeof import('./tsb');
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js
new file mode 100644
index 00000000000..f0e1958df7e
--- /dev/null
+++ b/build/lib/tsb/builder.js
@@ -0,0 +1,491 @@
+"use strict";
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.createTypeScriptBuilder = exports.CancellationToken = void 0;
+const fs_1 = require("fs");
+const path = require("path");
+const crypto = require("crypto");
+const utils = require("./utils");
+const log = require("fancy-log");
+const colors = require("ansi-colors");
+const ts = require("typescript");
+const Vinyl = require("vinyl");
+var CancellationToken;
+(function (CancellationToken) {
+ CancellationToken.None = {
+ isCancellationRequested() { return false; }
+ };
+})(CancellationToken = exports.CancellationToken || (exports.CancellationToken = {}));
+function normalize(path) {
+ return path.replace(/\\/g, '/');
+}
+function createTypeScriptBuilder(config, projectFile, cmd) {
+ function _log(topic, message) {
+ if (config.verbose) {
+ log(colors.cyan(topic), message);
+ }
+ }
+ let host = new LanguageServiceHost(cmd, projectFile, _log), service = ts.createLanguageService(host, ts.createDocumentRegistry()), lastBuildVersion = Object.create(null), lastDtsHash = Object.create(null), userWantsDeclarations = cmd.options.declaration, oldErrors = Object.create(null), headUsed = process.memoryUsage().heapUsed, emitSourceMapsInStream = true;
+ // always emit declaraction files
+ host.getCompilationSettings().declaration = true;
+ function file(file) {
+ // support gulp-sourcemaps
+ if (file.sourceMap) {
+ emitSourceMapsInStream = false;
+ }
+ if (!file.contents) {
+ host.removeScriptSnapshot(file.path);
+ }
+ else {
+ host.addScriptSnapshot(file.path, new VinylScriptSnapshot(file));
+ }
+ }
+ function baseFor(snapshot) {
+ if (snapshot instanceof VinylScriptSnapshot) {
+ return cmd.options.outDir || snapshot.getBase();
+ }
+ else {
+ return '';
+ }
+ }
+ function isExternalModule(sourceFile) {
+ return sourceFile.externalModuleIndicator
+ || /declare\s+module\s+('|")(.+)\1/.test(sourceFile.getText());
+ }
+ function build(out, onError, token = CancellationToken.None) {
+ function checkSyntaxSoon(fileName) {
+ return new Promise(resolve => {
+ process.nextTick(function () {
+ if (!host.getScriptSnapshot(fileName, false)) {
+ resolve([]); // no script, no problems
+ }
+ else {
+ resolve(service.getSyntacticDiagnostics(fileName));
+ }
+ });
+ });
+ }
+ function checkSemanticsSoon(fileName) {
+ return new Promise(resolve => {
+ process.nextTick(function () {
+ if (!host.getScriptSnapshot(fileName, false)) {
+ resolve([]); // no script, no problems
+ }
+ else {
+ resolve(service.getSemanticDiagnostics(fileName));
+ }
+ });
+ });
+ }
+ function emitSoon(fileName) {
+ return new Promise(resolve => {
+ process.nextTick(function () {
+ if (/\.d\.ts$/.test(fileName)) {
+ // if it's already a d.ts file just emit it signature
+ let snapshot = host.getScriptSnapshot(fileName);
+ let signature = crypto.createHash('md5')
+ .update(snapshot.getText(0, snapshot.getLength()))
+ .digest('base64');
+ return resolve({
+ fileName,
+ signature,
+ files: []
+ });
+ }
+ let output = service.getEmitOutput(fileName);
+ let files = [];
+ let signature;
+ for (let file of output.outputFiles) {
+ if (!emitSourceMapsInStream && /\.js\.map$/.test(file.name)) {
+ continue;
+ }
+ if (/\.d\.ts$/.test(file.name)) {
+ signature = crypto.createHash('md5')
+ .update(file.text)
+ .digest('base64');
+ if (!userWantsDeclarations) {
+ // don't leak .d.ts files if users don't want them
+ continue;
+ }
+ }
+ let vinyl = new Vinyl({
+ path: file.name,
+ contents: Buffer.from(file.text),
+ base: !config._emitWithoutBasePath && baseFor(host.getScriptSnapshot(fileName)) || undefined
+ });
+ if (!emitSourceMapsInStream && /\.js$/.test(file.name)) {
+ let sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0];
+ if (sourcemapFile) {
+ let extname = path.extname(vinyl.relative);
+ let basename = path.basename(vinyl.relative, extname);
+ let dirname = path.dirname(vinyl.relative);
+ let tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts';
+ let sourceMap = JSON.parse(sourcemapFile.text);
+ sourceMap.sources[0] = tsname.replace(/\\/g, '/');
+ vinyl.sourceMap = sourceMap;
+ }
+ }
+ files.push(vinyl);
+ }
+ resolve({
+ fileName,
+ signature,
+ files
+ });
+ });
+ });
+ }
+ let newErrors = Object.create(null);
+ let t1 = Date.now();
+ let toBeEmitted = [];
+ let toBeCheckedSyntactically = [];
+ let toBeCheckedSemantically = [];
+ let filesWithChangedSignature = [];
+ let dependentFiles = [];
+ let newLastBuildVersion = new Map();
+ for (let fileName of host.getScriptFileNames()) {
+ if (lastBuildVersion[fileName] !== host.getScriptVersion(fileName)) {
+ toBeEmitted.push(fileName);
+ toBeCheckedSyntactically.push(fileName);
+ toBeCheckedSemantically.push(fileName);
+ }
+ }
+ return new Promise(resolve => {
+ let semanticCheckInfo = new Map();
+ let seenAsDependentFile = new Set();
+ function workOnNext() {
+ let promise;
+ // let fileName: string;
+ // someone told us to stop this
+ if (token.isCancellationRequested()) {
+ _log('[CANCEL]', '>>This compile run was cancelled<<');
+ newLastBuildVersion.clear();
+ resolve();
+ return;
+ }
+ // (1st) emit code
+ else if (toBeEmitted.length) {
+ let fileName = toBeEmitted.pop();
+ promise = emitSoon(fileName).then(value => {
+ for (let file of value.files) {
+ _log('[emit code]', file.path);
+ out(file);
+ }
+ // remember when this was build
+ newLastBuildVersion.set(fileName, host.getScriptVersion(fileName));
+ // remeber the signature
+ if (value.signature && lastDtsHash[fileName] !== value.signature) {
+ lastDtsHash[fileName] = value.signature;
+ filesWithChangedSignature.push(fileName);
+ }
+ }).catch(e => {
+ // can't just skip this or make a result up..
+ host.error(`ERROR emitting ${fileName}`);
+ host.error(e);
+ });
+ }
+ // (2nd) check syntax
+ else if (toBeCheckedSyntactically.length) {
+ let fileName = toBeCheckedSyntactically.pop();
+ _log('[check syntax]', fileName);
+ promise = checkSyntaxSoon(fileName).then(diagnostics => {
+ delete oldErrors[fileName];
+ if (diagnostics.length > 0) {
+ diagnostics.forEach(d => onError(d));
+ newErrors[fileName] = diagnostics;
+ // stop the world when there are syntax errors
+ toBeCheckedSyntactically.length = 0;
+ toBeCheckedSemantically.length = 0;
+ filesWithChangedSignature.length = 0;
+ }
+ });
+ }
+ // (3rd) check semantics
+ else if (toBeCheckedSemantically.length) {
+ let fileName = toBeCheckedSemantically.pop();
+ while (fileName && semanticCheckInfo.has(fileName)) {
+ fileName = toBeCheckedSemantically.pop();
+ }
+ if (fileName) {
+ _log('[check semantics]', fileName);
+ promise = checkSemanticsSoon(fileName).then(diagnostics => {
+ delete oldErrors[fileName];
+ semanticCheckInfo.set(fileName, diagnostics.length);
+ if (diagnostics.length > 0) {
+ diagnostics.forEach(d => onError(d));
+ newErrors[fileName] = diagnostics;
+ }
+ });
+ }
+ }
+ // (4th) check dependents
+ else if (filesWithChangedSignature.length) {
+ while (filesWithChangedSignature.length) {
+ let fileName = filesWithChangedSignature.pop();
+ if (!isExternalModule(service.getProgram().getSourceFile(fileName))) {
+ _log('[check semantics*]', fileName + ' is an internal module and it has changed shape -> check whatever hasn\'t been checked yet');
+ toBeCheckedSemantically.push(...host.getScriptFileNames());
+ filesWithChangedSignature.length = 0;
+ dependentFiles.length = 0;
+ break;
+ }
+ host.collectDependents(fileName, dependentFiles);
+ }
+ }
+ // (5th) dependents contd
+ else if (dependentFiles.length) {
+ let fileName = dependentFiles.pop();
+ while (fileName && seenAsDependentFile.has(fileName)) {
+ fileName = dependentFiles.pop();
+ }
+ if (fileName) {
+ seenAsDependentFile.add(fileName);
+ let value = semanticCheckInfo.get(fileName);
+ if (value === 0) {
+ // already validated successfully -> look at dependents next
+ host.collectDependents(fileName, dependentFiles);
+ }
+ else if (typeof value === 'undefined') {
+ // first validate -> look at dependents next
+ dependentFiles.push(fileName);
+ toBeCheckedSemantically.push(fileName);
+ }
+ }
+ }
+ // (last) done
+ else {
+ resolve();
+ return;
+ }
+ if (!promise) {
+ promise = Promise.resolve();
+ }
+ promise.then(function () {
+ // change to change
+ process.nextTick(workOnNext);
+ }).catch(err => {
+ console.error(err);
+ });
+ }
+ workOnNext();
+ }).then(() => {
+ // store the build versions to not rebuilt the next time
+ newLastBuildVersion.forEach((value, key) => {
+ lastBuildVersion[key] = value;
+ });
+ // print old errors and keep them
+ utils.collections.forEach(oldErrors, entry => {
+ entry.value.forEach(diag => onError(diag));
+ newErrors[entry.key] = entry.value;
+ });
+ oldErrors = newErrors;
+ // print stats
+ if (config.verbose) {
+ const headNow = process.memoryUsage().heapUsed;
+ const MB = 1024 * 1024;
+ log('[tsb]', 'time:', colors.yellow((Date.now() - t1) + 'ms'), 'mem:', colors.cyan(Math.ceil(headNow / MB) + 'MB'), colors.bgcyan('delta: ' + Math.ceil((headNow - headUsed) / MB)));
+ headUsed = headNow;
+ }
+ });
+ }
+ return {
+ file,
+ build,
+ languageService: service
+ };
+}
+exports.createTypeScriptBuilder = createTypeScriptBuilder;
+class ScriptSnapshot {
+ constructor(text, mtime) {
+ this._text = text;
+ this._mtime = mtime;
+ }
+ getVersion() {
+ return this._mtime.toUTCString();
+ }
+ getText(start, end) {
+ return this._text.substring(start, end);
+ }
+ getLength() {
+ return this._text.length;
+ }
+ getChangeRange(_oldSnapshot) {
+ return undefined;
+ }
+}
+class VinylScriptSnapshot extends ScriptSnapshot {
+ constructor(file) {
+ super(file.contents.toString(), file.stat.mtime);
+ this._base = file.base;
+ }
+ getBase() {
+ return this._base;
+ }
+}
+class LanguageServiceHost {
+ constructor(_cmdLine, _projectPath, _log) {
+ this._cmdLine = _cmdLine;
+ this._projectPath = _projectPath;
+ this._log = _log;
+ this.directoryExists = ts.sys.directoryExists;
+ this.getDirectories = ts.sys.getDirectories;
+ this.fileExists = ts.sys.fileExists;
+ this.readFile = ts.sys.readFile;
+ this.readDirectory = ts.sys.readDirectory;
+ this._snapshots = Object.create(null);
+ this._filesInProject = new Set(_cmdLine.fileNames);
+ this._filesAdded = new Set();
+ this._dependencies = new utils.graph.Graph(s => s);
+ this._dependenciesRecomputeList = [];
+ this._fileNameToDeclaredModule = Object.create(null);
+ this._projectVersion = 1;
+ }
+ log(_s) {
+ // console.log(s);
+ }
+ trace(_s) {
+ // console.log(s);
+ }
+ error(s) {
+ console.error(s);
+ }
+ getCompilationSettings() {
+ return this._cmdLine.options;
+ }
+ getProjectVersion() {
+ return String(this._projectVersion);
+ }
+ getScriptFileNames() {
+ const res = Object.keys(this._snapshots).filter(path => this._filesInProject.has(path) || this._filesAdded.has(path));
+ return res;
+ }
+ getScriptVersion(filename) {
+ filename = normalize(filename);
+ const result = this._snapshots[filename];
+ if (result) {
+ return result.getVersion();
+ }
+ return 'UNKNWON_FILE_' + Math.random().toString(16).slice(2);
+ }
+ getScriptSnapshot(filename, resolve = true) {
+ filename = normalize(filename);
+ let result = this._snapshots[filename];
+ if (!result && resolve) {
+ try {
+ result = new VinylScriptSnapshot(new Vinyl({
+ path: filename,
+ contents: (0, fs_1.readFileSync)(filename),
+ base: this.getCompilationSettings().outDir,
+ stat: (0, fs_1.statSync)(filename)
+ }));
+ this.addScriptSnapshot(filename, result);
+ }
+ catch (e) {
+ // ignore
+ }
+ }
+ return result;
+ }
+ addScriptSnapshot(filename, snapshot) {
+ this._projectVersion++;
+ filename = normalize(filename);
+ const old = this._snapshots[filename];
+ if (!old && !this._filesInProject.has(filename) && !filename.endsWith('.d.ts')) {
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // not very proper!
+ this._filesAdded.add(filename);
+ }
+ if (!old || old.getVersion() !== snapshot.getVersion()) {
+ this._dependenciesRecomputeList.push(filename);
+ let node = this._dependencies.lookup(filename);
+ if (node) {
+ node.outgoing = Object.create(null);
+ }
+ // (cheap) check for declare module
+ LanguageServiceHost._declareModule.lastIndex = 0;
+ let match;
+ while ((match = LanguageServiceHost._declareModule.exec(snapshot.getText(0, snapshot.getLength())))) {
+ let declaredModules = this._fileNameToDeclaredModule[filename];
+ if (!declaredModules) {
+ this._fileNameToDeclaredModule[filename] = declaredModules = [];
+ }
+ declaredModules.push(match[2]);
+ }
+ }
+ this._snapshots[filename] = snapshot;
+ return old;
+ }
+ removeScriptSnapshot(filename) {
+ this._filesInProject.delete(filename);
+ this._filesAdded.delete(filename);
+ this._projectVersion++;
+ filename = normalize(filename);
+ delete this._fileNameToDeclaredModule[filename];
+ return delete this._snapshots[filename];
+ }
+ getCurrentDirectory() {
+ return path.dirname(this._projectPath);
+ }
+ getDefaultLibFileName(options) {
+ return ts.getDefaultLibFilePath(options);
+ }
+ // ---- dependency management
+ collectDependents(filename, target) {
+ while (this._dependenciesRecomputeList.length) {
+ this._processFile(this._dependenciesRecomputeList.pop());
+ }
+ filename = normalize(filename);
+ const node = this._dependencies.lookup(filename);
+ if (node) {
+ utils.collections.forEach(node.incoming, entry => target.push(entry.key));
+ }
+ }
+ _processFile(filename) {
+ if (filename.match(/.*\.d\.ts$/)) {
+ return;
+ }
+ filename = normalize(filename);
+ const snapshot = this.getScriptSnapshot(filename);
+ if (!snapshot) {
+ this._log('processFile', `Missing snapshot for: ${filename}`);
+ return;
+ }
+ const info = ts.preProcessFile(snapshot.getText(0, snapshot.getLength()), true);
+ // (1) ///-references
+ info.referencedFiles.forEach(ref => {
+ const resolvedPath = path.resolve(path.dirname(filename), ref.fileName);
+ const normalizedPath = normalize(resolvedPath);
+ this._dependencies.inertEdge(filename, normalizedPath);
+ });
+ // (2) import-require statements
+ info.importedFiles.forEach(ref => {
+ const stopDirname = normalize(this.getCurrentDirectory());
+ let dirname = filename;
+ let found = false;
+ while (!found && dirname.indexOf(stopDirname) === 0) {
+ dirname = path.dirname(dirname);
+ const resolvedPath = path.resolve(dirname, ref.fileName);
+ const normalizedPath = normalize(resolvedPath);
+ if (this.getScriptSnapshot(normalizedPath + '.ts')) {
+ this._dependencies.inertEdge(filename, normalizedPath + '.ts');
+ found = true;
+ }
+ else if (this.getScriptSnapshot(normalizedPath + '.d.ts')) {
+ this._dependencies.inertEdge(filename, normalizedPath + '.d.ts');
+ found = true;
+ }
+ }
+ if (!found) {
+ for (let key in this._fileNameToDeclaredModule) {
+ if (this._fileNameToDeclaredModule[key] && ~this._fileNameToDeclaredModule[key].indexOf(ref.fileName)) {
+ this._dependencies.inertEdge(filename, key);
+ }
+ }
+ }
+ });
+ }
+}
+LanguageServiceHost._declareModule = /declare\s+module\s+('|")(.+)\1/g;
diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts
new file mode 100644
index 00000000000..2f8753dd119
--- /dev/null
+++ b/build/lib/tsb/builder.ts
@@ -0,0 +1,616 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { statSync, readFileSync } from 'fs';
+import * as path from 'path';
+import * as crypto from 'crypto';
+import * as utils from './utils';
+import * as log from 'fancy-log';
+import * as colors from 'ansi-colors';
+import * as ts from 'typescript';
+import * as Vinyl from 'vinyl';
+
+export interface IConfiguration {
+ verbose: boolean;
+ _emitWithoutBasePath?: boolean;
+}
+
+export interface CancellationToken {
+ isCancellationRequested(): boolean;
+}
+
+export namespace CancellationToken {
+ export const None: CancellationToken = {
+ isCancellationRequested() { return false; }
+ };
+}
+
+export interface ITypeScriptBuilder {
+ build(out: (file: Vinyl) => void, onError: (err: ts.Diagnostic) => void, token?: CancellationToken): Promise<any>;
+ file(file: Vinyl): void;
+ languageService: ts.LanguageService;
+}
+
+function normalize(path: string): string {
+ return path.replace(/\\/g, '/');
+}
+
+export function createTypeScriptBuilder(config: IConfiguration, projectFile: string, cmd: ts.ParsedCommandLine): ITypeScriptBuilder {
+
+ function _log(topic: string, message: string): void {
+ if (config.verbose) {
+ log(colors.cyan(topic), message);
+ }
+ }
+
+ let host = new LanguageServiceHost(cmd, projectFile, _log),
+ service = ts.createLanguageService(host, ts.createDocumentRegistry()),
+ lastBuildVersion: { [path: string]: string } = Object.create(null),
+ lastDtsHash: { [path: string]: string } = Object.create(null),
+ userWantsDeclarations = cmd.options.declaration,
+ oldErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null),
+ headUsed = process.memoryUsage().heapUsed,
+ emitSourceMapsInStream = true;
+
+ // always emit declaraction files
+ host.getCompilationSettings().declaration = true;
+
+
+ function file(file: Vinyl): void {
+ // support gulp-sourcemaps
+ if ((<any>file).sourceMap) {
+ emitSourceMapsInStream = false;
+ }
+
+ if (!file.contents) {
+ host.removeScriptSnapshot(file.path);
+ } else {
+ host.addScriptSnapshot(file.path, new VinylScriptSnapshot(file));
+ }
+ }
+
+ function baseFor(snapshot: ScriptSnapshot): string {
+ if (snapshot instanceof VinylScriptSnapshot) {
+ return cmd.options.outDir || snapshot.getBase();
+ } else {
+ return '';
+ }
+ }
+
+ function isExternalModule(sourceFile: ts.SourceFile): boolean {
+ return (<any>sourceFile).externalModuleIndicator
+ || /declare\s+module\s+('|")(.+)\1/.test(sourceFile.getText());
+ }
+
+ function build(out: (file: Vinyl) => void, onError: (err: any) => void, token = CancellationToken.None): Promise<any> {
+
+ function checkSyntaxSoon(fileName: string): Promise<ts.Diagnostic[]> {
+ return new Promise<ts.Diagnostic[]>(resolve => {
+ process.nextTick(function () {
+ if (!host.getScriptSnapshot(fileName, false)) {
+ resolve([]); // no script, no problems
+ } else {
+ resolve(service.getSyntacticDiagnostics(fileName));
+ }
+ });
+ });
+ }
+
+ function checkSemanticsSoon(fileName: string): Promise<ts.Diagnostic[]> {
+ return new Promise<ts.Diagnostic[]>(resolve => {
+ process.nextTick(function () {
+ if (!host.getScriptSnapshot(fileName, false)) {
+ resolve([]); // no script, no problems
+ } else {
+ resolve(service.getSemanticDiagnostics(fileName));
+ }
+ });
+ });
+ }
+
+ function emitSoon(fileName: string): Promise<{ fileName: string; signature?: string; files: Vinyl[] }> {
+
+ return new Promise(resolve => {
+ process.nextTick(function () {
+
+ if (/\.d\.ts$/.test(fileName)) {
+ // if it's already a d.ts file just emit it signature
+ let snapshot = host.getScriptSnapshot(fileName);
+ let signature = crypto.createHash('md5')
+ .update(snapshot.getText(0, snapshot.getLength()))
+ .digest('base64');
+
+ return resolve({
+ fileName,
+ signature,
+ files: []
+ });
+ }
+
+ let output = service.getEmitOutput(fileName);
+ let files: Vinyl[] = [];
+ let signature: string | undefined;
+
+ for (let file of output.outputFiles) {
+ if (!emitSourceMapsInStream && /\.js\.map$/.test(file.name)) {
+ continue;
+ }
+
+ if (/\.d\.ts$/.test(file.name)) {
+ signature = crypto.createHash('md5')
+ .update(file.text)
+ .digest('base64');
+
+ if (!userWantsDeclarations) {
+ // don't leak .d.ts files if users don't want them
+ continue;
+ }
+ }
+
+ let vinyl = new Vinyl({
+ path: file.name,
+ contents: Buffer.from(file.text),
+ base: !config._emitWithoutBasePath && baseFor(host.getScriptSnapshot(fileName)) || undefined
+ });
+
+ if (!emitSourceMapsInStream && /\.js$/.test(file.name)) {
+ let sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0];
+
+ if (sourcemapFile) {
+ let extname = path.extname(vinyl.relative);
+ let basename = path.basename(vinyl.relative, extname);
+ let dirname = path.dirname(vinyl.relative);
+ let tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts';
+
+ let sourceMap = JSON.parse(sourcemapFile.text);
+ sourceMap.sources[0] = tsname.replace(/\\/g, '/');
+ (<any>vinyl).sourceMap = sourceMap;
+ }
+ }
+
+ files.push(vinyl);
+ }
+
+ resolve({
+ fileName,
+ signature,
+ files
+ });
+ });
+ });
+ }
+
+ let newErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null);
+ let t1 = Date.now();
+
+ let toBeEmitted: string[] = [];
+ let toBeCheckedSyntactically: string[] = [];
+ let toBeCheckedSemantically: string[] = [];
+ let filesWithChangedSignature: string[] = [];
+ let dependentFiles: string[] = [];
+ let newLastBuildVersion = new Map<string, string>();
+
+ for (let fileName of host.getScriptFileNames()) {
+ if (lastBuildVersion[fileName] !== host.getScriptVersion(fileName)) {
+
+ toBeEmitted.push(fileName);
+ toBeCheckedSyntactically.push(fileName);
+ toBeCheckedSemantically.push(fileName);
+ }
+ }
+
+ return new Promise<void>(resolve => {
+
+ let semanticCheckInfo = new Map<string, number>();
+ let seenAsDependentFile = new Set<string>();
+
+ function workOnNext() {
+
+ let promise: Promise<any> | undefined;
+ // let fileName: string;
+
+ // someone told us to stop this
+ if (token.isCancellationRequested()) {
+ _log('[CANCEL]', '>>This compile run was cancelled<<');
+ newLastBuildVersion.clear();
+ resolve();
+ return;
+ }
+
+ // (1st) emit code
+ else if (toBeEmitted.length) {
+ let fileName = toBeEmitted.pop()!;
+ promise = emitSoon(fileName).then(value => {
+
+ for (let file of value.files) {
+ _log('[emit code]', file.path);
+ out(file);
+ }
+
+ // remember when this was build
+ newLastBuildVersion.set(fileName, host.getScriptVersion(fileName));
+
+ // remeber the signature
+ if (value.signature && lastDtsHash[fileName] !== value.signature) {
+ lastDtsHash[fileName] = value.signature;
+ filesWithChangedSignature.push(fileName);
+ }
+ }).catch(e => {
+ // can't just skip this or make a result up..
+ host.error(`ERROR emitting ${fileName}`);
+ host.error(e);
+ });
+ }
+
+ // (2nd) check syntax
+ else if (toBeCheckedSyntactically.length) {
+ let fileName = toBeCheckedSyntactically.pop()!;
+ _log('[check syntax]', fileName);
+ promise = checkSyntaxSoon(fileName).then(diagnostics => {
+ delete oldErrors[fileName];
+ if (diagnostics.length > 0) {
+ diagnostics.forEach(d => onError(d));
+ newErrors[fileName] = diagnostics;
+
+ // stop the world when there are syntax errors
+ toBeCheckedSyntactically.length = 0;
+ toBeCheckedSemantically.length = 0;
+ filesWithChangedSignature.length = 0;
+ }
+ });
+ }
+
+ // (3rd) check semantics
+ else if (toBeCheckedSemantically.length) {
+
+ let fileName = toBeCheckedSemantically.pop();
+ while (fileName && semanticCheckInfo.has(fileName)) {
+ fileName = toBeCheckedSemantically.pop()!;
+ }
+
+ if (fileName) {
+ _log('[check semantics]', fileName);
+ promise = checkSemanticsSoon(fileName).then(diagnostics => {
+ delete oldErrors[fileName!];
+ semanticCheckInfo.set(fileName!, diagnostics.length);
+ if (diagnostics.length > 0) {
+ diagnostics.forEach(d => onError(d));
+ newErrors[fileName!] = diagnostics;
+ }
+ });
+ }
+ }
+
+ // (4th) check dependents
+ else if (filesWithChangedSignature.length) {
+ while (filesWithChangedSignature.length) {
+ let fileName = filesWithChangedSignature.pop()!;
+
+ if (!isExternalModule(service.getProgram()!.getSourceFile(fileName)!)) {
+ _log('[check semantics*]', fileName + ' is an internal module and it has changed shape -> check whatever hasn\'t been checked yet');
+ toBeCheckedSemantically.push(...host.getScriptFileNames());
+ filesWithChangedSignature.length = 0;
+ dependentFiles.length = 0;
+ break;
+ }
+
+ host.collectDependents(fileName, dependentFiles);
+ }
+ }
+
+ // (5th) dependents contd
+ else if (dependentFiles.length) {
+ let fileName = dependentFiles.pop();
+ while (fileName && seenAsDependentFile.has(fileName)) {
+ fileName = dependentFiles.pop();
+ }
+ if (fileName) {
+ seenAsDependentFile.add(fileName);
+ let value = semanticCheckInfo.get(fileName);
+ if (value === 0) {
+ // already validated successfully -> look at dependents next
+ host.collectDependents(fileName, dependentFiles);
+
+ } else if (typeof value === 'undefined') {
+ // first validate -> look at dependents next
+ dependentFiles.push(fileName);
+ toBeCheckedSemantically.push(fileName);
+ }
+ }
+ }
+
+ // (last) done
+ else {
+ resolve();
+ return;
+ }
+
+ if (!promise) {
+ promise = Promise.resolve();
+ }
+
+ promise.then(function () {
+ // change to change
+ process.nextTick(workOnNext);
+ }).catch(err => {
+ console.error(err);
+ });
+ }
+
+ workOnNext();
+
+ }).then(() => {
+ // store the build versions to not rebuilt the next time
+ newLastBuildVersion.forEach((value, key) => {
+ lastBuildVersion[key] = value;
+ });
+
+ // print old errors and keep them
+ utils.collections.forEach(oldErrors, entry => {
+ entry.value.forEach(diag => onError(diag));
+ newErrors[entry.key] = entry.value;
+ });
+ oldErrors = newErrors;
+
+ // print stats
+ if (config.verbose) {
+ const headNow = process.memoryUsage().heapUsed;
+ const MB = 1024 * 1024;
+ log('[tsb]',
+ 'time:', colors.yellow((Date.now() - t1) + 'ms'),
+ 'mem:', colors.cyan(Math.ceil(headNow / MB) + 'MB'), colors.bgcyan('delta: ' + Math.ceil((headNow - headUsed) / MB))
+ );
+ headUsed = headNow;
+ }
+ });
+ }
+
+ return {
+ file,
+ build,
+ languageService: service
+ };
+}
+
+class ScriptSnapshot implements ts.IScriptSnapshot {
+
+ private readonly _text: string;
+ private readonly _mtime: Date;
+
+ constructor(text: string, mtime: Date) {
+ this._text = text;
+ this._mtime = mtime;
+ }
+
+ getVersion(): string {
+ return this._mtime.toUTCString();
+ }
+
+ getText(start: number, end: number): string {
+ return this._text.substring(start, end);
+ }
+
+ getLength(): number {
+ return this._text.length;
+ }
+
+ getChangeRange(_oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange | undefined {
+ return undefined;
+ }
+}
+
+class VinylScriptSnapshot extends ScriptSnapshot {
+
+ private readonly _base: string;
+
+ constructor(file: Vinyl) {
+ super(file.contents!.toString(), file.stat!.mtime);
+ this._base = file.base;
+ }
+
+ getBase(): string {
+ return this._base;
+ }
+}
+
+class LanguageServiceHost implements ts.LanguageServiceHost {
+
+ private readonly _snapshots: { [path: string]: ScriptSnapshot };
+ private readonly _filesInProject: Set<string>;
+ private readonly _filesAdded: Set<string>;
+ private readonly _dependencies: utils.graph.Graph<string>;
+ private readonly _dependenciesRecomputeList: string[];
+ private readonly _fileNameToDeclaredModule: { [path: string]: string[] };
+
+ private _projectVersion: number;
+
+ constructor(
+ private readonly _cmdLine: ts.ParsedCommandLine,
+ private readonly _projectPath: string,
+ private readonly _log: (topic: string, message: string) => void
+ ) {
+ this._snapshots = Object.create(null);
+ this._filesInProject = new Set(_cmdLine.fileNames);
+ this._filesAdded = new Set();
+ this._dependencies = new utils.graph.Graph<string>(s => s);
+ this._dependenciesRecomputeList = [];
+ this._fileNameToDeclaredModule = Object.create(null);
+
+ this._projectVersion = 1;
+ }
+
+ log(_s: string): void {
+ // console.log(s);
+ }
+
+ trace(_s: string): void {
+ // console.log(s);
+ }
+
+ error(s: string): void {
+ console.error(s);
+ }
+
+ getCompilationSettings(): ts.CompilerOptions {
+ return this._cmdLine.options;
+ }
+
+ getProjectVersion(): string {
+ return String(this._projectVersion);
+ }
+
+ getScriptFileNames(): string[] {
+ const res = Object.keys(this._snapshots).filter(path => this._filesInProject.has(path) || this._filesAdded.has(path));
+ return res;
+ }
+
+ getScriptVersion(filename: string): string {
+ filename = normalize(filename);
+ const result = this._snapshots[filename];
+ if (result) {
+ return result.getVersion();
+ }
+ return 'UNKNWON_FILE_' + Math.random().toString(16).slice(2);
+ }
+
+ getScriptSnapshot(filename: string, resolve: boolean = true): ScriptSnapshot {
+ filename = normalize(filename);
+ let result = this._snapshots[filename];
+ if (!result && resolve) {
+ try {
+ result = new VinylScriptSnapshot(new Vinyl(<any>{
+ path: filename,
+ contents: readFileSync(filename),
+ base: this.getCompilationSettings().outDir,
+ stat: statSync(filename)
+ }));
+ this.addScriptSnapshot(filename, result);
+ } catch (e) {
+ // ignore
+ }
+ }
+ return result;
+ }
+
+ private static _declareModule = /declare\s+module\s+('|")(.+)\1/g;
+
+ addScriptSnapshot(filename: string, snapshot: ScriptSnapshot): ScriptSnapshot {
+ this._projectVersion++;
+ filename = normalize(filename);
+ const old = this._snapshots[filename];
+ if (!old && !this._filesInProject.has(filename) && !filename.endsWith('.d.ts')) {
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // not very proper!
+ this._filesAdded.add(filename);
+ }
+ if (!old || old.getVersion() !== snapshot.getVersion()) {
+ this._dependenciesRecomputeList.push(filename);
+ let node = this._dependencies.lookup(filename);
+ if (node) {
+ node.outgoing = Object.create(null);
+ }
+
+ // (cheap) check for declare module
+ LanguageServiceHost._declareModule.lastIndex = 0;
+ let match: RegExpExecArray | null | undefined;
+ while ((match = LanguageServiceHost._declareModule.exec(snapshot.getText(0, snapshot.getLength())))) {
+ let declaredModules = this._fileNameToDeclaredModule[filename];
+ if (!declaredModules) {
+ this._fileNameToDeclaredModule[filename] = declaredModules = [];
+ }
+ declaredModules.push(match[2]);
+ }
+ }
+ this._snapshots[filename] = snapshot;
+ return old;
+ }
+
+ removeScriptSnapshot(filename: string): boolean {
+ this._filesInProject.delete(filename);
+ this._filesAdded.delete(filename);
+ this._projectVersion++;
+ filename = normalize(filename);
+ delete this._fileNameToDeclaredModule[filename];
+ return delete this._snapshots[filename];
+ }
+
+ getCurrentDirectory(): string {
+ return path.dirname(this._projectPath);
+ }
+
+ getDefaultLibFileName(options: ts.CompilerOptions): string {
+ return ts.getDefaultLibFilePath(options);
+ }
+
+ readonly directoryExists = ts.sys.directoryExists;
+ readonly getDirectories = ts.sys.getDirectories;
+ readonly fileExists = ts.sys.fileExists;
+ readonly readFile = ts.sys.readFile;
+ readonly readDirectory = ts.sys.readDirectory;
+
+ // ---- dependency management
+
+ collectDependents(filename: string, target: string[]): void {
+ while (this._dependenciesRecomputeList.length) {
+ this._processFile(this._dependenciesRecomputeList.pop()!);
+ }
+ filename = normalize(filename);
+ const node = this._dependencies.lookup(filename);
+ if (node) {
+ utils.collections.forEach(node.incoming, entry => target.push(entry.key));
+ }
+ }
+
+ _processFile(filename: string): void {
+ if (filename.match(/.*\.d\.ts$/)) {
+ return;
+ }
+ filename = normalize(filename);
+ const snapshot = this.getScriptSnapshot(filename);
+ if (!snapshot) {
+ this._log('processFile', `Missing snapshot for: ${filename}`);
+ return;
+ }
+ const info = ts.preProcessFile(snapshot.getText(0, snapshot.getLength()), true);
+
+ // (1) ///-references
+ info.referencedFiles.forEach(ref => {
+ const resolvedPath = path.resolve(path.dirname(filename), ref.fileName);
+ const normalizedPath = normalize(resolvedPath);
+
+ this._dependencies.inertEdge(filename, normalizedPath);
+ });
+
+ // (2) import-require statements
+ info.importedFiles.forEach(ref => {
+ const stopDirname = normalize(this.getCurrentDirectory());
+ let dirname = filename;
+ let found = false;
+
+ while (!found && dirname.indexOf(stopDirname) === 0) {
+ dirname = path.dirname(dirname);
+ const resolvedPath = path.resolve(dirname, ref.fileName);
+ const normalizedPath = normalize(resolvedPath);
+
+ if (this.getScriptSnapshot(normalizedPath + '.ts')) {
+ this._dependencies.inertEdge(filename, normalizedPath + '.ts');
+ found = true;
+
+ } else if (this.getScriptSnapshot(normalizedPath + '.d.ts')) {
+ this._dependencies.inertEdge(filename, normalizedPath + '.d.ts');
+ found = true;
+ }
+ }
+
+ if (!found) {
+ for (let key in this._fileNameToDeclaredModule) {
+ if (this._fileNameToDeclaredModule[key] && ~this._fileNameToDeclaredModule[key].indexOf(ref.fileName)) {
+ this._dependencies.inertEdge(filename, key);
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/build/lib/tsb/index.js b/build/lib/tsb/index.js
new file mode 100644
index 00000000000..bd30013092c
--- /dev/null
+++ b/build/lib/tsb/index.js
@@ -0,0 +1,89 @@
+"use strict";
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.create = void 0;
+const Vinyl = require("vinyl");
+const through = require("through");
+const builder = require("./builder");
+const ts = require("typescript");
+const stream_1 = require("stream");
+const path_1 = require("path");
+const utils_1 = require("./utils");
+const fs_1 = require("fs");
+class EmptyDuplex extends stream_1.Duplex {
+ _write(_chunk, _encoding, callback) { callback(); }
+ _read() { this.push(null); }
+}
+function createNullCompiler() {
+ const result = function () { return new EmptyDuplex(); };
+ result.src = () => new EmptyDuplex();
+ return result;
+}
+const _defaultOnError = (err) => console.log(JSON.stringify(err, null, 4));
+function create(projectPath, existingOptions, verbose = false, onError = _defaultOnError) {
+ function printDiagnostic(diag) {
+ if (!diag.file || !diag.start) {
+ onError(ts.flattenDiagnosticMessageText(diag.messageText, '\n'));
+ }
+ else {
+ const lineAndCh = diag.file.getLineAndCharacterOfPosition(diag.start);
+ onError(utils_1.strings.format('{0}({1},{2}): {3}', diag.file.fileName, lineAndCh.line + 1, lineAndCh.character + 1, ts.flattenDiagnosticMessageText(diag.messageText, '\n')));
+ }
+ }
+ const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
+ if (parsed.error) {
+ printDiagnostic(parsed.error);
+ return createNullCompiler();
+ }
+ const cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, (0, path_1.dirname)(projectPath), existingOptions);
+ if (cmdLine.errors.length > 0) {
+ cmdLine.errors.forEach(printDiagnostic);
+ return createNullCompiler();
+ }
+ const _builder = builder.createTypeScriptBuilder({ verbose }, projectPath, cmdLine);
+ function createStream(token) {
+ return through(function (file) {
+ // give the file to the compiler
+ if (file.isStream()) {
+ this.emit('error', 'no support for streams');
+ return;
+ }
+ _builder.file(file);
+ }, function () {
+ // start the compilation process
+ _builder.build(file => this.queue(file), printDiagnostic, token).catch(e => console.error(e)).then(() => this.queue(null));
+ });
+ }
+ const result = (token) => createStream(token);
+ result.src = (opts) => {
+ let _pos = 0;
+ let _fileNames = cmdLine.fileNames.slice(0);
+ return new class extends stream_1.Readable {
+ constructor() {
+ super({ objectMode: true });
+ }
+ _read() {
+ let more = true;
+ let path;
+ for (; more && _pos < _fileNames.length; _pos++) {
+ path = _fileNames[_pos];
+ more = this.push(new Vinyl({
+ path,
+ contents: (0, fs_1.readFileSync)(path),
+ stat: (0, fs_1.statSync)(path),
+ cwd: opts && opts.cwd,
+ base: opts && opts.base || (0, path_1.dirname)(projectPath)
+ }));
+ }
+ if (_pos >= _fileNames.length) {
+ this.push(null);
+ }
+ }
+ };
+ };
+ return result;
+}
+exports.create = create;
diff --git a/build/lib/tsb/index.ts b/build/lib/tsb/index.ts
new file mode 100644
index 00000000000..6e8e3d6fb77
--- /dev/null
+++ b/build/lib/tsb/index.ts
@@ -0,0 +1,118 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import * as Vinyl from 'vinyl';
+import * as through from 'through';
+import * as builder from './builder';
+import * as ts from 'typescript';
+import { Readable, Writable, Duplex } from 'stream';
+import { dirname } from 'path';
+import { strings } from './utils';
+import { readFileSync, statSync } from 'fs';
+
+export interface IncrementalCompiler {
+ (token?: any): Readable & Writable;
+ src(opts?: { cwd?: string; base?: string }): Readable;
+}
+
+class EmptyDuplex extends Duplex {
+ _write(_chunk: any, _encoding: string, callback: (err?: Error) => void): void { callback(); }
+ _read() { this.push(null); }
+}
+
+function createNullCompiler(): IncrementalCompiler {
+ const result: IncrementalCompiler = function () { return new EmptyDuplex(); };
+ result.src = () => new EmptyDuplex();
+ return result;
+}
+
+const _defaultOnError = (err: string) => console.log(JSON.stringify(err, null, 4));
+
+export function create(
+ projectPath: string,
+ existingOptions: Partial<ts.CompilerOptions>,
+ verbose: boolean = false,
+ onError: (message: string) => void = _defaultOnError
+): IncrementalCompiler {
+
+ function printDiagnostic(diag: ts.Diagnostic): void {
+
+ if (!diag.file || !diag.start) {
+ onError(ts.flattenDiagnosticMessageText(diag.messageText, '\n'));
+ } else {
+ const lineAndCh = diag.file.getLineAndCharacterOfPosition(diag.start);
+ onError(strings.format('{0}({1},{2}): {3}',
+ diag.file.fileName,
+ lineAndCh.line + 1,
+ lineAndCh.character + 1,
+ ts.flattenDiagnosticMessageText(diag.messageText, '\n'))
+ );
+ }
+ }
+
+ const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
+ if (parsed.error) {
+ printDiagnostic(parsed.error);
+ return createNullCompiler();
+ }
+
+ const cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, dirname(projectPath), existingOptions);
+ if (cmdLine.errors.length > 0) {
+ cmdLine.errors.forEach(printDiagnostic);
+ return createNullCompiler();
+ }
+
+ const _builder = builder.createTypeScriptBuilder({ verbose }, projectPath, cmdLine);
+
+ function createStream(token?: builder.CancellationToken): Readable & Writable {
+
+ return through(function (this: through.ThroughStream, file: Vinyl) {
+ // give the file to the compiler
+ if (file.isStream()) {
+ this.emit('error', 'no support for streams');
+ return;
+ }
+ _builder.file(file);
+
+ }, function (this: { queue(a: any): void }) {
+ // start the compilation process
+ _builder.build(
+ file => this.queue(file),
+ printDiagnostic,
+ token
+ ).catch(e => console.error(e)).then(() => this.queue(null));
+ });
+ }
+
+ const result = (token: builder.CancellationToken) => createStream(token);
+ result.src = (opts?: { cwd?: string; base?: string }) => {
+ let _pos = 0;
+ let _fileNames = cmdLine.fileNames.slice(0);
+ return new class extends Readable {
+ constructor() {
+ super({ objectMode: true });
+ }
+ _read() {
+ let more: boolean = true;
+ let path: string;
+ for (; more && _pos < _fileNames.length; _pos++) {
+ path = _fileNames[_pos];
+ more = this.push(new Vinyl({
+ path,
+ contents: readFileSync(path),
+ stat: statSync(path),
+ cwd: opts && opts.cwd,
+ base: opts && opts.base || dirname(projectPath)
+ }));
+ }
+ if (_pos >= _fileNames.length) {
+ this.push(null);
+ }
+ }
+ };
+ };
+
+ return <IncrementalCompiler>result;
+}
diff --git a/build/lib/tsb/utils.js b/build/lib/tsb/utils.js
new file mode 100644
index 00000000000..810297dc246
--- /dev/null
+++ b/build/lib/tsb/utils.js
@@ -0,0 +1,124 @@
+"use strict";
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.graph = exports.strings = exports.collections = void 0;
+var collections;
+(function (collections) {
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
+ function lookup(collection, key) {
+ if (hasOwnProperty.call(collection, key)) {
+ return collection[key];
+ }
+ return null;
+ }
+ collections.lookup = lookup;
+ function insert(collection, key, value) {
+ collection[key] = value;
+ }
+ collections.insert = insert;
+ function lookupOrInsert(collection, key, value) {
+ if (hasOwnProperty.call(collection, key)) {
+ return collection[key];
+ }
+ else {
+ collection[key] = value;
+ return value;
+ }
+ }
+ collections.lookupOrInsert = lookupOrInsert;
+ function forEach(collection, callback) {
+ for (let key in collection) {
+ if (hasOwnProperty.call(collection, key)) {
+ callback({
+ key: key,
+ value: collection[key]
+ });
+ }
+ }
+ }
+ collections.forEach = forEach;
+ function contains(collection, key) {
+ return hasOwnProperty.call(collection, key);
+ }
+ collections.contains = contains;
+})(collections = exports.collections || (exports.collections = {}));
+var strings;
+(function (strings) {
+ /**
+ * The empty string. The one and only.
+ */
+ strings.empty = '';
+ strings.eolUnix = '\r\n';
+ function format(value, ...rest) {
+ return value.replace(/({\d+})/g, function (match) {
+ const index = Number(match.substring(1, match.length - 1));
+ return String(rest[index]) || match;
+ });
+ }
+ strings.format = format;
+})(strings = exports.strings || (exports.strings = {}));
+var graph;
+(function (graph) {
+ function newNode(data) {
+ return {
+ data: data,
+ incoming: {},
+ outgoing: {}
+ };
+ }
+ graph.newNode = newNode;
+ class Graph {
+ constructor(_hashFn) {
+ this._hashFn = _hashFn;
+ this._nodes = {};
+ // empty
+ }
+ traverse(start, inwards, callback) {
+ const startNode = this.lookup(start);
+ if (!startNode) {
+ return;
+ }
+ this._traverse(startNode, inwards, {}, callback);
+ }
+ _traverse(node, inwards, seen, callback) {
+ const key = this._hashFn(node.data);
+ if (collections.contains(seen, key)) {
+ return;
+ }
+ seen[key] = true;
+ callback(node.data);
+ const nodes = inwards ? node.outgoing : node.incoming;
+ collections.forEach(nodes, (entry) => this._traverse(entry.value, inwards, seen, callback));
+ }
+ inertEdge(from, to) {
+ const fromNode = this.lookupOrInsertNode(from);
+ const toNode = this.lookupOrInsertNode(to);
+ fromNode.outgoing[this._hashFn(to)] = toNode;
+ toNode.incoming[this._hashFn(from)] = fromNode;
+ }
+ removeNode(data) {
+ const key = this._hashFn(data);
+ delete this._nodes[key];
+ collections.forEach(this._nodes, (entry) => {
+ delete entry.value.outgoing[key];
+ delete entry.value.incoming[key];
+ });
+ }
+ lookupOrInsertNode(data) {
+ const key = this._hashFn(data);
+ let node = collections.lookup(this._nodes, key);
+ if (!node) {
+ node = newNode(data);
+ this._nodes[key] = node;
+ }
+ return node;
+ }
+ lookup(data) {
+ return collections.lookup(this._nodes, this._hashFn(data));
+ }
+ }
+ graph.Graph = Graph;
+})(graph = exports.graph || (exports.graph = {}));
diff --git a/build/lib/tsb/utils.ts b/build/lib/tsb/utils.ts
new file mode 100644
index 00000000000..295d873b63a
--- /dev/null
+++ b/build/lib/tsb/utils.ts
@@ -0,0 +1,140 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+export module collections {
+
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
+
+ export function lookup<T>(collection: { [keys: string]: T }, key: string): T | null {
+ if (hasOwnProperty.call(collection, key)) {
+ return collection[key];
+ }
+ return null;
+ }
+
+ export function insert<T>(collection: { [keys: string]: T }, key: string, value: T): void {
+ collection[key] = value;
+ }
+
+ export function lookupOrInsert<T>(collection: { [keys: string]: T }, key: string, value: T): T {
+ if (hasOwnProperty.call(collection, key)) {
+ return collection[key];
+ } else {
+ collection[key] = value;
+ return value;
+ }
+ }
+
+ export function forEach<T>(collection: { [keys: string]: T }, callback: (entry: { key: string; value: T }) => void): void {
+ for (let key in collection) {
+ if (hasOwnProperty.call(collection, key)) {
+ callback({
+ key: key,
+ value: collection[key]
+ });
+ }
+ }
+ }
+
+ export function contains(collection: { [keys: string]: any }, key: string): boolean {
+ return hasOwnProperty.call(collection, key);
+ }
+}
+
+export module strings {
+
+ /**
+ * The empty string. The one and only.
+ */
+ export const empty = '';
+
+ export const eolUnix = '\r\n';
+
+ export function format(value: string, ...rest: any[]): string {
+ return value.replace(/({\d+})/g, function (match) {
+ const index = Number(match.substring(1, match.length - 1));
+ return String(rest[index]) || match;
+ });
+ }
+}
+
+export module graph {
+
+ export interface Node<T> {
+ data: T;
+ incoming: { [key: string]: Node<T> };
+ outgoing: { [key: string]: Node<T> };
+ }
+
+ export function newNode<T>(data: T): Node<T> {
+ return {
+ data: data,
+ incoming: {},
+ outgoing: {}
+ };
+ }
+
+ export class Graph<T> {
+
+ private _nodes: { [key: string]: Node<T> } = {};
+
+ constructor(private _hashFn: (element: T) => string) {
+ // empty
+ }
+
+ traverse(start: T, inwards: boolean, callback: (data: T) => void): void {
+ const startNode = this.lookup(start);
+ if (!startNode) {
+ return;
+ }
+ this._traverse(startNode, inwards, {}, callback);
+ }
+
+ private _traverse(node: Node<T>, inwards: boolean, seen: { [key: string]: boolean }, callback: (data: T) => void): void {
+ const key = this._hashFn(node.data);
+ if (collections.contains(seen, key)) {
+ return;
+ }
+ seen[key] = true;
+ callback(node.data);
+ const nodes = inwards ? node.outgoing : node.incoming;
+ collections.forEach(nodes, (entry) => this._traverse(entry.value, inwards, seen, callback));
+ }
+
+ inertEdge(from: T, to: T): void {
+ const fromNode = this.lookupOrInsertNode(from);
+ const toNode = this.lookupOrInsertNode(to);
+
+ fromNode.outgoing[this._hashFn(to)] = toNode;
+ toNode.incoming[this._hashFn(from)] = fromNode;
+ }
+
+ removeNode(data: T): void {
+ const key = this._hashFn(data);
+ delete this._nodes[key];
+ collections.forEach(this._nodes, (entry) => {
+ delete entry.value.outgoing[key];
+ delete entry.value.incoming[key];
+ });
+ }
+
+ lookupOrInsertNode(data: T): Node<T> {
+ const key = this._hashFn(data);
+ let node = collections.lookup(this._nodes, key);
+
+ if (!node) {
+ node = newNode(data);
+ this._nodes[key] = node;
+ }
+
+ return node;
+ }
+
+ lookup(data: T): Node<T> | null {
+ return collections.lookup(this._nodes, this._hashFn(data));
+ }
+ }
+
+}
diff --git a/build/lib/typings/gulp-tsb.d.ts b/build/lib/typings/gulp-tsb.d.ts
deleted file mode 100644
index df9bb34d3fb..00000000000
--- a/build/lib/typings/gulp-tsb.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-declare module "gulp-tsb" {
-
- export interface ICancellationToken {
- isCancellationRequested(): boolean;
- }
-
- export interface IncrementalCompiler {
- (token?: ICancellationToken): NodeJS.ReadWriteStream;
- src(opts?: {
- cwd?: string;
- base?: string;
- }): NodeJS.ReadStream;
- }
- export function create(projectPath: string, existingOptions: any, verbose?: boolean, onError?: (message: any) => void): IncrementalCompiler;
-
-}
diff --git a/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js
index aa4f58de32d..64e2188f62e 100644
--- a/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js
+++ b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js
@@ -4,20 +4,20 @@
*--------------------------------------------------------------------------------------------*/
var gulp = require('gulp');
-var tsb = require('gulp-tsb');
+var tsb = require('../../../../build/lib/tsb');
var util = require('./lib/util');
var watcher = require('./lib/watch');
var assign = require('object-assign');
var compilation = tsb.create(assign({ verbose: true }, require('./tsconfig.json').compilerOptions));
-gulp.task('compile', function() {
+gulp.task('compile', function () {
return gulp.src('**/*.ts', { base: '.' })
.pipe(compilation())
.pipe(gulp.dest(''));
});
-gulp.task('watch', function() {
+gulp.task('watch', function () {
var src = gulp.src('**/*.ts', { base: '.' });
return watcher('**/*.ts', { base: '.' })
@@ -28,10 +28,10 @@ gulp.task('watch', function() {
gulp.task('default', ['compile']);
function cloneArray(arr) {
- _.foo();
- var r = [];
- for (var i = 0, len = arr.length; i < len; i++) {
- r[i] = doClone(arr[i]);
- }
- return r;
-} \ No newline at end of file
+ _.foo();
+ var r = [];
+ for (var i = 0, len = arr.length; i < len; i++) {
+ r[i] = doClone(arr[i]);
+ }
+ return r;
+}
diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_js.json b/extensions/vscode-colorize-tests/test/colorize-results/test_js.json
index 7cbcf150705..8ef32f838b9 100644
--- a/extensions/vscode-colorize-tests/test/colorize-results/test_js.json
+++ b/extensions/vscode-colorize-tests/test/colorize-results/test_js.json
@@ -336,7 +336,7 @@
}
},
{
- "c": "gulp-tsb",
+ "c": "../../../../build/lib/tsb",
"t": "source.js meta.var.expr.js string.quoted.single.js",
"r": {
"dark_plus": "string: #CE9178",
@@ -1356,6 +1356,18 @@
}
},
{
+ "c": " ",
+ "t": "source.js meta.function.expression.js",
+ "r": {
+ "dark_plus": "default: #D4D4D4",
+ "light_plus": "default: #000000",
+ "dark_vs": "default: #D4D4D4",
+ "light_vs": "default: #000000",
+ "hc_black": "default: #FFFFFF",
+ "hc_light": "default: #292929"
+ }
+ },
+ {
"c": "(",
"t": "source.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js",
"r": {
@@ -2052,6 +2064,18 @@
}
},
{
+ "c": " ",
+ "t": "source.js meta.function.expression.js",
+ "r": {
+ "dark_plus": "default: #D4D4D4",
+ "light_plus": "default: #000000",
+ "dark_vs": "default: #D4D4D4",
+ "light_vs": "default: #000000",
+ "hc_black": "default: #FFFFFF",
+ "hc_light": "default: #292929"
+ }
+ },
+ {
"c": "(",
"t": "source.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js",
"r": {
@@ -3312,7 +3336,7 @@
}
},
{
- "c": " ",
+ "c": "\t",
"t": "source.js meta.function.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
@@ -3384,7 +3408,7 @@
}
},
{
- "c": " ",
+ "c": "\t",
"t": "source.js meta.function.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
@@ -3492,7 +3516,7 @@
}
},
{
- "c": " ",
+ "c": "\t",
"t": "source.js meta.function.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
@@ -3900,7 +3924,7 @@
}
},
{
- "c": " ",
+ "c": "\t\t",
"t": "source.js meta.function.js meta.block.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
@@ -4092,7 +4116,7 @@
}
},
{
- "c": " ",
+ "c": "\t",
"t": "source.js meta.function.js meta.block.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
@@ -4116,7 +4140,7 @@
}
},
{
- "c": " ",
+ "c": "\t",
"t": "source.js meta.function.js meta.block.js",
"r": {
"dark_plus": "default: #D4D4D4",
diff --git a/package.json b/package.json
index 142fa369feb..b0de0019cf3 100644
--- a/package.json
+++ b/package.json
@@ -163,7 +163,6 @@
"gulp-replace": "^0.5.4",
"gulp-sourcemaps": "^3.0.0",
"gulp-svgmin": "^4.1.0",
- "gulp-tsb": "4.0.6",
"gulp-untar": "^0.0.7",
"gulp-vinyl-zip": "^2.1.2",
"husky": "^0.13.1",
diff --git a/yarn.lock b/yarn.lock
index 3448bd585d3..ec53256d136 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5983,16 +5983,6 @@ gulp-symdest@^1.2.0:
queue "^3.1.0"
vinyl-fs "^3.0.3"
-gulp-tsb@4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.6.tgz#526f07a2c74e1d2f8932b1500316f2a64b33363c"
- integrity sha512-55HSu1zvOOq7D+OqPScvGQaJPKveLbM1T5jEnSJUhbcbwX1Kx0SWv4UVe7MfFcBwFe3wMiWSkKoajNONEv5E9g==
- dependencies:
- ansi-colors "^1.0.1"
- fancy-log "^1.3.2"
- through "^2.3.6"
- vinyl "^2.1.0"
-
gulp-untar@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.7.tgz#92067d79e0fa1e92d60562a100233a44a5aa08b4"