Merge
This commit is contained in:
Коммит
43b8ce664c
|
@ -16,4 +16,5 @@ Jakefile.js
|
|||
.gitattributes
|
||||
.settings/
|
||||
.travis.yml
|
||||
.vscode/
|
||||
.vscode/
|
||||
test.config
|
|
@ -16,6 +16,7 @@ matrix:
|
|||
branches:
|
||||
only:
|
||||
- master
|
||||
- release-2.5
|
||||
|
||||
install:
|
||||
- npm uninstall typescript --no-save
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "tests",
|
||||
"showOutput": "silent",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
96
Gulpfile.ts
96
Gulpfile.ts
|
@ -28,7 +28,6 @@ import minimist = require("minimist");
|
|||
import browserify = require("browserify");
|
||||
import through2 = require("through2");
|
||||
import merge2 = require("merge2");
|
||||
import intoStream = require("into-stream");
|
||||
import * as os from "os";
|
||||
import fold = require("travis-fold");
|
||||
const gulp = helpMaker(originalGulp);
|
||||
|
@ -747,50 +746,75 @@ gulp.task(nodeServerOutFile, /*help*/ false, [servicesFile], () => {
|
|||
|
||||
import convertMap = require("convert-source-map");
|
||||
import sorcery = require("sorcery");
|
||||
declare module "convert-source-map" {
|
||||
export function fromSource(source: string, largeSource?: boolean): SourceMapConverter;
|
||||
}
|
||||
import Vinyl = require("vinyl");
|
||||
|
||||
gulp.task("browserify", "Runs browserify on run.js to produce a file suitable for running tests in the browser", [servicesFile, run], (done) => {
|
||||
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: "../../built/local/bundle.js" }, /*useBuiltCompiler*/ true));
|
||||
return testProject.src()
|
||||
.pipe(newer("built/local/bundle.js"))
|
||||
const bundlePath = path.resolve("built/local/bundle.js");
|
||||
|
||||
gulp.task("browserify", "Runs browserify on run.js to produce a file suitable for running tests in the browser", [servicesFile], (done) => {
|
||||
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: bundlePath, inlineSourceMap: true }, /*useBuiltCompiler*/ true));
|
||||
let originalMap: any;
|
||||
let prebundledContent: string;
|
||||
browserify(testProject.src()
|
||||
.pipe(newer(bundlePath))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(testProject())
|
||||
.pipe(through2.obj((file, enc, next) => {
|
||||
const originalMap = file.sourceMap;
|
||||
const prebundledContent = file.contents.toString();
|
||||
if (originalMap) {
|
||||
throw new Error("Should only recieve one file!");
|
||||
}
|
||||
console.log(`Saving sourcemaps for ${file.path}`);
|
||||
originalMap = file.sourceMap;
|
||||
prebundledContent = file.contents.toString();
|
||||
// Make paths absolute to help sorcery deal with all the terrible paths being thrown around
|
||||
originalMap.sources = originalMap.sources.map(s => path.resolve(path.join("src/harness", s)));
|
||||
// intoStream (below) makes browserify think the input file is named this, so this is what it puts in the sourcemap
|
||||
// browserify names input files this when they are streamed in, so this is what it puts in the sourcemap
|
||||
originalMap.file = "built/local/_stream_0.js";
|
||||
|
||||
browserify(intoStream(file.contents), { debug: true })
|
||||
.bundle((err, res) => {
|
||||
// assumes file.contents is a Buffer
|
||||
const maps = JSON.parse(convertMap.fromSource(res.toString(), /*largeSource*/ true).toJSON());
|
||||
delete maps.sourceRoot;
|
||||
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
|
||||
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
|
||||
file.contents = new Buffer(convertMap.removeComments(res.toString()));
|
||||
const chain = sorcery.loadSync("built/local/bundle.js", {
|
||||
content: {
|
||||
"built/local/_stream_0.js": prebundledContent,
|
||||
"built/local/bundle.js": file.contents.toString()
|
||||
},
|
||||
sourcemaps: {
|
||||
"built/local/_stream_0.js": originalMap,
|
||||
"built/local/bundle.js": maps,
|
||||
"node_modules/source-map-support/source-map-support.js": undefined,
|
||||
}
|
||||
});
|
||||
const finalMap = chain.apply();
|
||||
file.sourceMap = finalMap;
|
||||
next(/*err*/ undefined, file);
|
||||
});
|
||||
next(/*err*/ undefined, file.contents);
|
||||
}))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false }))
|
||||
.pipe(gulp.dest("src/harness"));
|
||||
.on("error", err => {
|
||||
return done(err);
|
||||
}), { debug: true, basedir: __dirname }) // Attach error handler to inner stream
|
||||
.bundle((err, contents) => {
|
||||
if (err) {
|
||||
if (err.message.match(/Cannot find module '.*_stream_0.js'/)) {
|
||||
return done(); // Browserify errors when we pass in no files when `newer` filters the input, we should count that as a success, though
|
||||
}
|
||||
return done(err);
|
||||
}
|
||||
const stringContent = contents.toString();
|
||||
const file = new Vinyl({ contents, path: bundlePath });
|
||||
console.log(`Fixing sourcemaps for ${file.path}`);
|
||||
// assumes contents is a Buffer, since that's what browserify yields
|
||||
const maps = convertMap.fromSource(stringContent, /*largeSource*/ true).toObject();
|
||||
delete maps.sourceRoot;
|
||||
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
|
||||
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
|
||||
file.contents = new Buffer(convertMap.removeComments(stringContent));
|
||||
const chain = sorcery.loadSync(bundlePath, {
|
||||
content: {
|
||||
"built/local/_stream_0.js": prebundledContent,
|
||||
[bundlePath]: stringContent
|
||||
},
|
||||
sourcemaps: {
|
||||
"built/local/_stream_0.js": originalMap,
|
||||
[bundlePath]: maps,
|
||||
"node_modules/source-map-support/source-map-support.js": undefined,
|
||||
}
|
||||
});
|
||||
const finalMap = chain.apply();
|
||||
file.sourceMap = finalMap;
|
||||
|
||||
const stream = through2.obj((file, enc, callback) => {
|
||||
return callback(/*err*/ undefined, file);
|
||||
});
|
||||
stream.pipe(sourcemaps.write(".", { includeContent: false }))
|
||||
.pipe(gulp.dest("."))
|
||||
.on("end", done)
|
||||
.on("error", done);
|
||||
stream.write(file);
|
||||
stream.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
38
Jakefile.js
38
Jakefile.js
|
@ -135,6 +135,7 @@ var harnessSources = harnessCoreSources.concat([
|
|||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"extractMethods.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"telemetry.ts",
|
||||
|
@ -536,7 +537,6 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
|
|||
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
|
||||
|
||||
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
|
||||
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
|
||||
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
|
||||
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
|
||||
|
@ -575,22 +575,6 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
|
|||
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
|
||||
});
|
||||
|
||||
compileFile(
|
||||
servicesFileInBrowserTest,
|
||||
servicesSources,
|
||||
[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/[copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{
|
||||
noOutFile: false,
|
||||
generateDeclarations: true,
|
||||
preserveConstEnums: true,
|
||||
keepComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: true,
|
||||
inlineSourceMap: true
|
||||
});
|
||||
|
||||
file(typescriptServicesDts, [servicesFile]);
|
||||
|
||||
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
|
||||
|
@ -737,7 +721,7 @@ compileFile(
|
|||
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prefixes*/[],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
/*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
|
||||
var internalTests = "internal/";
|
||||
|
||||
|
@ -973,13 +957,14 @@ var nodeServerInFile = "tests/webTestServer.ts";
|
|||
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" });
|
||||
|
||||
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
|
||||
task("browserify", ["tests", run, builtLocalDirectory, nodeServerOutFile], function() {
|
||||
var cmd = 'browserify built/local/run.js -t ./scripts/browserify-optional -d -o built/local/bundle.js';
|
||||
task("browserify", [], function() {
|
||||
// Shell out to `gulp`, since we do the work to handle sourcemaps correctly w/o inline maps there
|
||||
var cmd = 'gulp browserify --silent';
|
||||
exec(cmd);
|
||||
}, { async: true });
|
||||
|
||||
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]");
|
||||
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function () {
|
||||
task("runtests-browser", ["browserify", nodeServerOutFile], function () {
|
||||
cleanTestDirs();
|
||||
host = "node";
|
||||
browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
|
||||
|
@ -1134,14 +1119,15 @@ task("update-sublime", ["local", serverFile], function () {
|
|||
|
||||
var tslintRuleDir = "scripts/tslint";
|
||||
var tslintRules = [
|
||||
"nextLineRule",
|
||||
"booleanTriviaRule",
|
||||
"typeOperatorSpacingRule",
|
||||
"noInOperatorRule",
|
||||
"debugAssertRule",
|
||||
"nextLineRule",
|
||||
"noBomRule",
|
||||
"noIncrementDecrementRule",
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
"noInOperatorRule",
|
||||
"noTypeAssertionWhitespaceRule",
|
||||
"noBomRule"
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
"typeOperatorSpacingRule",
|
||||
];
|
||||
var tslintRulesFiles = tslintRules.map(function (p) {
|
||||
return path.join(tslintRuleDir, p + ".ts");
|
||||
|
|
|
@ -69,5 +69,3 @@ function createCancellationToken(args) {
|
|||
}
|
||||
}
|
||||
module.exports = createCancellationToken;
|
||||
|
||||
//# sourceMappingURL=cancellationToken.js.map
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -21,8 +21,8 @@ and limitations under the License.
|
|||
/// <reference path="lib.es2015.core.d.ts" />
|
||||
/// <reference path="lib.es2015.collection.d.ts" />
|
||||
/// <reference path="lib.es2015.generator.d.ts" />
|
||||
/// <reference path="lib.es2015.iterable.d.ts" />
|
||||
/// <reference path="lib.es2015.promise.d.ts" />
|
||||
/// <reference path="lib.es2015.iterable.d.ts" />
|
||||
/// <reference path="lib.es2015.proxy.d.ts" />
|
||||
/// <reference path="lib.es2015.reflect.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -22,4 +22,4 @@ and limitations under the License.
|
|||
/// <reference path="lib.es2017.object.d.ts" />
|
||||
/// <reference path="lib.es2017.sharedmemory.d.ts" />
|
||||
/// <reference path="lib.es2017.string.d.ts" />
|
||||
/// <reference path="lib.es2017.intl.d.ts" />
|
||||
/// <reference path="lib.es2017.intl.d.ts" />
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,30 @@
|
|||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
|
||||
type DateTimeFormatPartTypes = "day" | "dayPeriod" | "era" | "hour" | "literal" | "minute" | "month" | "second" | "timeZoneName" | "weekday" | "year";
|
||||
|
||||
interface DateTimeFormatPart {
|
||||
type: DateTimeFormatPartTypes;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface DateTimeFormat {
|
||||
formatToParts(date?: Date | number): DateTimeFormatPart[];
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -20,7 +20,7 @@ and limitations under the License.
|
|||
|
||||
|
||||
/////////////////////////////
|
||||
/// IE Worker APIs
|
||||
/// Worker APIs
|
||||
/////////////////////////////
|
||||
|
||||
interface Algorithm {
|
||||
|
@ -28,16 +28,16 @@ interface Algorithm {
|
|||
}
|
||||
|
||||
interface CacheQueryOptions {
|
||||
ignoreSearch?: boolean;
|
||||
ignoreMethod?: boolean;
|
||||
ignoreVary?: boolean;
|
||||
cacheName?: string;
|
||||
ignoreMethod?: boolean;
|
||||
ignoreSearch?: boolean;
|
||||
ignoreVary?: boolean;
|
||||
}
|
||||
|
||||
interface CloseEventInit extends EventInit {
|
||||
wasClean?: boolean;
|
||||
code?: number;
|
||||
reason?: string;
|
||||
wasClean?: boolean;
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
|
@ -69,16 +69,16 @@ interface MessageEventInit extends EventInit {
|
|||
channel?: string;
|
||||
data?: any;
|
||||
origin?: string;
|
||||
source?: any;
|
||||
ports?: MessagePort[];
|
||||
source?: any;
|
||||
}
|
||||
|
||||
interface NotificationOptions {
|
||||
dir?: NotificationDirection;
|
||||
lang?: string;
|
||||
body?: string;
|
||||
tag?: string;
|
||||
dir?: NotificationDirection;
|
||||
icon?: string;
|
||||
lang?: string;
|
||||
tag?: string;
|
||||
}
|
||||
|
||||
interface ObjectURLOptions {
|
||||
|
@ -86,29 +86,29 @@ interface ObjectURLOptions {
|
|||
}
|
||||
|
||||
interface PushSubscriptionOptionsInit {
|
||||
userVisibleOnly?: boolean;
|
||||
applicationServerKey?: any;
|
||||
userVisibleOnly?: boolean;
|
||||
}
|
||||
|
||||
interface RequestInit {
|
||||
method?: string;
|
||||
headers?: any;
|
||||
body?: any;
|
||||
referrer?: string;
|
||||
referrerPolicy?: ReferrerPolicy;
|
||||
mode?: RequestMode;
|
||||
credentials?: RequestCredentials;
|
||||
cache?: RequestCache;
|
||||
redirect?: RequestRedirect;
|
||||
credentials?: RequestCredentials;
|
||||
headers?: any;
|
||||
integrity?: string;
|
||||
keepalive?: boolean;
|
||||
method?: string;
|
||||
mode?: RequestMode;
|
||||
redirect?: RequestRedirect;
|
||||
referrer?: string;
|
||||
referrerPolicy?: ReferrerPolicy;
|
||||
window?: any;
|
||||
}
|
||||
|
||||
interface ResponseInit {
|
||||
headers?: any;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
headers?: any;
|
||||
}
|
||||
|
||||
interface ClientQueryOptions {
|
||||
|
@ -176,7 +176,7 @@ interface AudioBuffer {
|
|||
declare var AudioBuffer: {
|
||||
prototype: AudioBuffer;
|
||||
new(): AudioBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
interface Blob {
|
||||
readonly size: number;
|
||||
|
@ -189,7 +189,7 @@ interface Blob {
|
|||
declare var Blob: {
|
||||
prototype: Blob;
|
||||
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
|
||||
}
|
||||
};
|
||||
|
||||
interface Cache {
|
||||
add(request: RequestInfo): Promise<void>;
|
||||
|
@ -204,7 +204,7 @@ interface Cache {
|
|||
declare var Cache: {
|
||||
prototype: Cache;
|
||||
new(): Cache;
|
||||
}
|
||||
};
|
||||
|
||||
interface CacheStorage {
|
||||
delete(cacheName: string): Promise<boolean>;
|
||||
|
@ -217,7 +217,7 @@ interface CacheStorage {
|
|||
declare var CacheStorage: {
|
||||
prototype: CacheStorage;
|
||||
new(): CacheStorage;
|
||||
}
|
||||
};
|
||||
|
||||
interface CloseEvent extends Event {
|
||||
readonly code: number;
|
||||
|
@ -229,7 +229,7 @@ interface CloseEvent extends Event {
|
|||
declare var CloseEvent: {
|
||||
prototype: CloseEvent;
|
||||
new(typeArg: string, eventInitDict?: CloseEventInit): CloseEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface Console {
|
||||
assert(test?: boolean, message?: string, ...optionalParams: any[]): void;
|
||||
|
@ -240,8 +240,8 @@ interface Console {
|
|||
dirxml(value: any): void;
|
||||
error(message?: any, ...optionalParams: any[]): void;
|
||||
exception(message?: string, ...optionalParams: any[]): void;
|
||||
group(groupTitle?: string): void;
|
||||
groupCollapsed(groupTitle?: string): void;
|
||||
group(groupTitle?: string, ...optionalParams: any[]): void;
|
||||
groupCollapsed(groupTitle?: string, ...optionalParams: any[]): void;
|
||||
groupEnd(): void;
|
||||
info(message?: any, ...optionalParams: any[]): void;
|
||||
log(message?: any, ...optionalParams: any[]): void;
|
||||
|
@ -259,7 +259,7 @@ interface Console {
|
|||
declare var Console: {
|
||||
prototype: Console;
|
||||
new(): Console;
|
||||
}
|
||||
};
|
||||
|
||||
interface Coordinates {
|
||||
readonly accuracy: number;
|
||||
|
@ -274,7 +274,7 @@ interface Coordinates {
|
|||
declare var Coordinates: {
|
||||
prototype: Coordinates;
|
||||
new(): Coordinates;
|
||||
}
|
||||
};
|
||||
|
||||
interface CryptoKey {
|
||||
readonly algorithm: KeyAlgorithm;
|
||||
|
@ -286,7 +286,7 @@ interface CryptoKey {
|
|||
declare var CryptoKey: {
|
||||
prototype: CryptoKey;
|
||||
new(): CryptoKey;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMError {
|
||||
readonly name: string;
|
||||
|
@ -296,7 +296,7 @@ interface DOMError {
|
|||
declare var DOMError: {
|
||||
prototype: DOMError;
|
||||
new(): DOMError;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMException {
|
||||
readonly code: number;
|
||||
|
@ -316,10 +316,10 @@ interface DOMException {
|
|||
readonly INVALID_STATE_ERR: number;
|
||||
readonly NAMESPACE_ERR: number;
|
||||
readonly NETWORK_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly NO_DATA_ALLOWED_ERR: number;
|
||||
readonly NO_MODIFICATION_ALLOWED_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly PARSE_ERR: number;
|
||||
readonly QUOTA_EXCEEDED_ERR: number;
|
||||
readonly SECURITY_ERR: number;
|
||||
|
@ -348,10 +348,10 @@ declare var DOMException: {
|
|||
readonly INVALID_STATE_ERR: number;
|
||||
readonly NAMESPACE_ERR: number;
|
||||
readonly NETWORK_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly NO_DATA_ALLOWED_ERR: number;
|
||||
readonly NO_MODIFICATION_ALLOWED_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly PARSE_ERR: number;
|
||||
readonly QUOTA_EXCEEDED_ERR: number;
|
||||
readonly SECURITY_ERR: number;
|
||||
|
@ -362,7 +362,7 @@ declare var DOMException: {
|
|||
readonly URL_MISMATCH_ERR: number;
|
||||
readonly VALIDATION_ERR: number;
|
||||
readonly WRONG_DOCUMENT_ERR: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMStringList {
|
||||
readonly length: number;
|
||||
|
@ -374,7 +374,7 @@ interface DOMStringList {
|
|||
declare var DOMStringList: {
|
||||
prototype: DOMStringList;
|
||||
new(): DOMStringList;
|
||||
}
|
||||
};
|
||||
|
||||
interface ErrorEvent extends Event {
|
||||
readonly colno: number;
|
||||
|
@ -388,12 +388,12 @@ interface ErrorEvent extends Event {
|
|||
declare var ErrorEvent: {
|
||||
prototype: ErrorEvent;
|
||||
new(type: string, errorEventInitDict?: ErrorEventInit): ErrorEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface Event {
|
||||
readonly bubbles: boolean;
|
||||
cancelBubble: boolean;
|
||||
readonly cancelable: boolean;
|
||||
cancelBubble: boolean;
|
||||
readonly currentTarget: EventTarget;
|
||||
readonly defaultPrevented: boolean;
|
||||
readonly eventPhase: number;
|
||||
|
@ -420,7 +420,7 @@ declare var Event: {
|
|||
readonly AT_TARGET: number;
|
||||
readonly BUBBLING_PHASE: number;
|
||||
readonly CAPTURING_PHASE: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface EventTarget {
|
||||
addEventListener(type: string, listener?: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
|
@ -431,7 +431,7 @@ interface EventTarget {
|
|||
declare var EventTarget: {
|
||||
prototype: EventTarget;
|
||||
new(): EventTarget;
|
||||
}
|
||||
};
|
||||
|
||||
interface File extends Blob {
|
||||
readonly lastModifiedDate: any;
|
||||
|
@ -442,7 +442,7 @@ interface File extends Blob {
|
|||
declare var File: {
|
||||
prototype: File;
|
||||
new (parts: (ArrayBuffer | ArrayBufferView | Blob | string)[], filename: string, properties?: FilePropertyBag): File;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileList {
|
||||
readonly length: number;
|
||||
|
@ -453,7 +453,7 @@ interface FileList {
|
|||
declare var FileList: {
|
||||
prototype: FileList;
|
||||
new(): FileList;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileReader extends EventTarget, MSBaseReader {
|
||||
readonly error: DOMError;
|
||||
|
@ -468,8 +468,17 @@ interface FileReader extends EventTarget, MSBaseReader {
|
|||
declare var FileReader: {
|
||||
prototype: FileReader;
|
||||
new(): FileReader;
|
||||
};
|
||||
|
||||
interface FormData {
|
||||
append(name: string, value: string | Blob, fileName?: string): void;
|
||||
}
|
||||
|
||||
declare var FormData: {
|
||||
prototype: FormData;
|
||||
new(): FormData;
|
||||
};
|
||||
|
||||
interface Headers {
|
||||
append(name: string, value: string): void;
|
||||
delete(name: string): void;
|
||||
|
@ -482,7 +491,7 @@ interface Headers {
|
|||
declare var Headers: {
|
||||
prototype: Headers;
|
||||
new(init?: any): Headers;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBCursor {
|
||||
readonly direction: IDBCursorDirection;
|
||||
|
@ -506,7 +515,7 @@ declare var IDBCursor: {
|
|||
readonly NEXT_NO_DUPLICATE: string;
|
||||
readonly PREV: string;
|
||||
readonly PREV_NO_DUPLICATE: string;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBCursorWithValue extends IDBCursor {
|
||||
readonly value: any;
|
||||
|
@ -515,7 +524,7 @@ interface IDBCursorWithValue extends IDBCursor {
|
|||
declare var IDBCursorWithValue: {
|
||||
prototype: IDBCursorWithValue;
|
||||
new(): IDBCursorWithValue;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBDatabaseEventMap {
|
||||
"abort": Event;
|
||||
|
@ -532,7 +541,7 @@ interface IDBDatabase extends EventTarget {
|
|||
close(): void;
|
||||
createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore;
|
||||
deleteObjectStore(name: string): void;
|
||||
transaction(storeNames: string | string[], mode?: string): IDBTransaction;
|
||||
transaction(storeNames: string | string[], mode?: IDBTransactionMode): IDBTransaction;
|
||||
addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
|
||||
addEventListener<K extends keyof IDBDatabaseEventMap>(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
|
@ -541,7 +550,7 @@ interface IDBDatabase extends EventTarget {
|
|||
declare var IDBDatabase: {
|
||||
prototype: IDBDatabase;
|
||||
new(): IDBDatabase;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBFactory {
|
||||
cmp(first: any, second: any): number;
|
||||
|
@ -552,7 +561,7 @@ interface IDBFactory {
|
|||
declare var IDBFactory: {
|
||||
prototype: IDBFactory;
|
||||
new(): IDBFactory;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBIndex {
|
||||
keyPath: string | string[];
|
||||
|
@ -563,14 +572,14 @@ interface IDBIndex {
|
|||
count(key?: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
get(key: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
getKey(key: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
}
|
||||
|
||||
declare var IDBIndex: {
|
||||
prototype: IDBIndex;
|
||||
new(): IDBIndex;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBKeyRange {
|
||||
readonly lower: any;
|
||||
|
@ -586,7 +595,7 @@ declare var IDBKeyRange: {
|
|||
lowerBound(lower: any, open?: boolean): IDBKeyRange;
|
||||
only(value: any): IDBKeyRange;
|
||||
upperBound(upper: any, open?: boolean): IDBKeyRange;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBObjectStore {
|
||||
readonly indexNames: DOMStringList;
|
||||
|
@ -602,14 +611,14 @@ interface IDBObjectStore {
|
|||
deleteIndex(indexName: string): void;
|
||||
get(key: any): IDBRequest;
|
||||
index(name: string): IDBIndex;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
put(value: any, key?: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
}
|
||||
|
||||
declare var IDBObjectStore: {
|
||||
prototype: IDBObjectStore;
|
||||
new(): IDBObjectStore;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBOpenDBRequestEventMap extends IDBRequestEventMap {
|
||||
"blocked": Event;
|
||||
|
@ -626,7 +635,7 @@ interface IDBOpenDBRequest extends IDBRequest {
|
|||
declare var IDBOpenDBRequest: {
|
||||
prototype: IDBOpenDBRequest;
|
||||
new(): IDBOpenDBRequest;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBRequestEventMap {
|
||||
"error": Event;
|
||||
|
@ -634,7 +643,7 @@ interface IDBRequestEventMap {
|
|||
}
|
||||
|
||||
interface IDBRequest extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
readonly error: DOMException;
|
||||
onerror: (this: IDBRequest, ev: Event) => any;
|
||||
onsuccess: (this: IDBRequest, ev: Event) => any;
|
||||
readonly readyState: IDBRequestReadyState;
|
||||
|
@ -648,7 +657,7 @@ interface IDBRequest extends EventTarget {
|
|||
declare var IDBRequest: {
|
||||
prototype: IDBRequest;
|
||||
new(): IDBRequest;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBTransactionEventMap {
|
||||
"abort": Event;
|
||||
|
@ -658,7 +667,7 @@ interface IDBTransactionEventMap {
|
|||
|
||||
interface IDBTransaction extends EventTarget {
|
||||
readonly db: IDBDatabase;
|
||||
readonly error: DOMError;
|
||||
readonly error: DOMException;
|
||||
readonly mode: IDBTransactionMode;
|
||||
onabort: (this: IDBTransaction, ev: Event) => any;
|
||||
oncomplete: (this: IDBTransaction, ev: Event) => any;
|
||||
|
@ -678,7 +687,7 @@ declare var IDBTransaction: {
|
|||
readonly READ_ONLY: string;
|
||||
readonly READ_WRITE: string;
|
||||
readonly VERSION_CHANGE: string;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBVersionChangeEvent extends Event {
|
||||
readonly newVersion: number | null;
|
||||
|
@ -688,7 +697,7 @@ interface IDBVersionChangeEvent extends Event {
|
|||
declare var IDBVersionChangeEvent: {
|
||||
prototype: IDBVersionChangeEvent;
|
||||
new(): IDBVersionChangeEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface ImageData {
|
||||
data: Uint8ClampedArray;
|
||||
|
@ -700,7 +709,7 @@ declare var ImageData: {
|
|||
prototype: ImageData;
|
||||
new(width: number, height: number): ImageData;
|
||||
new(array: Uint8ClampedArray, width: number, height: number): ImageData;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessageChannel {
|
||||
readonly port1: MessagePort;
|
||||
|
@ -710,7 +719,7 @@ interface MessageChannel {
|
|||
declare var MessageChannel: {
|
||||
prototype: MessageChannel;
|
||||
new(): MessageChannel;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessageEvent extends Event {
|
||||
readonly data: any;
|
||||
|
@ -723,7 +732,7 @@ interface MessageEvent extends Event {
|
|||
declare var MessageEvent: {
|
||||
prototype: MessageEvent;
|
||||
new(type: string, eventInitDict?: MessageEventInit): MessageEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessagePortEventMap {
|
||||
"message": MessageEvent;
|
||||
|
@ -741,7 +750,7 @@ interface MessagePort extends EventTarget {
|
|||
declare var MessagePort: {
|
||||
prototype: MessagePort;
|
||||
new(): MessagePort;
|
||||
}
|
||||
};
|
||||
|
||||
interface NotificationEventMap {
|
||||
"click": Event;
|
||||
|
@ -771,7 +780,7 @@ declare var Notification: {
|
|||
prototype: Notification;
|
||||
new(title: string, options?: NotificationOptions): Notification;
|
||||
requestPermission(callback?: NotificationPermissionCallback): Promise<NotificationPermission>;
|
||||
}
|
||||
};
|
||||
|
||||
interface Performance {
|
||||
readonly navigation: PerformanceNavigation;
|
||||
|
@ -794,7 +803,7 @@ interface Performance {
|
|||
declare var Performance: {
|
||||
prototype: Performance;
|
||||
new(): Performance;
|
||||
}
|
||||
};
|
||||
|
||||
interface PerformanceNavigation {
|
||||
readonly redirectCount: number;
|
||||
|
@ -813,18 +822,18 @@ declare var PerformanceNavigation: {
|
|||
readonly TYPE_NAVIGATE: number;
|
||||
readonly TYPE_RELOAD: number;
|
||||
readonly TYPE_RESERVED: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface PerformanceTiming {
|
||||
readonly connectEnd: number;
|
||||
readonly connectStart: number;
|
||||
readonly domainLookupEnd: number;
|
||||
readonly domainLookupStart: number;
|
||||
readonly domComplete: number;
|
||||
readonly domContentLoadedEventEnd: number;
|
||||
readonly domContentLoadedEventStart: number;
|
||||
readonly domInteractive: number;
|
||||
readonly domLoading: number;
|
||||
readonly domainLookupEnd: number;
|
||||
readonly domainLookupStart: number;
|
||||
readonly fetchStart: number;
|
||||
readonly loadEventEnd: number;
|
||||
readonly loadEventStart: number;
|
||||
|
@ -844,7 +853,7 @@ interface PerformanceTiming {
|
|||
declare var PerformanceTiming: {
|
||||
prototype: PerformanceTiming;
|
||||
new(): PerformanceTiming;
|
||||
}
|
||||
};
|
||||
|
||||
interface Position {
|
||||
readonly coords: Coordinates;
|
||||
|
@ -854,7 +863,7 @@ interface Position {
|
|||
declare var Position: {
|
||||
prototype: Position;
|
||||
new(): Position;
|
||||
}
|
||||
};
|
||||
|
||||
interface PositionError {
|
||||
readonly code: number;
|
||||
|
@ -871,7 +880,7 @@ declare var PositionError: {
|
|||
readonly PERMISSION_DENIED: number;
|
||||
readonly POSITION_UNAVAILABLE: number;
|
||||
readonly TIMEOUT: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface ProgressEvent extends Event {
|
||||
readonly lengthComputable: boolean;
|
||||
|
@ -883,7 +892,7 @@ interface ProgressEvent extends Event {
|
|||
declare var ProgressEvent: {
|
||||
prototype: ProgressEvent;
|
||||
new(type: string, eventInitDict?: ProgressEventInit): ProgressEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushManager {
|
||||
getSubscription(): Promise<PushSubscription>;
|
||||
|
@ -894,7 +903,7 @@ interface PushManager {
|
|||
declare var PushManager: {
|
||||
prototype: PushManager;
|
||||
new(): PushManager;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushSubscription {
|
||||
readonly endpoint: USVString;
|
||||
|
@ -907,7 +916,7 @@ interface PushSubscription {
|
|||
declare var PushSubscription: {
|
||||
prototype: PushSubscription;
|
||||
new(): PushSubscription;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushSubscriptionOptions {
|
||||
readonly applicationServerKey: ArrayBuffer | null;
|
||||
|
@ -917,7 +926,7 @@ interface PushSubscriptionOptions {
|
|||
declare var PushSubscriptionOptions: {
|
||||
prototype: PushSubscriptionOptions;
|
||||
new(): PushSubscriptionOptions;
|
||||
}
|
||||
};
|
||||
|
||||
interface ReadableStream {
|
||||
readonly locked: boolean;
|
||||
|
@ -928,7 +937,7 @@ interface ReadableStream {
|
|||
declare var ReadableStream: {
|
||||
prototype: ReadableStream;
|
||||
new(): ReadableStream;
|
||||
}
|
||||
};
|
||||
|
||||
interface ReadableStreamReader {
|
||||
cancel(): Promise<void>;
|
||||
|
@ -939,7 +948,7 @@ interface ReadableStreamReader {
|
|||
declare var ReadableStreamReader: {
|
||||
prototype: ReadableStreamReader;
|
||||
new(): ReadableStreamReader;
|
||||
}
|
||||
};
|
||||
|
||||
interface Request extends Object, Body {
|
||||
readonly cache: RequestCache;
|
||||
|
@ -961,7 +970,7 @@ interface Request extends Object, Body {
|
|||
declare var Request: {
|
||||
prototype: Request;
|
||||
new(input: Request | string, init?: RequestInit): Request;
|
||||
}
|
||||
};
|
||||
|
||||
interface Response extends Object, Body {
|
||||
readonly body: ReadableStream | null;
|
||||
|
@ -977,7 +986,9 @@ interface Response extends Object, Body {
|
|||
declare var Response: {
|
||||
prototype: Response;
|
||||
new(body?: any, init?: ResponseInit): Response;
|
||||
}
|
||||
error: () => Response;
|
||||
redirect: (url: string, status?: number) => Response;
|
||||
};
|
||||
|
||||
interface ServiceWorkerEventMap extends AbstractWorkerEventMap {
|
||||
"statechange": Event;
|
||||
|
@ -995,7 +1006,7 @@ interface ServiceWorker extends EventTarget, AbstractWorker {
|
|||
declare var ServiceWorker: {
|
||||
prototype: ServiceWorker;
|
||||
new(): ServiceWorker;
|
||||
}
|
||||
};
|
||||
|
||||
interface ServiceWorkerRegistrationEventMap {
|
||||
"updatefound": Event;
|
||||
|
@ -1020,7 +1031,7 @@ interface ServiceWorkerRegistration extends EventTarget {
|
|||
declare var ServiceWorkerRegistration: {
|
||||
prototype: ServiceWorkerRegistration;
|
||||
new(): ServiceWorkerRegistration;
|
||||
}
|
||||
};
|
||||
|
||||
interface SyncManager {
|
||||
getTags(): any;
|
||||
|
@ -1030,7 +1041,7 @@ interface SyncManager {
|
|||
declare var SyncManager: {
|
||||
prototype: SyncManager;
|
||||
new(): SyncManager;
|
||||
}
|
||||
};
|
||||
|
||||
interface URL {
|
||||
hash: string;
|
||||
|
@ -1053,7 +1064,7 @@ declare var URL: {
|
|||
new(url: string, base?: string): URL;
|
||||
createObjectURL(object: any, options?: ObjectURLOptions): string;
|
||||
revokeObjectURL(url: string): void;
|
||||
}
|
||||
};
|
||||
|
||||
interface WebSocketEventMap {
|
||||
"close": CloseEvent;
|
||||
|
@ -1090,7 +1101,7 @@ declare var WebSocket: {
|
|||
readonly CLOSING: number;
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerEventMap extends AbstractWorkerEventMap {
|
||||
"message": MessageEvent;
|
||||
|
@ -1107,7 +1118,7 @@ interface Worker extends EventTarget, AbstractWorker {
|
|||
declare var Worker: {
|
||||
prototype: Worker;
|
||||
new(stringUrl: string): Worker;
|
||||
}
|
||||
};
|
||||
|
||||
interface XMLHttpRequestEventMap extends XMLHttpRequestEventTargetEventMap {
|
||||
"readystatechange": Event;
|
||||
|
@ -1153,7 +1164,7 @@ declare var XMLHttpRequest: {
|
|||
readonly LOADING: number;
|
||||
readonly OPENED: number;
|
||||
readonly UNSENT: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void;
|
||||
|
@ -1163,7 +1174,7 @@ interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
|
|||
declare var XMLHttpRequestUpload: {
|
||||
prototype: XMLHttpRequestUpload;
|
||||
new(): XMLHttpRequestUpload;
|
||||
}
|
||||
};
|
||||
|
||||
interface AbstractWorkerEventMap {
|
||||
"error": ErrorEvent;
|
||||
|
@ -1278,7 +1289,7 @@ interface Client {
|
|||
declare var Client: {
|
||||
prototype: Client;
|
||||
new(): Client;
|
||||
}
|
||||
};
|
||||
|
||||
interface Clients {
|
||||
claim(): Promise<void>;
|
||||
|
@ -1290,7 +1301,7 @@ interface Clients {
|
|||
declare var Clients: {
|
||||
prototype: Clients;
|
||||
new(): Clients;
|
||||
}
|
||||
};
|
||||
|
||||
interface DedicatedWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
|
||||
"message": MessageEvent;
|
||||
|
@ -1307,7 +1318,7 @@ interface DedicatedWorkerGlobalScope extends WorkerGlobalScope {
|
|||
declare var DedicatedWorkerGlobalScope: {
|
||||
prototype: DedicatedWorkerGlobalScope;
|
||||
new(): DedicatedWorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface ExtendableEvent extends Event {
|
||||
waitUntil(f: Promise<any>): void;
|
||||
|
@ -1316,7 +1327,7 @@ interface ExtendableEvent extends Event {
|
|||
declare var ExtendableEvent: {
|
||||
prototype: ExtendableEvent;
|
||||
new(type: string, eventInitDict?: ExtendableEventInit): ExtendableEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface ExtendableMessageEvent extends ExtendableEvent {
|
||||
readonly data: any;
|
||||
|
@ -1329,7 +1340,7 @@ interface ExtendableMessageEvent extends ExtendableEvent {
|
|||
declare var ExtendableMessageEvent: {
|
||||
prototype: ExtendableMessageEvent;
|
||||
new(type: string, eventInitDict?: ExtendableMessageEventInit): ExtendableMessageEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface FetchEvent extends ExtendableEvent {
|
||||
readonly clientId: string | null;
|
||||
|
@ -1341,7 +1352,7 @@ interface FetchEvent extends ExtendableEvent {
|
|||
declare var FetchEvent: {
|
||||
prototype: FetchEvent;
|
||||
new(type: string, eventInitDict: FetchEventInit): FetchEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileReaderSync {
|
||||
readAsArrayBuffer(blob: Blob): any;
|
||||
|
@ -1353,7 +1364,7 @@ interface FileReaderSync {
|
|||
declare var FileReaderSync: {
|
||||
prototype: FileReaderSync;
|
||||
new(): FileReaderSync;
|
||||
}
|
||||
};
|
||||
|
||||
interface NotificationEvent extends ExtendableEvent {
|
||||
readonly action: string;
|
||||
|
@ -1363,7 +1374,7 @@ interface NotificationEvent extends ExtendableEvent {
|
|||
declare var NotificationEvent: {
|
||||
prototype: NotificationEvent;
|
||||
new(type: string, eventInitDict: NotificationEventInit): NotificationEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushEvent extends ExtendableEvent {
|
||||
readonly data: PushMessageData | null;
|
||||
|
@ -1372,7 +1383,7 @@ interface PushEvent extends ExtendableEvent {
|
|||
declare var PushEvent: {
|
||||
prototype: PushEvent;
|
||||
new(type: string, eventInitDict?: PushEventInit): PushEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushMessageData {
|
||||
arrayBuffer(): ArrayBuffer;
|
||||
|
@ -1384,7 +1395,7 @@ interface PushMessageData {
|
|||
declare var PushMessageData: {
|
||||
prototype: PushMessageData;
|
||||
new(): PushMessageData;
|
||||
}
|
||||
};
|
||||
|
||||
interface ServiceWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
|
||||
"activate": ExtendableEvent;
|
||||
|
@ -1418,7 +1429,7 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
|
|||
declare var ServiceWorkerGlobalScope: {
|
||||
prototype: ServiceWorkerGlobalScope;
|
||||
new(): ServiceWorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface SyncEvent extends ExtendableEvent {
|
||||
readonly lastChance: boolean;
|
||||
|
@ -1428,7 +1439,7 @@ interface SyncEvent extends ExtendableEvent {
|
|||
declare var SyncEvent: {
|
||||
prototype: SyncEvent;
|
||||
new(type: string, init: SyncEventInit): SyncEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface WindowClient extends Client {
|
||||
readonly focused: boolean;
|
||||
|
@ -1440,7 +1451,7 @@ interface WindowClient extends Client {
|
|||
declare var WindowClient: {
|
||||
prototype: WindowClient;
|
||||
new(): WindowClient;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerGlobalScopeEventMap {
|
||||
"error": ErrorEvent;
|
||||
|
@ -1463,7 +1474,7 @@ interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, Glo
|
|||
declare var WorkerGlobalScope: {
|
||||
prototype: WorkerGlobalScope;
|
||||
new(): WorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerLocation {
|
||||
readonly hash: string;
|
||||
|
@ -1481,7 +1492,7 @@ interface WorkerLocation {
|
|||
declare var WorkerLocation: {
|
||||
prototype: WorkerLocation;
|
||||
new(): WorkerLocation;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, NavigatorBeacon, NavigatorConcurrentHardware {
|
||||
readonly hardwareConcurrency: number;
|
||||
|
@ -1490,7 +1501,7 @@ interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, Navigato
|
|||
declare var WorkerNavigator: {
|
||||
prototype: WorkerNavigator;
|
||||
new(): WorkerNavigator;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerUtils extends Object, WindowBase64 {
|
||||
readonly indexedDB: IDBFactory;
|
||||
|
@ -1533,38 +1544,38 @@ interface ImageBitmap {
|
|||
|
||||
interface URLSearchParams {
|
||||
/**
|
||||
* Appends a specified key/value pair as a new search parameter.
|
||||
*/
|
||||
* Appends a specified key/value pair as a new search parameter.
|
||||
*/
|
||||
append(name: string, value: string): void;
|
||||
/**
|
||||
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
|
||||
*/
|
||||
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
|
||||
*/
|
||||
delete(name: string): void;
|
||||
/**
|
||||
* Returns the first value associated to the given search parameter.
|
||||
*/
|
||||
* Returns the first value associated to the given search parameter.
|
||||
*/
|
||||
get(name: string): string | null;
|
||||
/**
|
||||
* Returns all the values association with a given search parameter.
|
||||
*/
|
||||
* Returns all the values association with a given search parameter.
|
||||
*/
|
||||
getAll(name: string): string[];
|
||||
/**
|
||||
* Returns a Boolean indicating if such a search parameter exists.
|
||||
*/
|
||||
* Returns a Boolean indicating if such a search parameter exists.
|
||||
*/
|
||||
has(name: string): boolean;
|
||||
/**
|
||||
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
|
||||
*/
|
||||
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
|
||||
*/
|
||||
set(name: string, value: string): void;
|
||||
}
|
||||
|
||||
declare var URLSearchParams: {
|
||||
prototype: URLSearchParams;
|
||||
/**
|
||||
* Constructor returning a URLSearchParams object.
|
||||
*/
|
||||
* Constructor returning a URLSearchParams object.
|
||||
*/
|
||||
new (init?: string | URLSearchParams): URLSearchParams;
|
||||
}
|
||||
};
|
||||
|
||||
interface BlobPropertyBag {
|
||||
type?: string;
|
||||
|
@ -1771,8 +1782,23 @@ interface AddEventListenerOptions extends EventListenerOptions {
|
|||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface DecodeErrorCallback {
|
||||
(error: DOMException): void;
|
||||
}
|
||||
interface DecodeSuccessCallback {
|
||||
(decodedData: AudioBuffer): void;
|
||||
}
|
||||
interface ErrorEventHandler {
|
||||
(message: string, filename?: string, lineno?: number, colno?: number, error?:Error): void;
|
||||
(message: string, filename?: string, lineno?: number, colno?: number, error?: Error): void;
|
||||
}
|
||||
interface ForEachCallback {
|
||||
(keyId: any, status: MediaKeyStatus): void;
|
||||
}
|
||||
interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
}
|
||||
interface NotificationPermissionCallback {
|
||||
(permission: NotificationPermission): void;
|
||||
}
|
||||
interface PositionCallback {
|
||||
(position: Position): void;
|
||||
|
@ -1780,21 +1806,6 @@ interface PositionCallback {
|
|||
interface PositionErrorCallback {
|
||||
(error: PositionError): void;
|
||||
}
|
||||
interface DecodeSuccessCallback {
|
||||
(decodedData: AudioBuffer): void;
|
||||
}
|
||||
interface DecodeErrorCallback {
|
||||
(error: DOMException): void;
|
||||
}
|
||||
interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
}
|
||||
interface ForEachCallback {
|
||||
(keyId: any, status: MediaKeyStatus): void;
|
||||
}
|
||||
interface NotificationPermissionCallback {
|
||||
(permission: NotificationPermission): void;
|
||||
}
|
||||
declare var onmessage: (this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any;
|
||||
declare function close(): void;
|
||||
declare function postMessage(message: any, transfer?: any[]): void;
|
||||
|
|
|
@ -2,51 +2,53 @@
|
|||
* Declaration module describing the TypeScript Server protocol
|
||||
*/
|
||||
declare namespace ts.server.protocol {
|
||||
namespace CommandTypes {
|
||||
type Brace = "brace";
|
||||
type BraceCompletion = "braceCompletion";
|
||||
type Change = "change";
|
||||
type Close = "close";
|
||||
type Completions = "completions";
|
||||
type CompletionDetails = "completionEntryDetails";
|
||||
type CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList";
|
||||
type CompileOnSaveEmitFile = "compileOnSaveEmitFile";
|
||||
type Configure = "configure";
|
||||
type Definition = "definition";
|
||||
type Implementation = "implementation";
|
||||
type Exit = "exit";
|
||||
type Format = "format";
|
||||
type Formatonkey = "formatonkey";
|
||||
type Geterr = "geterr";
|
||||
type GeterrForProject = "geterrForProject";
|
||||
type SemanticDiagnosticsSync = "semanticDiagnosticsSync";
|
||||
type SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
|
||||
type NavBar = "navbar";
|
||||
type Navto = "navto";
|
||||
type NavTree = "navtree";
|
||||
type NavTreeFull = "navtree-full";
|
||||
type Occurrences = "occurrences";
|
||||
type DocumentHighlights = "documentHighlights";
|
||||
type Open = "open";
|
||||
type Quickinfo = "quickinfo";
|
||||
type References = "references";
|
||||
type Reload = "reload";
|
||||
type Rename = "rename";
|
||||
type Saveto = "saveto";
|
||||
type SignatureHelp = "signatureHelp";
|
||||
type TypeDefinition = "typeDefinition";
|
||||
type ProjectInfo = "projectInfo";
|
||||
type ReloadProjects = "reloadProjects";
|
||||
type Unknown = "unknown";
|
||||
type OpenExternalProject = "openExternalProject";
|
||||
type OpenExternalProjects = "openExternalProjects";
|
||||
type CloseExternalProject = "closeExternalProject";
|
||||
type TodoComments = "todoComments";
|
||||
type Indentation = "indentation";
|
||||
type DocCommentTemplate = "docCommentTemplate";
|
||||
type CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects";
|
||||
type GetCodeFixes = "getCodeFixes";
|
||||
type GetSupportedCodeFixes = "getSupportedCodeFixes";
|
||||
const enum CommandTypes {
|
||||
Brace = "brace",
|
||||
BraceCompletion = "braceCompletion",
|
||||
Change = "change",
|
||||
Close = "close",
|
||||
Completions = "completions",
|
||||
CompletionDetails = "completionEntryDetails",
|
||||
CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList",
|
||||
CompileOnSaveEmitFile = "compileOnSaveEmitFile",
|
||||
Configure = "configure",
|
||||
Definition = "definition",
|
||||
Implementation = "implementation",
|
||||
Exit = "exit",
|
||||
Format = "format",
|
||||
Formatonkey = "formatonkey",
|
||||
Geterr = "geterr",
|
||||
GeterrForProject = "geterrForProject",
|
||||
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
|
||||
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
|
||||
NavBar = "navbar",
|
||||
Navto = "navto",
|
||||
NavTree = "navtree",
|
||||
NavTreeFull = "navtree-full",
|
||||
Occurrences = "occurrences",
|
||||
DocumentHighlights = "documentHighlights",
|
||||
Open = "open",
|
||||
Quickinfo = "quickinfo",
|
||||
References = "references",
|
||||
Reload = "reload",
|
||||
Rename = "rename",
|
||||
Saveto = "saveto",
|
||||
SignatureHelp = "signatureHelp",
|
||||
TypeDefinition = "typeDefinition",
|
||||
ProjectInfo = "projectInfo",
|
||||
ReloadProjects = "reloadProjects",
|
||||
Unknown = "unknown",
|
||||
OpenExternalProject = "openExternalProject",
|
||||
OpenExternalProjects = "openExternalProjects",
|
||||
CloseExternalProject = "closeExternalProject",
|
||||
TodoComments = "todoComments",
|
||||
Indentation = "indentation",
|
||||
DocCommentTemplate = "docCommentTemplate",
|
||||
CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects",
|
||||
GetCodeFixes = "getCodeFixes",
|
||||
GetSupportedCodeFixes = "getSupportedCodeFixes",
|
||||
GetApplicableRefactors = "getApplicableRefactors",
|
||||
GetEditsForRefactor = "getEditsForRefactor",
|
||||
}
|
||||
/**
|
||||
* A TypeScript Server message
|
||||
|
@ -287,6 +289,85 @@ declare namespace ts.server.protocol {
|
|||
*/
|
||||
offset: number;
|
||||
}
|
||||
type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs;
|
||||
/**
|
||||
* Request refactorings at a given position or selection area.
|
||||
*/
|
||||
interface GetApplicableRefactorsRequest extends Request {
|
||||
command: CommandTypes.GetApplicableRefactors;
|
||||
arguments: GetApplicableRefactorsRequestArgs;
|
||||
}
|
||||
type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs;
|
||||
/**
|
||||
* Response is a list of available refactorings.
|
||||
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
|
||||
*/
|
||||
interface GetApplicableRefactorsResponse extends Response {
|
||||
body?: ApplicableRefactorInfo[];
|
||||
}
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
interface ApplicableRefactorInfo {
|
||||
/**
|
||||
* The programmatic name of the refactoring
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* A description of this refactoring category to show to the user.
|
||||
* If the refactoring gets inlined (see below), this text will not be visible.
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Inlineable refactorings can have their actions hoisted out to the top level
|
||||
* of a context menu. Non-inlineanable refactorings should always be shown inside
|
||||
* their parent grouping.
|
||||
*
|
||||
* If not specified, this value is assumed to be 'true'
|
||||
*/
|
||||
inlineable?: boolean;
|
||||
actions: RefactorActionInfo[];
|
||||
}
|
||||
/**
|
||||
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
|
||||
* offer several actions, each corresponding to a surround class or closure to extract into.
|
||||
*/
|
||||
type RefactorActionInfo = {
|
||||
/**
|
||||
* The programmatic name of the refactoring action
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* A description of this refactoring action to show to the user.
|
||||
* If the parent refactoring is inlined away, this will be the only text shown,
|
||||
* so this description should make sense by itself if the parent is inlineable=true
|
||||
*/
|
||||
description: string;
|
||||
};
|
||||
interface GetEditsForRefactorRequest extends Request {
|
||||
command: CommandTypes.GetEditsForRefactor;
|
||||
arguments: GetEditsForRefactorRequestArgs;
|
||||
}
|
||||
/**
|
||||
* Request the edits that a particular refactoring action produces.
|
||||
* Callers must specify the name of the refactor and the name of the action.
|
||||
*/
|
||||
type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
refactor: string;
|
||||
action: string;
|
||||
};
|
||||
interface GetEditsForRefactorResponse extends Response {
|
||||
body?: RefactorEditInfo;
|
||||
}
|
||||
type RefactorEditInfo = {
|
||||
edits: FileCodeEdits[];
|
||||
/**
|
||||
* An optional location where the editor should start a rename operation once
|
||||
* the refactoring edits have been applied
|
||||
*/
|
||||
renameLocation?: Location;
|
||||
renameFilename?: string;
|
||||
};
|
||||
/**
|
||||
* Request for the available codefixes at a specific position.
|
||||
*/
|
||||
|
@ -294,10 +375,7 @@ declare namespace ts.server.protocol {
|
|||
command: CommandTypes.GetCodeFixes;
|
||||
arguments: CodeFixRequestArgs;
|
||||
}
|
||||
/**
|
||||
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
|
||||
*/
|
||||
interface CodeFixRequestArgs extends FileRequestArgs {
|
||||
interface FileRangeRequestArgs extends FileRequestArgs {
|
||||
/**
|
||||
* The line number for the request (1-based).
|
||||
*/
|
||||
|
@ -314,6 +392,11 @@ declare namespace ts.server.protocol {
|
|||
* The character offset (on the line) for the request (1-based).
|
||||
*/
|
||||
endOffset: number;
|
||||
}
|
||||
/**
|
||||
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
|
||||
*/
|
||||
interface CodeFixRequestArgs extends FileRangeRequestArgs {
|
||||
/**
|
||||
* Errorcodes we want to get the fixes for.
|
||||
*/
|
||||
|
@ -394,7 +477,7 @@ declare namespace ts.server.protocol {
|
|||
command: CommandTypes.Implementation;
|
||||
}
|
||||
/**
|
||||
* Location in source code expressed as (one-based) line and character offset.
|
||||
* Location in source code expressed as (one-based) line and (one-based) column offset.
|
||||
*/
|
||||
interface Location {
|
||||
line: number;
|
||||
|
@ -488,10 +571,9 @@ declare namespace ts.server.protocol {
|
|||
}
|
||||
/**
|
||||
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
|
||||
* Kind is taken from HighlightSpanKind type.
|
||||
*/
|
||||
interface HighlightSpan extends TextSpan {
|
||||
kind: string;
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
/**
|
||||
* Represents a set of highligh spans for a give name
|
||||
|
@ -609,7 +691,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The items's kind (such as 'className' or 'parameterName' or plain 'text').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
|
@ -957,7 +1039,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName' or plain 'text').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
|
@ -1143,7 +1225,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
|
@ -1170,7 +1252,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
|
@ -1417,6 +1499,12 @@ declare namespace ts.server.protocol {
|
|||
*/
|
||||
source?: string;
|
||||
}
|
||||
interface DiagnosticWithFileName extends Diagnostic {
|
||||
/**
|
||||
* Name of the file the diagnostic is in
|
||||
*/
|
||||
fileName: string;
|
||||
}
|
||||
interface DiagnosticEventBody {
|
||||
/**
|
||||
* The file for which diagnostic information is reported.
|
||||
|
@ -1446,7 +1534,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* An arry of diagnostic information items for the found config file.
|
||||
*/
|
||||
diagnostics: Diagnostic[];
|
||||
diagnostics: DiagnosticWithFileName[];
|
||||
}
|
||||
/**
|
||||
* Event message for "configFileDiag" event type.
|
||||
|
@ -1563,7 +1651,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* exact, substring, or prefix.
|
||||
*/
|
||||
|
@ -1596,7 +1684,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* Kind of symbol's container symbol (if any).
|
||||
*/
|
||||
containerKind?: string;
|
||||
containerKind?: ScriptElementKind;
|
||||
}
|
||||
/**
|
||||
* Navto response message. Body is an array of navto items. Each
|
||||
|
@ -1660,7 +1748,7 @@ declare namespace ts.server.protocol {
|
|||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
|
@ -1681,7 +1769,7 @@ declare namespace ts.server.protocol {
|
|||
/** protocol.NavigationTree is identical to ts.NavigationTree, except using protocol.TextSpan instead of ts.TextSpan */
|
||||
interface NavigationTree {
|
||||
text: string;
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
spans: TextSpan[];
|
||||
childItems?: NavigationTree[];
|
||||
|
@ -1756,12 +1844,11 @@ declare namespace ts.server.protocol {
|
|||
interface NavTreeResponse extends Response {
|
||||
body?: NavigationTree;
|
||||
}
|
||||
namespace IndentStyle {
|
||||
type None = "None";
|
||||
type Block = "Block";
|
||||
type Smart = "Smart";
|
||||
const enum IndentStyle {
|
||||
None = "None",
|
||||
Block = "Block",
|
||||
Smart = "Smart",
|
||||
}
|
||||
type IndentStyle = IndentStyle.None | IndentStyle.Block | IndentStyle.Smart;
|
||||
interface EditorSettings {
|
||||
baseIndentSize?: number;
|
||||
indentSize?: number;
|
||||
|
@ -1782,6 +1869,7 @@ declare namespace ts.server.protocol {
|
|||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
|
||||
insertSpaceAfterTypeAssertion?: boolean;
|
||||
insertSpaceBeforeFunctionParenthesis?: boolean;
|
||||
placeOpenBraceOnNewLineForFunctions?: boolean;
|
||||
placeOpenBraceOnNewLineForControlBlocks?: boolean;
|
||||
|
@ -1854,40 +1942,35 @@ declare namespace ts.server.protocol {
|
|||
typeRoots?: string[];
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
namespace JsxEmit {
|
||||
type None = "None";
|
||||
type Preserve = "Preserve";
|
||||
type ReactNative = "ReactNative";
|
||||
type React = "React";
|
||||
const enum JsxEmit {
|
||||
None = "None",
|
||||
Preserve = "Preserve",
|
||||
ReactNative = "ReactNative",
|
||||
React = "React",
|
||||
}
|
||||
type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative;
|
||||
namespace ModuleKind {
|
||||
type None = "None";
|
||||
type CommonJS = "CommonJS";
|
||||
type AMD = "AMD";
|
||||
type UMD = "UMD";
|
||||
type System = "System";
|
||||
type ES6 = "ES6";
|
||||
type ES2015 = "ES2015";
|
||||
const enum ModuleKind {
|
||||
None = "None",
|
||||
CommonJS = "CommonJS",
|
||||
AMD = "AMD",
|
||||
UMD = "UMD",
|
||||
System = "System",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
}
|
||||
type ModuleKind = ModuleKind.None | ModuleKind.CommonJS | ModuleKind.AMD | ModuleKind.UMD | ModuleKind.System | ModuleKind.ES6 | ModuleKind.ES2015;
|
||||
namespace ModuleResolutionKind {
|
||||
type Classic = "Classic";
|
||||
type Node = "Node";
|
||||
const enum ModuleResolutionKind {
|
||||
Classic = "Classic",
|
||||
Node = "Node",
|
||||
}
|
||||
type ModuleResolutionKind = ModuleResolutionKind.Classic | ModuleResolutionKind.Node;
|
||||
namespace NewLineKind {
|
||||
type Crlf = "Crlf";
|
||||
type Lf = "Lf";
|
||||
const enum NewLineKind {
|
||||
Crlf = "Crlf",
|
||||
Lf = "Lf",
|
||||
}
|
||||
type NewLineKind = NewLineKind.Crlf | NewLineKind.Lf;
|
||||
namespace ScriptTarget {
|
||||
type ES3 = "ES3";
|
||||
type ES5 = "ES5";
|
||||
type ES6 = "ES6";
|
||||
type ES2015 = "ES2015";
|
||||
const enum ScriptTarget {
|
||||
ES3 = "ES3",
|
||||
ES5 = "ES5",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
}
|
||||
type ScriptTarget = ScriptTarget.ES3 | ScriptTarget.ES5 | ScriptTarget.ES6 | ScriptTarget.ES2015;
|
||||
}
|
||||
declare namespace ts.server.protocol {
|
||||
|
||||
|
@ -1943,6 +2026,8 @@ declare namespace ts.server.protocol {
|
|||
}
|
||||
declare namespace ts {
|
||||
// these types are empty stubs for types from services and should not be used directly
|
||||
export type HighlightSpanKind = never;
|
||||
export type ScriptElementKind = never;
|
||||
export type ScriptKind = never;
|
||||
export type IndentStyle = never;
|
||||
export type JsxEmit = never;
|
||||
|
|
64135
lib/tsc.js
64135
lib/tsc.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
66414
lib/tsserver.js
66414
lib/tsserver.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
71805
lib/tsserverlibrary.js
71805
lib/tsserverlibrary.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
77853
lib/typescript.js
77853
lib/typescript.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
13825
lib/typingsInstaller.js
13825
lib/typingsInstaller.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -13,6 +13,7 @@ See the Apache Version 2.0 License for specific language governing permissions
|
|||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
"use strict";
|
||||
if (process.argv.length < 3) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ nodeVersions.each { nodeVer ->
|
|||
}
|
||||
|
||||
Utilities.standardJobSetup(newJob, project, true, "*/${branch}")
|
||||
Utilities.setMachineAffinity(newJob, 'Ubuntu', '20161020')
|
||||
Utilities.setMachineAffinity(newJob, 'Ubuntu14.04', '20170821-1')
|
||||
Utilities.addGithubPRTriggerForBranch(newJob, branch, "TypeScript Test Run ${newJobName}")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "typescript",
|
||||
"author": "Microsoft Corp.",
|
||||
"homepage": "http://typescriptlang.org/",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "TypeScript is a language for application scale JavaScript development",
|
||||
"keywords": [
|
||||
|
@ -60,7 +60,6 @@
|
|||
"gulp-newer": "latest",
|
||||
"gulp-sourcemaps": "latest",
|
||||
"gulp-typescript": "latest",
|
||||
"into-stream": "latest",
|
||||
"istanbul": "latest",
|
||||
"jake": "latest",
|
||||
"merge2": "latest",
|
||||
|
@ -91,7 +90,6 @@
|
|||
"setup-hooks": "node scripts/link-hooks.js"
|
||||
},
|
||||
"browser": {
|
||||
"buffer": false,
|
||||
"fs": false,
|
||||
"os": false,
|
||||
"path": false
|
||||
|
|
|
@ -7,11 +7,15 @@ function endsWith(s: string, suffix: string) {
|
|||
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
|
||||
}
|
||||
|
||||
function isStringEnum(declaration: ts.EnumDeclaration) {
|
||||
return declaration.members.length && declaration.members.every(m => m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
class DeclarationsWalker {
|
||||
private visitedTypes: ts.Type[] = [];
|
||||
private text = "";
|
||||
private removedTypes: ts.Type[] = [];
|
||||
|
||||
|
||||
private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) {
|
||||
}
|
||||
|
||||
|
@ -19,7 +23,7 @@ class DeclarationsWalker {
|
|||
let text = "declare namespace ts.server.protocol {\n";
|
||||
var walker = new DeclarationsWalker(typeChecker, protocolFile);
|
||||
walker.visitTypeNodes(protocolFile);
|
||||
text = walker.text
|
||||
text = walker.text
|
||||
? `declare namespace ts.server.protocol {\n${walker.text}}`
|
||||
: "";
|
||||
if (walker.removedTypes) {
|
||||
|
@ -52,7 +56,7 @@ class DeclarationsWalker {
|
|||
if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") {
|
||||
return;
|
||||
}
|
||||
if (decl.kind === ts.SyntaxKind.EnumDeclaration) {
|
||||
if (decl.kind === ts.SyntaxKind.EnumDeclaration && !isStringEnum(decl as ts.EnumDeclaration)) {
|
||||
this.removedTypes.push(type);
|
||||
return;
|
||||
}
|
||||
|
@ -91,7 +95,7 @@ class DeclarationsWalker {
|
|||
for (const type of heritageClauses[0].types) {
|
||||
this.processTypeOfNode(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +114,7 @@ class DeclarationsWalker {
|
|||
this.processType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) {
|
||||
|
|
|
@ -6,9 +6,7 @@ interface DiagnosticDetails {
|
|||
isEarly?: boolean;
|
||||
}
|
||||
|
||||
interface InputDiagnosticMessageTable {
|
||||
[msg: string]: DiagnosticDetails;
|
||||
}
|
||||
type InputDiagnosticMessageTable = ts.Map<DiagnosticDetails>;
|
||||
|
||||
function main(): void {
|
||||
var sys = ts.sys;
|
||||
|
@ -28,101 +26,66 @@ function main(): void {
|
|||
var inputFilePath = sys.args[0].replace(/\\/g, "/");
|
||||
var inputStr = sys.readFile(inputFilePath);
|
||||
|
||||
var diagnosticMessages: InputDiagnosticMessageTable = JSON.parse(inputStr);
|
||||
var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
|
||||
// Check that there are no duplicates.
|
||||
const seenNames = ts.createMap<true>();
|
||||
for (const name of Object.keys(diagnosticMessagesJson)) {
|
||||
if (seenNames.has(name))
|
||||
throw new Error(`Name ${name} appears twice`);
|
||||
seenNames.set(name, true);
|
||||
}
|
||||
|
||||
var names = Utilities.getObjectKeys(diagnosticMessages);
|
||||
var nameMap = buildUniqueNameMap(names);
|
||||
const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson);
|
||||
|
||||
var infoFileOutput = buildInfoFileOutput(diagnosticMessages, nameMap);
|
||||
checkForUniqueCodes(names, diagnosticMessages);
|
||||
var infoFileOutput = buildInfoFileOutput(diagnosticMessages);
|
||||
checkForUniqueCodes(diagnosticMessages);
|
||||
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
|
||||
|
||||
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages, nameMap);
|
||||
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
|
||||
writeFile("diagnosticMessages.generated.json", messageOutput);
|
||||
}
|
||||
|
||||
function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosticMessageTable) {
|
||||
const originalMessageForCode: string[] = [];
|
||||
let numConflicts = 0;
|
||||
|
||||
for (const currentMessage of messages) {
|
||||
const code = diagnosticTable[currentMessage].code;
|
||||
|
||||
if (code in originalMessageForCode) {
|
||||
const originalMessage = originalMessageForCode[code];
|
||||
ts.sys.write("\x1b[91m"); // High intensity red.
|
||||
ts.sys.write("Error");
|
||||
ts.sys.write("\x1b[0m"); // Reset formatting.
|
||||
ts.sys.write(`: Diagnostic code '${code}' conflicts between "${originalMessage}" and "${currentMessage}".`);
|
||||
ts.sys.write(ts.sys.newLine + ts.sys.newLine);
|
||||
|
||||
numConflicts++;
|
||||
}
|
||||
else {
|
||||
originalMessageForCode[code] = currentMessage;
|
||||
}
|
||||
}
|
||||
|
||||
if (numConflicts > 0) {
|
||||
throw new Error(`Found ${numConflicts} conflict(s) in diagnostic codes.`);
|
||||
}
|
||||
function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) {
|
||||
const allCodes: { [key: number]: true | undefined } = [];
|
||||
diagnosticTable.forEach(({ code }) => {
|
||||
if (allCodes[code])
|
||||
throw new Error(`Diagnostic code ${code} appears more than once.`);
|
||||
allCodes[code] = true;
|
||||
});
|
||||
}
|
||||
|
||||
function buildUniqueNameMap(names: string[]): ts.Map<string> {
|
||||
var nameMap = ts.createMap<string>();
|
||||
|
||||
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
nameMap.set(names[i], uniqueNames[i]);
|
||||
}
|
||||
|
||||
return nameMap;
|
||||
}
|
||||
|
||||
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
|
||||
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string {
|
||||
var result =
|
||||
'// <auto-generated />\r\n' +
|
||||
'/// <reference path="types.ts" />\r\n' +
|
||||
'/* @internal */\r\n' +
|
||||
'namespace ts {\r\n' +
|
||||
" function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" +
|
||||
" return { code, category, key, message };\r\n" +
|
||||
" }\r\n" +
|
||||
' export const Diagnostics = {\r\n';
|
||||
var names = Utilities.getObjectKeys(messageTable);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var diagnosticDetails = messageTable[name];
|
||||
var propName = convertPropertyName(nameMap.get(name));
|
||||
|
||||
result +=
|
||||
' ' + propName +
|
||||
': { code: ' + diagnosticDetails.code +
|
||||
', category: DiagnosticCategory.' + diagnosticDetails.category +
|
||||
', key: "' + createKey(propName, diagnosticDetails.code) + '"' +
|
||||
', message: "' + name.replace(/[\"]/g, '\\"') + '"' +
|
||||
' },\r\n';
|
||||
}
|
||||
messageTable.forEach(({ code, category }, name) => {
|
||||
const propName = convertPropertyName(name);
|
||||
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`;
|
||||
});
|
||||
|
||||
result += ' };\r\n}';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
|
||||
var result =
|
||||
'{';
|
||||
var names = Utilities.getObjectKeys(messageTable);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var diagnosticDetails = messageTable[name];
|
||||
var propName = convertPropertyName(nameMap.get(name));
|
||||
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string {
|
||||
let result = '{';
|
||||
messageTable.forEach(({ code }, name) => {
|
||||
const propName = convertPropertyName(name);
|
||||
result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`;
|
||||
});
|
||||
|
||||
result += '\r\n "' + createKey(propName, diagnosticDetails.code) + '"' + ' : "' + name.replace(/[\"]/g, '\\"') + '"';
|
||||
if (i !== names.length - 1) {
|
||||
result += ',';
|
||||
}
|
||||
}
|
||||
// Shave trailing comma, then add newline and ending brace
|
||||
result = result.slice(0, result.length - 1) + '\r\n}';
|
||||
|
||||
result += '\r\n}';
|
||||
// Assert that we generated valid JSON
|
||||
JSON.parse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -139,7 +102,6 @@ function convertPropertyName(origName: string): string {
|
|||
return /\w/.test(char) ? char : "_";
|
||||
}).join("");
|
||||
|
||||
|
||||
// get rid of all multi-underscores
|
||||
result = result.replace(/_+/g, "_");
|
||||
|
||||
|
@ -152,93 +114,4 @@ function convertPropertyName(origName: string): string {
|
|||
return result;
|
||||
}
|
||||
|
||||
module NameGenerator {
|
||||
export function ensureUniqueness(names: string[], isCaseSensitive: boolean, isFixed?: boolean[]): string[]{
|
||||
if (!isFixed) {
|
||||
isFixed = names.map(() => false)
|
||||
}
|
||||
|
||||
var names = names.slice();
|
||||
ensureUniquenessInPlace(names, isCaseSensitive, isFixed);
|
||||
return names;
|
||||
}
|
||||
|
||||
function ensureUniquenessInPlace(names: string[], isCaseSensitive: boolean, isFixed: boolean[]): void {
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var collisionIndices = Utilities.collectMatchingIndices(name, names, isCaseSensitive);
|
||||
|
||||
// We will always have one "collision" because getCollisionIndices returns the index of name itself as well;
|
||||
// so if we only have one collision, then there are no issues.
|
||||
if (collisionIndices.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
handleCollisions(name, names, isFixed, collisionIndices, isCaseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCollisions(name: string, proposedNames: string[], isFixed: boolean[], collisionIndices: number[], isCaseSensitive: boolean): void {
|
||||
var suffix = 1;
|
||||
|
||||
for (var i = 0; i < collisionIndices.length; i++) {
|
||||
var collisionIndex = collisionIndices[i];
|
||||
|
||||
if (isFixed[collisionIndex]) {
|
||||
// can't do anything about this name.
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var newName = name + suffix;
|
||||
suffix++;
|
||||
|
||||
// Check if we've synthesized a unique name, and if so
|
||||
// replace the conflicting name with the new one.
|
||||
if (!proposedNames.some(name => Utilities.stringEquals(name, newName, isCaseSensitive))) {
|
||||
proposedNames[collisionIndex] = newName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Utilities {
|
||||
/// Return a list of all indices where a string occurs.
|
||||
export function collectMatchingIndices(name: string, proposedNames: string[], isCaseSensitive: boolean): number[] {
|
||||
var matchingIndices: number[] = [];
|
||||
|
||||
for (var i = 0; i < proposedNames.length; i++) {
|
||||
if (stringEquals(name, proposedNames[i], isCaseSensitive)) {
|
||||
matchingIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingIndices;
|
||||
}
|
||||
|
||||
export function stringEquals(s1: string, s2: string, caseSensitive: boolean): boolean {
|
||||
if (caseSensitive) {
|
||||
s1 = s1.toLowerCase();
|
||||
s2 = s2.toLowerCase();
|
||||
}
|
||||
|
||||
return s1 == s2;
|
||||
}
|
||||
|
||||
// Like Object.keys
|
||||
export function getObjectKeys(obj: any): string[] {
|
||||
var result: string[] = [];
|
||||
|
||||
for (var name in obj) {
|
||||
if (obj.hasOwnProperty(name)) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -34,6 +34,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
|||
switch (methodName) {
|
||||
case "apply":
|
||||
case "assert":
|
||||
case "assertEqual":
|
||||
case "call":
|
||||
case "equal":
|
||||
case "fail":
|
||||
|
@ -69,7 +70,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
|||
|
||||
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
|
||||
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
|
||||
ctx.addFailureAtNode(arg, "Tag boolean argument with parameter name");
|
||||
ctx.addFailureAtNode(arg, "Tag argument with parameter name");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(ctx.sourceFile, function recur(node) {
|
||||
if (ts.isCallExpression(node)) {
|
||||
checkCall(node);
|
||||
}
|
||||
ts.forEachChild(node, recur);
|
||||
});
|
||||
|
||||
function checkCall(node: ts.CallExpression) {
|
||||
if (!isDebugAssert(node.expression) || node.arguments.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = node.arguments[1];
|
||||
if (!ts.isStringLiteral(message)) {
|
||||
ctx.addFailureAtNode(message, "Second argument to 'Debug.assert' should be a string literal.");
|
||||
}
|
||||
|
||||
if (node.arguments.length < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message2 = node.arguments[2];
|
||||
if (!ts.isStringLiteral(message2) && !ts.isArrowFunction(message2)) {
|
||||
ctx.addFailureAtNode(message, "Third argument to 'Debug.assert' should be a string literal or arrow function.");
|
||||
}
|
||||
}
|
||||
|
||||
function isDebugAssert(expr: ts.Node): boolean {
|
||||
return ts.isPropertyAccessExpression(expr) && isName(expr.expression, "Debug") && isName(expr.name, "assert");
|
||||
}
|
||||
|
||||
function isName(expr: ts.Node, text: string): boolean {
|
||||
return ts.isIdentifier(expr) && expr.text === text;
|
||||
}
|
||||
}
|
|
@ -13,13 +13,5 @@ declare module "gulp-insert" {
|
|||
export function transform(cb: (contents: string, file: {path: string, relative: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
|
||||
}
|
||||
|
||||
declare module "into-stream" {
|
||||
function IntoStream(content: string | Buffer | (string | Buffer)[]): NodeJS.ReadableStream;
|
||||
namespace IntoStream {
|
||||
export function obj(content: any): NodeJS.ReadableStream
|
||||
}
|
||||
export = IntoStream;
|
||||
}
|
||||
|
||||
declare module "sorcery";
|
||||
declare module "travis-fold";
|
||||
|
|
|
@ -806,11 +806,7 @@ namespace ts {
|
|||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowCondition>{
|
||||
flags,
|
||||
expression,
|
||||
antecedent
|
||||
};
|
||||
return { flags, expression, antecedent };
|
||||
}
|
||||
|
||||
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
|
||||
|
@ -818,31 +814,18 @@ namespace ts {
|
|||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowSwitchClause>{
|
||||
flags: FlowFlags.SwitchClause,
|
||||
switchStatement,
|
||||
clauseStart,
|
||||
clauseEnd,
|
||||
antecedent
|
||||
};
|
||||
return { flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent };
|
||||
}
|
||||
|
||||
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowAssignment>{
|
||||
flags: FlowFlags.Assignment,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
return { flags: FlowFlags.Assignment, antecedent, node };
|
||||
}
|
||||
|
||||
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowArrayMutation>{
|
||||
flags: FlowFlags.ArrayMutation,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
const res: FlowArrayMutation = { flags: FlowFlags.ArrayMutation, antecedent, node };
|
||||
return res;
|
||||
}
|
||||
|
||||
function finishFlowLabel(flow: FlowLabel): FlowNode {
|
||||
|
@ -2784,7 +2767,6 @@ namespace ts {
|
|||
|
||||
function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const name = node.name;
|
||||
const initializer = node.initializer;
|
||||
const dotDotDotToken = node.dotDotDotToken;
|
||||
|
@ -2799,7 +2781,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.ParameterPropertyModifier) {
|
||||
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
|
||||
}
|
||||
|
||||
|
@ -2844,9 +2826,8 @@ namespace ts {
|
|||
|
||||
function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
@ -2921,7 +2902,10 @@ namespace ts {
|
|||
function computeCatchClause(node: CatchClause, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
|
||||
if (node.variableDeclaration && isBindingPattern(node.variableDeclaration.name)) {
|
||||
if (!node.variableDeclaration) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
else if (isBindingPattern(node.variableDeclaration.name)) {
|
||||
transformFlags |= TransformFlags.AssertES2015;
|
||||
}
|
||||
|
||||
|
@ -3187,11 +3171,10 @@ namespace ts {
|
|||
|
||||
function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const declarationListTransformFlags = node.declarationList.transformFlags;
|
||||
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
else {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -340,7 +340,6 @@ namespace ts {
|
|||
isTSConfigOnly: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl
|
||||
|
||||
},
|
||||
{
|
||||
// this option can only be specified in tsconfig.json
|
||||
|
@ -384,6 +383,12 @@ namespace ts {
|
|||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
|
||||
},
|
||||
{
|
||||
name: "preserveSymlinks",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Do_not_resolve_the_real_path_of_symlinks,
|
||||
},
|
||||
|
||||
// Source Maps
|
||||
{
|
||||
|
@ -1111,7 +1116,7 @@ namespace ts {
|
|||
if (option && typeof option.type !== "string") {
|
||||
const customOption = <CommandLineOptionOfCustomType>option;
|
||||
// Validate custom option type
|
||||
if (!customOption.type.has(text)) {
|
||||
if (!customOption.type.has(text.toLowerCase())) {
|
||||
errors.push(
|
||||
createDiagnosticForInvalidCustomType(
|
||||
customOption,
|
||||
|
@ -1446,14 +1451,10 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
else {
|
||||
// If no includes were specified, exclude common package folders and the outDir
|
||||
const specs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
|
||||
|
||||
const outDir = raw["compilerOptions"] && raw["compilerOptions"]["outDir"];
|
||||
if (outDir) {
|
||||
specs.push(outDir);
|
||||
excludeSpecs = [outDir];
|
||||
}
|
||||
excludeSpecs = specs;
|
||||
}
|
||||
|
||||
if (fileNames === undefined && includeSpecs === undefined) {
|
||||
|
@ -1810,7 +1811,7 @@ namespace ts {
|
|||
return value;
|
||||
}
|
||||
else if (typeof option.type !== "string") {
|
||||
return option.type.get(value);
|
||||
return option.type.get(typeof value === "string" ? value.toLowerCase() : value);
|
||||
}
|
||||
return normalizeNonListOptionValue(option, basePath, value);
|
||||
}
|
||||
|
@ -2015,23 +2016,13 @@ namespace ts {
|
|||
}
|
||||
|
||||
function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string) {
|
||||
const validSpecs: string[] = [];
|
||||
for (const spec of specs) {
|
||||
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
|
||||
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
|
||||
return specs.filter(spec => {
|
||||
const diag = specToDiagnostic(spec, allowTrailingRecursion);
|
||||
if (diag !== undefined) {
|
||||
errors.push(createDiagnostic(diag, spec));
|
||||
}
|
||||
else if (invalidMultipleRecursionPatterns.test(spec)) {
|
||||
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
|
||||
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else {
|
||||
validSpecs.push(spec);
|
||||
}
|
||||
}
|
||||
|
||||
return validSpecs;
|
||||
return diag === undefined;
|
||||
});
|
||||
|
||||
function createDiagnostic(message: DiagnosticMessage, spec: string): Diagnostic {
|
||||
if (jsonSourceFile && jsonSourceFile.jsonObject) {
|
||||
|
@ -2049,6 +2040,18 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function specToDiagnostic(spec: string, allowTrailingRecursion: boolean): ts.DiagnosticMessage | undefined {
|
||||
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
|
||||
return Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0;
|
||||
}
|
||||
else if (invalidMultipleRecursionPatterns.test(spec)) {
|
||||
return Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0;
|
||||
}
|
||||
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
|
||||
return Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets directories in a set of include patterns that should be watched for changes.
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ts {
|
|||
setWriter(writer: EmitTextWriter): void;
|
||||
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
|
||||
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
|
||||
emitTrailingCommentsOfPosition(pos: number): void;
|
||||
emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean): void;
|
||||
emitLeadingCommentsOfPosition(pos: number): void;
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentsOfPosition(pos: number) {
|
||||
function emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ namespace ts {
|
|||
performance.mark("beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingCommentOfPosition);
|
||||
forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : emitTrailingCommentOfPosition);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beforeEmitTrailingCommentsOfPosition");
|
||||
|
@ -415,17 +415,7 @@ namespace ts {
|
|||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
function isTripleSlashComment(commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (currentText.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
currentText.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = currentText.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
return isRecognizedTripleSlashComment(currentText, commentPos, commentEnd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,27 +4,13 @@
|
|||
namespace ts {
|
||||
// WARNING: The script `configureNightly.ts` uses a regexp to parse out these values.
|
||||
// If changing the text in this section, be sure to test `configureNightly` too.
|
||||
export const versionMajorMinor = "2.5";
|
||||
export const versionMajorMinor = "2.6";
|
||||
/** The version of the TypeScript compiler release */
|
||||
export const version = `${versionMajorMinor}.0`;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
/**
|
||||
* Ternary values are defined such that
|
||||
* x & y is False if either x or y is False.
|
||||
* x & y is Maybe if either x or y is Maybe, but neither x or y is False.
|
||||
* x & y is True if both x and y are True.
|
||||
* x | y is False if both x and y are False.
|
||||
* x | y is Maybe if either x or y is Maybe, but neither x or y is True.
|
||||
* x | y is True if either x or y is True.
|
||||
*/
|
||||
export const enum Ternary {
|
||||
False = 0,
|
||||
Maybe = 1,
|
||||
True = -1
|
||||
}
|
||||
|
||||
// More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times.
|
||||
export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator(/*locales*/ undefined, { usage: "sort", sensitivity: "accent" }) : undefined;
|
||||
|
@ -375,11 +361,11 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
|
||||
export function filterMutate<T>(array: T[], f: (x: T, i: number, array: T[]) => boolean): void {
|
||||
let outIndex = 0;
|
||||
for (const item of array) {
|
||||
if (f(item)) {
|
||||
array[outIndex] = item;
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (f(array[i], i, array)) {
|
||||
array[outIndex] = array[i];
|
||||
outIndex++;
|
||||
}
|
||||
}
|
||||
|
@ -515,13 +501,15 @@ namespace ts {
|
|||
return result || array;
|
||||
}
|
||||
|
||||
export function mapDefined<T, U>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => U | undefined): U[] {
|
||||
export function mapDefined<T, U>(array: ReadonlyArray<T> | undefined, mapFn: (x: T, i: number) => U | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const mapped = mapFn(item, i);
|
||||
if (mapped !== undefined) {
|
||||
result.push(mapped);
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const mapped = mapFn(item, i);
|
||||
if (mapped !== undefined) {
|
||||
result.push(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -711,7 +699,7 @@ namespace ts {
|
|||
* are not present in `arrayA` but are present in `arrayB`. Assumes both arrays are sorted
|
||||
* based on the provided comparer.
|
||||
*/
|
||||
export function relativeComplement<T>(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: (x: T, y: T) => Comparison = compareValues, offsetA = 0, offsetB = 0): T[] | undefined {
|
||||
export function relativeComplement<T>(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: Comparer<T> = compareValues, offsetA = 0, offsetB = 0): T[] | undefined {
|
||||
if (!arrayB || !arrayA || arrayB.length === 0 || arrayA.length === 0) return arrayB;
|
||||
const result: T[] = [];
|
||||
outer: for (; offsetB < arrayB.length; offsetB++) {
|
||||
|
@ -1304,12 +1292,12 @@ namespace ts {
|
|||
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic {
|
||||
const end = start + length;
|
||||
|
||||
Debug.assert(start >= 0, "start must be non-negative, is " + start);
|
||||
Debug.assert(length >= 0, "length must be non-negative, is " + length);
|
||||
Debug.assertGreaterThanOrEqual(start, 0);
|
||||
Debug.assertGreaterThanOrEqual(length, 0);
|
||||
|
||||
if (file) {
|
||||
Debug.assert(start <= file.text.length, `start must be within the bounds of the file. ${start} > ${file.text.length}`);
|
||||
Debug.assert(end <= file.text.length, `end must be the bounds of the file. ${end} > ${file.text.length}`);
|
||||
Debug.assertLessThanOrEqual(start, file.text.length);
|
||||
Debug.assertLessThanOrEqual(end, file.text.length);
|
||||
}
|
||||
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
|
@ -1555,16 +1543,20 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function normalizePath(path: string): string {
|
||||
return normalizePathAndParts(path).path;
|
||||
}
|
||||
|
||||
export function normalizePathAndParts(path: string): { path: string, parts: string[] } {
|
||||
path = normalizeSlashes(path);
|
||||
const rootLength = getRootLength(path);
|
||||
const root = path.substr(0, rootLength);
|
||||
const normalized = getNormalizedParts(path, rootLength);
|
||||
if (normalized.length) {
|
||||
const joinedParts = root + normalized.join(directorySeparator);
|
||||
return pathEndsWithDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts;
|
||||
const parts = getNormalizedParts(path, rootLength);
|
||||
if (parts.length) {
|
||||
const joinedParts = root + parts.join(directorySeparator);
|
||||
return { path: pathEndsWithDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts, parts };
|
||||
}
|
||||
else {
|
||||
return root;
|
||||
return { path: root, parts };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1889,14 +1881,54 @@ namespace ts {
|
|||
const reservedCharacterPattern = /[^\w\s\/]/g;
|
||||
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
|
||||
|
||||
/**
|
||||
* Matches any single directory segment unless it is the last segment and a .min.js file
|
||||
* Breakdown:
|
||||
* [^./] # matches everything up to the first . character (excluding directory seperators)
|
||||
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
|
||||
*/
|
||||
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
|
||||
const singleAsteriskRegexFragmentOther = "[^/]*";
|
||||
/* @internal */
|
||||
export const commonPackageFolders: ReadonlyArray<string> = ["node_modules", "bower_components", "jspm_packages"];
|
||||
|
||||
const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join("|")})(/|$))`;
|
||||
|
||||
interface WildcardMatcher {
|
||||
singleAsteriskRegexFragment: string;
|
||||
doubleAsteriskRegexFragment: string;
|
||||
replaceWildcardCharacter: (match: string) => string;
|
||||
}
|
||||
|
||||
const filesMatcher: WildcardMatcher = {
|
||||
/**
|
||||
* Matches any single directory segment unless it is the last segment and a .min.js file
|
||||
* Breakdown:
|
||||
* [^./] # matches everything up to the first . character (excluding directory seperators)
|
||||
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
|
||||
*/
|
||||
singleAsteriskRegexFragment: "([^./]|(\\.(?!min\\.js$))?)*",
|
||||
/**
|
||||
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
|
||||
* files or directories, does not match subdirectories that start with a . character
|
||||
*/
|
||||
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
|
||||
replaceWildcardCharacter: match => replaceWildcardCharacter(match, filesMatcher.singleAsteriskRegexFragment)
|
||||
};
|
||||
|
||||
const directoriesMatcher: WildcardMatcher = {
|
||||
singleAsteriskRegexFragment: "[^/]*",
|
||||
/**
|
||||
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
|
||||
* files or directories, does not match subdirectories that start with a . character
|
||||
*/
|
||||
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
|
||||
replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment)
|
||||
};
|
||||
|
||||
const excludeMatcher: WildcardMatcher = {
|
||||
singleAsteriskRegexFragment: "[^/]*",
|
||||
doubleAsteriskRegexFragment: "(/.+?)?",
|
||||
replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment)
|
||||
};
|
||||
|
||||
const wildcardMatchers = {
|
||||
files: filesMatcher,
|
||||
directories: directoriesMatcher,
|
||||
exclude: excludeMatcher
|
||||
};
|
||||
|
||||
export function getRegularExpressionForWildcard(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
|
||||
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
|
||||
|
@ -1915,17 +1947,8 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther;
|
||||
const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther;
|
||||
|
||||
/**
|
||||
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
|
||||
* files or directories, does not match subdirectories that start with a . character
|
||||
*/
|
||||
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
|
||||
|
||||
return flatMap(specs, spec =>
|
||||
spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter));
|
||||
spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1936,7 +1959,7 @@ namespace ts {
|
|||
return !/[.*?]/.test(lastPathComponent);
|
||||
}
|
||||
|
||||
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", singleAsteriskRegexFragment: string, doubleAsteriskRegexFragment: string, replaceWildcardCharacter: (match: string) => string): string | undefined {
|
||||
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined {
|
||||
let subpattern = "";
|
||||
let hasRecursiveDirectoryWildcard = false;
|
||||
let hasWrittenComponent = false;
|
||||
|
@ -1975,20 +1998,36 @@ namespace ts {
|
|||
}
|
||||
|
||||
if (usage !== "exclude") {
|
||||
let componentPattern = "";
|
||||
// The * and ? wildcards should not match directories or files that start with . if they
|
||||
// appear first in a component. Dotted directories and files can be included explicitly
|
||||
// like so: **/.*/.*
|
||||
if (component.charCodeAt(0) === CharacterCodes.asterisk) {
|
||||
subpattern += "([^./]" + singleAsteriskRegexFragment + ")?";
|
||||
componentPattern += "([^./]" + singleAsteriskRegexFragment + ")?";
|
||||
component = component.substr(1);
|
||||
}
|
||||
else if (component.charCodeAt(0) === CharacterCodes.question) {
|
||||
subpattern += "[^./]";
|
||||
componentPattern += "[^./]";
|
||||
component = component.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
||||
componentPattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
||||
|
||||
// Patterns should not include subfolders like node_modules unless they are
|
||||
// explicitly included as part of the path.
|
||||
//
|
||||
// As an optimization, if the component pattern is the same as the component,
|
||||
// then there definitely were no wildcard characters and we do not need to
|
||||
// add the exclusion pattern.
|
||||
if (componentPattern !== component) {
|
||||
subpattern += implicitExcludePathRegexPattern;
|
||||
}
|
||||
|
||||
subpattern += componentPattern;
|
||||
}
|
||||
else {
|
||||
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
hasWrittenComponent = true;
|
||||
|
@ -2002,14 +2041,6 @@ namespace ts {
|
|||
return subpattern;
|
||||
}
|
||||
|
||||
function replaceWildCardCharacterFiles(match: string) {
|
||||
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentFiles);
|
||||
}
|
||||
|
||||
function replaceWildCardCharacterOther(match: string) {
|
||||
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentOther);
|
||||
}
|
||||
|
||||
function replaceWildcardCharacter(match: string, singleAsteriskRegexFragment: string) {
|
||||
return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match;
|
||||
}
|
||||
|
@ -2183,20 +2214,14 @@ namespace ts {
|
|||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
const allSupportedExtensions = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needAllExtensions = options && options.allowJs;
|
||||
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
|
||||
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
|
||||
}
|
||||
const extensions: string[] = allSupportedExtensions.slice(0);
|
||||
for (const extInfo of extraFileExtensions) {
|
||||
if (extensions.indexOf(extInfo.extension) === -1) {
|
||||
extensions.push(extInfo.extension);
|
||||
}
|
||||
}
|
||||
return extensions;
|
||||
return deduplicate([...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)]);
|
||||
}
|
||||
|
||||
export function hasJavaScriptFileExtension(fileName: string) {
|
||||
|
@ -2364,15 +2389,40 @@ namespace ts {
|
|||
return currentAssertionLevel >= level;
|
||||
}
|
||||
|
||||
export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string, stackCrawlMark?: Function): void {
|
||||
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: Function): void {
|
||||
if (!expression) {
|
||||
if (verboseDebugInfo) {
|
||||
message += "\r\nVerbose Debug Information: " + verboseDebugInfo();
|
||||
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
|
||||
}
|
||||
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
|
||||
if (a !== b) {
|
||||
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
|
||||
fail(`Expected ${a} === ${b}. ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThan(a: number, b: number, msg?: string): void {
|
||||
if (a >= b) {
|
||||
fail(`Expected ${a} < ${b}. ${msg || ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThanOrEqual(a: number, b: number): void {
|
||||
if (a > b) {
|
||||
fail(`Expected ${a} <= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertGreaterThanOrEqual(a: number, b: number): void {
|
||||
if (a < b) {
|
||||
fail(`Expected ${a} >= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function fail(message?: string, stackCrawlMark?: Function): void {
|
||||
debugger;
|
||||
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");
|
||||
|
@ -2538,6 +2588,11 @@ namespace ts {
|
|||
}
|
||||
Debug.fail(`File ${path} has unknown extension.`);
|
||||
}
|
||||
|
||||
export function isAnySupportedFileExtension(path: string): boolean {
|
||||
return tryGetExtensionFromPath(path) !== undefined;
|
||||
}
|
||||
|
||||
export function tryGetExtensionFromPath(path: string): Extension | undefined {
|
||||
return find<Extension>(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
|
||||
}
|
||||
|
|
|
@ -349,7 +349,6 @@ namespace ts {
|
|||
errorNameNode = declaration.name;
|
||||
const format = TypeFormatFlags.UseTypeOfFunction |
|
||||
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
|
||||
TypeFormatFlags.UseTypeAliasValue |
|
||||
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
|
||||
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
|
||||
errorNameNode = undefined;
|
||||
|
@ -368,7 +367,7 @@ namespace ts {
|
|||
resolver.writeReturnTypeOfSignatureDeclaration(
|
||||
signature,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
errorNameNode = undefined;
|
||||
}
|
||||
|
@ -633,7 +632,7 @@ namespace ts {
|
|||
resolver.writeTypeOfExpression(
|
||||
expr,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
write(";");
|
||||
writeLine();
|
||||
|
@ -1367,6 +1366,10 @@ namespace ts {
|
|||
}
|
||||
|
||||
function writeVariableStatement(node: VariableStatement) {
|
||||
// If binding pattern doesn't have name, then there is nothing to be emitted for declaration file i.e. const [,] = [1,2].
|
||||
if (every(node.declarationList && node.declarationList.declarations, decl => decl.name && isEmptyBindingPattern(decl.name))) {
|
||||
return;
|
||||
}
|
||||
emitJsDocComments(node);
|
||||
emitModuleElementDeclarationFlags(node);
|
||||
if (isLet(node.declarationList)) {
|
||||
|
|
|
@ -1908,6 +1908,14 @@
|
|||
"category": "Error",
|
||||
"code": 2559
|
||||
},
|
||||
"Value of type '{0}' has no properties in common with type '{1}'. Did you mean to call it?": {
|
||||
"category": "Error",
|
||||
"code": 2560
|
||||
},
|
||||
"Base class expressions cannot reference class type parameters.": {
|
||||
"category": "Error",
|
||||
"code": 2561
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
|
@ -2192,6 +2200,10 @@
|
|||
"category": "Error",
|
||||
"code": 2712
|
||||
},
|
||||
"Cannot access '{0}.{1}' because '{0}' is a type, but not a namespace. Did you mean to retrieve the type of the property '{1}' in '{0}' with '{0}[\"{1}\"]'?": {
|
||||
"category": "Error",
|
||||
"code": 2713
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
@ -2654,6 +2666,10 @@
|
|||
"category": "Message",
|
||||
"code": 6012
|
||||
},
|
||||
"Do not resolve the real path of symlinks.": {
|
||||
"category": "Message",
|
||||
"code": 6013
|
||||
},
|
||||
"Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'.": {
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
|
@ -3455,6 +3471,10 @@
|
|||
"category": "Error",
|
||||
"code": 8012
|
||||
},
|
||||
"'non-null assertions' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8013
|
||||
},
|
||||
"'enum declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8015
|
||||
|
@ -3653,6 +3673,10 @@
|
|||
"category": "Message",
|
||||
"code": 90025
|
||||
},
|
||||
"Rewrite as the indexed access type '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 90026
|
||||
},
|
||||
|
||||
"Convert function to an ES2015 class": {
|
||||
"category": "Message",
|
||||
|
@ -3661,5 +3685,15 @@
|
|||
"Convert function '{0}' to class": {
|
||||
"category": "Message",
|
||||
"code": 95002
|
||||
},
|
||||
|
||||
"Extract function": {
|
||||
"category": "Message",
|
||||
"code": 95003
|
||||
},
|
||||
|
||||
"Extract function into '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95004
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1195,7 +1195,9 @@ namespace ts {
|
|||
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
|
||||
const dotRangeStart = node.expression.end;
|
||||
const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1;
|
||||
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
|
||||
const dotToken = createToken(SyntaxKind.DotToken);
|
||||
dotToken.pos = dotRangeStart;
|
||||
dotToken.end = dotRangeEnd;
|
||||
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
|
||||
indentAfterDot = needsIndentation(node, dotToken, node.name);
|
||||
}
|
||||
|
@ -1346,7 +1348,9 @@ namespace ts {
|
|||
|
||||
emitExpression(node.left);
|
||||
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
|
||||
emitLeadingCommentsOfPosition(node.operatorToken.pos);
|
||||
writeTokenNode(node.operatorToken);
|
||||
emitTrailingCommentsOfPosition(node.operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts
|
||||
increaseIndentIf(indentAfterOperator, " ");
|
||||
emitExpression(node.right);
|
||||
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
|
||||
|
@ -1570,8 +1574,20 @@ namespace ts {
|
|||
write(";");
|
||||
}
|
||||
|
||||
function emitTokenWithComment(token: SyntaxKind, pos: number, contextNode?: Node) {
|
||||
const node = contextNode && getParseTreeNode(contextNode);
|
||||
if (node && node.kind === contextNode.kind) {
|
||||
pos = skipTrivia(currentSourceFile.text, pos);
|
||||
}
|
||||
pos = writeToken(token, pos, /*contextNode*/ contextNode);
|
||||
if (node && node.kind === contextNode.kind) {
|
||||
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ true);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
function emitReturnStatement(node: ReturnStatement) {
|
||||
writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
|
||||
emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
|
||||
emitExpressionWithPrefix(" ", node.expression);
|
||||
write(";");
|
||||
}
|
||||
|
@ -2131,10 +2147,12 @@ namespace ts {
|
|||
function emitCatchClause(node: CatchClause) {
|
||||
const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos);
|
||||
write(" ");
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos);
|
||||
emit(node.variableDeclaration);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos);
|
||||
write(" ");
|
||||
if (node.variableDeclaration) {
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos);
|
||||
emit(node.variableDeclaration);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration.end);
|
||||
write(" ");
|
||||
}
|
||||
emit(node.block);
|
||||
}
|
||||
|
||||
|
|
|
@ -2128,14 +2128,14 @@ namespace ts {
|
|||
: node;
|
||||
}
|
||||
|
||||
export function createCatchClause(variableDeclaration: string | VariableDeclaration, block: Block) {
|
||||
export function createCatchClause(variableDeclaration: string | VariableDeclaration | undefined, block: Block) {
|
||||
const node = <CatchClause>createSynthesizedNode(SyntaxKind.CatchClause);
|
||||
node.variableDeclaration = typeof variableDeclaration === "string" ? createVariableDeclaration(variableDeclaration) : variableDeclaration;
|
||||
node.block = block;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration, block: Block) {
|
||||
export function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) {
|
||||
return node.variableDeclaration !== variableDeclaration
|
||||
|| node.block !== block
|
||||
? updateNode(createCatchClause(variableDeclaration, block), node)
|
||||
|
@ -2586,7 +2586,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticLeadingComments(node, append(getSyntheticLeadingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
return setSyntheticLeadingComments(node, append<SynthesizedComment>(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
|
@ -2600,7 +2600,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticTrailingComments(node, append(getSyntheticTrailingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
return setSyntheticTrailingComments(node, append<SynthesizedComment>(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,13 +13,32 @@ namespace ts {
|
|||
return compilerOptions.traceResolution && host.trace !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of trying to resolve a module.
|
||||
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
|
||||
*/
|
||||
/** Array that is only intended to be pushed to, never read. */
|
||||
/* @internal */
|
||||
export interface Push<T> {
|
||||
push(value: T): void;
|
||||
}
|
||||
|
||||
function withPackageId(packageId: PackageId | undefined, r: PathAndExtension | undefined): Resolved {
|
||||
return r && { path: r.path, extension: r.ext, packageId };
|
||||
}
|
||||
|
||||
function noPackageId(r: PathAndExtension | undefined): Resolved {
|
||||
return withPackageId(/*packageId*/ undefined, r);
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module. */
|
||||
interface Resolved {
|
||||
path: string;
|
||||
extension: Extension;
|
||||
packageId: PackageId | undefined;
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
|
||||
interface PathAndExtension {
|
||||
path: string;
|
||||
// (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
|
||||
ext: Extension;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +62,7 @@ namespace ts {
|
|||
|
||||
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
|
||||
return {
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
|
||||
failedLookupLocations
|
||||
};
|
||||
}
|
||||
|
@ -54,9 +73,16 @@ namespace ts {
|
|||
traceEnabled: boolean;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
version?: string;
|
||||
typings?: string;
|
||||
types?: string;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
||||
function tryReadPackageJsonFields(readTypes: boolean, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
||||
|
||||
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
||||
|
@ -83,7 +109,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
|
||||
function readJson(path: string, host: ModuleResolutionHost): PackageJson {
|
||||
try {
|
||||
const jsonText = host.readFile(path);
|
||||
return jsonText ? JSON.parse(jsonText) : {};
|
||||
|
@ -174,7 +200,10 @@ namespace ts {
|
|||
|
||||
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
if (resolved) {
|
||||
resolved = realpath(resolved, host, traceEnabled);
|
||||
if (!options.preserveSymlinks) {
|
||||
resolved = realPath(resolved, host, traceEnabled);
|
||||
}
|
||||
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved, primary);
|
||||
}
|
||||
|
@ -646,7 +675,7 @@ namespace ts {
|
|||
if (extension !== undefined) {
|
||||
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
if (path !== undefined) {
|
||||
return { path, extension };
|
||||
return { path, extension, packageId: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -678,7 +707,7 @@ namespace ts {
|
|||
const { resolvedModule, failedLookupLocations } =
|
||||
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ts.ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
if (!resolvedModule) {
|
||||
throw new Error(`Could not resolve JS module ${moduleName} starting at ${initialDir}. Looked in: ${failedLookupLocations.join(", ")}`);
|
||||
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
|
||||
}
|
||||
return resolvedModule.resolvedFileName;
|
||||
}
|
||||
|
@ -708,18 +737,25 @@ namespace ts {
|
|||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
|
||||
}
|
||||
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
|
||||
if (!resolved) return undefined;
|
||||
|
||||
let resolvedValue = resolved.value;
|
||||
if (!compilerOptions.preserveSymlinks) {
|
||||
resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension };
|
||||
}
|
||||
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
|
||||
return resolved && { value: resolved.value && { resolved: { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }, isExternalLibraryImport: true } };
|
||||
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
|
||||
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
||||
return resolved && toSearchResult({ resolved, isExternalLibraryImport: false });
|
||||
// Treat explicit "node_modules" import as an external library import.
|
||||
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function realpath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
if (!host.realpath) {
|
||||
return path;
|
||||
}
|
||||
|
@ -747,7 +783,7 @@ namespace ts {
|
|||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
return resolvedFromFile;
|
||||
return noPackageId(resolvedFromFile);
|
||||
}
|
||||
}
|
||||
if (!onlyRecordFailures) {
|
||||
|
@ -768,11 +804,15 @@ namespace ts {
|
|||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
|
||||
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
|
||||
*/
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedByAddingExtension) {
|
||||
|
@ -792,7 +832,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
|
@ -810,9 +850,9 @@ namespace ts {
|
|||
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
|
||||
}
|
||||
|
||||
function tryExtension(extension: Extension): Resolved | undefined {
|
||||
const path = tryFile(candidate + extension, failedLookupLocations, onlyRecordFailures, state);
|
||||
return path && { path, extension };
|
||||
function tryExtension(ext: Extension): PathAndExtension | undefined {
|
||||
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
|
||||
return path && { path, ext };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,12 +878,23 @@ namespace ts {
|
|||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
|
||||
|
||||
let packageId: PackageId | undefined;
|
||||
|
||||
if (considerPackageJson) {
|
||||
const packageJsonPath = pathToPackageJson(candidate);
|
||||
if (directoryExists && state.host.fileExists(packageJsonPath)) {
|
||||
const fromPackageJson = loadModuleFromPackageJson(packageJsonPath, extensions, candidate, failedLookupLocations, state);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
|
||||
if (typeof jsonContent.name === "string" && typeof jsonContent.version === "string") {
|
||||
packageId = { name: jsonContent.name, version: jsonContent.version };
|
||||
}
|
||||
|
||||
const fromPackageJson = loadModuleFromPackageJson(jsonContent, extensions, candidate, failedLookupLocations, state);
|
||||
if (fromPackageJson) {
|
||||
return fromPackageJson;
|
||||
return withPackageId(packageId, fromPackageJson);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -855,15 +906,11 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
|
||||
return withPackageId(packageId, loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state));
|
||||
}
|
||||
|
||||
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, packageJsonPath, candidate, state);
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -883,13 +930,18 @@ namespace ts {
|
|||
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
||||
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
||||
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
||||
return nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
if (result) {
|
||||
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
||||
Debug.assert(result.packageId === undefined);
|
||||
return { path: result.path, ext: result.extension };
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
|
||||
const extension = tryGetExtensionFromPath(path);
|
||||
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined {
|
||||
const ext = tryGetExtensionFromPath(path);
|
||||
return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined;
|
||||
}
|
||||
|
||||
/** True if `extension` is one of the supported `extensions`. */
|
||||
|
@ -911,7 +963,7 @@ namespace ts {
|
|||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
|
||||
return loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
return loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
|
||||
}
|
||||
|
||||
|
@ -996,7 +1048,7 @@ namespace ts {
|
|||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
|
||||
}
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1010,7 +1062,7 @@ namespace ts {
|
|||
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
|
||||
|
||||
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFile, failedLookupLocations, state);
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
|
||||
if (resolvedUsingSettings) {
|
||||
return { value: resolvedUsingSettings };
|
||||
}
|
||||
|
@ -1024,7 +1076,7 @@ namespace ts {
|
|||
return resolutionFromCache;
|
||||
}
|
||||
const searchName = normalizePath(combinePaths(directory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
});
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
|
@ -1036,7 +1088,7 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2061,7 +2061,7 @@ namespace ts {
|
|||
return <TemplateMiddle | TemplateTail>fragment;
|
||||
}
|
||||
|
||||
function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
|
||||
function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
|
||||
const node = <LiteralExpression>createNode(kind);
|
||||
const text = scanner.getTokenValue();
|
||||
node.text = text;
|
||||
|
@ -2611,11 +2611,31 @@ namespace ts {
|
|||
return token() === SyntaxKind.DotToken ? undefined : node;
|
||||
}
|
||||
|
||||
function parseLiteralTypeNode(): LiteralTypeNode {
|
||||
const node = <LiteralTypeNode>createNode(SyntaxKind.LiteralType);
|
||||
node.literal = parseSimpleUnaryExpression();
|
||||
finishNode(node);
|
||||
return node;
|
||||
function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
|
||||
const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode;
|
||||
let unaryMinusExpression: PrefixUnaryExpression;
|
||||
if (negative) {
|
||||
unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression;
|
||||
unaryMinusExpression.operator = SyntaxKind.MinusToken;
|
||||
nextToken();
|
||||
}
|
||||
let expression: UnaryExpression;
|
||||
switch (token()) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
expression = parseLiteralLikeNode(token()) as LiteralExpression;
|
||||
break;
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
expression = parseTokenNode();
|
||||
}
|
||||
if (negative) {
|
||||
unaryMinusExpression.operand = expression;
|
||||
finishNode(unaryMinusExpression);
|
||||
expression = unaryMinusExpression;
|
||||
}
|
||||
node.literal = expression;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function nextTokenIsNumericLiteral() {
|
||||
|
@ -2650,7 +2670,7 @@ namespace ts {
|
|||
case SyntaxKind.FalseKeyword:
|
||||
return parseLiteralTypeNode();
|
||||
case SyntaxKind.MinusToken:
|
||||
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode() : parseTypeReference();
|
||||
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
|
||||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
return parseTokenNode<TypeNode>();
|
||||
|
@ -2700,6 +2720,7 @@ namespace ts {
|
|||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.AsteriskToken:
|
||||
return true;
|
||||
case SyntaxKind.MinusToken:
|
||||
return lookAhead(nextTokenIsNumericLiteral);
|
||||
|
@ -3181,7 +3202,7 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const isAsync = !!(getModifierFlags(arrowFunction) & ModifierFlags.Async);
|
||||
const isAsync = hasModifier(arrowFunction, ModifierFlags.Async);
|
||||
|
||||
// If we have an arrow, then try to parse the body. Even if not, try to parse if we
|
||||
// have an opening brace, just in case we're in an error state.
|
||||
|
@ -3361,7 +3382,7 @@ namespace ts {
|
|||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
node.modifiers = parseModifiersForArrowFunction();
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
|
||||
// Arrow functions are never generators.
|
||||
//
|
||||
|
@ -4494,7 +4515,7 @@ namespace ts {
|
|||
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
|
||||
|
||||
const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
node.name =
|
||||
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
|
@ -4778,11 +4799,16 @@ namespace ts {
|
|||
function parseCatchClause(): CatchClause {
|
||||
const result = <CatchClause>createNode(SyntaxKind.CatchClause);
|
||||
parseExpected(SyntaxKind.CatchKeyword);
|
||||
if (parseExpected(SyntaxKind.OpenParenToken)) {
|
||||
|
||||
if (parseOptional(SyntaxKind.OpenParenToken)) {
|
||||
result.variableDeclaration = parseVariableDeclaration();
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
}
|
||||
else {
|
||||
// Keep shape of node to avoid degrading performance.
|
||||
result.variableDeclaration = undefined;
|
||||
}
|
||||
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
result.block = parseBlock(/*ignoreMissingOpenBrace*/ false);
|
||||
return finishNode(result);
|
||||
}
|
||||
|
@ -6143,7 +6169,7 @@ namespace ts {
|
|||
|
||||
export function parseIsolatedJSDocComment(content: string, start: number, length: number): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
|
||||
initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
|
||||
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content };
|
||||
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content }; // tslint:disable-line no-object-literal-type-assertion
|
||||
const jsDoc = parseJSDocCommentWorker(start, length);
|
||||
const diagnostics = parseDiagnostics;
|
||||
clearState();
|
||||
|
|
|
@ -472,6 +472,15 @@ namespace ts {
|
|||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader);
|
||||
}
|
||||
|
||||
// Map from a stringified PackageId to the source file with that id.
|
||||
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
|
||||
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
|
||||
const packageIdToSourceFile = createMap<SourceFile>();
|
||||
// Maps from a SourceFile's `.path` to the name of the package it was imported with.
|
||||
let sourceFileToPackageName = createMap<string>();
|
||||
// See `sourceFileIsRedirectedTo`.
|
||||
let redirectTargetsSet = createMap<true>();
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
|
@ -548,6 +557,8 @@ namespace ts {
|
|||
isSourceFileFromExternalLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
|
@ -773,8 +784,12 @@ namespace ts {
|
|||
const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
|
||||
oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
|
||||
for (const oldSourceFile of oldProgram.getSourceFiles()) {
|
||||
const newSourceFile = host.getSourceFileByPath
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
const enum SeenPackageName { Exists, Modified }
|
||||
const seenPackageNames = createMap<SeenPackageName>();
|
||||
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
|
||||
|
@ -782,10 +797,46 @@ namespace ts {
|
|||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
|
||||
|
||||
let fileChanged: boolean;
|
||||
if (oldSourceFile.redirectInfo) {
|
||||
// We got `newSourceFile` by path, so it is actually for the unredirected file.
|
||||
// This lets us know if the unredirected file has changed. If it has we should break the redirect.
|
||||
if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
|
||||
// Underlying file has changed. Might not redirect anymore. Must rebuild program.
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
newSourceFile = oldSourceFile; // Use the redirect.
|
||||
}
|
||||
else if (oldProgram.redirectTargetsSet.has(oldSourceFile.path)) {
|
||||
// If a redirected-to source file changes, the redirect may be broken.
|
||||
if (newSourceFile !== oldSourceFile) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
}
|
||||
else {
|
||||
fileChanged = newSourceFile !== oldSourceFile;
|
||||
}
|
||||
|
||||
newSourceFile.path = oldSourceFile.path;
|
||||
filePaths.push(newSourceFile.path);
|
||||
|
||||
if (oldSourceFile !== newSourceFile) {
|
||||
const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
|
||||
if (packageName !== undefined) {
|
||||
// If there are 2 different source files for the same package name and at least one of them changes,
|
||||
// they might become redirects. So we must rebuild the program.
|
||||
const prevKind = seenPackageNames.get(packageName);
|
||||
const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
|
||||
if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
seenPackageNames.set(packageName, newKind);
|
||||
}
|
||||
|
||||
if (fileChanged) {
|
||||
// The `newSourceFile` object was created for the new program.
|
||||
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
|
@ -897,6 +948,9 @@ namespace ts {
|
|||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
redirectTargetsSet = oldProgram.redirectTargetsSet;
|
||||
|
||||
return oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
}
|
||||
|
||||
|
@ -1196,10 +1250,14 @@ namespace ts {
|
|||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
const typeAssertionExpression = <TypeAssertion>node;
|
||||
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
case SyntaxKind.NonNullExpression:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.non_null_assertions_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.AsExpression:
|
||||
diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX.
|
||||
}
|
||||
|
||||
const prevParent = parent;
|
||||
|
@ -1533,7 +1591,7 @@ namespace ts {
|
|||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd),
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, /*packageId*/ undefined),
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
|
@ -1552,8 +1610,26 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path): SourceFile {
|
||||
const redirect: SourceFile = Object.create(redirectTarget);
|
||||
redirect.fileName = fileName;
|
||||
redirect.path = path;
|
||||
redirect.redirectInfo = { redirectTarget, unredirected };
|
||||
Object.defineProperties(redirect, {
|
||||
id: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.id; },
|
||||
set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo.redirectTarget.id = value; },
|
||||
},
|
||||
symbol: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.symbol; },
|
||||
set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo.redirectTarget.symbol = value; },
|
||||
},
|
||||
});
|
||||
return redirect;
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
|
@ -1596,6 +1672,26 @@ namespace ts {
|
|||
}
|
||||
});
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = `${packageId.name}@${packageId.version}`;
|
||||
const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
|
||||
if (fileFromPackageId) {
|
||||
// Some other SourceFile already exists with this package name and version.
|
||||
// Instead of creating a duplicate, just redirect to the existing one.
|
||||
const dupFile = createRedirectSourceFile(fileFromPackageId, file, fileName, path);
|
||||
redirectTargetsSet.set(fileFromPackageId.path, true);
|
||||
filesByName.set(path, dupFile);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
files.push(dupFile);
|
||||
return dupFile;
|
||||
}
|
||||
else if (file) {
|
||||
// This is the first source file to have this packageId.
|
||||
packageIdToSourceFile.set(packageIdKey, file);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
}
|
||||
}
|
||||
|
||||
filesByName.set(path, file);
|
||||
if (file) {
|
||||
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
|
||||
|
@ -1758,7 +1854,7 @@ namespace ts {
|
|||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
|
|
|
@ -4,6 +4,18 @@ declare function setTimeout(handler: (...args: any[]) => void, timeout: number):
|
|||
declare function clearTimeout(handle: any): void;
|
||||
|
||||
namespace ts {
|
||||
/**
|
||||
* Set a high stack trace limit to provide more information in case of an error.
|
||||
* Called for command-line and server use cases.
|
||||
* Not called if TypeScript is used as a library.
|
||||
*/
|
||||
/* @internal */
|
||||
export function setStackTraceLimit() {
|
||||
if ((Error as any).stackTraceLimit < 100) { // Also tests that we won't set the property if it doesn't exist.
|
||||
(Error as any).stackTraceLimit = 100;
|
||||
}
|
||||
}
|
||||
|
||||
export enum FileWatcherEventKind {
|
||||
Created,
|
||||
Changed,
|
||||
|
@ -141,7 +153,7 @@ namespace ts {
|
|||
return;
|
||||
}
|
||||
watcher = _fs.watch(
|
||||
dirPath,
|
||||
dirPath || ".",
|
||||
{ persistent: true },
|
||||
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
|
||||
);
|
||||
|
|
|
@ -331,11 +331,14 @@ namespace ts {
|
|||
location
|
||||
);
|
||||
}
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)
|
||||
|| every(elements, isOmittedExpression)) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
// Or all the elements of the binding pattern are omitted expression such as "var [,] = [1,2]",
|
||||
// then we will create temporary variable.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0;
|
||||
value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location);
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ namespace ts {
|
|||
function shouldVisitNode(node: Node): boolean {
|
||||
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|
||||
|| convertedLoopState !== undefined
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatement(node))
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|
||||
|| isTypeScriptClassWrapper(node);
|
||||
}
|
||||
|
@ -840,7 +840,7 @@ namespace ts {
|
|||
outer.end = skipTrivia(currentText, node.pos);
|
||||
setEmitFlags(outer, EmitFlags.NoComments);
|
||||
|
||||
return createParen(
|
||||
const result = createParen(
|
||||
createCall(
|
||||
outer,
|
||||
/*typeArguments*/ undefined,
|
||||
|
@ -849,6 +849,8 @@ namespace ts {
|
|||
: []
|
||||
)
|
||||
);
|
||||
addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class ");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2105,13 +2107,14 @@ namespace ts {
|
|||
setCommentRange(declarationList, node);
|
||||
|
||||
if (node.transformFlags & TransformFlags.ContainsBindingPattern
|
||||
&& (isBindingPattern(node.declarations[0].name)
|
||||
|| isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
// If the first or last declaration is a binding pattern, we need to modify
|
||||
// the source map range for the declaration list.
|
||||
const firstDeclaration = firstOrUndefined(declarations);
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
if (firstDeclaration) {
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
}
|
||||
}
|
||||
|
||||
return declarationList;
|
||||
|
@ -2491,7 +2494,7 @@ namespace ts {
|
|||
const catchVariable = getGeneratedNameForNode(errorRecord);
|
||||
const returnMethod = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const values = createValuesHelper(context, expression, node.expression);
|
||||
const next = createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, []);
|
||||
const next = createCall(createPropertyAccess(iterator, "next"), /*typeArguments*/ undefined, []);
|
||||
|
||||
hoistVariableDeclaration(errorRecord);
|
||||
hoistVariableDeclaration(returnMethod);
|
||||
|
@ -3173,6 +3176,7 @@ namespace ts {
|
|||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
|
||||
let updated: CatchClause;
|
||||
Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015.");
|
||||
if (isBindingPattern(node.variableDeclaration.name)) {
|
||||
const temp = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const newVariableDeclaration = createVariableDeclaration(temp);
|
||||
|
|
|
@ -101,6 +101,8 @@ namespace ts {
|
|||
return visitExpressionStatement(node as ExpressionStatement);
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
@ -212,6 +214,17 @@ namespace ts {
|
|||
return visitEachChild(node, noDestructuringValue ? visitorNoDestructuringValue : visitor, context);
|
||||
}
|
||||
|
||||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
if (!node.variableDeclaration) {
|
||||
return updateCatchClause(
|
||||
node,
|
||||
createVariableDeclaration(createTempVariable(/*recordTempVariable*/ undefined)),
|
||||
visitNode(node.block, visitor, isBlock)
|
||||
);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a BinaryExpression that contains a destructuring assignment.
|
||||
*
|
||||
|
|
|
@ -164,12 +164,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
// A generated code block
|
||||
interface CodeBlock {
|
||||
kind: CodeBlockKind;
|
||||
}
|
||||
type CodeBlock = | ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock;
|
||||
|
||||
// a generated exception block, used for 'try' statements
|
||||
interface ExceptionBlock extends CodeBlock {
|
||||
interface ExceptionBlock {
|
||||
kind: CodeBlockKind.Exception;
|
||||
state: ExceptionBlockState;
|
||||
startLabel: Label;
|
||||
catchVariable?: Identifier;
|
||||
|
@ -179,27 +178,31 @@ namespace ts {
|
|||
}
|
||||
|
||||
// A generated code that tracks the target for 'break' statements in a LabeledStatement.
|
||||
interface LabeledBlock extends CodeBlock {
|
||||
interface LabeledBlock {
|
||||
kind: CodeBlockKind.Labeled;
|
||||
labelText: string;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the target for 'break' statements in a 'switch' statement
|
||||
interface SwitchBlock extends CodeBlock {
|
||||
interface SwitchBlock {
|
||||
kind: CodeBlockKind.Switch;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the targets for 'break' and 'continue' statements, used for iteration statements
|
||||
interface LoopBlock extends CodeBlock {
|
||||
interface LoopBlock {
|
||||
kind: CodeBlockKind.Loop;
|
||||
continueLabel: Label;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block associated with a 'with' statement
|
||||
interface WithBlock extends CodeBlock {
|
||||
interface WithBlock {
|
||||
kind: CodeBlockKind.With;
|
||||
expression: Identifier;
|
||||
startLabel: Label;
|
||||
endLabel: Label;
|
||||
|
@ -2070,7 +2073,7 @@ namespace ts {
|
|||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<WithBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.With,
|
||||
expression,
|
||||
startLabel,
|
||||
|
@ -2087,10 +2090,6 @@ namespace ts {
|
|||
markLabel(block.endLabel);
|
||||
}
|
||||
|
||||
function isWithBlock(block: CodeBlock): block is WithBlock {
|
||||
return block.kind === CodeBlockKind.With;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block for a generated `try` statement.
|
||||
*/
|
||||
|
@ -2098,7 +2097,7 @@ namespace ts {
|
|||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<ExceptionBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Exception,
|
||||
state: ExceptionBlockState.Try,
|
||||
startLabel,
|
||||
|
@ -2188,10 +2187,6 @@ namespace ts {
|
|||
exception.state = ExceptionBlockState.Done;
|
||||
}
|
||||
|
||||
function isExceptionBlock(block: CodeBlock): block is ExceptionBlock {
|
||||
return block.kind === CodeBlockKind.Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block that supports `break` or `continue` statements that are defined in
|
||||
* the source tree and not from generated code.
|
||||
|
@ -2199,7 +2194,7 @@ namespace ts {
|
|||
* @param labelText Names from containing labeled statements.
|
||||
*/
|
||||
function beginScriptLoopBlock(): void {
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: true,
|
||||
breakLabel: -1,
|
||||
|
@ -2217,7 +2212,7 @@ namespace ts {
|
|||
*/
|
||||
function beginLoopBlock(continueLabel: Label): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: false,
|
||||
breakLabel,
|
||||
|
@ -2245,7 +2240,7 @@ namespace ts {
|
|||
*
|
||||
*/
|
||||
function beginScriptSwitchBlock(): void {
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: true,
|
||||
breakLabel: -1
|
||||
|
@ -2259,7 +2254,7 @@ namespace ts {
|
|||
*/
|
||||
function beginSwitchBlock(): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: false,
|
||||
breakLabel,
|
||||
|
@ -2280,7 +2275,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function beginScriptLabeledBlock(labelText: string) {
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: true,
|
||||
labelText,
|
||||
|
@ -2290,7 +2285,7 @@ namespace ts {
|
|||
|
||||
function beginLabeledBlock(labelText: string) {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: false,
|
||||
labelText,
|
||||
|
@ -2448,7 +2443,7 @@ namespace ts {
|
|||
* @param location An optional source map location for the statement.
|
||||
*/
|
||||
function createInlineBreak(label: Label, location?: TextRange): ReturnStatement {
|
||||
Debug.assert(label > 0, `Invalid label: ${label}`);
|
||||
Debug.assertLessThan(0, label, "Invalid label");
|
||||
return setTextRange(
|
||||
createReturn(
|
||||
createArrayLiteral([
|
||||
|
@ -2878,34 +2873,37 @@ namespace ts {
|
|||
for (; blockIndex < blockActions.length && blockOffsets[blockIndex] <= operationIndex; blockIndex++) {
|
||||
const block = blocks[blockIndex];
|
||||
const blockAction = blockActions[blockIndex];
|
||||
if (isExceptionBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
switch (block.kind) {
|
||||
case CodeBlockKind.Exception:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
}
|
||||
else if (isWithBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
case CodeBlockKind.With:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
}
|
||||
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
// default: do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace ts {
|
|||
compilerOptions.reactNamespace,
|
||||
tagName,
|
||||
objectProperties,
|
||||
filter(map(children, transformJsxChildToExpression), isDefined),
|
||||
mapDefined(children, transformJsxChildToExpression),
|
||||
node,
|
||||
location
|
||||
);
|
||||
|
|
|
@ -151,7 +151,17 @@ namespace ts {
|
|||
break;
|
||||
}
|
||||
|
||||
recordEmittedDeclarationInScope(node);
|
||||
// Record these declarations provided that they have a name.
|
||||
if ((node as ClassDeclaration | FunctionDeclaration).name) {
|
||||
recordEmittedDeclarationInScope(node as ClassDeclaration | FunctionDeclaration);
|
||||
}
|
||||
else {
|
||||
// These nodes should always have names unless they are default-exports;
|
||||
// however, class declaration parsing allows for undefined names, so syntactically invalid
|
||||
// programs may also have an undefined name.
|
||||
Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasModifier(node, ModifierFlags.Default));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2639,36 +2649,33 @@ namespace ts {
|
|||
/**
|
||||
* Records that a declaration was emitted in the current scope, if it was the first
|
||||
* declaration for the provided symbol.
|
||||
*
|
||||
* NOTE: if there is ever a transformation above this one, we may not be able to rely
|
||||
* on symbol names.
|
||||
*/
|
||||
function recordEmittedDeclarationInScope(node: Node) {
|
||||
const name = node.symbol && node.symbol.escapedName;
|
||||
if (name) {
|
||||
if (!currentScopeFirstDeclarationsOfName) {
|
||||
currentScopeFirstDeclarationsOfName = createUnderscoreEscapedMap<Node>();
|
||||
}
|
||||
function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) {
|
||||
if (!currentScopeFirstDeclarationsOfName) {
|
||||
currentScopeFirstDeclarationsOfName = createUnderscoreEscapedMap<Node>();
|
||||
}
|
||||
|
||||
if (!currentScopeFirstDeclarationsOfName.has(name)) {
|
||||
currentScopeFirstDeclarationsOfName.set(name, node);
|
||||
}
|
||||
const name = declaredNameInScope(node);
|
||||
if (!currentScopeFirstDeclarationsOfName.has(name)) {
|
||||
currentScopeFirstDeclarationsOfName.set(name, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a declaration is the first declaration with the same name emitted
|
||||
* in the current scope.
|
||||
* Determines whether a declaration is the first declaration with
|
||||
* the same name emitted in the current scope.
|
||||
*/
|
||||
function isFirstEmittedDeclarationInScope(node: Node) {
|
||||
function isFirstEmittedDeclarationInScope(node: ModuleDeclaration | EnumDeclaration) {
|
||||
if (currentScopeFirstDeclarationsOfName) {
|
||||
const name = node.symbol && node.symbol.escapedName;
|
||||
if (name) {
|
||||
return currentScopeFirstDeclarationsOfName.get(name) === node;
|
||||
}
|
||||
const name = declaredNameInScope(node);
|
||||
return currentScopeFirstDeclarationsOfName.get(name) === node;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String {
|
||||
Debug.assertNode(node.name, isIdentifier);
|
||||
return (node.name as Identifier).escapedText;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2746,7 +2753,7 @@ namespace ts {
|
|||
return createNotEmittedStatement(node);
|
||||
}
|
||||
|
||||
Debug.assert(isIdentifier(node.name), "TypeScript module should have an Identifier name.");
|
||||
Debug.assertNode(node.name, isIdentifier, "A TypeScript namespace should have an Identifier name.");
|
||||
enableSubstitutionForNamespaceExports();
|
||||
|
||||
const statements: Statement[] = [];
|
||||
|
|
|
@ -665,6 +665,8 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
ts.setStackTraceLimit();
|
||||
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
|
|
|
@ -999,6 +999,7 @@ namespace ts {
|
|||
export interface StringLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
/* @internal */ textSourceNode?: Identifier | StringLiteral | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms).
|
||||
/* @internal */ singleQuote?: boolean;
|
||||
}
|
||||
|
||||
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.
|
||||
|
@ -1808,7 +1809,7 @@ namespace ts {
|
|||
export interface CatchClause extends Node {
|
||||
kind: SyntaxKind.CatchClause;
|
||||
parent?: TryStatement;
|
||||
variableDeclaration: VariableDeclaration;
|
||||
variableDeclaration?: VariableDeclaration;
|
||||
block: Block;
|
||||
}
|
||||
|
||||
|
@ -2176,16 +2177,18 @@ namespace ts {
|
|||
locked?: boolean;
|
||||
}
|
||||
|
||||
export interface AfterFinallyFlow extends FlowNode, FlowLock {
|
||||
export interface AfterFinallyFlow extends FlowNodeBase, FlowLock {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface PreFinallyFlow extends FlowNode {
|
||||
export interface PreFinallyFlow extends FlowNodeBase {
|
||||
antecedent: FlowNode;
|
||||
lock: FlowLock;
|
||||
}
|
||||
|
||||
export interface FlowNode {
|
||||
export type FlowNode =
|
||||
| AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation;
|
||||
export interface FlowNodeBase {
|
||||
flags: FlowFlags;
|
||||
id?: number; // Node id used by flow type cache in checker
|
||||
}
|
||||
|
@ -2193,30 +2196,30 @@ namespace ts {
|
|||
// FlowStart represents the start of a control flow. For a function expression or arrow
|
||||
// function, the container property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
export interface FlowStart extends FlowNode {
|
||||
export interface FlowStart extends FlowNodeBase {
|
||||
container?: FunctionExpression | ArrowFunction | MethodDeclaration;
|
||||
}
|
||||
|
||||
// FlowLabel represents a junction with multiple possible preceding control flows.
|
||||
export interface FlowLabel extends FlowNode {
|
||||
export interface FlowLabel extends FlowNodeBase {
|
||||
antecedents: FlowNode[];
|
||||
}
|
||||
|
||||
// FlowAssignment represents a node that assigns a value to a narrowable reference,
|
||||
// i.e. an identifier or a dotted name that starts with an identifier or 'this'.
|
||||
export interface FlowAssignment extends FlowNode {
|
||||
export interface FlowAssignment extends FlowNodeBase {
|
||||
node: Expression | VariableDeclaration | BindingElement;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
// FlowCondition represents a condition that is known to be true or false at the
|
||||
// node's location in the control flow.
|
||||
export interface FlowCondition extends FlowNode {
|
||||
export interface FlowCondition extends FlowNodeBase {
|
||||
expression: Expression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface FlowSwitchClause extends FlowNode {
|
||||
export interface FlowSwitchClause extends FlowNodeBase {
|
||||
switchStatement: SwitchStatement;
|
||||
clauseStart: number; // Start index of case/default clause range
|
||||
clauseEnd: number; // End index of case/default clause range
|
||||
|
@ -2225,7 +2228,7 @@ namespace ts {
|
|||
|
||||
// FlowArrayMutation represents a node potentially mutates an array, i.e. an
|
||||
// operation of the form 'x.push(value)', 'x.unshift(value)' or 'x[n] = value'.
|
||||
export interface FlowArrayMutation extends FlowNode {
|
||||
export interface FlowArrayMutation extends FlowNodeBase {
|
||||
node: CallExpression | BinaryExpression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
@ -2255,6 +2258,17 @@ namespace ts {
|
|||
}
|
||||
|
||||
|
||||
/* @internal */
|
||||
export interface RedirectInfo {
|
||||
/** Source file this redirects to. */
|
||||
readonly redirectTarget: SourceFile;
|
||||
/**
|
||||
* Source file for the duplicate package. This will not be used by the Program,
|
||||
* but we need to keep this around so we can watch for changes in underlying.
|
||||
*/
|
||||
readonly unredirected: SourceFile;
|
||||
}
|
||||
|
||||
// Source files are declarations when they are external modules.
|
||||
export interface SourceFile extends Declaration {
|
||||
kind: SyntaxKind.SourceFile;
|
||||
|
@ -2265,6 +2279,13 @@ namespace ts {
|
|||
/* @internal */ path: Path;
|
||||
text: string;
|
||||
|
||||
/**
|
||||
* If two source files are for the same version of the same package, one will redirect to the other.
|
||||
* (See `createRedirectSourceFile` in program.ts.)
|
||||
* The redirect will have this set. The other will not have anything set, but see Program#sourceFileIsRedirectedTo.
|
||||
*/
|
||||
/* @internal */ redirectInfo?: RedirectInfo | undefined;
|
||||
|
||||
amdDependencies: AmdDependency[];
|
||||
moduleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
|
@ -2435,6 +2456,11 @@ namespace ts {
|
|||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
|
||||
|
||||
/** Given a source file, get the name of the package it was imported from. */
|
||||
/* @internal */ sourceFileToPackageName: Map<string>;
|
||||
/** Set of all source files that some other source file redirects to. */
|
||||
/* @internal */ redirectTargetsSet: Map<true>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -2542,6 +2568,15 @@ namespace ts {
|
|||
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
|
||||
getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined;
|
||||
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol | undefined;
|
||||
/**
|
||||
* If a symbol is a local symbol with an associated exported symbol, returns the exported symbol.
|
||||
* Otherwise returns its input.
|
||||
* For example, at `export type T = number;`:
|
||||
* - `getSymbolAtLocation` at the location `T` will return the exported symbol for `T`.
|
||||
* - But the result of `getSymbolsInScope` will contain the *local* symbol for `T`, not the exported symbol.
|
||||
* - Calling `getExportSymbolOfSymbol` on that local symbol will return the exported symbol.
|
||||
*/
|
||||
getExportSymbolOfSymbol(symbol: Symbol): Symbol;
|
||||
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
getTypeFromTypeNode(node: TypeNode): Type;
|
||||
|
@ -2606,9 +2641,8 @@ namespace ts {
|
|||
* Does not include properties of primitive types.
|
||||
*/
|
||||
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];
|
||||
|
||||
/* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags): Symbol | undefined;
|
||||
/* @internal */ getJsxNamespace(): string;
|
||||
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
|
||||
}
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
|
@ -2683,11 +2717,12 @@ namespace ts {
|
|||
UseFullyQualifiedType = 1 << 8, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
|
||||
InFirstTypeArgument = 1 << 9, // Writing first type argument of the instantiated type
|
||||
InTypeAlias = 1 << 10, // Writing type in type alias declaration
|
||||
UseTypeAliasValue = 1 << 11, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
|
||||
SuppressAnyReturnType = 1 << 12, // If the return type is any-like, don't offer a return type.
|
||||
AddUndefined = 1 << 13, // Add undefined to types of initialized, non-optional parameters
|
||||
WriteClassExpressionAsTypeLiteral = 1 << 14, // Write a type literal instead of (Anonymous class)
|
||||
InArrayType = 1 << 15, // Writing an array element type
|
||||
UseAliasDefinedOutsideCurrentScope = 1 << 16, // For a `type T = ... ` defined in a different file, write `T` instead of its value,
|
||||
// even though `T` can't be accessed in the current scope.
|
||||
}
|
||||
|
||||
export const enum SymbolFormatFlags {
|
||||
|
@ -2896,7 +2931,7 @@ namespace ts {
|
|||
|
||||
export interface Symbol {
|
||||
flags: SymbolFlags; // Symbol flags
|
||||
escapedName: __String; // Name of symbol
|
||||
escapedName: __String; // Name of symbol
|
||||
declarations?: Declaration[]; // Declarations associated with this symbol
|
||||
valueDeclaration?: Declaration; // First value declaration of the symbol
|
||||
members?: SymbolTable; // Class, interface or literal instance members
|
||||
|
@ -3067,6 +3102,7 @@ namespace ts {
|
|||
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
|
||||
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
|
||||
resolvedJsxElementAttributesType?: Type; // resolved element attributes type of a JSX openinglike element
|
||||
resolvedJsxElementAllAttributesType?: Type; // resolved all element attributes type of a JSX openinglike element
|
||||
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
|
||||
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
|
||||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
|
@ -3100,7 +3136,7 @@ namespace ts {
|
|||
/* @internal */
|
||||
ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains the anyFunctionType
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
/* @internal */
|
||||
JsxAttributes = 1 << 25, // Jsx attributes type
|
||||
|
@ -3317,6 +3353,11 @@ namespace ts {
|
|||
awaitedTypeOfType?: Type;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface SyntheticDefaultModuleType extends Type {
|
||||
syntheticType?: Type;
|
||||
}
|
||||
|
||||
export interface TypeVariable extends Type {
|
||||
/* @internal */
|
||||
resolvedBaseConstraint: Type;
|
||||
|
@ -3425,11 +3466,29 @@ namespace ts {
|
|||
AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ternary values are defined such that
|
||||
* x & y is False if either x or y is False.
|
||||
* x & y is Maybe if either x or y is Maybe, but neither x or y is False.
|
||||
* x & y is True if both x and y are True.
|
||||
* x | y is False if both x and y are False.
|
||||
* x | y is Maybe if either x or y is Maybe, but neither x or y is True.
|
||||
* x | y is True if either x or y is True.
|
||||
*/
|
||||
export const enum Ternary {
|
||||
False = 0,
|
||||
Maybe = 1,
|
||||
True = -1
|
||||
}
|
||||
|
||||
export type TypeComparer = (s: Type, t: Type, reportErrors?: boolean) => Ternary;
|
||||
|
||||
/* @internal */
|
||||
export interface InferenceContext extends TypeMapper {
|
||||
signature: Signature; // Generic signature for which inferences are made
|
||||
inferences: InferenceInfo[]; // Inferences made for each type parameter
|
||||
flags: InferenceFlags; // Inference flags
|
||||
compareTypes: TypeComparer; // Type comparer function
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -3559,6 +3618,7 @@ namespace ts {
|
|||
paths?: MapLike<string[]>;
|
||||
/*@internal*/ plugins?: PluginImport[];
|
||||
preserveConstEnums?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
project?: string;
|
||||
/* @internal */ pretty?: DiagnosticStyle;
|
||||
reactNamespace?: string;
|
||||
|
@ -3874,6 +3934,10 @@ namespace ts {
|
|||
readFile(fileName: string): string | undefined;
|
||||
trace?(s: string): void;
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
/**
|
||||
* Resolve a symbolic link.
|
||||
* @see https://nodejs.org/api/fs.html#fs_fs_realpathsync_path_options
|
||||
*/
|
||||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
|
@ -3889,18 +3953,14 @@ namespace ts {
|
|||
export interface ResolvedModule {
|
||||
/** Path of the file the module was resolved to. */
|
||||
resolvedFileName: string;
|
||||
/**
|
||||
* Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be a proper external module:
|
||||
* - be a .d.ts file
|
||||
* - use top level imports\exports
|
||||
* - don't use tripleslash references
|
||||
*/
|
||||
/** True if `resolvedFileName` comes from `node_modules`. */
|
||||
isExternalLibraryImport?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* ResolvedModule with an explicitly provided `extension` property.
|
||||
* Prefer this over `ResolvedModule`.
|
||||
* If changing this, remember to change `moduleResolutionIsEqualTo`.
|
||||
*/
|
||||
export interface ResolvedModuleFull extends ResolvedModule {
|
||||
/**
|
||||
|
@ -3908,6 +3968,22 @@ namespace ts {
|
|||
* This is optional for backwards-compatibility, but will be added if not provided.
|
||||
*/
|
||||
extension: Extension;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier with a package name and version.
|
||||
* If changing this, remember to change `packageIdIsEqual`.
|
||||
*/
|
||||
export interface PackageId {
|
||||
/**
|
||||
* Name of the package.
|
||||
* Should not include `@types`.
|
||||
* If accessing a non-index file, this should include its name e.g. "foo/bar".
|
||||
*/
|
||||
name: string;
|
||||
/** Version of the package, e.g. "1.2.3" */
|
||||
version: string;
|
||||
}
|
||||
|
||||
export const enum Extension {
|
||||
|
@ -4001,7 +4077,6 @@ namespace ts {
|
|||
ContainsBindingPattern = 1 << 23,
|
||||
ContainsYield = 1 << 24,
|
||||
ContainsHoistedDeclarationOrCompletion = 1 << 25,
|
||||
|
||||
ContainsDynamicImport = 1 << 26,
|
||||
|
||||
// Please leave this as 1 << 29.
|
||||
|
|
|
@ -27,20 +27,6 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function findDeclaration<T extends Declaration>(symbol: Symbol, predicate: (node: Declaration) => node is T): T | undefined;
|
||||
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined;
|
||||
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined {
|
||||
const declarations = symbol.declarations;
|
||||
if (declarations) {
|
||||
for (const declaration of declarations) {
|
||||
if (predicate(declaration)) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface StringSymbolWriter extends SymbolWriter {
|
||||
string(): string;
|
||||
}
|
||||
|
@ -112,19 +98,21 @@ namespace ts {
|
|||
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, resolvedTypeReferenceDirective);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean {
|
||||
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
|
||||
oldResolution.extension === newResolution.extension &&
|
||||
oldResolution.resolvedFileName === newResolution.resolvedFileName;
|
||||
oldResolution.resolvedFileName === newResolution.resolvedFileName &&
|
||||
packageIdIsEqual(oldResolution.packageId, newResolution.packageId);
|
||||
}
|
||||
|
||||
function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean {
|
||||
return a === b || a && b && a.name === b.name && a.version === b.version;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean {
|
||||
return oldResolution.resolvedFileName === newResolution.resolvedFileName && oldResolution.primary === newResolution.primary;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function hasChangesInResolutions<T>(
|
||||
names: ReadonlyArray<string>,
|
||||
newResolutions: ReadonlyArray<T>,
|
||||
|
@ -203,14 +191,6 @@ namespace ts {
|
|||
return `${file.fileName}(${loc.line + 1},${loc.character + 1})`;
|
||||
}
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
export function isDefined(value: any): boolean {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
export function getEndLinePosition(line: number, sourceFile: SourceFileLike): number {
|
||||
Debug.assert(line >= 0);
|
||||
const lineStarts = getLineStarts(sourceFile);
|
||||
|
@ -262,6 +242,32 @@ namespace ts {
|
|||
return !nodeIsMissing(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given comment is a triple-slash
|
||||
*
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
export function isRecognizedTripleSlashComment(text: string, commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (text.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
text.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = text.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashReferenceTypeReferenceDirectiveRegEx) ||
|
||||
textSubStr.match(defaultLibReferenceRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isPinnedComment(text: string, comment: CommentRange) {
|
||||
return text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, includeJsDoc?: boolean): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
|
@ -338,15 +344,20 @@ namespace ts {
|
|||
// or a (possibly escaped) quoted form of the original text if it's string-like.
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
return '"' + escapeText(node.text) + '"';
|
||||
if ((<StringLiteral>node).singleQuote) {
|
||||
return "'" + escapeText(node.text, CharacterCodes.singleQuote) + "'";
|
||||
}
|
||||
else {
|
||||
return '"' + escapeText(node.text, CharacterCodes.doubleQuote) + '"';
|
||||
}
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return "`" + escapeText(node.text) + "`";
|
||||
return "`" + escapeText(node.text, CharacterCodes.backtick) + "`";
|
||||
case SyntaxKind.TemplateHead:
|
||||
return "`" + escapeText(node.text) + "${";
|
||||
return "`" + escapeText(node.text, CharacterCodes.backtick) + "${";
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
return "}" + escapeText(node.text) + "${";
|
||||
return "}" + escapeText(node.text, CharacterCodes.backtick) + "${";
|
||||
case SyntaxKind.TemplateTail:
|
||||
return "}" + escapeText(node.text) + "`";
|
||||
return "}" + escapeText(node.text, CharacterCodes.backtick) + "`";
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return node.text;
|
||||
}
|
||||
|
@ -437,6 +448,7 @@ namespace ts {
|
|||
return isExternalModule(node) || compilerOptions.isolatedModules;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isBlockScope(node: Node, parentNode: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
|
@ -635,11 +647,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode: SourceFile) {
|
||||
return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
|
||||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNodeFromText(node: Node, text: string) {
|
||||
return getLeadingCommentRanges(text, node.pos);
|
||||
return node.kind !== SyntaxKind.JsxText ? getLeadingCommentRanges(sourceFileOfNode.text, node.pos) : undefined;
|
||||
}
|
||||
|
||||
export function getJSDocCommentRanges(node: Node, text: string) {
|
||||
|
@ -649,7 +657,7 @@ namespace ts {
|
|||
node.kind === SyntaxKind.ArrowFunction ||
|
||||
node.kind === SyntaxKind.ParenthesizedExpression) ?
|
||||
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
|
||||
getLeadingCommentRangesOfNodeFromText(node, text);
|
||||
getLeadingCommentRanges(text, node.pos);
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return filter(commentRanges, comment =>
|
||||
text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
|
@ -657,9 +665,10 @@ namespace ts {
|
|||
text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash);
|
||||
}
|
||||
|
||||
export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export let fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*<reference\s+types\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export let fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*<reference\s+types\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
const defaultLibReferenceRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/;
|
||||
|
||||
export function isPartOfTypeNode(node: Node): boolean {
|
||||
if (SyntaxKind.FirstTypeNode <= node.kind && node.kind <= SyntaxKind.LastTypeNode) {
|
||||
|
@ -922,21 +931,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function getContainingFunction(node: Node): FunctionLike {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node || isFunctionLike(node)) {
|
||||
return <FunctionLike>node;
|
||||
}
|
||||
}
|
||||
return findAncestor(node.parent, isFunctionLike);
|
||||
}
|
||||
|
||||
export function getContainingClass(node: Node): ClassLikeDeclaration {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node || isClassLike(node)) {
|
||||
return <ClassLikeDeclaration>node;
|
||||
}
|
||||
}
|
||||
return findAncestor(node.parent, isClassLike);
|
||||
}
|
||||
|
||||
export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {
|
||||
|
@ -1509,8 +1508,8 @@ namespace ts {
|
|||
parent.parent.kind === SyntaxKind.VariableStatement;
|
||||
const variableStatementNode =
|
||||
isInitializerOfVariableDeclarationInStatement ? parent.parent.parent :
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
if (variableStatementNode) {
|
||||
getJSDocCommentsAndTagsWorker(variableStatementNode);
|
||||
}
|
||||
|
@ -1624,7 +1623,7 @@ namespace ts {
|
|||
if (isInJavaScriptFile(node)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType ||
|
||||
forEach(getJSDocParameterTags(node),
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1781,7 +1780,8 @@ namespace ts {
|
|||
// Property name in binding element or import specifier
|
||||
return (<BindingElement | ImportSpecifier>parent).propertyName === node;
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
// Any name in an export specifier
|
||||
case SyntaxKind.JsxAttribute:
|
||||
// Any name in an export specifier or JSX Attribute
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1855,7 +1855,7 @@ namespace ts {
|
|||
|
||||
export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
|
||||
const simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
|
||||
const isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
|
||||
const isNoDefaultLibRegEx = new RegExp(defaultLibReferenceRegEx.source, "gim");
|
||||
if (simpleReferenceRegEx.test(comment)) {
|
||||
if (isNoDefaultLibRegEx.test(comment)) {
|
||||
return { isNoDefaultLib: true };
|
||||
|
@ -2077,10 +2077,6 @@ namespace ts {
|
|||
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
|
||||
}
|
||||
|
||||
export function getOriginalSourceFiles(sourceFiles: ReadonlyArray<SourceFile>) {
|
||||
return sameMap(sourceFiles, getOriginalSourceFile);
|
||||
}
|
||||
|
||||
export const enum Associativity {
|
||||
Left,
|
||||
Right
|
||||
|
@ -2365,7 +2361,9 @@ namespace ts {
|
|||
// the language service. These characters should be escaped when printing, and if any characters are added,
|
||||
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
|
||||
// There is no reason for this other than that JSON.stringify does not handle it either.
|
||||
const escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const doubleQuoteEscapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const backtickQuoteEscapedCharsRegExp = /[\\\`\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const escapedCharsMap = createMapFromTemplate({
|
||||
"\0": "\\0",
|
||||
"\t": "\\t",
|
||||
|
@ -2376,18 +2374,23 @@ namespace ts {
|
|||
"\n": "\\n",
|
||||
"\\": "\\\\",
|
||||
"\"": "\\\"",
|
||||
"\'": "\\\'",
|
||||
"\`": "\\\`",
|
||||
"\u2028": "\\u2028", // lineSeparator
|
||||
"\u2029": "\\u2029", // paragraphSeparator
|
||||
"\u0085": "\\u0085" // nextLine
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
|
||||
* but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine)
|
||||
* Note that this doesn't actually wrap the input in double quotes.
|
||||
*/
|
||||
export function escapeString(s: string): string {
|
||||
export function escapeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string {
|
||||
const escapedCharsRegExp =
|
||||
quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp :
|
||||
quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp :
|
||||
doubleQuoteEscapedCharsRegExp;
|
||||
return s.replace(escapedCharsRegExp, getReplacement);
|
||||
}
|
||||
|
||||
|
@ -2409,8 +2412,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
const nonAsciiCharacters = /[^\u0000-\u007F]/g;
|
||||
export function escapeNonAsciiString(s: string): string {
|
||||
s = escapeString(s);
|
||||
export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string {
|
||||
s = escapeString(s, quoteChar);
|
||||
// Replace non-ASCII characters with '\uNNNN' escapes if any exist.
|
||||
// Otherwise just return the original string.
|
||||
return nonAsciiCharacters.test(s) ?
|
||||
|
@ -2832,7 +2835,7 @@ namespace ts {
|
|||
//
|
||||
// var x = 10;
|
||||
if (node.pos === 0) {
|
||||
leadingComments = filter(getLeadingCommentRanges(text, node.pos), isPinnedComment);
|
||||
leadingComments = filter(getLeadingCommentRanges(text, node.pos), isPinnedCommentLocal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2878,9 +2881,8 @@ namespace ts {
|
|||
|
||||
return currentDetachedCommentInfo;
|
||||
|
||||
function isPinnedComment(comment: CommentRange) {
|
||||
return text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
|
||||
function isPinnedCommentLocal(comment: CommentRange) {
|
||||
return isPinnedComment(text, comment);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2986,8 +2988,12 @@ namespace ts {
|
|||
return getModifierFlags(node) !== ModifierFlags.None;
|
||||
}
|
||||
|
||||
export function hasModifier(node: Node, flags: ModifierFlags) {
|
||||
return (getModifierFlags(node) & flags) !== 0;
|
||||
export function hasModifier(node: Node, flags: ModifierFlags): boolean {
|
||||
return !!getSelectedModifierFlags(node, flags);
|
||||
}
|
||||
|
||||
export function getSelectedModifierFlags(node: Node, flags: ModifierFlags): ModifierFlags {
|
||||
return getModifierFlags(node) & flags;
|
||||
}
|
||||
|
||||
export function getModifierFlags(node: Node): ModifierFlags {
|
||||
|
@ -3073,24 +3079,6 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Returns false if this heritage clause element's expression contains something unsupported
|
||||
// (i.e. not a name or dotted name).
|
||||
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
|
||||
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
|
||||
}
|
||||
|
||||
function isSupportedExpressionWithTypeArgumentsRest(node: Expression): boolean {
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
return true;
|
||||
}
|
||||
else if (isPropertyAccessExpression(node)) {
|
||||
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
|
||||
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
|
||||
}
|
||||
|
@ -3227,81 +3215,6 @@ namespace ts {
|
|||
return carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a node and its subtree is simple enough to have its position
|
||||
* information ignored when emitting source maps in a destructuring assignment.
|
||||
*
|
||||
* @param node The expression to test.
|
||||
*/
|
||||
export function isSimpleExpression(node: Expression): boolean {
|
||||
return isSimpleExpressionWorker(node, 0);
|
||||
}
|
||||
|
||||
function isSimpleExpressionWorker(node: Expression, depth: number): boolean {
|
||||
if (depth <= 5) {
|
||||
const kind = node.kind;
|
||||
if (kind === SyntaxKind.StringLiteral
|
||||
|| kind === SyntaxKind.NumericLiteral
|
||||
|| kind === SyntaxKind.RegularExpressionLiteral
|
||||
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral
|
||||
|| kind === SyntaxKind.Identifier
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.SuperKeyword
|
||||
|| kind === SyntaxKind.TrueKeyword
|
||||
|| kind === SyntaxKind.FalseKeyword
|
||||
|| kind === SyntaxKind.NullKeyword) {
|
||||
return true;
|
||||
}
|
||||
else if (kind === SyntaxKind.PropertyAccessExpression) {
|
||||
return isSimpleExpressionWorker((<PropertyAccessExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ElementAccessExpression) {
|
||||
return isSimpleExpressionWorker((<ElementAccessExpression>node).expression, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ElementAccessExpression>node).argumentExpression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.PrefixUnaryExpression
|
||||
|| kind === SyntaxKind.PostfixUnaryExpression) {
|
||||
return isSimpleExpressionWorker((<PrefixUnaryExpression | PostfixUnaryExpression>node).operand, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.BinaryExpression) {
|
||||
return (<BinaryExpression>node).operatorToken.kind !== SyntaxKind.AsteriskAsteriskToken
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).left, depth + 1)
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).right, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ConditionalExpression) {
|
||||
return isSimpleExpressionWorker((<ConditionalExpression>node).condition, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenTrue, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenFalse, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.VoidExpression
|
||||
|| kind === SyntaxKind.TypeOfExpression
|
||||
|| kind === SyntaxKind.DeleteExpression) {
|
||||
return isSimpleExpressionWorker((<VoidExpression | TypeOfExpression | DeleteExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
return (<ArrayLiteralExpression>node).elements.length === 0;
|
||||
}
|
||||
else if (kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return (<ObjectLiteralExpression>node).properties.length === 0;
|
||||
}
|
||||
else if (kind === SyntaxKind.CallExpression) {
|
||||
if (!isSimpleExpressionWorker((<CallExpression>node).expression, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const argument of (<CallExpression>node).arguments) {
|
||||
if (!isSimpleExpressionWorker(argument, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an enum value as a string for debugging and debug assertions.
|
||||
*/
|
||||
|
@ -3374,24 +3287,6 @@ namespace ts {
|
|||
return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function getRangePos(range: TextRange | undefined) {
|
||||
return range ? range.pos : -1;
|
||||
}
|
||||
|
||||
export function getRangeEnd(range: TextRange | undefined) {
|
||||
return range ? range.end : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases (or decreases) a position by the provided amount.
|
||||
*
|
||||
* @param pos The position.
|
||||
* @param value The delta.
|
||||
*/
|
||||
export function movePos(pos: number, value: number) {
|
||||
return positionIsSynthesized(pos) ? -1 : pos + value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from the provided pos and end.
|
||||
*
|
||||
|
@ -3449,26 +3344,6 @@ namespace ts {
|
|||
return range.pos === range.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from a provided range with its end position collapsed to its
|
||||
* start position.
|
||||
*
|
||||
* @param range A TextRange.
|
||||
*/
|
||||
export function collapseRangeToStart(range: TextRange): TextRange {
|
||||
return isCollapsedRange(range) ? range : moveRangeEnd(range, range.pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from a provided range with its start position collapsed to its
|
||||
* end position.
|
||||
*
|
||||
* @param range A TextRange.
|
||||
*/
|
||||
export function collapseRangeToEnd(range: TextRange): TextRange {
|
||||
return isCollapsedRange(range) ? range : moveRangePos(range, range.end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange for a token at the provides start position.
|
||||
*
|
||||
|
@ -3532,31 +3407,6 @@ namespace ts {
|
|||
return node.initializer !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a node is merged with a class declaration in the same scope.
|
||||
*/
|
||||
export function isMergedWithClass(node: Node) {
|
||||
if (node.symbol) {
|
||||
for (const declaration of node.symbol.declarations) {
|
||||
if (declaration.kind === SyntaxKind.ClassDeclaration && declaration !== node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a node is the first declaration of its kind.
|
||||
*
|
||||
* @param node A Declaration node.
|
||||
* @param kind The SyntaxKind to find among related declarations.
|
||||
*/
|
||||
export function isFirstDeclarationOfKind(node: Node, kind: SyntaxKind) {
|
||||
return node.symbol && getDeclarationOfKind(node.symbol, kind) === node;
|
||||
}
|
||||
|
||||
export function isWatchSet(options: CompilerOptions) {
|
||||
// Firefox has Object.prototype.watch
|
||||
return options.watch && options.hasOwnProperty("watch");
|
||||
|
@ -3865,6 +3715,20 @@ namespace ts {
|
|||
return hasModifier(node, ModifierFlags.ParameterPropertyModifier) && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
export function isEmptyBindingPattern(node: BindingName): node is BindingPattern {
|
||||
if (isBindingPattern(node)) {
|
||||
return every(node.elements, isEmptyBindingElement);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isEmptyBindingElement(node: BindingElement): boolean {
|
||||
if (isOmittedExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
return isEmptyBindingPattern(node.name);
|
||||
}
|
||||
|
||||
function walkUpBindingElementsAndPatterns(node: Node): Node {
|
||||
while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) {
|
||||
node = node.parent;
|
||||
|
@ -5132,6 +4996,19 @@ namespace ts {
|
|||
return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return true;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
return (<PrefixUnaryExpression>expr).operator === SyntaxKind.PlusPlusToken ||
|
||||
(<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusMinusToken;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isExpressionKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.ConditionalExpression
|
||||
|| kind === SyntaxKind.YieldExpression
|
||||
|
@ -5346,7 +5223,17 @@ namespace ts {
|
|||
const kind = node.kind;
|
||||
return isStatementKindButNotDeclarationKind(kind)
|
||||
|| isDeclarationStatementKind(kind)
|
||||
|| kind === SyntaxKind.Block;
|
||||
|| isBlockStatement(node);
|
||||
}
|
||||
|
||||
function isBlockStatement(node: Node): node is Block {
|
||||
if (node.kind !== SyntaxKind.Block) return false;
|
||||
if (node.parent !== undefined) {
|
||||
if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !isFunctionBlock(node);
|
||||
}
|
||||
|
||||
// Module references
|
||||
|
|
|
@ -187,6 +187,9 @@ namespace FourSlash {
|
|||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
// The position of the end of the current selection, or -1 if nothing is selected
|
||||
public selectionEnd = -1;
|
||||
|
||||
public lastKnownMarker = "";
|
||||
|
||||
// The file that's currently 'opened'
|
||||
|
@ -433,11 +436,19 @@ namespace FourSlash {
|
|||
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker);
|
||||
this.goToPosition(start.position);
|
||||
this.selectionEnd = end.position;
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
this.currentCaretPosition += count;
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
// Opens a file given its 0-based index or fileName
|
||||
|
@ -451,7 +462,7 @@ namespace FourSlash {
|
|||
this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, shouldExist: boolean) {
|
||||
const startMarker = this.getMarkerByName(startMarkerName);
|
||||
const endMarker = this.getMarkerByName(endMarkerName);
|
||||
const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) =>
|
||||
|
@ -459,9 +470,9 @@ namespace FourSlash {
|
|||
|
||||
const exists = this.anyErrorInRange(predicate, startMarker, endMarker);
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, this.getAllDiagnostics());
|
||||
throw new Error(`Failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, this.getAllDiagnostics());
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,10 +494,11 @@ namespace FourSlash {
|
|||
}
|
||||
|
||||
private getAllDiagnostics(): ts.Diagnostic[] {
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => this.getDiagnostics(fileName));
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName =>
|
||||
ts.isAnySupportedFileExtension(fileName) ? this.getDiagnostics(fileName) : []);
|
||||
}
|
||||
|
||||
public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) {
|
||||
public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) {
|
||||
const marker: Marker = this.getMarkerByName(markerName);
|
||||
let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean;
|
||||
|
||||
|
@ -502,30 +514,15 @@ namespace FourSlash {
|
|||
const exists = this.anyErrorInRange(predicate, marker);
|
||||
const diagnostics = this.getAllDiagnostics();
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, diagnostics);
|
||||
throw new Error("Failure at marker: " + markerName);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, diagnostics);
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure at marker '${markerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) {
|
||||
|
||||
const errors = this.getDiagnostics(startMarker.fileName);
|
||||
let exists = false;
|
||||
|
||||
const startPos = startMarker.position;
|
||||
let endPos: number = undefined;
|
||||
if (endMarker !== undefined) {
|
||||
endPos = endMarker.position;
|
||||
}
|
||||
|
||||
errors.forEach(function (error: ts.Diagnostic) {
|
||||
if (predicate(error.start, error.start + error.length, startPos, endPos)) {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
return exists;
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker): boolean {
|
||||
return this.getDiagnostics(startMarker.fileName).some(({ start, length }) =>
|
||||
predicate(start, start + length, startMarker.position, endMarker === undefined ? undefined : endMarker.position));
|
||||
}
|
||||
|
||||
private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
|
||||
|
@ -550,6 +547,7 @@ namespace FourSlash {
|
|||
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!ts.isAnySupportedFileExtension(fileName)) return;
|
||||
const errors = this.getDiagnostics(fileName);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
|
@ -980,9 +978,9 @@ namespace FourSlash {
|
|||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
const { fileName, start, end } = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
const { isWriteAccess, isDefinition } = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
|
@ -1193,7 +1191,7 @@ namespace FourSlash {
|
|||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
) {
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
|
||||
|
@ -1789,19 +1787,16 @@ namespace FourSlash {
|
|||
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
|
||||
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
|
||||
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
for (let i = 0; i < edits.length - 1; i++) {
|
||||
const firstEditSpan = edits[i].span;
|
||||
const firstEditEnd = firstEditSpan.start + firstEditSpan.length;
|
||||
assert.isTrue(firstEditEnd <= edits[i + 1].span.start);
|
||||
}
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
edits = JSON.parse(JSON.stringify(edits));
|
||||
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
let runningOffset = 0;
|
||||
|
||||
for (const edit of edits) {
|
||||
const offsetStart = edit.span.start + runningOffset;
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
const offsetStart = edit.span.start;
|
||||
const offsetEnd = offsetStart + edit.span.length;
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
const editDelta = edit.newText.length - edit.span.length;
|
||||
|
@ -1816,8 +1811,13 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
|
||||
// this.languageService.getScriptLexicalStructure(fileName);
|
||||
|
||||
// Update positions of any future edits affected by this change
|
||||
for (let j = i + 1; j < edits.length; j++) {
|
||||
if (edits[j].span.start >= edits[i].span.start) {
|
||||
edits[j].span.start += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFormattingEdit) {
|
||||
|
@ -1901,7 +1901,7 @@ namespace FourSlash {
|
|||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
public goToRangeStart({fileName, start}: Range) {
|
||||
public goToRangeStart({ fileName, start }: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
}
|
||||
|
@ -2075,7 +2075,7 @@ namespace FourSlash {
|
|||
return result;
|
||||
}
|
||||
|
||||
private rangeText({fileName, start, end}: Range): string {
|
||||
private rangeText({ fileName, start, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
}
|
||||
|
||||
|
@ -2361,7 +2361,7 @@ namespace FourSlash {
|
|||
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" }`);
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
|
@ -2508,6 +2508,23 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifySpanOfEnclosingComment(negative: boolean, onlyMultiLineDiverges?: boolean) {
|
||||
const expected = !negative;
|
||||
const position = this.currentCaretPosition;
|
||||
const fileName = this.activeFile.fileName;
|
||||
const actual = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ false);
|
||||
const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ true);
|
||||
if (expected !== actual || onlyMultiLineDiverges === (actual === actualOnlyMultiLine)) {
|
||||
this.raiseError(`verifySpanOfEnclosingComment failed:
|
||||
position: '${position}'
|
||||
fileName: '${fileName}'
|
||||
onlyMultiLineDiverges: '${onlyMultiLineDiverges}'
|
||||
actual: '${actual}'
|
||||
actualOnlyMultiLine: '${actualOnlyMultiLine}'
|
||||
expected: '${expected}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check number of navigationItems which match both searchValue and matchKind,
|
||||
if a filename is passed in, limit the results to that file.
|
||||
|
@ -2736,6 +2753,30 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
private getSelection() {
|
||||
return ({
|
||||
pos: this.currentCaretPosition,
|
||||
end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd
|
||||
});
|
||||
}
|
||||
|
||||
public verifyRefactorAvailable(negative: boolean, name?: string, subName?: string) {
|
||||
const selection = this.getSelection();
|
||||
|
||||
let refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, selection) || [];
|
||||
if (name) {
|
||||
refactors = refactors.filter(r => r.name === name && (subName === undefined || r.actions.some(a => a.name === subName)));
|
||||
}
|
||||
const isAvailable = refactors.length > 0;
|
||||
|
||||
if (negative && isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some: ${refactors.map(r => r.name).join(", ")}`);
|
||||
}
|
||||
else if (!negative && !isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyApplicableRefactorAvailableForRange(negative: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
if (!(ranges && ranges.length === 1)) {
|
||||
|
@ -2752,6 +2793,20 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
const range = this.getSelection();
|
||||
const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
|
||||
const refactor = ts.find(refactors, r => r.name === refactorName);
|
||||
if (!refactor) {
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName);
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyFileAfterApplyingRefactorAtMarker(
|
||||
markerName: string,
|
||||
expectedContent: string,
|
||||
|
@ -3496,6 +3551,10 @@ namespace FourSlashInterface {
|
|||
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
|
||||
this.state.openFile(indexOrName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
this.state.select(startMarker, endMarker);
|
||||
}
|
||||
}
|
||||
|
||||
export class VerifyNegatable {
|
||||
|
@ -3606,6 +3665,10 @@ namespace FourSlashInterface {
|
|||
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
|
||||
}
|
||||
|
||||
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
|
||||
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
|
||||
}
|
||||
|
||||
public codeFixAvailable() {
|
||||
this.state.verifyCodeFixAvailable(this.negative);
|
||||
}
|
||||
|
@ -3617,6 +3680,10 @@ namespace FourSlashInterface {
|
|||
public applicableRefactorAvailableForRange() {
|
||||
this.state.verifyApplicableRefactorAvailableForRange(this.negative);
|
||||
}
|
||||
|
||||
public refactorAvailable(name?: string, subName?: string) {
|
||||
this.state.verifyRefactorAvailable(this.negative, name, subName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Verify extends VerifyNegatable {
|
||||
|
@ -4012,6 +4079,10 @@ namespace FourSlashInterface {
|
|||
public disableFormatting() {
|
||||
this.state.enableFormatting = false;
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
this.state.applyRefactor(refactorName, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Debug {
|
||||
|
|
|
@ -67,17 +67,16 @@ namespace Utils {
|
|||
|
||||
export let currentExecutionEnvironment = getExecutionEnvironment();
|
||||
|
||||
const Buffer: typeof global.Buffer = currentExecutionEnvironment !== ExecutionEnvironment.Browser
|
||||
? require("buffer").Buffer
|
||||
: undefined;
|
||||
// Thanks to browserify, Buffer is always available nowadays
|
||||
const Buffer: typeof global.Buffer = require("buffer").Buffer;
|
||||
|
||||
export function encodeString(s: string): string {
|
||||
return Buffer ? (new Buffer(s)).toString("utf8") : s;
|
||||
return Buffer.from(s).toString("utf8");
|
||||
}
|
||||
|
||||
export function byteLength(s: string, encoding?: string): number {
|
||||
// stub implementation if Buffer is not available (in-browser case)
|
||||
return Buffer ? Buffer.byteLength(s, encoding) : s.length;
|
||||
return Buffer.byteLength(s, encoding);
|
||||
}
|
||||
|
||||
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
|
||||
|
@ -133,17 +132,18 @@ namespace Utils {
|
|||
return content;
|
||||
}
|
||||
|
||||
export function memoize<T extends Function>(f: T): T {
|
||||
const cache: { [idx: string]: any } = {};
|
||||
export function memoize<T extends Function>(f: T, memoKey: (...anything: any[]) => string): T {
|
||||
const cache = ts.createMap<any>();
|
||||
|
||||
return <any>(function(this: any) {
|
||||
const key = Array.prototype.join.call(arguments);
|
||||
const cachedResult = cache[key];
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
return <any>(function(this: any, ...args: any[]) {
|
||||
const key = memoKey(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
else {
|
||||
return cache[key] = f.apply(this, arguments);
|
||||
const value = f.apply(this, args);
|
||||
cache.set(key, value);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ namespace Utils {
|
|||
|
||||
const maxHarnessFrames = 1;
|
||||
|
||||
export function filterStack(error: Error, stackTraceLimit: number = Infinity) {
|
||||
export function filterStack(error: Error, stackTraceLimit = Infinity) {
|
||||
const stack = <string>(<any>error).stack;
|
||||
if (stack) {
|
||||
const lines = stack.split(/\r\n?|\n/g);
|
||||
|
@ -564,7 +564,7 @@ namespace Harness {
|
|||
}
|
||||
|
||||
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
|
||||
options = options || <{ recursive?: boolean; }>{};
|
||||
options = options || {};
|
||||
|
||||
function filesInFolder(folder: string): string[] {
|
||||
let paths: string[] = [];
|
||||
|
@ -686,7 +686,7 @@ namespace Harness {
|
|||
|
||||
return dirPath;
|
||||
}
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl);
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl, path => path);
|
||||
|
||||
export function resolvePath(path: string) {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path + "?resolve=true");
|
||||
|
@ -703,21 +703,22 @@ namespace Harness {
|
|||
return response.status === 200;
|
||||
}
|
||||
|
||||
export let listFiles = Utils.memoize((path: string, spec?: RegExp): string[] => {
|
||||
export const listFiles = Utils.memoize((path: string, spec?: RegExp, options?: { recursive?: boolean }): string[] => {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path);
|
||||
if (response.status === 200) {
|
||||
const results = response.responseText.split(",");
|
||||
let results = response.responseText.split(",");
|
||||
if (spec) {
|
||||
return results.filter(file => spec.test(file));
|
||||
results = results.filter(file => spec.test(file));
|
||||
}
|
||||
else {
|
||||
return results;
|
||||
if (options && !options.recursive) {
|
||||
results = results.filter(file => (ts.getDirectoryPath(ts.normalizeSlashes(file)) === path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
else {
|
||||
return [""];
|
||||
}
|
||||
});
|
||||
}, (path: string, spec?: RegExp, options?: { recursive?: boolean }) => `${path}|${spec}|${options ? options.recursive : undefined}`);
|
||||
|
||||
export function readFile(file: string): string | undefined {
|
||||
const response = Http.getFileFromServerSync(serverRoot + file);
|
||||
|
@ -1194,13 +1195,21 @@ namespace Harness {
|
|||
return { result, options };
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(inputFiles: TestFile[],
|
||||
export interface DeclarationCompilationContext {
|
||||
declInputFiles: TestFile[];
|
||||
declOtherFiles: TestFile[];
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions;
|
||||
options: ts.CompilerOptions;
|
||||
currentDirectory: string;
|
||||
}
|
||||
|
||||
export function prepareDeclarationCompilationContext(inputFiles: TestFile[],
|
||||
otherFiles: TestFile[],
|
||||
result: CompilerResult,
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
|
||||
options: ts.CompilerOptions,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string) {
|
||||
currentDirectory: string): DeclarationCompilationContext | undefined {
|
||||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
|
||||
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
|
||||
}
|
||||
|
@ -1212,8 +1221,7 @@ namespace Harness {
|
|||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
|
||||
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
|
||||
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory || harnessSettings["currentDirectory"]);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings["currentDirectory"] };
|
||||
}
|
||||
|
||||
function addDtsFile(file: TestFile, dtsFiles: TestFile[]) {
|
||||
|
@ -1259,6 +1267,15 @@ namespace Harness {
|
|||
}
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context;
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
}
|
||||
|
||||
function normalizeLineEndings(text: string, lineEnding: string): string {
|
||||
let normalized = text.replace(/\r\n?/g, "\n");
|
||||
if (lineEnding !== "\n") {
|
||||
|
@ -1273,10 +1290,19 @@ namespace Harness {
|
|||
|
||||
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
|
||||
diagnostics.sort(ts.compareDiagnostics);
|
||||
const outputLines: string[] = [];
|
||||
let outputLines = "";
|
||||
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
|
||||
let totalErrorsReportedInNonLibraryFiles = 0;
|
||||
|
||||
let firstLine = true;
|
||||
function newLine() {
|
||||
if (firstLine) {
|
||||
firstLine = false;
|
||||
return "";
|
||||
}
|
||||
return "\r\n";
|
||||
}
|
||||
|
||||
function outputErrorText(error: ts.Diagnostic) {
|
||||
const message = ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine());
|
||||
|
||||
|
@ -1285,7 +1311,7 @@ namespace Harness {
|
|||
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
|
||||
.filter(s => s.length > 0)
|
||||
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
|
||||
errLines.forEach(e => outputLines.push(e));
|
||||
errLines.forEach(e => outputLines += (newLine() + e));
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
|
@ -1311,7 +1337,7 @@ namespace Harness {
|
|||
|
||||
|
||||
// Header
|
||||
outputLines.push("==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
outputLines += (newLine() + "==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
|
||||
// Make sure we emit something for every error
|
||||
let markedErrorCount = 0;
|
||||
|
@ -1340,7 +1366,7 @@ namespace Harness {
|
|||
nextLineStart = lineStarts[lineIndex + 1];
|
||||
}
|
||||
// Emit this line from the original file
|
||||
outputLines.push(" " + line);
|
||||
outputLines += (newLine() + " " + line);
|
||||
fileErrors.forEach(err => {
|
||||
// Does any error start or continue on to this line? Emit squiggles
|
||||
const end = ts.textSpanEnd(err);
|
||||
|
@ -1352,7 +1378,7 @@ namespace Harness {
|
|||
// Calculate the start of the squiggle
|
||||
const squiggleStart = Math.max(0, relativeOffset);
|
||||
// TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another
|
||||
outputLines.push(" " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
outputLines += (newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
|
||||
// If the error ended here, or we're at the end of the file, emit its message
|
||||
if ((lineIndex === lines.length - 1) || nextLineStart > end) {
|
||||
|
@ -1383,7 +1409,7 @@ namespace Harness {
|
|||
assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors");
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines;
|
||||
}
|
||||
|
||||
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
|
||||
|
@ -1586,9 +1612,10 @@ namespace Harness {
|
|||
}
|
||||
}
|
||||
|
||||
const declFileCompilationResult =
|
||||
Harness.Compiler.compileDeclarationFiles(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
|
||||
const declFileContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
|
||||
);
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declFileContext);
|
||||
|
||||
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
|
||||
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
|
||||
|
@ -1963,7 +1990,7 @@ namespace Harness {
|
|||
IO.writeFile(actualFileName + ".delete", "");
|
||||
}
|
||||
else {
|
||||
IO.writeFile(actualFileName, actual);
|
||||
IO.writeFile(actualFileName, encoded_actual);
|
||||
}
|
||||
throw new Error(`The baseline file ${relativeFileName} has changed.`);
|
||||
}
|
||||
|
|
|
@ -193,7 +193,9 @@ namespace Harness.LanguageService {
|
|||
}
|
||||
getCurrentDirectory(): string { return virtualFileSystemRoot; }
|
||||
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
getScriptFileNames(): string[] {
|
||||
return this.getFilenames().filter(ts.isAnySupportedFileExtension);
|
||||
}
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
const script = this.getScriptInfo(fileName);
|
||||
return script ? new ScriptSnapshot(script) : undefined;
|
||||
|
@ -485,6 +487,9 @@ namespace Harness.LanguageService {
|
|||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
|
||||
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
|
||||
}
|
||||
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
|
||||
return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine));
|
||||
}
|
||||
getCodeFixesAtPosition(): ts.CodeAction[] {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
|
@ -681,11 +686,11 @@ namespace Harness.LanguageService {
|
|||
}
|
||||
|
||||
info(message: string): void {
|
||||
return this.host.log(message);
|
||||
this.host.log(message);
|
||||
}
|
||||
|
||||
msg(message: string) {
|
||||
return this.host.log(message);
|
||||
msg(message: string): void {
|
||||
this.host.log(message);
|
||||
}
|
||||
|
||||
loggingEnabled() {
|
||||
|
@ -700,17 +705,13 @@ namespace Harness.LanguageService {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
endGroup(): void {
|
||||
}
|
||||
startGroup() { throw ts.notImplemented(); }
|
||||
endGroup() { throw ts.notImplemented(); }
|
||||
|
||||
perftrc(message: string): void {
|
||||
return this.host.log(message);
|
||||
}
|
||||
|
||||
startGroup(): void {
|
||||
}
|
||||
|
||||
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
|
||||
return setTimeout(callback, ms, args);
|
||||
}
|
||||
|
@ -795,7 +796,7 @@ namespace Harness.LanguageService {
|
|||
default:
|
||||
return {
|
||||
module: undefined,
|
||||
error: "Could not resolve module"
|
||||
error: new Error("Could not resolve module")
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -828,6 +829,7 @@ namespace Harness.LanguageService {
|
|||
host: serverHost,
|
||||
cancellationToken: ts.server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
|
|
|
@ -426,12 +426,12 @@ class ProjectRunner extends RunnerBase {
|
|||
compilerResult.program ?
|
||||
ts.filter(compilerResult.program.getSourceFiles(), sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)) :
|
||||
[]),
|
||||
sourceFile => <Harness.Compiler.TestFile>{
|
||||
(sourceFile): Harness.Compiler.TestFile => ({
|
||||
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
|
||||
RunnerBase.removeFullPaths(sourceFile.fileName) :
|
||||
sourceFile.fileName,
|
||||
content: sourceFile.text
|
||||
});
|
||||
}));
|
||||
|
||||
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ namespace RWC {
|
|||
useCustomLibraryFile = undefined;
|
||||
});
|
||||
|
||||
it("can compile", () => {
|
||||
it("can compile", function(this: Mocha.ITestCallbackContext) {
|
||||
this.timeout(800000); // Allow long timeouts for RWC compilations
|
||||
let opts: ts.ParsedCommandLine;
|
||||
|
||||
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
|
||||
|
@ -89,9 +90,16 @@ namespace RWC {
|
|||
ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile);
|
||||
}
|
||||
|
||||
// Load the files
|
||||
// Deduplicate files so they are only printed once in baselines (they are deduplicated within the compiler already)
|
||||
const uniqueNames = ts.createMap<true>();
|
||||
for (const fileName of fileNames) {
|
||||
inputFiles.push(getHarnessCompilerInputUnit(fileName));
|
||||
// Must maintain order, build result list while checking map
|
||||
const normalized = ts.normalizeSlashes(fileName);
|
||||
if (!uniqueNames.has(normalized)) {
|
||||
uniqueNames.set(normalized, true);
|
||||
// Load the file
|
||||
inputFiles.push(getHarnessCompilerInputUnit(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
// Add files to compilation
|
||||
|
@ -207,6 +215,14 @@ namespace RWC {
|
|||
}, baselineOpts);
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
// declaration file errors as part of the baseline.
|
||||
it("has the expected errors in generated declaration files", () => {
|
||||
|
@ -216,8 +232,12 @@ namespace RWC {
|
|||
return null;
|
||||
}
|
||||
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
|
||||
const declContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory
|
||||
);
|
||||
// Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed
|
||||
compilerResult = undefined;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() +
|
||||
|
@ -225,14 +245,6 @@ namespace RWC {
|
|||
}, baselineOpts);
|
||||
}
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,11 +74,6 @@
|
|||
"../services/formatting/tokenRange.ts",
|
||||
"../services/codeFixProvider.ts",
|
||||
"../services/codefixes/fixes.ts",
|
||||
"../services/codefixes/fixExtendsInterfaceBecomesImplements.ts",
|
||||
"../services/codefixes/fixClassIncorrectlyImplementsInterface.ts",
|
||||
"../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
|
||||
"../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts",
|
||||
"../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
|
||||
"../services/codefixes/helpers.ts",
|
||||
"../services/codefixes/importFixes.ts",
|
||||
"../services/codefixes/fixUnusedIdentifier.ts",
|
||||
|
|
|
@ -52,23 +52,12 @@ namespace ts {
|
|||
}
|
||||
|
||||
function createProject(rootFile: string, serverHost: server.ServerHost): { project: server.Project, rootScriptInfo: server.ScriptInfo } {
|
||||
const logger: server.Logger = {
|
||||
close: noop,
|
||||
hasLevel: () => false,
|
||||
loggingEnabled: () => false,
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
msg: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
|
||||
const svcOpts: server.ProjectServiceOptions = {
|
||||
host: serverHost,
|
||||
logger,
|
||||
logger: projectSystem.nullLogger,
|
||||
cancellationToken: { isCancellationRequested: () => false },
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined
|
||||
};
|
||||
const projectService = new server.ProjectService(svcOpts);
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace ts.projectSystem {
|
|||
host,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: typingsInstaller || server.nullTypingsInstaller,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
|
@ -518,18 +519,20 @@ namespace ts.projectSystem {
|
|||
};
|
||||
const host = createServerHost([f], { newLine });
|
||||
const session = createSession(host);
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
const openRequest: server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
command: server.protocol.CommandTypes.Open,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
session.executeCommand(<server.protocol.CompileOnSaveEmitFileRequest>{
|
||||
};
|
||||
session.executeCommand(openRequest);
|
||||
const emitFileRequest: server.protocol.CompileOnSaveEmitFileRequest = {
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "compileOnSaveEmitFile",
|
||||
command: server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
};
|
||||
session.executeCommand(emitFileRequest);
|
||||
const emitOutput = host.readFile(path + ts.Extension.Js);
|
||||
assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline");
|
||||
}
|
||||
|
@ -550,7 +553,7 @@ namespace ts.projectSystem {
|
|||
};
|
||||
const host = createServerHost([file1, file2, configFile, libFile], { newLine: "\r\n" });
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = createSession(host, typingsInstaller);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
openFilesForSession([file1, file2], session);
|
||||
const compileFileRequest = makeSessionRequest<server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path });
|
||||
|
|
|
@ -67,14 +67,14 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -92,7 +92,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -100,7 +100,7 @@ namespace ts {
|
|||
allowJs: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -117,7 +117,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -146,7 +146,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
|
@ -174,7 +174,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
|
@ -201,7 +201,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
|
@ -227,7 +227,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
|
@ -255,7 +255,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -286,7 +286,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -317,7 +317,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -348,7 +348,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -379,7 +379,7 @@ namespace ts {
|
|||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
|
@ -415,8 +415,8 @@ namespace ts {
|
|||
it("Convert default tsconfig.json to compiler-options ", () => {
|
||||
assertCompilerOptions({}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: {} as CompilerOptions,
|
||||
errors: <Diagnostic[]>[]
|
||||
compilerOptions: {},
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -434,7 +434,7 @@ namespace ts {
|
|||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: true,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
|
@ -445,7 +445,7 @@ namespace ts {
|
|||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -463,7 +463,7 @@ namespace ts {
|
|||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: false,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
|
@ -474,7 +474,7 @@ namespace ts {
|
|||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -516,7 +516,7 @@ namespace ts {
|
|||
allowSyntheticDefaultImports: true,
|
||||
skipLibCheck: true
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,591 @@
|
|||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const newLineCharacter = "\n";
|
||||
function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractMethods", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + [#|2 + 3|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + 2 + [#|3 + 4|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing labeled break or continue with target outside of the range."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod8",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + [#|a1 + x|] + 100;
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
function testExtractMethod(caption: string, text: string) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: -1,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const result = refactor.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(result.errors, undefined, "expect no errors");
|
||||
const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context);
|
||||
const data: string[] = [];
|
||||
data.push(`==ORIGINAL==`);
|
||||
data.push(sourceFile.text);
|
||||
for (const r of results) {
|
||||
const changes = refactor.extractMethod.getPossibleExtractions(result.targetRange, context, results.indexOf(r))[0].changes;
|
||||
data.push(`==SCOPE::${r.scopeDescription}==`);
|
||||
data.push(textChanges.applyChanges(sourceFile.text, changes[0].textChanges));
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@ namespace ts {
|
|||
"c:/dev/a.d.ts",
|
||||
"c:/dev/a.js",
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts"
|
||||
|
@ -109,23 +110,21 @@ namespace ts {
|
|||
}
|
||||
{
|
||||
const actual = ts.parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack);
|
||||
expected.errors = map(expected.errors, error => {
|
||||
return <Diagnostic>{
|
||||
category: error.category,
|
||||
code: error.code,
|
||||
file: undefined,
|
||||
length: undefined,
|
||||
messageText: error.messageText,
|
||||
start: undefined,
|
||||
};
|
||||
});
|
||||
expected.errors = expected.errors.map<Diagnostic>(error => ({
|
||||
category: error.category,
|
||||
code: error.code,
|
||||
file: undefined,
|
||||
length: undefined,
|
||||
messageText: error.messageText,
|
||||
start: undefined,
|
||||
}));
|
||||
assertParsed(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function createDiagnosticForConfigFile(json: any, start: number, length: number, diagnosticMessage: DiagnosticMessage, arg0: string) {
|
||||
const text = JSON.stringify(json);
|
||||
const file = <SourceFile>{
|
||||
const file = <SourceFile>{ // tslint:disable-line no-object-literal-type-assertion
|
||||
fileName: caseInsensitiveTsconfigPath,
|
||||
kind: SyntaxKind.SourceFile,
|
||||
text
|
||||
|
@ -141,7 +140,8 @@ namespace ts {
|
|||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/b.ts"
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
|
@ -462,7 +462,6 @@ namespace ts {
|
|||
};
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
it("same named declarations are excluded", () => {
|
||||
const json = {
|
||||
include: [
|
||||
|
@ -651,71 +650,127 @@ namespace ts {
|
|||
};
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and no exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: [
|
||||
"a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and empty exclude", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: <string[]>[]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
describe("with common package folders", () => {
|
||||
it("and no exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/?.ts"
|
||||
],
|
||||
exclude: [
|
||||
"a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and empty exclude", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: <string[]>[]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and explicit recursive include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts",
|
||||
"**/node_modules/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and wildcard include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"*/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and explicit wildcard include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"*/a.ts",
|
||||
"node_modules/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
it("exclude .js files when allowJs=false", () => {
|
||||
const json = {
|
||||
|
@ -1066,6 +1121,7 @@ namespace ts {
|
|||
};
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
describe("with trailing recursive directory", () => {
|
||||
it("in includes", () => {
|
||||
const json = {
|
||||
|
@ -1264,6 +1320,7 @@ namespace ts {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with files or folders that begin with a .", () => {
|
||||
it("that are not explicitly included", () => {
|
||||
const json = {
|
||||
|
|
|
@ -26,10 +26,19 @@ namespace ts {
|
|||
interface File {
|
||||
name: string;
|
||||
content?: string;
|
||||
symlinks?: string[];
|
||||
}
|
||||
|
||||
function createModuleResolutionHost(hasDirectoryExists: boolean, ...files: File[]): ModuleResolutionHost {
|
||||
const map = arrayToMap(files, f => f.name);
|
||||
const map = createMap<File>();
|
||||
for (const file of files) {
|
||||
map.set(file.name, file);
|
||||
if (file.symlinks) {
|
||||
for (const symlink of file.symlinks) {
|
||||
map.set(symlink, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDirectoryExists) {
|
||||
const directories = createMap<string>();
|
||||
|
@ -46,6 +55,7 @@ namespace ts {
|
|||
}
|
||||
return {
|
||||
readFile,
|
||||
realpath,
|
||||
directoryExists: path => directories.has(path),
|
||||
fileExists: path => {
|
||||
assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
|
||||
|
@ -54,12 +64,15 @@ namespace ts {
|
|||
};
|
||||
}
|
||||
else {
|
||||
return { readFile, fileExists: path => map.has(path) };
|
||||
return { readFile, realpath, fileExists: path => map.has(path) };
|
||||
}
|
||||
function readFile(path: string): string | undefined {
|
||||
const file = map.get(path);
|
||||
return file && file.content;
|
||||
}
|
||||
function realpath(path: string): string {
|
||||
return map.get(path).name;
|
||||
}
|
||||
}
|
||||
|
||||
describe("Node module resolution - relative paths", () => {
|
||||
|
@ -233,8 +246,8 @@ namespace ts {
|
|||
test(/*hasDirectoryExists*/ true);
|
||||
|
||||
function test(hasDirectoryExists: boolean) {
|
||||
const containingFile = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const containingFile: File = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile));
|
||||
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [
|
||||
"/a/node_modules/b/c/node_modules/d/node_modules/foo.ts",
|
||||
|
@ -289,6 +302,19 @@ namespace ts {
|
|||
]);
|
||||
}
|
||||
});
|
||||
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ false);
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ true);
|
||||
function testPreserveSymlinks(preserveSymlinks: boolean) {
|
||||
it(`preserveSymlinks: ${preserveSymlinks}`, () => {
|
||||
const realFileName = "/linked/index.d.ts";
|
||||
const symlinkFileName = "/app/node_modulex/linked/index.d.ts";
|
||||
const host = createModuleResolutionHost(/*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] });
|
||||
const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host);
|
||||
const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName;
|
||||
checkResolvedModule(resolution.resolvedModule, { resolvedFileName, isExternalLibraryImport: true, extension: Extension.Dts });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("Module resolution - relative imports", () => {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
namespace ts.projectSystem {
|
||||
describe("Project errors", () => {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: string[]) {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.isTrue(projectFiles !== undefined, "missing project files");
|
||||
checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors);
|
||||
}
|
||||
|
||||
function checkProjectErrorsWorker(errors: Diagnostic[], expectedErrors: string[]) {
|
||||
function checkProjectErrorsWorker(errors: ReadonlyArray<Diagnostic>, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
|
||||
if (expectedErrors.length) {
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
|
|
|
@ -109,7 +109,10 @@ namespace ts {
|
|||
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
|
||||
const files = arrayToMap(texts, t => t.name, t => {
|
||||
if (oldProgram) {
|
||||
const oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
let oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
if (oldFile && oldFile.redirectInfo) {
|
||||
oldFile = oldFile.redirectInfo.unredirected;
|
||||
}
|
||||
if (oldFile && oldFile.sourceText.getVersion() === t.text.getVersion()) {
|
||||
return oldFile;
|
||||
}
|
||||
|
@ -171,11 +174,16 @@ namespace ts {
|
|||
return program;
|
||||
}
|
||||
|
||||
function updateProgramText(files: ReadonlyArray<NamedSourceText>, fileName: string, newProgramText: string) {
|
||||
const file = find(files, f => f.name === fileName)!;
|
||||
file.text = file.text.updateProgram(newProgramText);
|
||||
}
|
||||
|
||||
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.isTrue(expected.primary === actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
assert.equal(expected.resolvedFileName, actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.equal(expected.primary, actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -238,7 +246,7 @@ namespace ts {
|
|||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
|
@ -249,7 +257,7 @@ namespace ts {
|
|||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
|
@ -263,19 +271,19 @@ namespace ts {
|
|||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["b"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if change doesn't affect type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["a"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
});
|
||||
|
||||
it("fails if change affects imports", () => {
|
||||
|
@ -283,7 +291,7 @@ namespace ts {
|
|||
updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[2].text = files[2].text.updateImportsAndExports("import x from 'b'");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type directives", () => {
|
||||
|
@ -295,25 +303,25 @@ namespace ts {
|
|||
/// <reference types="typerefs1" />`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if module kind changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.AMD }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if rootdir changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if config path changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if missing files remain missing", () => {
|
||||
|
@ -357,7 +365,7 @@ namespace ts {
|
|||
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") }));
|
||||
|
@ -367,7 +375,7 @@ namespace ts {
|
|||
const program_3 = updateProgram(program_2, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateImportsAndExports("");
|
||||
});
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_3, "a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
const program_4 = updateProgram(program_3, ["a.ts"], options, files => {
|
||||
|
@ -376,7 +384,7 @@ namespace ts {
|
|||
`;
|
||||
files[0].text = files[0].text.updateImportsAndExports(newImports);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined }));
|
||||
});
|
||||
|
||||
|
@ -394,7 +402,7 @@ namespace ts {
|
|||
const program_2 = updateProgram(program_1, ["/a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
|
@ -405,7 +413,7 @@ namespace ts {
|
|||
files[0].text = files[0].text.updateReferences("");
|
||||
});
|
||||
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_3, "/a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
updateProgram(program_3, ["/a.ts"], options, files => {
|
||||
|
@ -414,7 +422,7 @@ namespace ts {
|
|||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
});
|
||||
|
||||
|
@ -454,7 +462,7 @@ namespace ts {
|
|||
"initialProgram: execute module resolution normally.");
|
||||
|
||||
const initialProgramDiagnostics = initialProgram.getSemanticDiagnostics(initialProgram.getSourceFile("file1.ts"));
|
||||
assert(initialProgramDiagnostics.length === 1, `initialProgram: import should fail.`);
|
||||
assert.lengthOf(initialProgramDiagnostics, 1, `initialProgram: import should fail.`);
|
||||
}
|
||||
|
||||
const afterNpmInstallProgram = updateProgram(initialProgram, rootFiles.map(f => f.name), options, f => {
|
||||
|
@ -478,7 +486,7 @@ namespace ts {
|
|||
"afterNpmInstallProgram: execute module resolution normally.");
|
||||
|
||||
const afterNpmInstallProgramDiagnostics = afterNpmInstallProgram.getSemanticDiagnostics(afterNpmInstallProgram.getSourceFile("file1.ts"));
|
||||
assert(afterNpmInstallProgramDiagnostics.length === 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
assert.lengthOf(afterNpmInstallProgramDiagnostics, 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -617,10 +625,10 @@ namespace ts {
|
|||
"File 'f1.ts' exist - use it as a name resolution result.",
|
||||
"======== Module name './f1' was successfully resolved to 'f1.ts'. ========"
|
||||
],
|
||||
"program_1: execute module reoslution normally.");
|
||||
"program_1: execute module resolution normally.");
|
||||
|
||||
const program_1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("f2.ts"));
|
||||
assert(program_1Diagnostics.length === expectedErrors, `initial program should be well-formed`);
|
||||
assert.lengthOf(program_1Diagnostics, expectedErrors, `initial program should be well-formed`);
|
||||
}
|
||||
const indexOfF1 = 6;
|
||||
const program_2 = updateProgram(program_1, program_1.getRootFileNames(), options, f => {
|
||||
|
@ -630,7 +638,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_2Diagnostics = program_2.getSemanticDiagnostics(program_2.getSourceFile("f2.ts"));
|
||||
assert(program_2Diagnostics.length === expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
assert.lengthOf(program_2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
|
||||
assert.deepEqual(program_2.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========",
|
||||
|
@ -659,7 +667,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_3Diagnostics = program_3.getSemanticDiagnostics(program_3.getSourceFile("f2.ts"));
|
||||
assert(program_3Diagnostics.length === expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_3.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
|
@ -684,7 +692,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_4Diagnostics = program_4.getSemanticDiagnostics(program_4.getSourceFile("f2.ts"));
|
||||
assert(program_4Diagnostics.length === expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_4.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
|
@ -708,7 +716,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_5Diagnostics = program_5.getSemanticDiagnostics(program_5.getSourceFile("f2.ts"));
|
||||
assert(program_5Diagnostics.length === ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
assert.lengthOf(program_5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
|
||||
assert.deepEqual(program_5.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
|
@ -725,7 +733,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_6Diagnostics = program_6.getSemanticDiagnostics(program_6.getSourceFile("f2.ts"));
|
||||
assert(program_6Diagnostics.length === expectedErrors, `import of BB in f1 fails.`);
|
||||
assert.lengthOf(program_6Diagnostics, expectedErrors, `import of BB in f1 fails.`);
|
||||
|
||||
assert.deepEqual(program_6.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
|
@ -749,7 +757,7 @@ namespace ts {
|
|||
|
||||
{
|
||||
const program_7Diagnostics = program_7.getSemanticDiagnostics(program_7.getSourceFile("f2.ts"));
|
||||
assert(program_7Diagnostics.length === expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
assert.lengthOf(program_7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
|
||||
assert.deepEqual(program_7.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========",
|
||||
|
@ -762,6 +770,98 @@ namespace ts {
|
|||
], "program_7 should reuse module resolutions in f2 since it is unchanged");
|
||||
}
|
||||
});
|
||||
|
||||
describe("redirects", () => {
|
||||
const axIndex = "/node_modules/a/node_modules/x/index.d.ts";
|
||||
const axPackage = "/node_modules/a/node_modules/x/package.json";
|
||||
const bxIndex = "/node_modules/b/node_modules/x/index.d.ts";
|
||||
const bxPackage = "/node_modules/b/node_modules/x/package.json";
|
||||
const root = "/a.ts";
|
||||
const compilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs };
|
||||
|
||||
function createRedirectProgram(options?: { bText: string, bVersion: string }): ProgramWithSourceTexts {
|
||||
const files: NamedSourceText[] = [
|
||||
{
|
||||
name: "/node_modules/a/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export function a(x: X): void;"),
|
||||
},
|
||||
{
|
||||
name: axIndex,
|
||||
text: SourceText.New("", "", "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: axPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: "/node_modules/b/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export const b: X;"),
|
||||
},
|
||||
{
|
||||
name: bxIndex,
|
||||
text: SourceText.New("", "", options ? options.bText : "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: bxPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: root,
|
||||
text: SourceText.New("", 'import { a } from "a"; import { b } from "b";', "a(b)"),
|
||||
},
|
||||
];
|
||||
|
||||
return newProgram(files, [root], compilerOptions);
|
||||
}
|
||||
|
||||
function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void): ProgramWithSourceTexts {
|
||||
return updateProgram(program, [root], compilerOptions, updater);
|
||||
}
|
||||
|
||||
it("No changes -> redirect not broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, root, "const x = 1;");
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), emptyArray);
|
||||
});
|
||||
|
||||
it("Target changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
assert.deepEqual(program_1.getSemanticDiagnostics(), emptyArray);
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }'));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Underlying changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Previously duplicate packages -> program structure not reused", () => {
|
||||
const program_1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" });
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), []);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("host is optional", () => {
|
||||
|
|
|
@ -28,18 +28,6 @@ namespace ts.server {
|
|||
createHash: Harness.LanguageService.mockHash,
|
||||
};
|
||||
|
||||
const mockLogger: Logger = {
|
||||
close: noop,
|
||||
hasLevel(): boolean { return false; },
|
||||
loggingEnabled(): boolean { return false; },
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
msg: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
|
||||
class TestSession extends Session {
|
||||
getProjectService() {
|
||||
return this.projectService;
|
||||
|
@ -55,10 +43,11 @@ namespace ts.server {
|
|||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: mockLogger,
|
||||
logger: projectSystem.nullLogger,
|
||||
canUseEvents: true
|
||||
};
|
||||
return new TestSession(opts);
|
||||
|
@ -93,14 +82,15 @@ namespace ts.server {
|
|||
|
||||
session.executeCommand(req);
|
||||
|
||||
expect(lastSent).to.deep.equal(<protocol.Response>{
|
||||
const expected: protocol.Response = {
|
||||
command: CommandNames.Unknown,
|
||||
type: "response",
|
||||
seq: 0,
|
||||
message: "Unrecognized JSON command: foobar",
|
||||
request_seq: 0,
|
||||
success: false
|
||||
});
|
||||
};
|
||||
expect(lastSent).to.deep.equal(expected);
|
||||
});
|
||||
it("should return a tuple containing the response and if a response is required on success", () => {
|
||||
const req: protocol.ConfigureRequest = {
|
||||
|
@ -405,10 +395,11 @@ namespace ts.server {
|
|||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: mockLogger,
|
||||
logger: projectSystem.nullLogger,
|
||||
canUseEvents: true
|
||||
});
|
||||
this.addProtocolHandler(this.customHandler, () => {
|
||||
|
@ -472,10 +463,11 @@ namespace ts.server {
|
|||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: mockLogger,
|
||||
logger: projectSystem.nullLogger,
|
||||
canUseEvents: true
|
||||
});
|
||||
this.addProtocolHandler("echo", (req: protocol.Request) => ({
|
||||
|
|
|
@ -74,6 +74,70 @@ namespace ts {
|
|||
}
|
||||
}).outputText;
|
||||
});
|
||||
|
||||
testBaseline("rewrittenNamespace", () => {
|
||||
return ts.transpileModule(`namespace Reflect { const x = 1; }`, {
|
||||
transformers: {
|
||||
before: [forceNamespaceRewrite],
|
||||
},
|
||||
compilerOptions: {
|
||||
newLine: NewLineKind.CarriageReturnLineFeed,
|
||||
}
|
||||
}).outputText;
|
||||
});
|
||||
|
||||
testBaseline("rewrittenNamespaceFollowingClass", () => {
|
||||
return ts.transpileModule(`
|
||||
class C { foo = 10; static bar = 20 }
|
||||
namespace C { export let x = 10; }
|
||||
`, {
|
||||
transformers: {
|
||||
before: [forceNamespaceRewrite],
|
||||
},
|
||||
compilerOptions: {
|
||||
target: ts.ScriptTarget.ESNext,
|
||||
newLine: NewLineKind.CarriageReturnLineFeed,
|
||||
}
|
||||
}).outputText;
|
||||
});
|
||||
|
||||
testBaseline("synthesizedClassAndNamespaceCombination", () => {
|
||||
return ts.transpileModule("", {
|
||||
transformers: {
|
||||
before: [replaceWithClassAndNamespace],
|
||||
},
|
||||
compilerOptions: {
|
||||
target: ts.ScriptTarget.ESNext,
|
||||
newLine: NewLineKind.CarriageReturnLineFeed,
|
||||
}
|
||||
}).outputText;
|
||||
|
||||
function replaceWithClassAndNamespace() {
|
||||
return (sourceFile: ts.SourceFile) => {
|
||||
const result = getMutableClone(sourceFile);
|
||||
result.statements = ts.createNodeArray([
|
||||
ts.createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined),
|
||||
ts.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier("Foo"), createModuleBlock([createEmptyStatement()]))
|
||||
]);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function forceNamespaceRewrite(context: ts.TransformationContext) {
|
||||
return (sourceFile: ts.SourceFile): ts.SourceFile => {
|
||||
return visitNode(sourceFile);
|
||||
|
||||
function visitNode<T extends ts.Node>(node: T): T {
|
||||
if (node.kind === ts.SyntaxKind.ModuleBlock) {
|
||||
const block = node as T & ts.ModuleBlock;
|
||||
const statements = ts.createNodeArray([...block.statements]);
|
||||
return ts.updateModuleBlock(block, statements) as typeof block;
|
||||
}
|
||||
return ts.visitEachChild(node, visitNode, context);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -48,18 +48,18 @@ namespace ts.projectSystem {
|
|||
}
|
||||
|
||||
export const nullLogger: server.Logger = {
|
||||
close: () => void 0,
|
||||
hasLevel: () => void 0,
|
||||
close: noop,
|
||||
hasLevel: () => false,
|
||||
loggingEnabled: () => false,
|
||||
perftrc: () => void 0,
|
||||
info: () => void 0,
|
||||
startGroup: () => void 0,
|
||||
endGroup: () => void 0,
|
||||
msg: () => void 0,
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
msg: noop,
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
|
||||
export const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
|
||||
const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
|
||||
export const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
|
@ -132,7 +132,7 @@ namespace ts.projectSystem {
|
|||
return JSON.stringify({ dependencies });
|
||||
}
|
||||
|
||||
export function getExecutingFilePathFromLibFile(): string {
|
||||
function getExecutingFilePathFromLibFile(): string {
|
||||
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ namespace ts.projectSystem {
|
|||
return map(fileNames, toExternalFile);
|
||||
}
|
||||
|
||||
export class TestServerEventManager {
|
||||
class TestServerEventManager {
|
||||
public events: server.ProjectServiceEvent[] = [];
|
||||
|
||||
handler: server.ProjectServiceEventHandler = (event: server.ProjectServiceEvent) => {
|
||||
|
@ -157,7 +157,7 @@ namespace ts.projectSystem {
|
|||
}
|
||||
}
|
||||
|
||||
export interface TestServerHostCreationParameters {
|
||||
interface TestServerHostCreationParameters {
|
||||
useCaseSensitiveFileNames?: boolean;
|
||||
executingFilePath?: string;
|
||||
currentDirectory?: string;
|
||||
|
@ -200,26 +200,31 @@ namespace ts.projectSystem {
|
|||
}
|
||||
}
|
||||
|
||||
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler, cancellationToken?: server.ServerCancellationToken, throttleWaitMilliseconds?: number) {
|
||||
if (typingsInstaller === undefined) {
|
||||
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
|
||||
export function createSession(host: server.ServerHost, opts: Partial<server.SessionOptions> = {}) {
|
||||
if (opts.typingsInstaller === undefined) {
|
||||
opts.typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/ 5, host);
|
||||
}
|
||||
const opts: server.SessionOptions = {
|
||||
|
||||
if (opts.eventHandler !== undefined) {
|
||||
opts.canUseEvents = true;
|
||||
}
|
||||
|
||||
const sessionOptions: server.SessionOptions = {
|
||||
host,
|
||||
cancellationToken: cancellationToken || server.nullCancellationToken,
|
||||
cancellationToken: server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
typingsInstaller,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: nullLogger,
|
||||
canUseEvents: projectServiceEventHandler !== undefined,
|
||||
eventHandler: projectServiceEventHandler,
|
||||
throttleWaitMilliseconds
|
||||
canUseEvents: false
|
||||
};
|
||||
return new TestSession(opts);
|
||||
|
||||
return new TestSession({ ...sessionOptions, ...opts });
|
||||
}
|
||||
|
||||
export interface CreateProjectServiceParameters {
|
||||
interface CreateProjectServiceParameters {
|
||||
cancellationToken?: HostCancellationToken;
|
||||
logger?: server.Logger;
|
||||
useSingleInferredProject?: boolean;
|
||||
|
@ -230,9 +235,17 @@ namespace ts.projectSystem {
|
|||
|
||||
export class TestProjectService extends server.ProjectService {
|
||||
constructor(host: server.ServerHost, logger: server.Logger, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean,
|
||||
typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler) {
|
||||
typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler, opts: Partial<server.ProjectServiceOptions> = {}) {
|
||||
super({
|
||||
host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, eventHandler, typesMapLocation: customTypesMap.path
|
||||
host,
|
||||
logger,
|
||||
cancellationToken,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller,
|
||||
typesMapLocation: customTypesMap.path,
|
||||
eventHandler,
|
||||
...opts
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -267,15 +280,15 @@ namespace ts.projectSystem {
|
|||
entries: FSEntry[];
|
||||
}
|
||||
|
||||
export function isFolder(s: FSEntry): s is Folder {
|
||||
function isFolder(s: FSEntry): s is Folder {
|
||||
return isArray((<Folder>s).entries);
|
||||
}
|
||||
|
||||
export function isFile(s: FSEntry): s is File {
|
||||
function isFile(s: FSEntry): s is File {
|
||||
return typeof (<File>s).content === "string";
|
||||
}
|
||||
|
||||
export function addFolder(fullPath: string, toPath: (s: string) => Path, fs: Map<FSEntry>): Folder {
|
||||
function addFolder(fullPath: string, toPath: (s: string) => Path, fs: Map<FSEntry>): Folder {
|
||||
const path = toPath(fullPath);
|
||||
if (fs.has(path)) {
|
||||
Debug.assert(isFolder(fs.get(path)));
|
||||
|
@ -293,26 +306,29 @@ namespace ts.projectSystem {
|
|||
return entry;
|
||||
}
|
||||
|
||||
export function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
|
||||
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
|
||||
assert.equal(map.size, expectedKeys.length, `${caption}: incorrect size of map`);
|
||||
for (const name of expectedKeys) {
|
||||
assert.isTrue(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(map.keys())}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
|
||||
assert.sameMembers(actualFileNames, expectedFileNames, caption);
|
||||
function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
|
||||
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected ${JSON.stringify(expectedFileNames)}, got ${actualFileNames}`);
|
||||
for (const f of expectedFileNames) {
|
||||
assert.isTrue(contains(actualFileNames, f), `${caption}: expected to find ${f} in ${JSON.stringify(actualFileNames)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
||||
function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
||||
assert.equal(projectService.configuredProjects.length, expected, `expected ${expected} configured project(s)`);
|
||||
}
|
||||
|
||||
export function checkNumberOfExternalProjects(projectService: server.ProjectService, expected: number) {
|
||||
function checkNumberOfExternalProjects(projectService: server.ProjectService, expected: number) {
|
||||
assert.equal(projectService.externalProjects.length, expected, `expected ${expected} external project(s)`);
|
||||
}
|
||||
|
||||
export function checkNumberOfInferredProjects(projectService: server.ProjectService, expected: number) {
|
||||
function checkNumberOfInferredProjects(projectService: server.ProjectService, expected: number) {
|
||||
assert.equal(projectService.inferredProjects.length, expected, `expected ${expected} inferred project(s)`);
|
||||
}
|
||||
|
||||
|
@ -326,7 +342,7 @@ namespace ts.projectSystem {
|
|||
checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles);
|
||||
}
|
||||
|
||||
export function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[]) {
|
||||
function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[]) {
|
||||
checkMapKeys("watchedDirectories", host.watchedDirectories, expectedDirectories);
|
||||
}
|
||||
|
||||
|
@ -334,11 +350,11 @@ namespace ts.projectSystem {
|
|||
checkFileNames(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
|
||||
}
|
||||
|
||||
export function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
|
||||
function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
|
||||
checkFileNames(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
|
||||
}
|
||||
|
||||
export class Callbacks {
|
||||
class Callbacks {
|
||||
private map: TimeOutCallback[] = [];
|
||||
private nextId = 1;
|
||||
|
||||
|
@ -374,7 +390,7 @@ namespace ts.projectSystem {
|
|||
}
|
||||
}
|
||||
|
||||
export type TimeOutCallback = () => any;
|
||||
type TimeOutCallback = () => any;
|
||||
|
||||
export class TestServerHost implements server.ServerHost {
|
||||
args: string[] = [];
|
||||
|
@ -643,7 +659,7 @@ namespace ts.projectSystem {
|
|||
}
|
||||
}
|
||||
|
||||
describe("tsserver-project-system", () => {
|
||||
describe("tsserverProjectSystem", () => {
|
||||
const commonFile1: FileOrFolder = {
|
||||
path: "/a/b/commonFile1.ts",
|
||||
content: "let x = 1"
|
||||
|
@ -2241,13 +2257,16 @@ namespace ts.projectSystem {
|
|||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ContextEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ContextEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
assert.equal(e.data.project.getProjectName(), config.path, "project name");
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
assert.equal(e.data.project.getProjectName(), config.path, "project name");
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
});
|
||||
session.executeCommand(<protocol.OpenRequest>{
|
||||
seq: 0,
|
||||
|
@ -2291,12 +2310,15 @@ namespace ts.projectSystem {
|
|||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
});
|
||||
session.executeCommand(<protocol.OpenRequest>{
|
||||
seq: 0,
|
||||
|
@ -2342,6 +2364,50 @@ namespace ts.projectSystem {
|
|||
const navbar = projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems(f1.path);
|
||||
assert.equal(navbar[0].spans[0].length, f1.content.length);
|
||||
});
|
||||
|
||||
it("deleting config file opened from the external project works", () => {
|
||||
const site = {
|
||||
path: "/user/someuser/project/js/site.js",
|
||||
content: ""
|
||||
};
|
||||
const configFile = {
|
||||
path: "/user/someuser/project/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const projectFileName = "/user/someuser/project/WebApplication6.csproj";
|
||||
const host = createServerHost([libFile, site, configFile]);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
const externalProject: protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { "include": [] }
|
||||
};
|
||||
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
const configProject = projectService.configuredProjects[0];
|
||||
checkProjectActualFiles(configProject, [libFile.path]);
|
||||
|
||||
const diagnostics = configProject.getAllProjectErrors();
|
||||
assert.equal(diagnostics[0].code, Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
|
||||
|
||||
host.reloadFS([libFile, site]);
|
||||
host.triggerFileWatcherCallback(configFile.path, FileWatcherEventKind.Deleted);
|
||||
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info));
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Proper errors", () => {
|
||||
|
@ -3036,7 +3102,10 @@ namespace ts.projectSystem {
|
|||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
|
||||
|
@ -3063,7 +3132,10 @@ namespace ts.projectSystem {
|
|||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
});
|
||||
|
@ -3082,7 +3154,10 @@ namespace ts.projectSystem {
|
|||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
|
||||
|
@ -3471,6 +3546,93 @@ namespace ts.projectSystem {
|
|||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [f.path]);
|
||||
});
|
||||
|
||||
it("inferred projects per project root", () => {
|
||||
const file1 = { path: "/a/file1.ts", content: "let x = 1;", projectRootPath: "/a" };
|
||||
const file2 = { path: "/a/file2.ts", content: "let y = 2;", projectRootPath: "/a" };
|
||||
const file3 = { path: "/b/file2.ts", content: "let x = 3;", projectRootPath: "/b" };
|
||||
const file4 = { path: "/c/file3.ts", content: "let z = 4;" };
|
||||
const host = createServerHost([file1, file2, file3, file4]);
|
||||
const session = createSession(host, {
|
||||
useSingleInferredProject: true,
|
||||
useInferredProjectPerProjectRoot: true
|
||||
});
|
||||
session.executeCommand(<server.protocol.SetCompilerOptionsForInferredProjectsRequest>{
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: CommandNames.CompilerOptionsForInferredProjects,
|
||||
arguments: {
|
||||
options: {
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ESNext
|
||||
}
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.SetCompilerOptionsForInferredProjectsRequest>{
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: CommandNames.CompilerOptionsForInferredProjects,
|
||||
arguments: {
|
||||
options: {
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ES2015
|
||||
},
|
||||
projectRootPath: "/b"
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 3,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file1.path,
|
||||
fileContent: file1.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file1.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 4,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file2.path,
|
||||
fileContent: file2.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file2.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 5,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file3.path,
|
||||
fileContent: file3.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file3.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 6,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file4.path,
|
||||
fileContent: file4.content,
|
||||
scriptKindName: "JS"
|
||||
}
|
||||
});
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 3 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [file4.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[1], [file1.path, file2.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]);
|
||||
assert.equal(projectService.inferredProjects[0].getCompilerOptions().target, ScriptTarget.ESNext);
|
||||
assert.equal(projectService.inferredProjects[1].getCompilerOptions().target, ScriptTarget.ESNext);
|
||||
assert.equal(projectService.inferredProjects[2].getCompilerOptions().target, ScriptTarget.ES2015);
|
||||
});
|
||||
});
|
||||
|
||||
describe("No overwrite emit error", () => {
|
||||
|
@ -3664,7 +3826,7 @@ namespace ts.projectSystem {
|
|||
resetRequest: noop
|
||||
};
|
||||
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, /*projectServiceEventHandler*/ undefined, cancellationToken);
|
||||
const session = createSession(host, { cancellationToken });
|
||||
|
||||
expectedRequestId = session.getNextSeq();
|
||||
session.executeCommandSeq(<server.protocol.OpenRequest>{
|
||||
|
@ -3704,7 +3866,11 @@ namespace ts.projectSystem {
|
|||
|
||||
const cancellationToken = new TestServerCancellationToken();
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, () => { }, cancellationToken);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: () => { },
|
||||
cancellationToken
|
||||
});
|
||||
{
|
||||
session.executeCommandSeq(<protocol.OpenRequest>{
|
||||
command: "open",
|
||||
|
@ -3837,7 +4003,12 @@ namespace ts.projectSystem {
|
|||
};
|
||||
const cancellationToken = new TestServerCancellationToken(/*cancelAfterRequest*/ 3);
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, () => { }, cancellationToken, /*throttleWaitMilliseconds*/ 0);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: () => { },
|
||||
cancellationToken,
|
||||
throttleWaitMilliseconds: 0
|
||||
});
|
||||
{
|
||||
session.executeCommandSeq(<protocol.OpenRequest>{
|
||||
command: "open",
|
||||
|
|
|
@ -935,25 +935,26 @@ namespace ts.projectSystem {
|
|||
import * as cmd from "commander
|
||||
`
|
||||
};
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
const openRequest: server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
command: server.protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: f.path,
|
||||
fileContent: f.content
|
||||
}
|
||||
});
|
||||
};
|
||||
session.executeCommand(openRequest);
|
||||
const projectService = session.getProjectService();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const proj = projectService.inferredProjects[0];
|
||||
const version1 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
|
||||
// make a change that should not affect the structure of the program
|
||||
session.executeCommand(<server.protocol.ChangeRequest>{
|
||||
const changeRequest: server.protocol.ChangeRequest = {
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "change",
|
||||
command: server.protocol.CommandTypes.Change,
|
||||
arguments: {
|
||||
file: f.path,
|
||||
insertString: "\nlet x = 1;",
|
||||
|
@ -962,7 +963,8 @@ namespace ts.projectSystem {
|
|||
endLine: 2,
|
||||
endOffset: 0
|
||||
}
|
||||
});
|
||||
};
|
||||
session.executeCommand(changeRequest);
|
||||
host.checkTimeoutQueueLength(1);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
|
@ -1050,6 +1052,7 @@ namespace ts.projectSystem {
|
|||
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), safeList, emptyMap, { enable: true }, emptyArray);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from file names: ["jquery","chroma-js"]',
|
||||
"Inferred typings from unresolved imports: []",
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["jquery","chroma-js"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
|
||||
|
@ -1114,6 +1117,8 @@ namespace ts.projectSystem {
|
|||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, /*unresolvedImports*/ []);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Searching for typing names in /node_modules; all files: ["/node_modules/a/package.json"]',
|
||||
' Found package names: ["a"]',
|
||||
"Inferred typings from unresolved imports: []",
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["a"],"filesToWatch":["/bower_components","/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result, {
|
||||
|
|
|
@ -49,6 +49,12 @@ var q:Point=<Point>p;`;
|
|||
validateEditAtLineCharIndex = undefined;
|
||||
});
|
||||
|
||||
it("handles empty lines array", () => {
|
||||
const lineIndex = new server.LineIndex();
|
||||
lineIndex.load([]);
|
||||
assert.deepEqual(lineIndex.positionToLineOffset(0), { line: 1, offset: 1 });
|
||||
});
|
||||
|
||||
it(`change 9 1 0 1 {"y"}`, () => {
|
||||
validateEditAtLineCharIndex(9, 1, 0, "y");
|
||||
});
|
||||
|
|
|
@ -110,7 +110,7 @@ interface Map<K, V> {
|
|||
readonly [Symbol.toStringTag]: "Map";
|
||||
}
|
||||
|
||||
interface WeakMap<K extends object, V>{
|
||||
interface WeakMap<K extends object, V> {
|
||||
readonly [Symbol.toStringTag]: "WeakMap";
|
||||
}
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ interface ObjectConstructor {
|
|||
* Returns the names of the enumerable properties and methods of an object.
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
keys(o: any): string[];
|
||||
keys(o: {}): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -980,12 +980,12 @@ interface ReadonlyArray<T> {
|
|||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: T[][]): T[];
|
||||
concat(...items: ReadonlyArray<T>[]): T[];
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: (T | T[])[]): T[];
|
||||
concat(...items: (T | ReadonlyArray<T>)[]): T[];
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
|
||||
|
@ -1099,12 +1099,12 @@ interface Array<T> {
|
|||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: T[][]): T[];
|
||||
concat(...items: ReadonlyArray<T>[]): T[];
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: (T | T[])[]): T[];
|
||||
concat(...items: (T | ReadonlyArray<T>)[]): T[];
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
|
||||
|
|
|
@ -527,6 +527,10 @@ namespace ts.server {
|
|||
return notImplemented();
|
||||
}
|
||||
|
||||
getSpanOfEnclosingComment(_fileName: string, _position: number, _onlyMultiLine: boolean): TextSpan {
|
||||
return notImplemented();
|
||||
}
|
||||
|
||||
getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: number[]): CodeAction[] {
|
||||
const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes };
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ts.server {
|
|||
|
||||
export interface ConfigFileDiagEvent {
|
||||
eventName: typeof ConfigFileDiagEvent;
|
||||
data: { triggerFile: string, configFileName: string, diagnostics: Diagnostic[] };
|
||||
data: { triggerFile: string, configFileName: string, diagnostics: ReadonlyArray<Diagnostic> };
|
||||
}
|
||||
|
||||
export interface ProjectLanguageServiceStateEvent {
|
||||
|
@ -205,7 +205,7 @@ namespace ts.server {
|
|||
/**
|
||||
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
|
||||
*/
|
||||
export function combineProjectOutput<T>(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
export function combineProjectOutput<T>(projects: ReadonlyArray<Project>, action: (project: Project) => ReadonlyArray<T>, comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
const result = flatMap(projects, action).sort(comparer);
|
||||
return projects.length > 1 ? deduplicate(result, areEqual) : result;
|
||||
}
|
||||
|
@ -225,14 +225,14 @@ namespace ts.server {
|
|||
|
||||
interface OpenConfigFileResult {
|
||||
success: boolean;
|
||||
errors?: Diagnostic[];
|
||||
errors?: ReadonlyArray<Diagnostic>;
|
||||
|
||||
project?: ConfiguredProject;
|
||||
}
|
||||
|
||||
export interface OpenConfiguredProjectResult {
|
||||
configFileName?: NormalizedPath;
|
||||
configFileErrors?: Diagnostic[];
|
||||
configFileErrors?: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
interface FilePropertyReader<T> {
|
||||
|
@ -328,11 +328,12 @@ namespace ts.server {
|
|||
logger: Logger;
|
||||
cancellationToken: HostCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
throttleWaitMilliseconds?: number;
|
||||
globalPlugins?: string[];
|
||||
pluginProbeLocations?: string[];
|
||||
globalPlugins?: ReadonlyArray<string>;
|
||||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads?: boolean;
|
||||
typesMapLocation?: string;
|
||||
}
|
||||
|
@ -370,7 +371,7 @@ namespace ts.server {
|
|||
readonly openFiles: ScriptInfo[] = [];
|
||||
|
||||
private compilerOptionsForInferredProjects: CompilerOptions;
|
||||
private compileOnSaveForInferredProjects: boolean;
|
||||
private compilerOptionsForInferredProjectsPerProjectRoot = createMap<CompilerOptions>();
|
||||
private readonly projectToSizeMap: Map<number> = createMap<number>();
|
||||
private readonly directoryWatchers: DirectoryWatchers;
|
||||
private readonly throttledOperations: ThrottledOperations;
|
||||
|
@ -388,6 +389,7 @@ namespace ts.server {
|
|||
public readonly logger: Logger;
|
||||
public readonly cancellationToken: HostCancellationToken;
|
||||
public readonly useSingleInferredProject: boolean;
|
||||
public readonly useInferredProjectPerProjectRoot: boolean;
|
||||
public readonly typingsInstaller: ITypingsInstaller;
|
||||
public readonly throttleWaitMilliseconds?: number;
|
||||
private readonly eventHandler?: ProjectServiceEventHandler;
|
||||
|
@ -405,6 +407,7 @@ namespace ts.server {
|
|||
this.logger = opts.logger;
|
||||
this.cancellationToken = opts.cancellationToken;
|
||||
this.useSingleInferredProject = opts.useSingleInferredProject;
|
||||
this.useInferredProjectPerProjectRoot = opts.useInferredProjectPerProjectRoot;
|
||||
this.typingsInstaller = opts.typingsInstaller || nullTypingsInstaller;
|
||||
this.throttleWaitMilliseconds = opts.throttleWaitMilliseconds;
|
||||
this.eventHandler = opts.eventHandler;
|
||||
|
@ -453,19 +456,21 @@ namespace ts.server {
|
|||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
this.eventHandler(<ProjectLanguageServiceStateEvent>{
|
||||
const event: ProjectLanguageServiceStateEvent = {
|
||||
eventName: ProjectLanguageServiceStateEvent,
|
||||
data: { project, languageServiceEnabled }
|
||||
});
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
|
||||
private loadTypesMap() {
|
||||
if (!this.host.fileExists(this.typesMapLocation)) {
|
||||
this.logger.info(`Provided types map file "${this.typesMapLocation}" doesn't exist`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const raw: TypesMapFile = JSON.parse(this.host.readFile(this.typesMapLocation));
|
||||
const fileContent = this.host.readFile(this.typesMapLocation);
|
||||
if (fileContent === undefined) {
|
||||
this.logger.info(`Provided types map file "${this.typesMapLocation}" doesn't exist`);
|
||||
return;
|
||||
}
|
||||
const raw: TypesMapFile = JSON.parse(fileContent);
|
||||
// Parse the regexps
|
||||
for (const k of Object.keys(raw.typesMap)) {
|
||||
raw.typesMap[k].match = new RegExp(raw.typesMap[k].match as {} as string, "i");
|
||||
|
@ -495,17 +500,42 @@ namespace ts.server {
|
|||
project.updateGraph();
|
||||
}
|
||||
|
||||
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions): void {
|
||||
this.compilerOptionsForInferredProjects = convertCompilerOptions(projectCompilerOptions);
|
||||
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions, projectRootPath?: string): void {
|
||||
Debug.assert(projectRootPath === undefined || this.useInferredProjectPerProjectRoot, "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled");
|
||||
|
||||
const compilerOptions = convertCompilerOptions(projectCompilerOptions);
|
||||
|
||||
// always set 'allowNonTsExtensions' for inferred projects since user cannot configure it from the outside
|
||||
// previously we did not expose a way for user to change these settings and this option was enabled by default
|
||||
this.compilerOptionsForInferredProjects.allowNonTsExtensions = true;
|
||||
this.compileOnSaveForInferredProjects = projectCompilerOptions.compileOnSave;
|
||||
for (const proj of this.inferredProjects) {
|
||||
proj.setCompilerOptions(this.compilerOptionsForInferredProjects);
|
||||
proj.compileOnSaveEnabled = projectCompilerOptions.compileOnSave;
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
|
||||
if (projectRootPath) {
|
||||
this.compilerOptionsForInferredProjectsPerProjectRoot.set(projectRootPath, compilerOptions);
|
||||
}
|
||||
this.updateProjectGraphs(this.inferredProjects);
|
||||
else {
|
||||
this.compilerOptionsForInferredProjects = compilerOptions;
|
||||
}
|
||||
|
||||
const updatedProjects: Project[] = [];
|
||||
for (const project of this.inferredProjects) {
|
||||
// Only update compiler options in the following cases:
|
||||
// - Inferred projects without a projectRootPath, if the new options do not apply to
|
||||
// a workspace root
|
||||
// - Inferred projects with a projectRootPath, if the new options do not apply to a
|
||||
// workspace root and there is no more specific set of options for that project's
|
||||
// root path
|
||||
// - Inferred projects with a projectRootPath, if the new options apply to that
|
||||
// project root path.
|
||||
if (projectRootPath ?
|
||||
project.projectRootPath === projectRootPath :
|
||||
!project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath)) {
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
project.compileOnSaveEnabled = compilerOptions.compileOnSave;
|
||||
updatedProjects.push(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateProjectGraphs(updatedProjects);
|
||||
}
|
||||
|
||||
stopWatchingDirectory(directory: string) {
|
||||
|
@ -634,10 +664,11 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
for (const openFile of this.openFiles) {
|
||||
this.eventHandler(<ContextEvent>{
|
||||
const event: ContextEvent = {
|
||||
eventName: ContextEvent,
|
||||
data: { project: openFile.getDefaultProject(), fileName: openFile.fileName }
|
||||
});
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,7 +776,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private assignScriptInfoToInferredProjectIfNecessary(info: ScriptInfo, addToListOfOpenFiles: boolean): void {
|
||||
private assignScriptInfoToInferredProjectIfNecessary(info: ScriptInfo, addToListOfOpenFiles: boolean, projectRootPath?: string): void {
|
||||
const externalProject = this.findContainingExternalProject(info.fileName);
|
||||
if (externalProject) {
|
||||
// file is already included in some external project - do nothing
|
||||
|
@ -773,30 +804,30 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
if (info.containingProjects.length === 0) {
|
||||
// create new inferred project p with the newly opened file as root
|
||||
// or add root to existing inferred project if 'useOneInferredProject' is true
|
||||
const inferredProject = this.createInferredProjectWithRootFileIfNecessary(info);
|
||||
if (!this.useSingleInferredProject) {
|
||||
// if useOneInferredProject is not set then try to fixup ownership of open files
|
||||
// check 'defaultProject !== inferredProject' is necessary to handle cases
|
||||
// when creation inferred project for some file has added other open files into this project (i.e. as referenced files)
|
||||
// we definitely don't want to delete the project that was just created
|
||||
// get (or create) an inferred project using the newly opened file as a root.
|
||||
const inferredProject = this.createInferredProjectWithRootFileIfNecessary(info, projectRootPath);
|
||||
if (!this.useSingleInferredProject && !inferredProject.projectRootPath) {
|
||||
// if useSingleInferredProject is false and the inferred project is not associated
|
||||
// with a project root, then try to repair the ownership of open files.
|
||||
for (const f of this.openFiles) {
|
||||
if (f.containingProjects.length === 0 || !inferredProject.containsScriptInfo(f)) {
|
||||
// this is orphaned file that we have not processed yet - skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const fContainingProject of f.containingProjects) {
|
||||
if (fContainingProject.projectKind === ProjectKind.Inferred &&
|
||||
fContainingProject.isRoot(f) &&
|
||||
fContainingProject !== inferredProject) {
|
||||
|
||||
for (const containingProject of f.containingProjects) {
|
||||
// We verify 'containingProject !== inferredProject' to handle cases
|
||||
// where the inferred project for some file has added other open files
|
||||
// into this project (i.e. as referenced files) as we don't want to
|
||||
// delete the project that was just created
|
||||
if (containingProject.projectKind === ProjectKind.Inferred &&
|
||||
containingProject !== inferredProject &&
|
||||
containingProject.isRoot(f)) {
|
||||
// open file used to be root in inferred project,
|
||||
// this inferred project is different from the one we've just created for current file
|
||||
// and new inferred project references this open file.
|
||||
// We should delete old inferred project and attach open file to the new one
|
||||
this.removeProject(fContainingProject);
|
||||
this.removeProject(containingProject);
|
||||
f.attachToProject(inferredProject);
|
||||
}
|
||||
}
|
||||
|
@ -961,11 +992,20 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
this.logger.startGroup();
|
||||
|
||||
let counter = 0;
|
||||
counter = printProjects(this.logger, this.externalProjects, counter);
|
||||
counter = printProjects(this.logger, this.configuredProjects, counter);
|
||||
counter = printProjects(this.logger, this.inferredProjects, counter);
|
||||
const printProjects = (projects: Project[], counter: number): number => {
|
||||
for (const project of projects) {
|
||||
project.updateGraph();
|
||||
this.logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
|
||||
this.logger.info(project.filesToString());
|
||||
this.logger.info("-----------------------------------------------");
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
};
|
||||
counter = printProjects(this.externalProjects, counter);
|
||||
counter = printProjects(this.configuredProjects, counter);
|
||||
printProjects(this.inferredProjects, counter);
|
||||
|
||||
this.logger.info("Open files: ");
|
||||
for (const rootFile of this.openFiles) {
|
||||
|
@ -973,17 +1013,6 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
this.logger.endGroup();
|
||||
|
||||
function printProjects(logger: Logger, projects: Project[], counter: number) {
|
||||
for (const project of projects) {
|
||||
project.updateGraph();
|
||||
logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
|
||||
logger.info(project.filesToString());
|
||||
logger.info("-----------------------------------------------");
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
|
||||
private findConfiguredProjectByProjectName(configFileName: NormalizedPath) {
|
||||
|
@ -1134,18 +1163,19 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile: string) {
|
||||
private reportConfigFileDiagnostics(configFileName: string, diagnostics: ReadonlyArray<Diagnostic>, triggerFile: string) {
|
||||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventHandler(<ConfigFileDiagEvent>{
|
||||
const event: ConfigFileDiagEvent = {
|
||||
eventName: ConfigFileDiagEvent,
|
||||
data: { configFileName, diagnostics: diagnostics || [], triggerFile }
|
||||
});
|
||||
data: { configFileName, diagnostics: diagnostics || emptyArray, triggerFile }
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
|
||||
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: Diagnostic[], clientFileName?: string) {
|
||||
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: ReadonlyArray<Diagnostic>, clientFileName?: string) {
|
||||
const sizeLimitExceeded = this.exceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
|
||||
const project = new ConfiguredProject(
|
||||
configFileName,
|
||||
|
@ -1177,7 +1207,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typeAcquisition: TypeAcquisition, configFileErrors: Diagnostic[]): void {
|
||||
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typeAcquisition: TypeAcquisition, configFileErrors: ReadonlyArray<Diagnostic>): void {
|
||||
let errors: Diagnostic[];
|
||||
for (const f of files) {
|
||||
const rootFilename = propertyReader.getFileName(f);
|
||||
|
@ -1317,11 +1347,74 @@ namespace ts.server {
|
|||
return configFileErrors;
|
||||
}
|
||||
|
||||
createInferredProjectWithRootFileIfNecessary(root: ScriptInfo) {
|
||||
const useExistingProject = this.useSingleInferredProject && this.inferredProjects.length;
|
||||
const project = useExistingProject
|
||||
? this.inferredProjects[0]
|
||||
: new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects);
|
||||
private getOrCreateInferredProjectForProjectRootPathIfEnabled(root: ScriptInfo, projectRootPath: string | undefined): InferredProject | undefined {
|
||||
if (!this.useInferredProjectPerProjectRoot) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (projectRootPath) {
|
||||
// if we have an explicit project root path, find (or create) the matching inferred project.
|
||||
for (const project of this.inferredProjects) {
|
||||
if (project.projectRootPath === projectRootPath) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
return this.createInferredProject(/*isSingleInferredProject*/ false, projectRootPath);
|
||||
}
|
||||
|
||||
// we don't have an explicit root path, so we should try to find an inferred project
|
||||
// that more closely contains the file.
|
||||
let bestMatch: InferredProject;
|
||||
for (const project of this.inferredProjects) {
|
||||
// ignore single inferred projects (handled elsewhere)
|
||||
if (!project.projectRootPath) continue;
|
||||
// ignore inferred projects that don't contain the root's path
|
||||
if (!containsPath(project.projectRootPath, root.path, this.host.getCurrentDirectory(), !this.host.useCaseSensitiveFileNames)) continue;
|
||||
// ignore inferred projects that are higher up in the project root.
|
||||
// TODO(rbuckton): Should we add the file as a root to these as well?
|
||||
if (bestMatch && bestMatch.projectRootPath.length > project.projectRootPath.length) continue;
|
||||
bestMatch = project;
|
||||
}
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
private getOrCreateSingleInferredProjectIfEnabled(): InferredProject | undefined {
|
||||
if (!this.useSingleInferredProject) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If `useInferredProjectPerProjectRoot` is not enabled, then there will only be one
|
||||
// inferred project for all files. If `useInferredProjectPerProjectRoot` is enabled
|
||||
// then we want to put all files that are not opened with a `projectRootPath` into
|
||||
// the same inferred project.
|
||||
//
|
||||
// To avoid the cost of searching through the array and to optimize for the case where
|
||||
// `useInferredProjectPerProjectRoot` is not enabled, we will always put the inferred
|
||||
// project for non-rooted files at the front of the array.
|
||||
if (this.inferredProjects.length > 0 && this.inferredProjects[0].projectRootPath === undefined) {
|
||||
return this.inferredProjects[0];
|
||||
}
|
||||
|
||||
return this.createInferredProject(/*isSingleInferredProject*/ true);
|
||||
}
|
||||
|
||||
private createInferredProject(isSingleInferredProject?: boolean, projectRootPath?: string): InferredProject {
|
||||
const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects;
|
||||
const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath);
|
||||
if (isSingleInferredProject) {
|
||||
this.inferredProjects.unshift(project);
|
||||
}
|
||||
else {
|
||||
this.inferredProjects.push(project);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
createInferredProjectWithRootFileIfNecessary(root: ScriptInfo, projectRootPath?: string) {
|
||||
const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(root, projectRootPath) ||
|
||||
this.getOrCreateSingleInferredProjectIfEnabled() ||
|
||||
this.createInferredProject();
|
||||
|
||||
project.addRoot(root);
|
||||
|
||||
|
@ -1332,9 +1425,6 @@ namespace ts.server {
|
|||
|
||||
project.updateGraph();
|
||||
|
||||
if (!useExistingProject) {
|
||||
this.inferredProjects.push(project);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
|
@ -1490,7 +1580,7 @@ namespace ts.server {
|
|||
|
||||
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
|
||||
let configFileName: NormalizedPath;
|
||||
let configFileErrors: Diagnostic[];
|
||||
let configFileErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
let project: ConfiguredProject | ExternalProject = this.findContainingExternalProject(fileName);
|
||||
if (!project) {
|
||||
|
@ -1508,7 +1598,7 @@ namespace ts.server {
|
|||
|
||||
// at this point if file is the part of some configured/external project then this project should be created
|
||||
const info = this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
|
||||
this.assignScriptInfoToInferredProjectIfNecessary(info, /*addToListOfOpenFiles*/ true);
|
||||
this.assignScriptInfoToInferredProjectIfNecessary(info, /*addToListOfOpenFiles*/ true, projectRootPath);
|
||||
// Delete the orphan files here because there might be orphan script infos (which are not part of project)
|
||||
// when some file/s were closed which resulted in project removal.
|
||||
// It was then postponed to cleanup these script infos so that they can be reused if
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace ts.server {
|
|||
|
||||
/* @internal */
|
||||
export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles {
|
||||
projectErrors: Diagnostic[];
|
||||
projectErrors: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
export class UnresolvedImportsMap {
|
||||
|
@ -147,7 +147,7 @@ namespace ts.server {
|
|||
|
||||
private typingFiles: SortedReadonlyArray<string>;
|
||||
|
||||
protected projectErrors: Diagnostic[];
|
||||
protected projectErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
public typesVersion = 0;
|
||||
|
||||
|
@ -170,7 +170,8 @@ namespace ts.server {
|
|||
log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`);
|
||||
const result = host.require(resolvedPath, moduleName);
|
||||
if (result.error) {
|
||||
log(`Failed to load module: ${JSON.stringify(result.error)}`);
|
||||
const err = result.error.stack || result.error.message || JSON.stringify(result.error);
|
||||
log(`Failed to load module '${moduleName}': ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
return result.module;
|
||||
|
@ -362,7 +363,7 @@ namespace ts.server {
|
|||
return map(this.program.getSourceFiles(), sourceFile => {
|
||||
const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.path);
|
||||
if (!scriptInfo) {
|
||||
Debug.assert(false, `scriptInfo for a file '${sourceFile.fileName}' is missing.`);
|
||||
Debug.fail(`scriptInfo for a file '${sourceFile.fileName}' is missing.`);
|
||||
}
|
||||
return scriptInfo;
|
||||
});
|
||||
|
@ -498,7 +499,7 @@ namespace ts.server {
|
|||
this.projectStateVersion++;
|
||||
}
|
||||
|
||||
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: string[]) {
|
||||
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: Push<string>) {
|
||||
const cached = this.cachedUnresolvedImportsPerFile.get(file.path);
|
||||
if (cached) {
|
||||
// found cached result - use it and return
|
||||
|
@ -558,7 +559,7 @@ namespace ts.server {
|
|||
for (const sourceFile of this.program.getSourceFiles()) {
|
||||
this.extractUnresolvedImportsFromSourceFile(sourceFile, result);
|
||||
}
|
||||
this.lastCachedUnresolvedImportsList = toSortedArray(result);
|
||||
this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result);
|
||||
}
|
||||
unresolvedImports = this.lastCachedUnresolvedImportsList;
|
||||
|
||||
|
@ -840,6 +841,7 @@ namespace ts.server {
|
|||
* the file and its imports/references are put into an InferredProject.
|
||||
*/
|
||||
export class InferredProject extends Project {
|
||||
public readonly projectRootPath: string | undefined;
|
||||
|
||||
private static readonly newName = (() => {
|
||||
let nextId = 1;
|
||||
|
@ -879,7 +881,7 @@ namespace ts.server {
|
|||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
|
||||
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions) {
|
||||
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, projectRootPath?: string) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
projectService,
|
||||
|
@ -888,6 +890,7 @@ namespace ts.server {
|
|||
/*languageServiceEnabled*/ true,
|
||||
compilerOptions,
|
||||
/*compileOnSaveEnabled*/ false);
|
||||
this.projectRootPath = projectRootPath;
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
|
@ -940,9 +943,9 @@ namespace ts.server {
|
|||
export class ConfiguredProject extends Project {
|
||||
private typeAcquisition: TypeAcquisition;
|
||||
private projectFileWatcher: FileWatcher;
|
||||
private directoryWatcher: FileWatcher;
|
||||
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
private typeRootsWatchers: FileWatcher[];
|
||||
private directoryWatcher: FileWatcher | undefined;
|
||||
private directoriesWatchedForWildcards: Map<FileWatcher> | undefined;
|
||||
private typeRootsWatchers: FileWatcher[] | undefined;
|
||||
readonly canonicalConfigFilePath: NormalizedPath;
|
||||
|
||||
private plugins: PluginModule[] = [];
|
||||
|
@ -1048,7 +1051,7 @@ namespace ts.server {
|
|||
return getDirectoryPath(this.getConfigFilePath());
|
||||
}
|
||||
|
||||
setProjectErrors(projectErrors: Diagnostic[]) {
|
||||
setProjectErrors(projectErrors: ReadonlyArray<Diagnostic>) {
|
||||
this.projectErrors = projectErrors;
|
||||
}
|
||||
|
||||
|
@ -1138,10 +1141,12 @@ namespace ts.server {
|
|||
this.typeRootsWatchers = undefined;
|
||||
}
|
||||
|
||||
this.directoriesWatchedForWildcards.forEach(watcher => {
|
||||
watcher.close();
|
||||
});
|
||||
this.directoriesWatchedForWildcards = undefined;
|
||||
if (this.directoriesWatchedForWildcards) {
|
||||
this.directoriesWatchedForWildcards.forEach(watcher => {
|
||||
watcher.close();
|
||||
});
|
||||
this.directoriesWatchedForWildcards = undefined;
|
||||
}
|
||||
|
||||
this.stopWatchingDirectory();
|
||||
}
|
||||
|
@ -1196,7 +1201,7 @@ namespace ts.server {
|
|||
return this.typeAcquisition;
|
||||
}
|
||||
|
||||
setProjectErrors(projectErrors: Diagnostic[]) {
|
||||
setProjectErrors(projectErrors: ReadonlyArray<Diagnostic>) {
|
||||
this.projectErrors = projectErrors;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace ts.server.protocol {
|
|||
/* @internal */
|
||||
BraceFull = "brace-full",
|
||||
BraceCompletion = "braceCompletion",
|
||||
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
|
||||
Change = "change",
|
||||
Close = "close",
|
||||
Completions = "completions",
|
||||
|
@ -241,6 +242,21 @@ namespace ts.server.protocol {
|
|||
body?: TodoComment[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to determine if the caret is inside a comment.
|
||||
*/
|
||||
export interface SpanOfEnclosingCommentRequest extends FileLocationRequest {
|
||||
command: CommandTypes.GetSpanOfEnclosingComment;
|
||||
arguments: SpanOfEnclosingCommentRequestArgs;
|
||||
}
|
||||
|
||||
export interface SpanOfEnclosingCommentRequestArgs extends FileLocationRequestArgs {
|
||||
/**
|
||||
* Requires that the enclosing span be a multi-line comment, or else the request returns undefined.
|
||||
*/
|
||||
onlyMultiLine: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to obtain outlining spans in file.
|
||||
*/
|
||||
|
@ -914,7 +930,7 @@ namespace ts.server.protocol {
|
|||
/**
|
||||
* An array of span groups (one per file) that refer to the item to be renamed.
|
||||
*/
|
||||
locs: SpanGroup[];
|
||||
locs: ReadonlyArray<SpanGroup>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1304,6 +1320,13 @@ namespace ts.server.protocol {
|
|||
* Compiler options to be used with inferred projects.
|
||||
*/
|
||||
options: ExternalProjectCompilerOptions;
|
||||
|
||||
/**
|
||||
* Specifies the project root path used to scope compiler options.
|
||||
* It is an error to provide this property if the server has not been started with
|
||||
* `useInferredProjectPerProjectRoot` enabled.
|
||||
*/
|
||||
projectRootPath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2429,6 +2452,7 @@ namespace ts.server.protocol {
|
|||
paths?: MapLike<string[]>;
|
||||
plugins?: PluginImport[];
|
||||
preserveConstEnums?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
project?: string;
|
||||
reactNamespace?: string;
|
||||
removeComments?: boolean;
|
||||
|
@ -2465,6 +2489,7 @@ namespace ts.server.protocol {
|
|||
System = "System",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
ESNext = "ESNext"
|
||||
}
|
||||
|
||||
export const enum ModuleResolutionKind {
|
||||
|
@ -2482,5 +2507,8 @@ namespace ts.server.protocol {
|
|||
ES5 = "ES5",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
ES2016 = "ES2016",
|
||||
ES2017 = "ES2017",
|
||||
ESNext = "ESNext"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ts.server {
|
|||
|
||||
public getVersion() {
|
||||
return this.svc
|
||||
? `SVC-${this.svcVersion}-${this.svc.getSnapshot().version}`
|
||||
? `SVC-${this.svcVersion}-${this.svc.getSnapshotVersion()}`
|
||||
: `Text-${this.textVersion}`;
|
||||
}
|
||||
|
||||
|
@ -62,22 +62,19 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
public getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line);
|
||||
return this.switchToScriptVersionCache().getLineInfo(line);
|
||||
}
|
||||
/**
|
||||
* @param line 0 based index
|
||||
*/
|
||||
lineToTextSpan(line: number) {
|
||||
lineToTextSpan(line: number): TextSpan {
|
||||
if (!this.svc) {
|
||||
const lineMap = this.getLineMap();
|
||||
const start = lineMap[line]; // -1 since line is 1-based
|
||||
const end = line + 1 < lineMap.length ? lineMap[line + 1] : this.text.length;
|
||||
return createTextSpanFromBounds(start, end);
|
||||
}
|
||||
const index = this.svc.getSnapshot().index;
|
||||
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
|
||||
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
|
||||
return createTextSpan(absolutePosition, len);
|
||||
return this.svc.lineToTextSpan(line);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +87,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
// TODO: assert this offset is actually on the line
|
||||
return this.svc.getSnapshot().index.absolutePositionOfStartOfLine(line) + (offset - 1);
|
||||
return this.svc.lineOffsetToPosition(line, offset);
|
||||
}
|
||||
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
|
@ -98,7 +95,7 @@ namespace ts.server {
|
|||
const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position);
|
||||
return { line: line + 1, offset: character + 1 };
|
||||
}
|
||||
return this.svc.getSnapshot().index.positionToLineOffset(position);
|
||||
return this.svc.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
private getFileText(tempFileName?: string) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace ts.server {
|
||||
const lineCollectionCapacity = 4;
|
||||
|
||||
export interface LineCollection {
|
||||
interface LineCollection {
|
||||
charCount(): number;
|
||||
lineCount(): number;
|
||||
isLeaf(): this is LineLeaf;
|
||||
|
@ -17,7 +17,7 @@ namespace ts.server {
|
|||
lineText: string | undefined;
|
||||
}
|
||||
|
||||
export enum CharRangeSection {
|
||||
const enum CharRangeSection {
|
||||
PreStart,
|
||||
Start,
|
||||
Entire,
|
||||
|
@ -26,7 +26,7 @@ namespace ts.server {
|
|||
PostEnd
|
||||
}
|
||||
|
||||
export interface ILineIndexWalker {
|
||||
interface ILineIndexWalker {
|
||||
goSubtree: boolean;
|
||||
done: boolean;
|
||||
leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void;
|
||||
|
@ -243,7 +243,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
// text change information
|
||||
export class TextChange {
|
||||
class TextChange {
|
||||
constructor(public pos: number, public deleteLen: number, public insertedText?: string) {
|
||||
}
|
||||
|
||||
|
@ -285,17 +285,6 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
latest() {
|
||||
return this.versions[this.currentVersionToIndex()];
|
||||
}
|
||||
|
||||
latestVersion() {
|
||||
if (this.changes.length > 0) {
|
||||
this.getSnapshot();
|
||||
}
|
||||
return this.currentVersion;
|
||||
}
|
||||
|
||||
// reload whole script, leaving no change history behind reload
|
||||
reload(script: string) {
|
||||
this.currentVersion++;
|
||||
|
@ -314,7 +303,9 @@ namespace ts.server {
|
|||
this.minVersion = this.currentVersion;
|
||||
}
|
||||
|
||||
getSnapshot() {
|
||||
getSnapshot(): IScriptSnapshot { return this._getSnapshot(); }
|
||||
|
||||
private _getSnapshot(): LineIndexSnapshot {
|
||||
let snap = this.versions[this.currentVersionToIndex()];
|
||||
if (this.changes.length > 0) {
|
||||
let snapIndex = snap.index;
|
||||
|
@ -334,6 +325,29 @@ namespace ts.server {
|
|||
return snap;
|
||||
}
|
||||
|
||||
getSnapshotVersion(): number {
|
||||
return this._getSnapshot().version;
|
||||
}
|
||||
|
||||
getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this._getSnapshot().index.lineNumberToInfo(line);
|
||||
}
|
||||
|
||||
lineOffsetToPosition(line: number, column: number): number {
|
||||
return this._getSnapshot().index.absolutePositionOfStartOfLine(line) + (column - 1);
|
||||
}
|
||||
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
return this._getSnapshot().index.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
lineToTextSpan(line: number): TextSpan {
|
||||
const index = this._getSnapshot().index;
|
||||
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
|
||||
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
|
||||
return createTextSpan(absolutePosition, len);
|
||||
}
|
||||
|
||||
getTextChangesBetweenVersions(oldVersion: number, newVersion: number) {
|
||||
if (oldVersion < newVersion) {
|
||||
if (oldVersion >= this.minVersion) {
|
||||
|
@ -365,7 +379,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
export class LineIndexSnapshot implements IScriptSnapshot {
|
||||
class LineIndexSnapshot implements IScriptSnapshot {
|
||||
constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: ReadonlyArray<TextChange> = emptyArray) {
|
||||
}
|
||||
|
||||
|
@ -389,6 +403,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export class LineIndex {
|
||||
root: LineNode;
|
||||
// set this to true to check each edit for accuracy
|
||||
|
@ -561,7 +576,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
export class LineNode implements LineCollection {
|
||||
class LineNode implements LineCollection {
|
||||
totalChars = 0;
|
||||
totalLines = 0;
|
||||
|
||||
|
@ -660,45 +675,29 @@ namespace ts.server {
|
|||
// Input position is relative to the start of this node.
|
||||
// Output line number is absolute.
|
||||
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
|
||||
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
|
||||
if (!childInfo.child) {
|
||||
return {
|
||||
oneBasedLine: lineNumberAccumulator,
|
||||
zeroBasedColumn: relativePosition,
|
||||
lineText: undefined,
|
||||
};
|
||||
if (this.children.length === 0) {
|
||||
// Root node might have no children if this is an empty document.
|
||||
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined };
|
||||
}
|
||||
else if (childInfo.childIndex < this.children.length) {
|
||||
if (childInfo.child.isLeaf()) {
|
||||
return {
|
||||
oneBasedLine: childInfo.lineNumberAccumulator,
|
||||
zeroBasedColumn: childInfo.relativePosition,
|
||||
lineText: childInfo.child.text,
|
||||
};
|
||||
|
||||
for (const child of this.children) {
|
||||
if (child.charCount() > relativePosition) {
|
||||
if (child.isLeaf()) {
|
||||
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text };
|
||||
}
|
||||
else {
|
||||
return (<LineNode>child).charOffsetToLineInfo(lineNumberAccumulator, relativePosition);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
|
||||
relativePosition -= child.charCount();
|
||||
lineNumberAccumulator += child.lineCount();
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
|
||||
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
|
||||
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
|
||||
if (!childInfo.child) {
|
||||
return { position: positionAccumulator, leaf: undefined };
|
||||
}
|
||||
else if (childInfo.child.isLeaf()) {
|
||||
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
|
||||
}
|
||||
// Skipped all children
|
||||
const { leaf } = this.lineNumberToInfo(this.lineCount(), 0);
|
||||
return { oneBasedLine: this.lineCount(), zeroBasedColumn: leaf.charCount(), lineText: undefined };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -706,39 +705,19 @@ namespace ts.server {
|
|||
* Output line number is relative to the child.
|
||||
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
|
||||
*/
|
||||
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let i: number;
|
||||
for (i = 0; i < this.children.length; i++) {
|
||||
child = this.children[i];
|
||||
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
|
||||
for (const child of this.children) {
|
||||
const childLineCount = child.lineCount();
|
||||
if (childLineCount >= relativeOneBasedLine) {
|
||||
break;
|
||||
return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (<LineNode>child).lineNumberToInfo(relativeOneBasedLine, positionAccumulator);
|
||||
}
|
||||
else {
|
||||
relativeOneBasedLine -= childLineCount;
|
||||
positionAccumulator += child.charCount();
|
||||
}
|
||||
}
|
||||
return { child, relativeOneBasedLine, positionAccumulator };
|
||||
}
|
||||
|
||||
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
|
||||
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let i: number;
|
||||
let len: number;
|
||||
for (i = 0, len = this.children.length; i < len; i++) {
|
||||
child = this.children[i];
|
||||
if (child.charCount() > relativePosition) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
relativePosition -= child.charCount();
|
||||
lineNumberAccumulator += child.lineCount();
|
||||
}
|
||||
}
|
||||
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
|
||||
return { position: positionAccumulator, leaf: undefined };
|
||||
}
|
||||
|
||||
private splitAfter(childIndex: number) {
|
||||
|
@ -844,7 +823,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
export class LineLeaf implements LineCollection {
|
||||
class LineLeaf implements LineCollection {
|
||||
constructor(public text: string) {
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace ts.server {
|
|||
canUseEvents: boolean;
|
||||
installerEventPort: number;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
disableAutomaticTypingAcquisition: boolean;
|
||||
globalTypingsCacheLocation: string;
|
||||
logger: Logger;
|
||||
|
@ -16,8 +17,8 @@ namespace ts.server {
|
|||
typesMapLocation: string | undefined;
|
||||
npmLocation: string | undefined;
|
||||
telemetryEnabled: boolean;
|
||||
globalPlugins: string[];
|
||||
pluginProbeLocations: string[];
|
||||
globalPlugins: ReadonlyArray<string>;
|
||||
pluginProbeLocations: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads: boolean;
|
||||
}
|
||||
|
||||
|
@ -117,8 +118,6 @@ namespace ts.server {
|
|||
birthtime: Date;
|
||||
}
|
||||
|
||||
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
|
||||
|
||||
const readline: {
|
||||
createInterface(options: ReadLineOptions): NodeJS.EventEmitter;
|
||||
} = require("readline");
|
||||
|
@ -180,6 +179,10 @@ namespace ts.server {
|
|||
this.msg(s, Msg.Info);
|
||||
}
|
||||
|
||||
err(s: string) {
|
||||
this.msg(s, Msg.Err);
|
||||
}
|
||||
|
||||
startGroup() {
|
||||
this.inGroup = true;
|
||||
this.firstInGroup = true;
|
||||
|
@ -187,8 +190,6 @@ namespace ts.server {
|
|||
|
||||
endGroup() {
|
||||
this.inGroup = false;
|
||||
this.seq++;
|
||||
this.firstInGroup = true;
|
||||
}
|
||||
|
||||
loggingEnabled() {
|
||||
|
@ -200,25 +201,31 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
msg(s: string, type: Msg.Types = Msg.Err) {
|
||||
if (this.fd >= 0 || this.traceToConsole) {
|
||||
s = `[${nowString()}] ${s}\n`;
|
||||
if (!this.canWrite) return;
|
||||
|
||||
s = `[${nowString()}] ${s}\n`;
|
||||
if (!this.inGroup || this.firstInGroup) {
|
||||
const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " ");
|
||||
if (this.firstInGroup) {
|
||||
s = prefix + s;
|
||||
this.firstInGroup = false;
|
||||
}
|
||||
if (!this.inGroup) {
|
||||
this.seq++;
|
||||
this.firstInGroup = true;
|
||||
}
|
||||
if (this.fd >= 0) {
|
||||
const buf = new Buffer(s);
|
||||
// tslint:disable-next-line no-null-keyword
|
||||
fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null);
|
||||
}
|
||||
if (this.traceToConsole) {
|
||||
console.warn(s);
|
||||
}
|
||||
s = prefix + s;
|
||||
}
|
||||
this.write(s);
|
||||
if (!this.inGroup) {
|
||||
this.seq++;
|
||||
}
|
||||
}
|
||||
|
||||
private get canWrite() {
|
||||
return this.fd >= 0 || this.traceToConsole;
|
||||
}
|
||||
|
||||
private write(s: string) {
|
||||
if (this.fd >= 0) {
|
||||
const buf = new Buffer(s);
|
||||
// tslint:disable-next-line no-null-keyword
|
||||
fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null);
|
||||
}
|
||||
if (this.traceToConsole) {
|
||||
console.warn(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,6 +422,7 @@ namespace ts.server {
|
|||
host,
|
||||
cancellationToken,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot,
|
||||
typingsInstaller: typingsInstaller || nullTypingsInstaller,
|
||||
byteLength: Buffer.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
|
@ -762,15 +770,26 @@ namespace ts.server {
|
|||
validateLocaleAndSetLanguage(localeStr, sys);
|
||||
}
|
||||
|
||||
setStackTraceLimit();
|
||||
|
||||
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation);
|
||||
const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(sys.getExecutingFilePath(), "../typesMap.json");
|
||||
const npmLocation = findArgument(Arguments.NpmLocation);
|
||||
|
||||
const globalPlugins = (findArgument("--globalPlugins") || "").split(",");
|
||||
const pluginProbeLocations = (findArgument("--pluginProbeLocations") || "").split(",");
|
||||
function parseStringArray(argName: string): ReadonlyArray<string> {
|
||||
const arg = findArgument(argName);
|
||||
if (arg === undefined) {
|
||||
return emptyArray;
|
||||
}
|
||||
return arg.split(",").filter(name => name !== "");
|
||||
}
|
||||
|
||||
const globalPlugins = parseStringArray("--globalPlugins");
|
||||
const pluginProbeLocations = parseStringArray("--pluginProbeLocations");
|
||||
const allowLocalPluginLoads = hasArgument("--allowLocalPluginLoads");
|
||||
|
||||
const useSingleInferredProject = hasArgument("--useSingleInferredProject");
|
||||
const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot");
|
||||
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
|
||||
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
|
||||
|
||||
|
@ -780,6 +799,7 @@ namespace ts.server {
|
|||
installerEventPort: eventPort,
|
||||
canUseEvents: eventPort === undefined,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot,
|
||||
disableAutomaticTypingAcquisition,
|
||||
globalTypingsCacheLocation: getGlobalTypingsCacheLocation(),
|
||||
typingSafeListLocation,
|
||||
|
|
|
@ -163,26 +163,22 @@ namespace ts.server {
|
|||
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
|
||||
*/
|
||||
class MultistepOperation implements NextStep {
|
||||
private requestId: number;
|
||||
private requestId: number | undefined;
|
||||
private timerHandle: any;
|
||||
private immediateId: any;
|
||||
private completed = true;
|
||||
private immediateId: number | undefined;
|
||||
|
||||
constructor(private readonly operationHost: MultistepOperationHost) {}
|
||||
|
||||
public startNew(action: (next: NextStep) => void) {
|
||||
this.complete();
|
||||
this.requestId = this.operationHost.getCurrentRequestId();
|
||||
this.completed = false;
|
||||
this.executeAction(action);
|
||||
}
|
||||
|
||||
private complete() {
|
||||
if (!this.completed) {
|
||||
if (this.requestId) {
|
||||
this.operationHost.sendRequestCompletedEvent(this.requestId);
|
||||
}
|
||||
this.completed = true;
|
||||
if (this.requestId !== undefined) {
|
||||
this.operationHost.sendRequestCompletedEvent(this.requestId);
|
||||
this.requestId = undefined;
|
||||
}
|
||||
this.setTimerHandle(undefined);
|
||||
this.setImmediateId(undefined);
|
||||
|
@ -251,6 +247,7 @@ namespace ts.server {
|
|||
host: ServerHost;
|
||||
cancellationToken: ServerCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
byteLength: (buf: string, encoding?: string) => number;
|
||||
hrtime: (start?: number[]) => number[];
|
||||
|
@ -259,8 +256,8 @@ namespace ts.server {
|
|||
eventHandler?: ProjectServiceEventHandler;
|
||||
throttleWaitMilliseconds?: number;
|
||||
|
||||
globalPlugins?: string[];
|
||||
pluginProbeLocations?: string[];
|
||||
globalPlugins?: ReadonlyArray<string>;
|
||||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads?: boolean;
|
||||
}
|
||||
|
||||
|
@ -311,6 +308,7 @@ namespace ts.server {
|
|||
logger: this.logger,
|
||||
cancellationToken: this.cancellationToken,
|
||||
useSingleInferredProject: opts.useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot: opts.useInferredProjectPerProjectRoot,
|
||||
typingsInstaller: this.typingsInstaller,
|
||||
throttleWaitMilliseconds,
|
||||
eventHandler: this.eventHandler,
|
||||
|
@ -337,7 +335,7 @@ namespace ts.server {
|
|||
case ContextEvent:
|
||||
const { project, fileName } = event.data;
|
||||
this.projectService.logger.info(`got context event, updating diagnostics for ${fileName}`);
|
||||
this.errorCheck.startNew(next => this.updateErrorCheck(next, [{ fileName, project }], this.changeSeq, (n) => n === this.changeSeq, 100));
|
||||
this.errorCheck.startNew(next => this.updateErrorCheck(next, [{ fileName, project }], 100));
|
||||
break;
|
||||
case ConfigFileDiagEvent:
|
||||
const { triggerFile, configFileName, diagnostics } = event.data;
|
||||
|
@ -383,7 +381,7 @@ namespace ts.server {
|
|||
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
|
||||
}
|
||||
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: Diagnostic[]) {
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ReadonlyArray<Diagnostic>) {
|
||||
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
|
||||
const ev: protocol.ConfigFileDiagnosticEvent = {
|
||||
seq: 0,
|
||||
|
@ -453,22 +451,23 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private updateProjectStructure(seq: number, matchSeq: (seq: number) => boolean, ms = 1500) {
|
||||
private updateProjectStructure() {
|
||||
const ms = 1500;
|
||||
const seq = this.changeSeq;
|
||||
this.host.setTimeout(() => {
|
||||
if (matchSeq(seq)) {
|
||||
if (this.changeSeq === seq) {
|
||||
this.projectService.refreshInferredProjects();
|
||||
}
|
||||
}, ms);
|
||||
}
|
||||
|
||||
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], seq: number, matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200, requireOpen = true) {
|
||||
if (followMs > ms) {
|
||||
followMs = ms;
|
||||
}
|
||||
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], ms: number, requireOpen = true) {
|
||||
const seq = this.changeSeq;
|
||||
const followMs = Math.min(ms, 200);
|
||||
|
||||
let index = 0;
|
||||
const checkOne = () => {
|
||||
if (matchSeq(seq)) {
|
||||
if (this.changeSeq === seq) {
|
||||
const checkSpec = checkList[index];
|
||||
index++;
|
||||
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
|
||||
|
@ -483,7 +482,7 @@ namespace ts.server {
|
|||
}
|
||||
};
|
||||
|
||||
if ((checkList.length > index) && (matchSeq(seq))) {
|
||||
if (checkList.length > index && this.changeSeq === seq) {
|
||||
next.delay(ms, checkOne);
|
||||
}
|
||||
}
|
||||
|
@ -542,8 +541,8 @@ namespace ts.server {
|
|||
);
|
||||
}
|
||||
|
||||
private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: Diagnostic[]) {
|
||||
return diagnostics.map(d => <protocol.DiagnosticWithLinePosition>{
|
||||
private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: ReadonlyArray<Diagnostic>): protocol.DiagnosticWithLinePosition[] {
|
||||
return diagnostics.map<protocol.DiagnosticWithLinePosition>(d => ({
|
||||
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
|
||||
start: d.start,
|
||||
length: d.length,
|
||||
|
@ -551,7 +550,7 @@ namespace ts.server {
|
|||
code: d.code,
|
||||
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
|
||||
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private getCompilerOptionsDiagnostics(args: protocol.CompilerOptionsDiagnosticsRequestArgs) {
|
||||
|
@ -568,7 +567,7 @@ namespace ts.server {
|
|||
);
|
||||
}
|
||||
|
||||
private convertToDiagnosticsWithLinePosition(diagnostics: Diagnostic[], scriptInfo: ScriptInfo) {
|
||||
private convertToDiagnosticsWithLinePosition(diagnostics: ReadonlyArray<Diagnostic>, scriptInfo: ScriptInfo): protocol.DiagnosticWithLinePosition[] {
|
||||
return diagnostics.map(d => <protocol.DiagnosticWithLinePosition>{
|
||||
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
|
||||
start: d.start,
|
||||
|
@ -581,10 +580,12 @@ namespace ts.server {
|
|||
});
|
||||
}
|
||||
|
||||
private getDiagnosticsWorker(args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => Diagnostic[], includeLinePosition: boolean) {
|
||||
private getDiagnosticsWorker(
|
||||
args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => ReadonlyArray<Diagnostic>, includeLinePosition: boolean
|
||||
): ReadonlyArray<protocol.DiagnosticWithLinePosition> | ReadonlyArray<protocol.Diagnostic> {
|
||||
const { project, file } = this.getFileAndProject(args);
|
||||
if (isSemantic && isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const diagnostics = selector(project, file);
|
||||
|
@ -593,14 +594,14 @@ namespace ts.server {
|
|||
: diagnostics.map(d => formatDiag(file, project, d));
|
||||
}
|
||||
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | DefinitionInfo[] {
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<DefinitionInfo> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const definitions = project.getLanguageService().getDefinitionAtPosition(file, position);
|
||||
if (!definitions) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
|
@ -618,14 +619,14 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): protocol.FileSpan[] {
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.FileSpan> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const definitions = project.getLanguageService().getTypeDefinitionAtPosition(file, position);
|
||||
if (!definitions) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return definitions.map(def => {
|
||||
|
@ -638,12 +639,12 @@ namespace ts.server {
|
|||
});
|
||||
}
|
||||
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | ImplementationLocation[] {
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<ImplementationLocation> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file));
|
||||
const implementations = project.getLanguageService().getImplementationAtPosition(file, position);
|
||||
if (!implementations) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
if (simplifiedResult) {
|
||||
return implementations.map(({ fileName, textSpan }) => {
|
||||
|
@ -660,7 +661,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private getOccurrences(args: protocol.FileLocationRequestArgs): protocol.OccurrencesResponseItem[] {
|
||||
private getOccurrences(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.OccurrencesResponseItem> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
@ -668,7 +669,7 @@ namespace ts.server {
|
|||
const occurrences = project.getLanguageService().getOccurrencesAtPosition(file, position);
|
||||
|
||||
if (!occurrences) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return occurrences.map(occurrence => {
|
||||
|
@ -690,17 +691,17 @@ namespace ts.server {
|
|||
});
|
||||
}
|
||||
|
||||
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
|
||||
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
|
||||
const { configFile } = this.getConfigFileAndProject(args);
|
||||
if (configFile) {
|
||||
// all the config file errors are reported as part of semantic check so nothing to report here
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return this.getDiagnosticsWorker(args, /*isSemantic*/ false, (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), args.includeLinePosition);
|
||||
}
|
||||
|
||||
private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
|
||||
private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
|
||||
const { configFile, project } = this.getConfigFileAndProject(args);
|
||||
if (configFile) {
|
||||
return this.getConfigFileDiagnostics(configFile, project, args.includeLinePosition);
|
||||
|
@ -708,14 +709,14 @@ namespace ts.server {
|
|||
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
|
||||
}
|
||||
|
||||
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): protocol.DocumentHighlightsItem[] | DocumentHighlights[] {
|
||||
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.DocumentHighlightsItem> | ReadonlyArray<DocumentHighlights> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
const documentHighlights = project.getLanguageService().getDocumentHighlights(file, position, args.filesToSearch);
|
||||
|
||||
if (!documentHighlights) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
|
@ -744,7 +745,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
private setCompilerOptionsForInferredProjects(args: protocol.SetCompilerOptionsForInferredProjectsArgs): void {
|
||||
this.projectService.setCompilerOptionsForInferredProjects(args.options);
|
||||
this.projectService.setCompilerOptionsForInferredProjects(args.options, args.projectRootPath);
|
||||
}
|
||||
|
||||
private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo {
|
||||
|
@ -799,7 +800,7 @@ namespace ts.server {
|
|||
return info.getDefaultProject();
|
||||
}
|
||||
|
||||
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | RenameLocation[] {
|
||||
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | ReadonlyArray<RenameLocation> {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const info = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, info);
|
||||
|
@ -816,7 +817,7 @@ namespace ts.server {
|
|||
if (!renameInfo.canRename) {
|
||||
return {
|
||||
info: renameInfo,
|
||||
locs: []
|
||||
locs: emptyArray
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -825,12 +826,12 @@ namespace ts.server {
|
|||
(project: Project) => {
|
||||
const renameLocations = project.getLanguageService().findRenameLocations(file, position, args.findInStrings, args.findInComments);
|
||||
if (!renameLocations) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return renameLocations.map(location => {
|
||||
const locationScriptInfo = project.getScriptInfo(location.fileName);
|
||||
return <protocol.FileSpan>{
|
||||
return {
|
||||
file: location.fileName,
|
||||
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
|
||||
end: locationScriptInfo.positionToLineOffset(textSpanEnd(location.textSpan)),
|
||||
|
@ -902,7 +903,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | ReferencedSymbol[] {
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | undefined | ReadonlyArray<ReferencedSymbol> {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
|
@ -924,7 +925,7 @@ namespace ts.server {
|
|||
(project: Project) => {
|
||||
const references = project.getLanguageService().getReferencesAtPosition(file, position);
|
||||
if (!references) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return references.map(ref => {
|
||||
|
@ -981,7 +982,7 @@ namespace ts.server {
|
|||
if (this.eventHandler) {
|
||||
this.eventHandler({
|
||||
eventName: "configFileDiag",
|
||||
data: { triggerFile: fileName, configFileName, diagnostics: configFileErrors || [] }
|
||||
data: { triggerFile: fileName, configFileName, diagnostics: configFileErrors || emptyArray }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1024,6 +1025,14 @@ namespace ts.server {
|
|||
return project.getLanguageService(/*ensureSynchronized*/ false).getDocCommentTemplateAtPosition(file, position);
|
||||
}
|
||||
|
||||
private getSpanOfEnclosingComment(args: protocol.SpanOfEnclosingCommentRequestArgs) {
|
||||
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const onlyMultiLine = args.onlyMultiLine;
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
return project.getLanguageService(/*ensureSynchronized*/ false).getSpanOfEnclosingComment(file, position, onlyMultiLine);
|
||||
}
|
||||
|
||||
private getIndentation(args: protocol.IndentationRequestArgs) {
|
||||
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
|
||||
const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file));
|
||||
|
@ -1166,7 +1175,7 @@ namespace ts.server {
|
|||
});
|
||||
}
|
||||
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, simplifiedResult: boolean): protocol.CompletionEntry[] | CompletionInfo {
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CompletionEntry> | CompletionInfo | undefined {
|
||||
const prefix = args.prefix || "";
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
|
||||
|
@ -1174,11 +1183,8 @@ namespace ts.server {
|
|||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(file, position);
|
||||
if (!completions) {
|
||||
return undefined;
|
||||
}
|
||||
if (simplifiedResult) {
|
||||
return mapDefined(completions.entries, entry => {
|
||||
return mapDefined(completions && completions.entries, entry => {
|
||||
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
|
||||
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
|
||||
const convertedSpan = replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
|
||||
|
@ -1191,7 +1197,7 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): protocol.CompletionEntryDetails[] {
|
||||
private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): ReadonlyArray<protocol.CompletionEntryDetails> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
@ -1200,12 +1206,12 @@ namespace ts.server {
|
|||
project.getLanguageService().getCompletionEntryDetails(file, position, entryName));
|
||||
}
|
||||
|
||||
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): protocol.CompileOnSaveAffectedFileListSingleProject[] {
|
||||
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): ReadonlyArray<protocol.CompileOnSaveAffectedFileListSingleProject> {
|
||||
const info = this.projectService.getScriptInfo(args.file);
|
||||
const result: protocol.CompileOnSaveAffectedFileListSingleProject[] = [];
|
||||
|
||||
if (!info) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
// if specified a project, we only return affected file list in this project
|
||||
|
@ -1262,14 +1268,14 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
|
||||
const checkList = mapDefined(fileNames, uncheckedFileName => {
|
||||
const checkList = mapDefined<string, PendingErrorCheck>(fileNames, uncheckedFileName => {
|
||||
const fileName = toNormalizedPath(uncheckedFileName);
|
||||
const project = this.projectService.getDefaultProjectForFile(fileName, /*refreshInferredProjects*/ true);
|
||||
return project && { fileName, project };
|
||||
});
|
||||
|
||||
if (checkList.length > 0) {
|
||||
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
|
||||
this.updateErrorCheck(next, checkList, delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1283,7 +1289,7 @@ namespace ts.server {
|
|||
scriptInfo.editContent(start, end, args.insertString);
|
||||
this.changeSeq++;
|
||||
}
|
||||
this.updateProjectStructure(this.changeSeq, n => n === this.changeSeq);
|
||||
this.updateProjectStructure();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1363,7 +1369,7 @@ namespace ts.server {
|
|||
: tree;
|
||||
}
|
||||
|
||||
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): protocol.NavtoItem[] | NavigateToItem[] {
|
||||
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.NavtoItem> | ReadonlyArray<NavigateToItem> {
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
const fileName = args.currentFileOnly ? args.file && normalizeSlashes(args.file) : undefined;
|
||||
|
@ -1373,7 +1379,7 @@ namespace ts.server {
|
|||
project => {
|
||||
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject());
|
||||
if (!navItems) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return navItems.map((navItem) => {
|
||||
|
@ -1638,7 +1644,7 @@ namespace ts.server {
|
|||
const checkList = fileNamesInProject.map(fileName => ({ fileName, project }));
|
||||
// Project level error analysis runs on background files too, therefore
|
||||
// doesn't require the file to be opened
|
||||
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay, 200, /*requireOpen*/ false);
|
||||
this.updateErrorCheck(next, checkList, delay, /*requireOpen*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1767,6 +1773,9 @@ namespace ts.server {
|
|||
[CommandNames.DocCommentTemplate]: (request: protocol.DocCommentTemplateRequest) => {
|
||||
return this.requiredResponse(this.getDocCommentTemplate(request.arguments));
|
||||
},
|
||||
[CommandNames.GetSpanOfEnclosingComment]: (request: protocol.SpanOfEnclosingCommentRequest) => {
|
||||
return this.requiredResponse(this.getSpanOfEnclosingComment(request.arguments));
|
||||
},
|
||||
[CommandNames.Format]: (request: protocol.FormatRequest) => {
|
||||
return this.requiredResponse(this.getFormattingEditsForRange(request.arguments));
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ declare namespace ts.server {
|
|||
data: any;
|
||||
}
|
||||
|
||||
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
|
||||
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: { stack?: string, message?: string } };
|
||||
export interface ServerHost extends System {
|
||||
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
clearTimeout(timeoutId: any): void;
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace ts.server.typingsInstaller {
|
|||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Updating ${TypesRegistryPackageName} npm package...`);
|
||||
}
|
||||
this.execSync(`${this.npmPath} install ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation, stdio: "ignore" });
|
||||
this.execSync(`${this.npmPath} install --ignore-scripts ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation, stdio: "ignore" });
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Updated ${TypesRegistryPackageName} npm package`);
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ namespace ts.server.typingsInstaller {
|
|||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`#${requestId} with arguments'${JSON.stringify(args)}'.`);
|
||||
}
|
||||
const command = `${this.npmPath} install ${args.join(" ")} --save-dev --user-agent="typesInstaller/${version}"`;
|
||||
const command = `${this.npmPath} install --ignore-scripts ${args.join(" ")} --save-dev --user-agent="typesInstaller/${version}"`;
|
||||
const start = Date.now();
|
||||
let stdout: Buffer;
|
||||
let stderr: Buffer;
|
||||
|
|
|
@ -371,14 +371,15 @@ namespace ts.server.typingsInstaller {
|
|||
this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles)));
|
||||
}
|
||||
finally {
|
||||
this.sendResponse(<EndInstallTypes>{
|
||||
const response: EndInstallTypes = {
|
||||
kind: EventEndInstallTypes,
|
||||
eventId: requestId,
|
||||
projectName: req.projectName,
|
||||
packagesToInstall: scopedTypings,
|
||||
installSuccess: ok,
|
||||
typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing
|
||||
});
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -126,9 +126,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
export function createNormalizedPathMap<T>(): NormalizedPathMap<T> {
|
||||
/* tslint:disable:no-null-keyword */
|
||||
const map = createMap<T>();
|
||||
/* tslint:enable:no-null-keyword */
|
||||
return {
|
||||
get(path) {
|
||||
return map.get(path);
|
||||
|
@ -176,44 +174,6 @@ namespace ts.server {
|
|||
return [] as SortedArray<T>;
|
||||
}
|
||||
|
||||
export function toSortedArray(arr: string[]): SortedArray<string>;
|
||||
export function toSortedArray<T>(arr: T[], comparer: Comparer<T>): SortedArray<T>;
|
||||
export function toSortedArray<T>(arr: T[], comparer?: Comparer<T>): SortedArray<T> {
|
||||
arr.sort(comparer);
|
||||
return arr as SortedArray<T>;
|
||||
}
|
||||
|
||||
export function enumerateInsertsAndDeletes<T>(newItems: SortedReadonlyArray<T>, oldItems: SortedReadonlyArray<T>, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, compare?: Comparer<T>) {
|
||||
compare = compare || compareValues;
|
||||
let newIndex = 0;
|
||||
let oldIndex = 0;
|
||||
const newLen = newItems.length;
|
||||
const oldLen = oldItems.length;
|
||||
while (newIndex < newLen && oldIndex < oldLen) {
|
||||
const newItem = newItems[newIndex];
|
||||
const oldItem = oldItems[oldIndex];
|
||||
const compareResult = compare(newItem, oldItem);
|
||||
if (compareResult === Comparison.LessThan) {
|
||||
inserted(newItem);
|
||||
newIndex++;
|
||||
}
|
||||
else if (compareResult === Comparison.GreaterThan) {
|
||||
deleted(oldItem);
|
||||
oldIndex++;
|
||||
}
|
||||
else {
|
||||
newIndex++;
|
||||
oldIndex++;
|
||||
}
|
||||
}
|
||||
while (newIndex < newLen) {
|
||||
inserted(newItems[newIndex++]);
|
||||
}
|
||||
while (oldIndex < oldLen) {
|
||||
deleted(oldItems[oldIndex++]);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThrottledOperations {
|
||||
private pendingTimeouts: Map<any> = createMap<any>();
|
||||
constructor(private readonly host: ServerHost) {
|
||||
|
@ -261,7 +221,10 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace ts.server {
|
||||
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
|
||||
if (array.length === 0) {
|
||||
array.push(insert);
|
||||
|
@ -289,4 +252,51 @@ namespace ts.server {
|
|||
array.splice(removeIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export function toSortedArray(arr: string[]): SortedArray<string>;
|
||||
export function toSortedArray<T>(arr: T[], comparer: Comparer<T>): SortedArray<T>;
|
||||
export function toSortedArray<T>(arr: T[], comparer?: Comparer<T>): SortedArray<T> {
|
||||
arr.sort(comparer);
|
||||
return arr as SortedArray<T>;
|
||||
}
|
||||
|
||||
export function toDeduplicatedSortedArray(arr: string[]): SortedArray<string> {
|
||||
arr.sort();
|
||||
filterMutate(arr, isNonDuplicateInSortedArray);
|
||||
return arr as SortedArray<string>;
|
||||
}
|
||||
function isNonDuplicateInSortedArray<T>(value: T, index: number, array: T[]) {
|
||||
return index === 0 || value !== array[index - 1];
|
||||
}
|
||||
|
||||
export function enumerateInsertsAndDeletes<T>(newItems: SortedReadonlyArray<T>, oldItems: SortedReadonlyArray<T>, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, compare?: Comparer<T>) {
|
||||
compare = compare || compareValues;
|
||||
let newIndex = 0;
|
||||
let oldIndex = 0;
|
||||
const newLen = newItems.length;
|
||||
const oldLen = oldItems.length;
|
||||
while (newIndex < newLen && oldIndex < oldLen) {
|
||||
const newItem = newItems[newIndex];
|
||||
const oldItem = oldItems[oldIndex];
|
||||
const compareResult = compare(newItem, oldItem);
|
||||
if (compareResult === Comparison.LessThan) {
|
||||
inserted(newItem);
|
||||
newIndex++;
|
||||
}
|
||||
else if (compareResult === Comparison.GreaterThan) {
|
||||
deleted(oldItem);
|
||||
oldIndex++;
|
||||
}
|
||||
else {
|
||||
newIndex++;
|
||||
oldIndex++;
|
||||
}
|
||||
}
|
||||
while (newIndex < newLen) {
|
||||
inserted(newItems[newIndex++]);
|
||||
}
|
||||
while (oldIndex < oldLen) {
|
||||
deleted(oldItems[oldIndex++]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -260,11 +260,11 @@ namespace ts {
|
|||
templateStack.pop();
|
||||
}
|
||||
else {
|
||||
Debug.assert(token === SyntaxKind.TemplateMiddle, "Should have been a template middle. Was " + token);
|
||||
Debug.assertEqual(token, SyntaxKind.TemplateMiddle, "Should have been a template middle.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assert(lastTemplateStackToken === SyntaxKind.OpenBraceToken, "Should have been an open brace. Was: " + token);
|
||||
Debug.assertEqual(lastTemplateStackToken, SyntaxKind.OpenBraceToken, "Should have been an open brace");
|
||||
templateStack.pop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1.code],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false);
|
||||
const qualifiedName = getAncestor(token, SyntaxKind.QualifiedName) as QualifiedName;
|
||||
Debug.assert(!!qualifiedName, "Expected position to be owned by a qualified name.");
|
||||
if (!isIdentifier(qualifiedName.left)) {
|
||||
return undefined;
|
||||
}
|
||||
const leftText = qualifiedName.left.getText(sourceFile);
|
||||
const rightText = qualifiedName.right.getText(sourceFile);
|
||||
const replacement = createIndexedAccessTypeNode(
|
||||
createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined),
|
||||
createLiteralTypeNode(createLiteral(rightText)));
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
changeTracker.replaceNode(sourceFile, qualifiedName, replacement);
|
||||
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Rewrite_as_the_indexed_access_type_0), [`${leftText}["${rightText}"]`]),
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
|
@ -15,7 +15,8 @@ namespace ts.codefix {
|
|||
const node = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); // TODO: GH#15852
|
||||
const checker = context.program.getTypeChecker();
|
||||
let suggestion: string;
|
||||
if (node.kind === SyntaxKind.Identifier && isPropertyAccessExpression(node.parent)) {
|
||||
if (isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
||||
Debug.assert(node.kind === SyntaxKind.Identifier);
|
||||
const containingType = checker.getTypeAtLocation(node.parent.expression);
|
||||
suggestion = checker.getSuggestionForNonexistentProperty(node as Identifier, containingType);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference path="correctQualifiedNameToIndexedAccessType.ts" />
|
||||
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
|
||||
/// <reference path="fixAddMissingMember.ts" />
|
||||
/// <reference path="fixSpelling.ts" />
|
||||
|
|
|
@ -147,7 +147,7 @@ namespace ts.codefix {
|
|||
}
|
||||
else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) {
|
||||
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
|
||||
symbol = checker.getAliasedSymbol(checker.resolveNameAtLocation(token, checker.getJsxNamespace(), SymbolFlags.Value));
|
||||
symbol = checker.getAliasedSymbol(checker.resolveName(checker.getJsxNamespace(), token.parent.tagName, SymbolFlags.Value));
|
||||
symbolName = symbol.name;
|
||||
}
|
||||
else {
|
||||
|
@ -174,7 +174,7 @@ namespace ts.codefix {
|
|||
if (localSymbol && localSymbol.escapedName === name && checkSymbolHasMeaning(localSymbol, currentTokenMeaning)) {
|
||||
// check if this symbol is already used
|
||||
const symbolId = getUniqueSymbolId(localSymbol);
|
||||
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name, /*isDefault*/ true));
|
||||
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name, /*isNamespaceImport*/ true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,9 +394,11 @@ namespace ts.codefix {
|
|||
: isNamespaceImport
|
||||
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(symbolName)))
|
||||
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(symbolName))]));
|
||||
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes));
|
||||
const moduleSpecifierLiteral = createLiteral(moduleSpecifierWithoutQuotes);
|
||||
moduleSpecifierLiteral.singleQuote = getSingleQuoteStyleFromExistingImports();
|
||||
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, moduleSpecifierLiteral);
|
||||
if (!lastImportDeclaration) {
|
||||
changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
|
||||
changeTracker.insertNodeAt(sourceFile, getSourceFileImportLocation(sourceFile), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
|
||||
}
|
||||
else {
|
||||
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: context.newLineCharacter });
|
||||
|
@ -413,6 +415,46 @@ namespace ts.codefix {
|
|||
moduleSpecifierWithoutQuotes
|
||||
);
|
||||
|
||||
function getSourceFileImportLocation(node: SourceFile) {
|
||||
// For a source file, it is possible there are detached comments we should not skip
|
||||
const text = node.text;
|
||||
let ranges = getLeadingCommentRanges(text, 0);
|
||||
if (!ranges) return 0;
|
||||
let position = 0;
|
||||
// However we should still skip a pinned comment at the top
|
||||
if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) {
|
||||
position = ranges[0].end + 1;
|
||||
ranges = ranges.slice(1);
|
||||
}
|
||||
// As well as any triple slash references
|
||||
for (const range of ranges) {
|
||||
if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) {
|
||||
position = range.end + 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
function getSingleQuoteStyleFromExistingImports() {
|
||||
const firstModuleSpecifier = forEach(sourceFile.statements, node => {
|
||||
if (isImportDeclaration(node) || isExportDeclaration(node)) {
|
||||
if (node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)) {
|
||||
return node.moduleSpecifier;
|
||||
}
|
||||
}
|
||||
else if (isImportEqualsDeclaration(node)) {
|
||||
if (isExternalModuleReference(node.moduleReference) && isStringLiteral(node.moduleReference.expression)) {
|
||||
return node.moduleReference.expression;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (firstModuleSpecifier) {
|
||||
return sourceFile.text.charCodeAt(firstModuleSpecifier.getStart()) === CharacterCodes.singleQuote;
|
||||
}
|
||||
}
|
||||
|
||||
function getModuleSpecifierForNewImport() {
|
||||
const fileName = sourceFile.fileName;
|
||||
const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName;
|
||||
|
@ -562,8 +604,8 @@ namespace ts.codefix {
|
|||
|
||||
function getNodeModulePathParts(fullPath: string) {
|
||||
// If fullPath can't be valid module file within node_modules, returns undefined.
|
||||
// Example of expected pattern: /base/path/node_modules/[otherpackage/node_modules/]package/[subdirectory/]file.js
|
||||
// Returns indices: ^ ^ ^ ^
|
||||
// Example of expected pattern: /base/path/node_modules/[@scope/otherpackage/@otherscope/node_modules/]package/[subdirectory/]file.js
|
||||
// Returns indices: ^ ^ ^ ^
|
||||
|
||||
let topLevelNodeModulesIndex = 0;
|
||||
let topLevelPackageNameIndex = 0;
|
||||
|
@ -573,6 +615,7 @@ namespace ts.codefix {
|
|||
const enum States {
|
||||
BeforeNodeModules,
|
||||
NodeModules,
|
||||
Scope,
|
||||
PackageContent
|
||||
}
|
||||
|
||||
|
@ -592,8 +635,14 @@ namespace ts.codefix {
|
|||
}
|
||||
break;
|
||||
case States.NodeModules:
|
||||
packageRootIndex = partEnd;
|
||||
state = States.PackageContent;
|
||||
case States.Scope:
|
||||
if (state === States.NodeModules && fullPath.charAt(partStart + 1) === "@") {
|
||||
state = States.Scope;
|
||||
}
|
||||
else {
|
||||
packageRootIndex = partEnd;
|
||||
state = States.PackageContent;
|
||||
}
|
||||
break;
|
||||
case States.PackageContent:
|
||||
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
|
||||
|
|
|
@ -1000,7 +1000,7 @@ namespace ts.Completions {
|
|||
const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
|
||||
if (!typeForObject) return false;
|
||||
// In a binding pattern, get only known properties. Everywhere else we will get all possible properties.
|
||||
typeMembers = typeChecker.getPropertiesOfType(typeForObject);
|
||||
typeMembers = typeChecker.getPropertiesOfType(typeForObject).filter((symbol) => !(getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.NonPublicAccessibilityModifier));
|
||||
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -604,11 +604,16 @@ namespace ts.FindAllReferences.Core {
|
|||
|
||||
function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined {
|
||||
const bindingElement = getObjectBindingElementWithoutPropertyName(symbol);
|
||||
if (bindingElement) {
|
||||
const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent);
|
||||
return typeOfPattern && checker.getPropertyOfType(typeOfPattern, (<Identifier>bindingElement.name).text);
|
||||
if (!bindingElement) return undefined;
|
||||
|
||||
const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent);
|
||||
const propSymbol = typeOfPattern && checker.getPropertyOfType(typeOfPattern, (<Identifier>bindingElement.name).text);
|
||||
if (propSymbol && propSymbol.flags & SymbolFlags.Accessor) {
|
||||
// See GH#16922
|
||||
Debug.assert(!!(propSymbol.flags & SymbolFlags.Transient));
|
||||
return (propSymbol as TransientSymbol).target;
|
||||
}
|
||||
return undefined;
|
||||
return propSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -647,10 +652,15 @@ namespace ts.FindAllReferences.Core {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// If the symbol has a parent, it's globally visible.
|
||||
// Unless that parent is an external module, then we should only search in the module (and recurse on the export later).
|
||||
// But if the parent is a module that has `export as namespace`, then the symbol *is* globally visible.
|
||||
if (parent && !((parent.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent) && !parent.globalExports)) {
|
||||
/*
|
||||
If the symbol has a parent, it's globally visible unless:
|
||||
- It's a private property (handled above).
|
||||
- It's a type parameter.
|
||||
- The parent is an external module: then we should only search in the module (and recurse on the export later).
|
||||
- But if the parent has `export as namespace`, the symbol is globally visible through that namespace.
|
||||
*/
|
||||
const exposedByParent = parent && !(symbol.flags & SymbolFlags.TypeParameter);
|
||||
if (exposedByParent && !((parent.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent) && !parent.globalExports)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -677,7 +687,7 @@ namespace ts.FindAllReferences.Core {
|
|||
// declare module "a" { export type T = number; }
|
||||
// declare module "b" { import { T } from "a"; export const x: T; }
|
||||
// So we must search the whole source file. (Because we will mark the source file as seen, we we won't return to it when searching for imports.)
|
||||
return parent ? scope.getSourceFile() : scope;
|
||||
return exposedByParent ? scope.getSourceFile() : scope;
|
||||
}
|
||||
|
||||
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): number[] {
|
||||
|
|
|
@ -398,7 +398,6 @@ namespace ts.formatting {
|
|||
|
||||
// formatting context is used by rules provider
|
||||
const formattingContext = new FormattingContext(sourceFile, requestKind, options);
|
||||
let previousRangeHasError: boolean;
|
||||
let previousRange: TextRangeWithKind;
|
||||
let previousParent: Node;
|
||||
let previousRangeStartLine: number;
|
||||
|
@ -883,7 +882,7 @@ namespace ts.formatting {
|
|||
|
||||
const rangeHasError = rangeContainsError(range);
|
||||
let lineAdded: boolean;
|
||||
if (!rangeHasError && !previousRangeHasError) {
|
||||
if (!rangeHasError) {
|
||||
if (!previousRange) {
|
||||
// trim whitespaces starting from the beginning of the span up to the current line
|
||||
const originalStart = sourceFile.getLineAndCharacterOfPosition(originalRange.pos);
|
||||
|
@ -898,7 +897,6 @@ namespace ts.formatting {
|
|||
previousRange = range;
|
||||
previousParent = parent;
|
||||
previousRangeStartLine = rangeStart.line;
|
||||
previousRangeHasError = rangeHasError;
|
||||
|
||||
return lineAdded;
|
||||
}
|
||||
|
@ -1152,6 +1150,56 @@ namespace ts.formatting {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param precedingToken pass `null` if preceding token was already computed and result was `undefined`.
|
||||
*/
|
||||
export function getRangeOfEnclosingComment(
|
||||
sourceFile: SourceFile,
|
||||
position: number,
|
||||
onlyMultiLine: boolean,
|
||||
precedingToken?: Node | null, // tslint:disable-line:no-null-keyword
|
||||
tokenAtPosition = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false),
|
||||
predicate?: (c: CommentRange) => boolean): CommentRange | undefined {
|
||||
const tokenStart = tokenAtPosition.getStart(sourceFile);
|
||||
if (tokenStart <= position && position < tokenAtPosition.getEnd()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (precedingToken === undefined) {
|
||||
precedingToken = findPrecedingToken(position, sourceFile);
|
||||
}
|
||||
|
||||
// Between two consecutive tokens, all comments are either trailing on the former
|
||||
// or leading on the latter (and none are in both lists).
|
||||
const trailingRangesOfPreviousToken = precedingToken && getTrailingCommentRanges(sourceFile.text, precedingToken.end);
|
||||
const leadingCommentRangesOfNextToken = getLeadingCommentRangesOfNode(tokenAtPosition, sourceFile);
|
||||
const commentRanges = trailingRangesOfPreviousToken && leadingCommentRangesOfNextToken ?
|
||||
trailingRangesOfPreviousToken.concat(leadingCommentRangesOfNextToken) :
|
||||
trailingRangesOfPreviousToken || leadingCommentRangesOfNextToken;
|
||||
if (commentRanges) {
|
||||
for (const range of commentRanges) {
|
||||
// The end marker of a single-line comment does not include the newline character.
|
||||
// With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position):
|
||||
//
|
||||
// // asdf ^\n
|
||||
//
|
||||
// But for closed multi-line comments, we don't want to be inside the comment in the following case:
|
||||
//
|
||||
// /* asdf */^
|
||||
//
|
||||
// However, unterminated multi-line comments *do* contain their end.
|
||||
//
|
||||
// Internally, we represent the end of the comment at the newline and closing '/', respectively.
|
||||
//
|
||||
if ((range.pos < position && position < range.end ||
|
||||
position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth()))) {
|
||||
return (range.kind === SyntaxKind.MultiLineCommentTrivia || !onlyMultiLine) && (!predicate || predicate(range)) ? range : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getOpenTokenForList(node: Node, list: ReadonlyArray<Node>) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
|
|
|
@ -195,6 +195,7 @@ namespace ts.formatting {
|
|||
// Insert space after opening and before closing nonempty parenthesis
|
||||
public SpaceAfterOpenParen: Rule;
|
||||
public SpaceBeforeCloseParen: Rule;
|
||||
public SpaceBetweenOpenParens: Rule;
|
||||
public NoSpaceBetweenParens: Rule;
|
||||
public NoSpaceAfterOpenParen: Rule;
|
||||
public NoSpaceBeforeCloseParen: Rule;
|
||||
|
@ -457,6 +458,7 @@ namespace ts.formatting {
|
|||
// Insert space after opening and before closing nonempty parenthesis
|
||||
this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
|
||||
this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
|
||||
this.SpaceBetweenOpenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
|
||||
this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
|
||||
|
@ -544,7 +546,7 @@ namespace ts.formatting {
|
|||
this.SpaceAfterComma, this.NoSpaceAfterComma,
|
||||
this.SpaceAfterAnonymousFunctionKeyword, this.NoSpaceAfterAnonymousFunctionKeyword,
|
||||
this.SpaceAfterKeywordInControl, this.NoSpaceAfterKeywordInControl,
|
||||
this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen,
|
||||
this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.SpaceBetweenOpenParens, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen,
|
||||
this.SpaceAfterOpenBracket, this.SpaceBeforeCloseBracket, this.NoSpaceBetweenBrackets, this.NoSpaceAfterOpenBracket, this.NoSpaceBeforeCloseBracket,
|
||||
this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NoSpaceBetweenEmptyBraceBrackets, this.NoSpaceAfterOpenBrace, this.NoSpaceBeforeCloseBrace,
|
||||
this.SpaceAfterTemplateHeadAndMiddle, this.SpaceBeforeTemplateMiddleAndTail, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail,
|
||||
|
|
|
@ -32,13 +32,36 @@ namespace ts.formatting {
|
|||
}
|
||||
|
||||
const precedingToken = findPrecedingToken(position, sourceFile);
|
||||
|
||||
const enclosingCommentRange = getRangeOfEnclosingComment(sourceFile, position, /*onlyMultiLine*/ true, precedingToken || null); // tslint:disable-line:no-null-keyword
|
||||
if (enclosingCommentRange) {
|
||||
const previousLine = getLineAndCharacterOfPosition(sourceFile, position).line - 1;
|
||||
const commentStartLine = getLineAndCharacterOfPosition(sourceFile, enclosingCommentRange.pos).line;
|
||||
|
||||
Debug.assert(commentStartLine >= 0);
|
||||
|
||||
if (previousLine <= commentStartLine) {
|
||||
return findFirstNonWhitespaceColumn(getStartPositionOfLine(commentStartLine, sourceFile), position, sourceFile, options);
|
||||
}
|
||||
|
||||
const startPostionOfLine = getStartPositionOfLine(previousLine, sourceFile);
|
||||
const { column, character } = findFirstNonWhitespaceCharacterAndColumn(startPostionOfLine, position, sourceFile, options);
|
||||
|
||||
if (column === 0) {
|
||||
return column;
|
||||
}
|
||||
|
||||
const firstNonWhitespaceCharacterCode = sourceFile.text.charCodeAt(startPostionOfLine + character);
|
||||
return firstNonWhitespaceCharacterCode === CharacterCodes.asterisk ? column - 1 : column;
|
||||
}
|
||||
|
||||
if (!precedingToken) {
|
||||
return getBaseIndentation(options);
|
||||
}
|
||||
|
||||
// no indentation in string \regex\template literals
|
||||
const precedingTokenIsLiteral = isStringOrRegularExpressionOrTemplateLiteral(precedingToken.kind);
|
||||
if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) {
|
||||
if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && position < precedingToken.end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -405,13 +428,13 @@ namespace ts.formatting {
|
|||
return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options);
|
||||
}
|
||||
|
||||
/*
|
||||
Character is the actual index of the character since the beginning of the line.
|
||||
Column - position of the character after expanding tabs to spaces
|
||||
"0\t2$"
|
||||
value of 'character' for '$' is 3
|
||||
value of 'column' for '$' is 6 (assuming that tab size is 4)
|
||||
*/
|
||||
/**
|
||||
* Character is the actual index of the character since the beginning of the line.
|
||||
* Column - position of the character after expanding tabs to spaces.
|
||||
* "0\t2$"
|
||||
* value of 'character' for '$' is 3
|
||||
* value of 'column' for '$' is 6 (assuming that tab size is 4)
|
||||
*/
|
||||
export function findFirstNonWhitespaceCharacterAndColumn(startPos: number, endPos: number, sourceFile: SourceFileLike, options: EditorSettings) {
|
||||
let character = 0;
|
||||
let column = 0;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче