Merge branch 'master' into promised

This commit is contained in:
Ron Buckton
2017-08-07 17:49:33 -07:00
624 changed files with 240523 additions and 215652 deletions
+61 -37
View File
@@ -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);
@@ -294,7 +293,7 @@ gulp.task("configure-nightly", "Runs scripts/configureNightly.ts to prepare a bu
exec(host, [configureNightlyJs, packageJson, versionFile], done, done);
});
gulp.task("publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => {
return runSequence("clean", "useDebugMode", "runtests", (done) => {
return runSequence("clean", "useDebugMode", "runtests-parallel", (done) => {
exec("npm", ["publish", "--tag", "next"], done, done);
});
});
@@ -737,50 +736,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();
});
});
+3 -2
View File
@@ -505,7 +505,7 @@ task("configure-nightly", [configureNightlyJs], function () {
}, { async: true });
desc("Configure, build, test, and publish the nightly release.");
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests"], function () {
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests-parallel"], function () {
var cmd = "npm publish --tag next";
console.log(cmd);
exec(cmd);
@@ -840,7 +840,8 @@ function runConsoleTests(defaultReporter, runInParallel) {
testTimeout = 800000;
}
var colors = process.env.colors || process.env.color || true;
var colorsFlag = process.env.color || process.env.colors;
var colors = colorsFlag !== "false" && colorsFlag !== "0";
var reporter = process.env.reporter || process.env.r || defaultReporter;
var bail = process.env.bail || process.env.b;
var lintFlag = process.env.lint !== 'false';
+1 -1
View File
@@ -8,7 +8,7 @@
```ts
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
```
**Expected behavior:**
-2
View File
@@ -69,5 +69,3 @@ function createCancellationToken(args) {
}
}
module.exports = createCancellationToken;
//# sourceMappingURL=cancellationToken.js.map
+4346 -4803
View File
File diff suppressed because it is too large Load Diff
+4200 -4452
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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" />
+4200 -6276
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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" />
+4200 -6275
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -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[];
}
+146 -351
View File
File diff suppressed because it is too large Load Diff
+4346 -4803
View File
File diff suppressed because it is too large Load Diff
+4200 -6276
View File
File diff suppressed because it is too large Load Diff
+145 -134
View File
@@ -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;
+180 -95
View File
@@ -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;
+32264 -31871
View File
File diff suppressed because it is too large Load Diff
+34381 -32033
View File
File diff suppressed because it is too large Load Diff
+939 -685
View File
File diff suppressed because it is too large Load Diff
+37069 -34736
View File
File diff suppressed because it is too large Load Diff
+803 -446
View File
File diff suppressed because it is too large Load Diff
+40242 -37611
View File
File diff suppressed because it is too large Load Diff
+803 -446
View File
File diff suppressed because it is too large Load Diff
+40242 -37611
View File
File diff suppressed because it is too large Load Diff
+11502 -2323
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -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);
}
-1
View File
@@ -60,7 +60,6 @@
"gulp-newer": "latest",
"gulp-sourcemaps": "latest",
"gulp-typescript": "latest",
"into-stream": "latest",
"istanbul": "latest",
"jake": "latest",
"merge2": "latest",
+34 -24
View File
@@ -19,47 +19,57 @@ function main(): void {
// Acquire the version from the package.json file and modify it appropriately.
const packageJsonFilePath = ts.normalizePath(sys.args[0]);
const packageJsonContents = sys.readFile(packageJsonFilePath);
const packageJsonValue: PackageJson = JSON.parse(packageJsonContents);
const packageJsonValue: PackageJson = JSON.parse(sys.readFile(packageJsonFilePath));
const nightlyVersion = getNightlyVersionString(packageJsonValue.version);
// Modify the package.json structure
packageJsonValue.version = nightlyVersion;
const { majorMinor, patch } = parsePackageJsonVersion(packageJsonValue.version);
const nightlyPatch = getNightlyPatch(patch);
// Acquire and modify the source file that exposes the version string.
const tsFilePath = ts.normalizePath(sys.args[1]);
const tsFileContents = sys.readFile(tsFilePath);
const versionAssignmentRegExp = /export\s+const\s+version\s+=\s+".*";/;
const modifiedTsFileContents = tsFileContents.replace(versionAssignmentRegExp, `export const version = "${nightlyVersion}";`);
const tsFileContents = ts.sys.readFile(tsFilePath);
const modifiedTsFileContents = updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch);
// Ensure we are actually changing something - the user probably wants to know that the update failed.
if (tsFileContents === modifiedTsFileContents) {
let err = `\n '${tsFilePath}' was not updated while configuring for a nightly publish.\n `;
if (tsFileContents.match(versionAssignmentRegExp)) {
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
}
else {
err += `The file seems to no longer have a string matching '${versionAssignmentRegExp}'.`;
}
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
throw err + "\n";
}
// Finally write the changes to disk.
// Modify the package.json structure
packageJsonValue.version = `${majorMinor}.${nightlyPatch}`;
sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4))
sys.writeFile(tsFilePath, modifiedTsFileContents);
}
function getNightlyVersionString(versionString: string): string {
// If the version string already contains "-nightly",
// then get the base string and update based on that.
const dashNightlyPos = versionString.indexOf("-dev");
if (dashNightlyPos >= 0) {
versionString = versionString.slice(0, dashNightlyPos);
function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string {
const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/;
const majorMinorMatch = majorMinorRgx.exec(tsFileContents);
ts.Debug.assert(majorMinorMatch !== null, "", () => `The file seems to no longer have a string matching '${majorMinorRgx}'.`);
const parsedMajorMinor = majorMinorMatch[1];
ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)`;/;
const patchMatch = versionRgx.exec(tsFileContents);
ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString());
const parsedPatch = patchMatch[1];
if (parsedPatch !== patch) {
throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`);
}
return tsFileContents.replace(versionRgx, `export const version = \`\${versionMajorMinor}.${nightlyPatch}\`;`);
}
function parsePackageJsonVersion(versionString: string): { majorMinor: string, patch: string } {
const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/;
const match = versionString.match(versionRgx);
ts.Debug.assert(match !== null, "package.json 'version' should match", () => versionRgx.toString());
return { majorMinor: match[1], patch: match[2] };
}
/** e.g. 0-dev.20170707 */
function getNightlyPatch(plainPatch: string): string {
// We're going to append a representation of the current time at the end of the current version.
// String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ',
// but we'd prefer to just remove separators and limit ourselves to YYYYMMDD.
@@ -67,7 +77,7 @@ function getNightlyVersionString(versionString: string): string {
const now = new Date();
const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8);
return `${versionString}-dev.${timeStr}`;
return `${plainPatch}-dev.${timeStr}`;
}
main();
+38 -165
View File
@@ -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();
+1 -1
View File
@@ -19,7 +19,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(node, recur);
}
function check(types: ts.TypeNode[]): void {
function check(types: ReadonlyArray<ts.TypeNode>): void {
let expectedStart = types[0].end + 2; // space, | or &
for (let i = 1; i < types.length; i++) {
const currentType = types[i];
-8
View File
@@ -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";
+61 -67
View File
@@ -242,7 +242,7 @@ namespace ts {
}
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores((<PropertyAccessExpression>nameExpression).name.text));
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores((<PropertyAccessExpression>nameExpression).name.escapedText));
}
return getEscapedTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
}
@@ -287,8 +287,8 @@ namespace ts {
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
if (nameIdentifier.kind === SyntaxKind.Identifier) {
nameFromParentNode = (<Identifier>nameIdentifier).text;
if (isIdentifier(nameIdentifier)) {
nameFromParentNode = nameIdentifier.escapedText;
}
}
}
@@ -308,7 +308,7 @@ namespace ts {
* @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
* @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
*/
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean): Symbol {
Debug.assert(!hasDynamicName(node));
const isDefaultExport = hasModifier(node, ModifierFlags.Default);
@@ -345,15 +345,20 @@ namespace ts {
// you have multiple 'vars' with the same name in the same container). In this case
// just add this node into the declarations list of the symbol.
symbol = symbolTable.get(name);
if (!symbol) {
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
}
if (name && (includes & SymbolFlags.Classifiable)) {
if (includes & SymbolFlags.Classifiable) {
classifiableNames.set(name, true);
}
if (symbol.flags & excludes) {
if (!symbol) {
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
if (isReplaceableByMethod) symbol.isReplaceableByMethod = true;
}
else if (isReplaceableByMethod && !symbol.isReplaceableByMethod) {
// A symbol already exists, so don't add this as a declaration.
return symbol;
}
else if (symbol.flags & excludes) {
if (symbol.isReplaceableByMethod) {
// Javascript constructor-declared symbols can be discarded in favor of
// prototype symbols like methods.
@@ -416,9 +421,8 @@ namespace ts {
}
}
else {
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue,
// ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set
// on it. There are 2 main reasons:
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
// and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
//
// 1. We treat locals and exports of the same name as mutually exclusive within a container.
// That means the binder will issue a Duplicate Identifier error if you mix locals and exports
@@ -438,10 +442,7 @@ namespace ts {
(node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
((node as JSDocTypedefTag).name as Identifier).isInJSDocNamespace;
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
const exportKind =
(symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) |
(symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) |
(symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0);
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
node.localSymbol = local;
@@ -1030,7 +1031,7 @@ namespace ts {
function bindBreakOrContinueStatement(node: BreakOrContinueStatement): void {
bind(node.label);
if (node.label) {
const activeLabel = findActiveLabel(node.label.text);
const activeLabel = findActiveLabel(node.label.escapedText);
if (activeLabel) {
activeLabel.referenced = true;
bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
@@ -1191,7 +1192,7 @@ namespace ts {
const postStatementLabel = createBranchLabel();
bind(node.label);
addAntecedent(preStatementLabel, currentFlow);
const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel);
const activeLabel = pushActiveLabel(node.label.escapedText, postStatementLabel, preStatementLabel);
bind(node.statement);
popActiveLabel();
if (!activeLabel.referenced && !options.allowUnusedLabels) {
@@ -1331,7 +1332,7 @@ namespace ts {
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
const name = !isOmittedExpression(node) ? node.name : undefined;
if (isBindingPattern(name)) {
for (const child of <ArrayBindingElement[]>name.elements) {
for (const child of name.elements) {
bindInitializedVariableFlow(child);
}
}
@@ -1399,14 +1400,12 @@ namespace ts {
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JsxAttributes:
return ContainerFlags.IsContainer;
case SyntaxKind.InterfaceDeclaration:
return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.MappedType:
@@ -1426,9 +1425,10 @@ namespace ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.CallSignature:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
@@ -1504,10 +1504,9 @@ namespace ts {
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JsxAttributes:
// Interface/Object-types always have their children added to the 'members' of
// their container. They are only accessible through an instance of their
@@ -1650,7 +1649,7 @@ namespace ts {
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = createSymbolTable();
typeLiteralSymbol.members.set(symbol.name, symbol);
typeLiteralSymbol.members.set(symbol.escapedName, symbol);
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
@@ -1681,9 +1680,9 @@ namespace ts {
? ElementKind.Property
: ElementKind.Accessor;
const existingKind = seen.get(identifier.text);
const existingKind = seen.get(identifier.escapedText);
if (!existingKind) {
seen.set(identifier.text, currentKind);
seen.set(identifier.escapedText, currentKind);
continue;
}
@@ -1793,8 +1792,7 @@ namespace ts {
}
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
return isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
}
function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) {
@@ -1805,7 +1803,7 @@ namespace ts {
// otherwise report generic error message.
const span = getErrorSpanForNode(file, name);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
getStrictModeEvalOrArgumentsMessage(contextNode), unescapeLeadingUnderscores(identifier.text)));
getStrictModeEvalOrArgumentsMessage(contextNode), unescapeLeadingUnderscores(identifier.escapedText)));
}
}
}
@@ -2067,8 +2065,10 @@ namespace ts {
case SyntaxKind.Parameter:
return bindParameter(<ParameterDeclaration>node);
case SyntaxKind.VariableDeclaration:
return bindVariableDeclarationOrBindingElement(<VariableDeclaration>node);
case SyntaxKind.BindingElement:
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
node.flowNode = currentFlow;
return bindVariableDeclarationOrBindingElement(<BindingElement>node);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
return bindPropertyWorker(node as PropertyDeclaration | PropertySignature);
@@ -2099,11 +2099,13 @@ namespace ts {
case SyntaxKind.SetAccessor:
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
case SyntaxKind.FunctionType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ConstructorType:
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.MappedType:
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode);
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral);
case SyntaxKind.ObjectLiteralExpression:
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
case SyntaxKind.FunctionExpression:
@@ -2161,18 +2163,17 @@ namespace ts {
case SyntaxKind.ModuleBlock:
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
case SyntaxKind.JSDocRecordMember:
return bindPropertyWorker(node as JSDocRecordMember);
case SyntaxKind.JSDocParameterTag:
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
break;
}
// falls through
case SyntaxKind.JSDocPropertyTag:
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag,
(node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ?
SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property,
SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocFunctionType:
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocRecordType:
return bindAnonymousTypeWorker(node as JSDocTypeLiteral | JSDocRecordType);
const propTag = node as JSDocPropertyLikeTag;
const flags = propTag.isBracketed || propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ?
SymbolFlags.Property | SymbolFlags.Optional :
SymbolFlags.Property;
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocTypedefTag: {
const { fullName } = node as JSDocTypedefTag;
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
@@ -2187,7 +2188,7 @@ namespace ts {
return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
}
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral | JSDocRecordType) {
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) {
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, InternalSymbolName.Type);
}
@@ -2288,7 +2289,7 @@ namespace ts {
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
// expression is the declaration
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
}
function isExportsOrModuleExportsOrAlias(node: Node): boolean {
@@ -2298,14 +2299,10 @@ namespace ts {
}
function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
if (node.kind === SyntaxKind.Identifier) {
const symbol = lookupSymbolForName((<Identifier>node).text);
if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
const declaration = symbol.valueDeclaration as VariableDeclaration;
if (declaration.initializer) {
return isExportsOrModuleExportsOrAliasOrAssignment(declaration.initializer);
}
}
if (isIdentifier(node)) {
const symbol = lookupSymbolForName(node.escapedText);
return symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(symbol.valueDeclaration.initializer);
}
return false;
}
@@ -2329,7 +2326,7 @@ namespace ts {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule, SymbolFlags.None);
}
function bindThisPropertyAssignment(node: BinaryExpression) {
@@ -2352,11 +2349,8 @@ namespace ts {
// this.foo assignment in a JavaScript class
// Bind this property to the containing class
const containingClass = container.parent;
const symbol = declareSymbol(hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None);
if (symbol) {
// symbols declared through 'this' property assignements can be overwritten by subsequent method declarations
(symbol as Symbol).isReplaceableByMethod = true;
}
const symbolTable = hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members;
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true);
break;
}
}
@@ -2375,7 +2369,7 @@ namespace ts {
constructorFunction.parent = classPrototype;
classPrototype.parent = leftSideOfAssignment;
bindPropertyAssignment(constructorFunction.text, leftSideOfAssignment, /*isPrototypeProperty*/ true);
bindPropertyAssignment(constructorFunction.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ true);
}
function bindStaticPropertyAssignment(node: BinaryExpression) {
@@ -2397,7 +2391,7 @@ namespace ts {
bindExportsPropertyAssignment(node);
}
else {
bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
bindPropertyAssignment(target.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ false);
}
}
@@ -2438,11 +2432,11 @@ namespace ts {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
}
else {
const bindingName = node.name ? node.name.text : InternalSymbolName.Class;
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Class;
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
// Add name of class expression into the map for semantic classifier
if (node.name) {
classifiableNames.set(node.name.text, true);
classifiableNames.set(node.name.escapedText, true);
}
}
@@ -2458,14 +2452,14 @@ namespace ts {
// module might have an exported variable called 'prototype'. We can't allow that as
// that would clash with the built-in 'prototype' for the class.
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype" as __String);
const symbolExport = symbol.exports.get(prototypeSymbol.name);
const symbolExport = symbol.exports.get(prototypeSymbol.escapedName);
if (symbolExport) {
if (node.name) {
node.name.parent = node;
}
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(prototypeSymbol.name)));
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(prototypeSymbol.escapedName)));
}
symbol.exports.set(prototypeSymbol.name, prototypeSymbol);
symbol.exports.set(prototypeSymbol.escapedName, prototypeSymbol);
prototypeSymbol.parent = symbol;
}
@@ -2551,7 +2545,7 @@ namespace ts {
node.flowNode = currentFlow;
}
checkStrictModeFunctionName(node);
const bindingName = node.name ? node.name.text : InternalSymbolName.Function;
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Function;
return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName);
}
+783 -483
View File
File diff suppressed because it is too large Load Diff
+85 -95
View File
@@ -105,7 +105,7 @@ namespace ts {
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_es2015_or_ESNext,
description: Diagnostics.Specify_module_code_generation_Colon_none_commonjs_amd_system_umd_es2015_or_ESNext,
},
{
name: "lib",
@@ -728,12 +728,12 @@ namespace ts {
}
/* @internal */
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) {
return convertJsonOptionOfCustomType(opt, trimString(value || ""), errors);
}
/* @internal */
export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Diagnostic[]): (string | number)[] | undefined {
export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): (string | number)[] | undefined {
value = trimString(value);
if (startsWith(value, "-")) {
return undefined;
@@ -752,7 +752,7 @@ namespace ts {
}
}
export function parseCommandLine(commandLine: string[], readFile?: (path: string) => string): ParsedCommandLine {
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
const options: CompilerOptions = {};
const fileNames: string[] = [];
const errors: Diagnostic[] = [];
@@ -764,7 +764,7 @@ namespace ts {
errors
};
function parseStrings(args: string[]) {
function parseStrings(args: ReadonlyArray<string>) {
let i = 0;
while (i < args.length) {
const s = args[i];
@@ -878,15 +878,9 @@ namespace ts {
* Read tsconfig.json file
* @param fileName The path to the config file
*/
export function readConfigFile(fileName: string, readFile: (path: string) => string): { config?: any; error?: Diagnostic } {
let text = "";
try {
text = readFile(fileName);
}
catch (e) {
return { config: {}, error: createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) };
}
return parseConfigFileTextToJson(fileName, text);
export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } {
const textOrDiagnostic = tryReadFile(fileName, readFile);
return typeof textOrDiagnostic === "string" ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
}
/**
@@ -906,18 +900,23 @@ namespace ts {
* Read tsconfig.json file
* @param fileName The path to the config file
*/
export function readJsonConfigFile(fileName: string, readFile: (path: string) => string): JsonSourceFile {
let text = "";
export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): JsonSourceFile {
const textOrDiagnostic = tryReadFile(fileName, readFile);
return typeof textOrDiagnostic === "string" ? parseJsonText(fileName, textOrDiagnostic) : <JsonSourceFile>{ parseDiagnostics: [textOrDiagnostic] };
}
function tryReadFile(fileName: string, readFile: (path: string) => string | undefined): string | Diagnostic {
let text: string | undefined;
try {
text = readFile(fileName);
}
catch (e) {
return <JsonSourceFile>{ parseDiagnostics: [createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message)] };
return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message);
}
return parseJsonText(fileName, text);
return text === undefined ? createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, fileName) : text;
}
function commandLineOptionsToMap(options: CommandLineOption[]) {
function commandLineOptionsToMap(options: ReadonlyArray<CommandLineOption>) {
return arrayToMap(options, option => option.name);
}
@@ -1008,7 +1007,7 @@ namespace ts {
/**
* Convert the json syntax tree into the json value
*/
export function convertToObject(sourceFile: JsonSourceFile, errors: Diagnostic[]): any {
export function convertToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>): any {
return convertToObjectWorker(sourceFile, errors, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
}
@@ -1017,7 +1016,7 @@ namespace ts {
*/
function convertToObjectWorker(
sourceFile: JsonSourceFile,
errors: Diagnostic[],
errors: Push<Diagnostic>,
knownRootOptions: Map<CommandLineOption> | undefined,
jsonConversionNotifier: JsonConversionNotifier | undefined): any {
if (!sourceFile.jsonObject) {
@@ -1086,11 +1085,7 @@ namespace ts {
elements: NodeArray<Expression>,
elementOption: CommandLineOption | undefined
): any[] {
const result: any[] = [];
for (const element of elements) {
result.push(convertPropertyValueToJson(element, elementOption));
}
return result;
return elements.map(element => convertPropertyValueToJson(element, elementOption));
}
function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption): any {
@@ -1203,17 +1198,9 @@ namespace ts {
* @param fileNames array of filenames to be generated into tsconfig.json
*/
/* @internal */
export function generateTSConfig(options: CompilerOptions, fileNames: string[], newLine: string): string {
export function generateTSConfig(options: CompilerOptions, fileNames: ReadonlyArray<string>, newLine: string): string {
const compilerOptions = extend(options, defaultInitCompilerOptions);
const configurations: { compilerOptions: MapLike<CompilerOptionsValue>; files?: string[] } = {
compilerOptions: serializeCompilerOptions(compilerOptions)
};
if (fileNames && fileNames.length) {
// only set the files property if we have at least one file
configurations.files = fileNames;
}
const compilerOptionsMap = serializeCompilerOptions(compilerOptions);
return writeConfigurations();
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
@@ -1238,8 +1225,8 @@ namespace ts {
});
}
function serializeCompilerOptions(options: CompilerOptions): MapLike<CompilerOptionsValue> {
const result: ts.MapLike<CompilerOptionsValue> = {};
function serializeCompilerOptions(options: CompilerOptions): Map<CompilerOptionsValue> {
const result = createMap<CompilerOptionsValue>();
const optionsNameMap = getOptionNameMap().optionNameMap;
for (const name in options) {
@@ -1256,19 +1243,15 @@ namespace ts {
if (!customTypeMap) {
// There is no map associated with this compiler option then use the value as-is
// This is the case if the value is expect to be string, number, boolean or list of string
result[name] = value;
result.set(name, value);
}
else {
if (optionDefinition.type === "list") {
const convertedValue: string[] = [];
for (const element of value as (string | number)[]) {
convertedValue.push(getNameOfCompilerOptionValue(element, customTypeMap));
}
result[name] = convertedValue;
result.set(name, (value as ReadonlyArray<string | number>).map(element => getNameOfCompilerOptionValue(element, customTypeMap)));
}
else {
// There is a typeMap associated with this command-line option so use it to map value back to its name
result[name] = getNameOfCompilerOptionValue(value, customTypeMap);
result.set(name, getNameOfCompilerOptionValue(value, customTypeMap));
}
}
}
@@ -1300,33 +1283,30 @@ namespace ts {
function writeConfigurations() {
// Filter applicable options to place in the file
const categorizedOptions = reduceLeft(
filter(optionDeclarations, o => o.category !== Diagnostics.Command_line_Options && o.category !== Diagnostics.Advanced_Options),
(memo, value) => {
if (value.category) {
const name = getLocaleSpecificMessage(value.category);
(memo[name] || (memo[name] = [])).push(value);
}
return memo;
}, <MapLike<CommandLineOption[]>>{});
const categorizedOptions = createMultiMap<CommandLineOption>();
for (const option of optionDeclarations) {
const { category } = option;
if (category !== undefined && category !== Diagnostics.Command_line_Options && category !== Diagnostics.Advanced_Options) {
categorizedOptions.add(getLocaleSpecificMessage(category), option);
}
}
// Serialize all options and thier descriptions
// Serialize all options and their descriptions
let marginLength = 0;
let seenKnownKeys = 0;
const nameColumn: string[] = [];
const descriptionColumn: string[] = [];
const knownKeysCount = getOwnKeys(configurations.compilerOptions).length;
for (const category in categorizedOptions) {
categorizedOptions.forEach((options, category) => {
if (nameColumn.length !== 0) {
nameColumn.push("");
descriptionColumn.push("");
}
nameColumn.push(`/* ${category} */`);
descriptionColumn.push("");
for (const option of categorizedOptions[category]) {
for (const option of options) {
let optionName;
if (hasProperty(configurations.compilerOptions, option.name)) {
optionName = `"${option.name}": ${JSON.stringify(configurations.compilerOptions[option.name])}${(seenKnownKeys += 1) === knownKeysCount ? "" : ","}`;
if (compilerOptionsMap.has(option.name)) {
optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`;
}
else {
optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option))},`;
@@ -1335,7 +1315,7 @@ namespace ts {
descriptionColumn.push(`/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */`);
marginLength = Math.max(optionName.length, marginLength);
}
}
});
// Write the output
const tab = makePadding(2);
@@ -1348,11 +1328,11 @@ namespace ts {
const description = descriptionColumn[i];
result.push(optionName && `${tab}${tab}${optionName}${ description && (makePadding(marginLength - optionName.length + 2) + description)}`);
}
if (configurations.files && configurations.files.length) {
if (fileNames.length) {
result.push(`${tab}},`);
result.push(`${tab}"files": [`);
for (let i = 0; i < configurations.files.length; i++) {
result.push(`${tab}${tab}${JSON.stringify(configurations.files[i])}${i === configurations.files.length - 1 ? "" : ","}`);
for (let i = 0; i < fileNames.length; i++) {
result.push(`${tab}${tab}${JSON.stringify(fileNames[i])}${i === fileNames.length - 1 ? "" : ","}`);
}
result.push(`${tab}]`);
}
@@ -1372,7 +1352,7 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: JsFileExtensionInfo[]): ParsedCommandLine {
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions);
}
@@ -1383,7 +1363,7 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonSourceFileConfigFileContent(sourceFile: JsonSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: JsFileExtensionInfo[]): ParsedCommandLine {
export function parseJsonSourceFileConfigFileContent(sourceFile: JsonSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions);
}
@@ -1411,7 +1391,7 @@ namespace ts {
existingOptions: CompilerOptions = {},
configFileName?: string,
resolutionStack: Path[] = [],
extraFileExtensions: JsFileExtensionInfo[] = [],
extraFileExtensions: ReadonlyArray<JsFileExtensionInfo> = [],
): ParsedCommandLine {
Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
const errors: Diagnostic[] = [];
@@ -1433,10 +1413,10 @@ namespace ts {
};
function getFileNames(): ExpandResult {
let fileNames: string[];
let fileNames: ReadonlyArray<string>;
if (hasProperty(raw, "files")) {
if (isArray(raw["files"])) {
fileNames = <string[]>raw["files"];
fileNames = <ReadonlyArray<string>>raw["files"];
if (fileNames.length === 0) {
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
}
@@ -1446,20 +1426,20 @@ namespace ts {
}
}
let includeSpecs: string[];
let includeSpecs: ReadonlyArray<string>;
if (hasProperty(raw, "include")) {
if (isArray(raw["include"])) {
includeSpecs = <string[]>raw["include"];
includeSpecs = <ReadonlyArray<string>>raw["include"];
}
else {
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array");
}
}
let excludeSpecs: string[];
let excludeSpecs: ReadonlyArray<string>;
if (hasProperty(raw, "exclude")) {
if (isArray(raw["exclude"])) {
excludeSpecs = <string[]>raw["exclude"];
excludeSpecs = <ReadonlyArray<string>>raw["exclude"];
}
else {
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array");
@@ -1467,12 +1447,13 @@ namespace ts {
}
else {
// If no includes were specified, exclude common package folders and the outDir
excludeSpecs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
const specs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
const outDir = raw["compilerOptions"] && raw["compilerOptions"]["outDir"];
if (outDir) {
excludeSpecs.push(outDir);
specs.push(outDir);
}
excludeSpecs = specs;
}
if (fileNames === undefined && includeSpecs === undefined) {
@@ -1522,7 +1503,7 @@ namespace ts {
basePath: string,
configFileName: string,
resolutionStack: Path[],
errors: Diagnostic[],
errors: Push<Diagnostic>,
): ParsedTsconfig {
basePath = normalizeSlashes(basePath);
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
@@ -1571,7 +1552,7 @@ namespace ts {
basePath: string,
getCanonicalFileName: (fileName: string) => string,
configFileName: string,
errors: Diagnostic[]
errors: Push<Diagnostic>
): ParsedTsconfig {
if (hasProperty(json, "excludes")) {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
@@ -1601,7 +1582,7 @@ namespace ts {
basePath: string,
getCanonicalFileName: (fileName: string) => string,
configFileName: string,
errors: Diagnostic[]
errors: Push<Diagnostic>
): ParsedTsconfig {
const options = getDefaultCompilerOptions(configFileName);
let typeAcquisition: TypeAcquisition, typingOptionstypeAcquisition: TypeAcquisition;
@@ -1632,7 +1613,7 @@ namespace ts {
);
return;
case "files":
if ((<string[]>value).length === 0) {
if ((<ReadonlyArray<string>>value).length === 0) {
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueNode, Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"));
}
return;
@@ -1668,7 +1649,7 @@ namespace ts {
host: ParseConfigHost,
basePath: string,
getCanonicalFileName: (fileName: string) => string,
errors: Diagnostic[],
errors: Push<Diagnostic>,
createDiagnostic: (message: DiagnosticMessage, arg1?: string) => Diagnostic) {
extendedConfig = normalizeSlashes(extendedConfig);
// If the path isn't a rooted or relative path, don't try to resolve it (we reserve the right to special case module-id like paths in the future)
@@ -1694,7 +1675,7 @@ namespace ts {
basePath: string,
getCanonicalFileName: (fileName: string) => string,
resolutionStack: Path[],
errors: Diagnostic[],
errors: Push<Diagnostic>,
): ParsedTsconfig | undefined {
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
if (sourceFile) {
@@ -1731,7 +1712,7 @@ namespace ts {
return extendedConfig;
}
function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Diagnostic[]): boolean {
function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean {
if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) {
return undefined;
}
@@ -1762,7 +1743,7 @@ namespace ts {
}
function convertCompilerOptionsFromJsonWorker(jsonOptions: any,
basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions {
basePath: string, errors: Push<Diagnostic>, configFileName?: string): CompilerOptions {
const options = getDefaultCompilerOptions(configFileName);
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
@@ -1775,7 +1756,7 @@ namespace ts {
}
function convertTypeAcquisitionFromJsonWorker(jsonOptions: any,
basePath: string, errors: Diagnostic[], configFileName?: string): TypeAcquisition {
basePath: string, errors: Push<Diagnostic>, configFileName?: string): TypeAcquisition {
const options = getDefaultTypeAcquisition(configFileName);
const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions);
@@ -1784,8 +1765,8 @@ namespace ts {
return options;
}
function convertOptionsFromJson(optionDeclarations: CommandLineOption[], jsonOptions: any, basePath: string,
defaultOptions: CompilerOptions | TypeAcquisition, diagnosticMessage: DiagnosticMessage, errors: Diagnostic[]) {
function convertOptionsFromJson(optionDeclarations: ReadonlyArray<CommandLineOption>, jsonOptions: any, basePath: string,
defaultOptions: CompilerOptions | TypeAcquisition, diagnosticMessage: DiagnosticMessage, errors: Push<Diagnostic>) {
if (!jsonOptions) {
return;
@@ -1804,7 +1785,7 @@ namespace ts {
}
}
function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Diagnostic[]): CompilerOptionsValue {
function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push<Diagnostic>): CompilerOptionsValue {
if (isCompilerOptionsValue(opt, value)) {
const optType = opt.type;
if (optType === "list" && isArray(value)) {
@@ -1844,7 +1825,7 @@ namespace ts {
return value;
}
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) {
const key = value.toLowerCase();
const val = opt.type.get(key);
if (val !== undefined) {
@@ -1855,7 +1836,7 @@ namespace ts {
}
}
function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: any[], basePath: string, errors: Diagnostic[]): any[] {
function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: ReadonlyArray<any>, basePath: string, errors: Push<Diagnostic>): any[] {
return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => !!v);
}
@@ -1946,7 +1927,16 @@ namespace ts {
* @param host The host used to resolve files and directories.
* @param errors An array for diagnostic reporting.
*/
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[], extraFileExtensions: JsFileExtensionInfo[], jsonSourceFile: JsonSourceFile): ExpandResult {
function matchFileNames(
fileNames: ReadonlyArray<string>,
include: ReadonlyArray<string>,
exclude: ReadonlyArray<string>,
basePath: string,
options: CompilerOptions,
host: ParseConfigHost,
errors: Push<Diagnostic>,
extraFileExtensions: ReadonlyArray<JsFileExtensionInfo>,
jsonSourceFile: JsonSourceFile): ExpandResult {
basePath = normalizePath(basePath);
// The exclude spec list is converted into a regular expression, which allows us to quickly
@@ -2024,7 +2014,7 @@ namespace ts {
};
}
function validateSpecs(specs: string[], errors: Diagnostic[], allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string) {
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)) {
@@ -2048,7 +2038,7 @@ namespace ts {
for (const property of getPropertyAssignment(jsonSourceFile.jsonObject, specKey)) {
if (isArrayLiteralExpression(property.initializer)) {
for (const element of property.initializer.elements) {
if (element.kind === SyntaxKind.StringLiteral && (<StringLiteral>element).text === spec) {
if (isStringLiteral(element) && element.text === spec) {
return createDiagnosticForNodeInSourceFile(jsonSourceFile, element, message, spec);
}
}
@@ -2062,7 +2052,7 @@ namespace ts {
/**
* Gets directories in a set of include patterns that should be watched for changes.
*/
function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
function getWildcardDirectories(include: ReadonlyArray<string>, exclude: ReadonlyArray<string>, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
// of the pattern:
//
@@ -2136,7 +2126,7 @@ namespace ts {
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: ReadonlyArray<string>, keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority, extensions);
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
@@ -2158,7 +2148,7 @@ namespace ts {
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: ReadonlyArray<string>, keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority, extensions);
for (let i = nextExtensionPriority; i < extensions.length; i++) {
+128 -142
View File
@@ -2,6 +2,8 @@
/// <reference path="performance.ts" />
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";
/** The version of the TypeScript compiler release */
export const version = `${versionMajorMinor}.0`;
@@ -9,20 +11,6 @@ namespace ts {
/* @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;
@@ -53,11 +41,11 @@ namespace ts {
}
/* @internal */
export function createSymbolTable(symbols?: Symbol[]): SymbolTable {
export function createSymbolTable(symbols?: ReadonlyArray<Symbol>): SymbolTable {
const result = createMap<Symbol>() as SymbolTable;
if (symbols) {
for (const symbol of symbols) {
result.set(symbol.name, symbol);
result.set(symbol.escapedName, symbol);
}
}
return result;
@@ -88,7 +76,7 @@ namespace ts {
class MapIterator<T, U extends (string | T | [string, T])> {
private data: MapLike<T>;
private keys: string[];
private keys: ReadonlyArray<string>;
private index = 0;
private selector: (data: MapLike<T>, key: string) => U;
constructor(data: MapLike<T>, selector: (data: MapLike<T>, key: string) => U) {
@@ -162,50 +150,6 @@ namespace ts {
};
}
export function createFileMap<T>(keyMapper: (key: string) => string): FileMap<T> {
const files = createMap<T>();
return {
get,
set,
contains,
remove,
forEachValue: forEachValueInMap,
getKeys,
clear,
};
function forEachValueInMap(f: (key: Path, value: T) => void) {
files.forEach((file, key) => {
f(<Path>key, file);
});
}
function getKeys() {
return arrayFrom(files.keys()) as Path[];
}
// path should already be well-formed so it does not need to be normalized
function get(path: Path): T {
return files.get(keyMapper(path));
}
function set(path: Path, value: T) {
files.set(keyMapper(path), value);
}
function contains(path: Path) {
return files.has(keyMapper(path));
}
function remove(path: Path) {
files.delete(keyMapper(path));
}
function clear() {
files.clear();
}
}
export function toPath(fileName: string, basePath: string, getCanonicalFileName: (path: string) => string): Path {
const nonCanonicalizedPath = isRootedDiskPath(fileName)
? normalizePath(fileName)
@@ -219,7 +163,7 @@ namespace ts {
GreaterThan = 1
}
export function length(array: any[]) {
export function length(array: ReadonlyArray<any>) {
return array ? array.length : 0;
}
@@ -228,7 +172,7 @@ namespace ts {
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
export function forEach<T, U>(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
export function forEach<T, U>(array: ReadonlyArray<T> | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
for (let i = 0; i < array.length; i++) {
const result = callback(array[i], i);
@@ -261,14 +205,14 @@ namespace ts {
return undefined;
}
export function zipWith<T, U>(arrayA: T[], arrayB: U[], callback: (a: T, b: U, index: number) => void): void {
export function zipWith<T, U>(arrayA: ReadonlyArray<T>, arrayB: ReadonlyArray<U>, callback: (a: T, b: U, index: number) => void): void {
Debug.assert(arrayA.length === arrayB.length);
for (let i = 0; i < arrayA.length; i++) {
callback(arrayA[i], arrayB[i], i);
}
}
export function zipToMap<T>(keys: string[], values: T[]): Map<T> {
export function zipToMap<T>(keys: ReadonlyArray<string>, values: ReadonlyArray<T>): Map<T> {
Debug.assert(keys.length === values.length);
const map = createMap<T>();
for (let i = 0; i < keys.length; ++i) {
@@ -282,7 +226,7 @@ namespace ts {
* returns a falsey value, then returns false.
* If no such value is found, the callback is applied to each element of array and `true` is returned.
*/
export function every<T>(array: T[], callback: (element: T, index: number) => boolean): boolean {
export function every<T>(array: ReadonlyArray<T>, callback: (element: T, index: number) => boolean): boolean {
if (array) {
for (let i = 0; i < array.length; i++) {
if (!callback(array[i], i)) {
@@ -295,7 +239,7 @@ namespace ts {
}
/** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */
export function find<T>(array: T[], predicate: (element: T, index: number) => boolean): T | undefined {
export function find<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): T | undefined {
for (let i = 0; i < array.length; i++) {
const value = array[i];
if (predicate(value, i)) {
@@ -306,7 +250,7 @@ namespace ts {
}
/** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */
export function findIndex<T>(array: T[], predicate: (element: T, index: number) => boolean): number {
export function findIndex<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): number {
for (let i = 0; i < array.length; i++) {
if (predicate(array[i], i)) {
return i;
@@ -319,7 +263,7 @@ namespace ts {
* Returns the first truthy result of `callback`, or else fails.
* This is like `forEach`, but never returns undefined.
*/
export function findMap<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
export function findMap<T, U>(array: ReadonlyArray<T>, callback: (element: T, index: number) => U | undefined): U {
for (let i = 0; i < array.length; i++) {
const result = callback(array[i], i);
if (result) {
@@ -329,7 +273,7 @@ namespace ts {
Debug.fail();
}
export function contains<T>(array: T[], value: T): boolean {
export function contains<T>(array: ReadonlyArray<T>, value: T): boolean {
if (array) {
for (const v of array) {
if (v === value) {
@@ -340,7 +284,7 @@ namespace ts {
return false;
}
export function indexOf<T>(array: T[], value: T): number {
export function indexOf<T>(array: ReadonlyArray<T>, value: T): number {
if (array) {
for (let i = 0; i < array.length; i++) {
if (array[i] === value) {
@@ -351,7 +295,7 @@ namespace ts {
return -1;
}
export function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number {
export function indexOfAnyCharCode(text: string, charCodes: ReadonlyArray<number>, start?: number): number {
for (let i = start || 0; i < text.length; i++) {
if (contains(charCodes, text.charCodeAt(i))) {
return i;
@@ -360,7 +304,7 @@ namespace ts {
return -1;
}
export function countWhere<T>(array: T[], predicate: (x: T, i: number) => boolean): number {
export function countWhere<T>(array: ReadonlyArray<T>, predicate: (x: T, i: number) => boolean): number {
let count = 0;
if (array) {
for (let i = 0; i < array.length; i++) {
@@ -379,6 +323,8 @@ namespace ts {
*/
export function filter<T, U extends T>(array: T[], f: (x: T) => x is U): U[];
export function filter<T>(array: T[], f: (x: T) => boolean): T[];
export function filter<T, U extends T>(array: ReadonlyArray<T>, f: (x: T) => x is U): ReadonlyArray<U>;
export function filter<T, U extends T>(array: ReadonlyArray<T>, f: (x: T) => boolean): ReadonlyArray<T>;
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
if (array) {
const len = array.length;
@@ -426,7 +372,11 @@ namespace ts {
array.length = outIndex;
}
export function map<T, U>(array: T[], f: (x: T, i: number) => U): U[] {
export function clear(array: {}[]): void {
array.length = 0;
}
export function map<T, U>(array: ReadonlyArray<T>, f: (x: T, i: number) => U): U[] {
let result: U[];
if (array) {
result = [];
@@ -438,6 +388,8 @@ namespace ts {
}
// Maps from T to T and avoids allocation if all elements map to themselves
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[];
export function sameMap<T>(array: ReadonlyArray<T>, f: (x: T, i: number) => T): ReadonlyArray<T>;
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[] {
let result: T[];
if (array) {
@@ -463,7 +415,7 @@ namespace ts {
*
* @param array The array to flatten.
*/
export function flatten<T>(array: (T | T[])[]): T[] {
export function flatten<T>(array: ReadonlyArray<T | ReadonlyArray<T>>): T[] {
let result: T[];
if (array) {
result = [];
@@ -488,7 +440,7 @@ namespace ts {
* @param array The array to map.
* @param mapfn The callback used to map the result into one or more values.
*/
export function flatMap<T, U>(array: T[] | undefined, mapfn: (x: T, i: number) => U | U[] | undefined): U[] | undefined {
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined {
let result: U[];
if (array) {
result = [];
@@ -507,6 +459,17 @@ namespace ts {
return result;
}
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U[] | undefined): U[] {
const result: U[] = [];
while (true) {
const { value, done } = iter.next();
if (done) break;
const res = mapfn(value);
if (res) result.push(...res);
}
return result;
}
/**
* Maps an array. If the mapped value is an array, it is spread into the result.
* Avoids allocation if all elements map to themselves.
@@ -514,6 +477,8 @@ namespace ts {
* @param array The array to map.
* @param mapfn The callback used to map the result into one or more values.
*/
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | ReadonlyArray<T>): T[];
export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] {
let result: T[];
if (array) {
@@ -552,7 +517,7 @@ namespace ts {
* Computes the first matching span of elements and returns a tuple of the first span
* and the remaining elements.
*/
export function span<T>(array: T[], f: (x: T, i: number) => boolean): [T[], T[]] {
export function span<T>(array: ReadonlyArray<T>, f: (x: T, i: number) => boolean): [T[], T[]] {
if (array) {
for (let i = 0; i < array.length; i++) {
if (!f(array[i], i)) {
@@ -572,7 +537,7 @@ namespace ts {
* @param keyfn A callback used to select the key for an element.
* @param mapfn A callback used to map a contiguous chunk of values to a single value.
*/
export function spanMap<T, K, U>(array: T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] {
export function spanMap<T, K, U>(array: ReadonlyArray<T>, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] {
let result: U[];
if (array) {
result = [];
@@ -612,7 +577,7 @@ namespace ts {
return result;
}
export function mapEntries<T, U>(map: Map<T>, f: (key: string, value: T) => [string, U]): Map<U> {
export function mapEntries<T, U>(map: ReadonlyMap<T>, f: (key: string, value: T) => [string, U]): Map<U> {
if (!map) {
return undefined;
}
@@ -625,7 +590,7 @@ namespace ts {
return result;
}
export function some<T>(array: T[], predicate?: (value: T) => boolean): boolean {
export function some<T>(array: ReadonlyArray<T>, predicate?: (value: T) => boolean): boolean {
if (array) {
if (predicate) {
for (const v of array) {
@@ -641,6 +606,8 @@ namespace ts {
return false;
}
export function concatenate<T>(array1: T[], array2: T[]): T[];
export function concatenate<T>(array1: ReadonlyArray<T>, array2: ReadonlyArray<T>): ReadonlyArray<T>;
export function concatenate<T>(array1: T[], array2: T[]): T[] {
if (!some(array2)) return array1;
if (!some(array1)) return array2;
@@ -648,7 +615,7 @@ namespace ts {
}
// TODO: fixme (N^2) - add optional comparer so collection can be sorted before deduplication.
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] {
export function deduplicate<T>(array: ReadonlyArray<T>, areEqual?: (a: T, b: T) => boolean): T[] {
let result: T[];
if (array) {
result = [];
@@ -705,6 +672,8 @@ namespace ts {
/**
* Compacts an array, removing any falsey elements.
*/
export function compact<T>(array: T[]): T[];
export function compact<T>(array: ReadonlyArray<T>): ReadonlyArray<T>;
export function compact<T>(array: T[]): T[] {
let result: T[];
if (array) {
@@ -728,7 +697,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++) {
@@ -744,10 +713,11 @@ namespace ts {
return result;
}
export function sum(array: any[], prop: string): number {
export function sum<T extends Record<K, number>, K extends string>(array: T[], prop: K): number {
let result = 0;
for (const v of array) {
result += v[prop];
// Note: we need the following type assertion because of GH #17069
result += v[prop] as number;
}
return result;
}
@@ -771,7 +741,7 @@ namespace ts {
* Gets the actual offset into an array for a relative offset. Negative offsets indicate a
* position offset from the end of the array.
*/
function toOffset(array: any[], offset: number) {
function toOffset(array: ReadonlyArray<any>, offset: number) {
return offset < 0 ? array.length + offset : offset;
}
@@ -785,7 +755,7 @@ namespace ts {
* @param start The offset in `from` at which to start copying values.
* @param end The offset in `from` at which to stop copying values (non-inclusive).
*/
export function addRange<T>(to: T[] | undefined, from: T[] | undefined, start?: number, end?: number): T[] | undefined {
export function addRange<T>(to: T[] | undefined, from: ReadonlyArray<T> | undefined, start?: number, end?: number): T[] | undefined {
if (from === undefined) return to;
if (to === undefined) return from.slice(start, end);
start = start === undefined ? 0 : toOffset(from, start);
@@ -802,14 +772,14 @@ namespace ts {
/**
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
*/
export function stableSort<T>(array: T[], comparer: (x: T, y: T) => Comparison = compareValues) {
export function stableSort<T>(array: ReadonlyArray<T>, comparer: Comparer<T> = compareValues) {
return array
.map((_, i) => i) // create array of indices
.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y)) // sort indices by value then position
.map(i => array[i]); // get sorted array
}
export function rangeEquals<T>(array1: T[], array2: T[], pos: number, end: number) {
export function rangeEquals<T>(array1: ReadonlyArray<T>, array2: ReadonlyArray<T>, pos: number, end: number) {
while (pos < end) {
if (array1[pos] !== array2[pos]) {
return false;
@@ -823,7 +793,7 @@ namespace ts {
* Returns the element at a specific offset in an array if non-empty, `undefined` otherwise.
* A negative offset indicates the element should be retrieved from the end of the array.
*/
export function elementAt<T>(array: T[] | undefined, offset: number): T | undefined {
export function elementAt<T>(array: ReadonlyArray<T> | undefined, offset: number): T | undefined {
if (array) {
offset = toOffset(array, offset);
if (offset < array.length) {
@@ -836,21 +806,21 @@ namespace ts {
/**
* Returns the first element of an array if non-empty, `undefined` otherwise.
*/
export function firstOrUndefined<T>(array: T[]): T | undefined {
export function firstOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
return elementAt(array, 0);
}
/**
* Returns the last element of an array if non-empty, `undefined` otherwise.
*/
export function lastOrUndefined<T>(array: T[]): T | undefined {
export function lastOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
return elementAt(array, -1);
}
/**
* Returns the only element of an array if it contains only one element, `undefined` otherwise.
*/
export function singleOrUndefined<T>(array: T[]): T | undefined {
export function singleOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
return array && array.length === 1
? array[0]
: undefined;
@@ -860,18 +830,22 @@ namespace ts {
* Returns the only element of an array if it contains only one element; otheriwse, returns the
* array.
*/
export function singleOrMany<T>(array: T[]): T | T[];
export function singleOrMany<T>(array: ReadonlyArray<T>): T | ReadonlyArray<T>;
export function singleOrMany<T>(array: T[]): T | T[] {
return array && array.length === 1
? array[0]
: array;
}
export function replaceElement<T>(array: T[], index: number, value: T): T[] {
export function replaceElement<T>(array: ReadonlyArray<T>, index: number, value: T): T[] {
const result = array.slice(0);
result[index] = value;
return result;
}
export type Comparer<T> = (a: T, b: T) => Comparison;
/**
* Performs a binary search, finding the index at which 'value' occurs in 'array'.
* If no such index is found, returns the 2's-complement of first index at which
@@ -879,7 +853,7 @@ namespace ts {
* @param array A sorted array whose first element must be no larger than number
* @param number The value to be searched for in the array.
*/
export function binarySearch<T>(array: T[], value: T, comparer?: (v1: T, v2: T) => number, offset?: number): number {
export function binarySearch<T>(array: ReadonlyArray<T>, value: T, comparer?: Comparer<T>, offset?: number): number {
if (!array || array.length === 0) {
return -1;
}
@@ -908,8 +882,8 @@ namespace ts {
return ~low;
}
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceLeft<T, U>(array: ReadonlyArray<T>, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
export function reduceLeft<T>(array: ReadonlyArray<T>, f: (memo: T, value: T, i: number) => T): T;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T {
if (array && array.length > 0) {
const size = array.length;
@@ -934,8 +908,8 @@ namespace ts {
return initial;
}
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceRight<T, U>(array: ReadonlyArray<T>, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
export function reduceRight<T>(array: ReadonlyArray<T>, f: (memo: T, value: T, i: number) => T): T;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T {
if (array) {
const size = array.length;
@@ -1016,9 +990,9 @@ namespace ts {
* Calls `callback` for each entry in the map, returning the first truthy result.
* Use `map.forEach` instead for normal iteration.
*/
export function forEachEntry<T, U>(map: UnderscoreEscapedMap<T>, callback: (value: T, key: __String) => U | undefined): U | undefined;
export function forEachEntry<T, U>(map: Map<T>, callback: (value: T, key: string) => U | undefined): U | undefined;
export function forEachEntry<T, U>(map: UnderscoreEscapedMap<T> | Map<T>, callback: (value: T, key: (string & __String)) => U | undefined): U | undefined {
export function forEachEntry<T, U>(map: ReadonlyUnderscoreEscapedMap<T>, callback: (value: T, key: __String) => U | undefined): U | undefined;
export function forEachEntry<T, U>(map: ReadonlyMap<T>, callback: (value: T, key: string) => U | undefined): U | undefined;
export function forEachEntry<T, U>(map: ReadonlyUnderscoreEscapedMap<T> | ReadonlyMap<T>, callback: (value: T, key: (string & __String)) => U | undefined): U | undefined {
const iterator = map.entries();
for (let { value: pair, done } = iterator.next(); !done; { value: pair, done } = iterator.next()) {
const [key, value] = pair;
@@ -1031,9 +1005,9 @@ namespace ts {
}
/** `forEachEntry` for just keys. */
export function forEachKey<T>(map: UnderscoreEscapedMap<{}>, callback: (key: __String) => T | undefined): T | undefined;
export function forEachKey<T>(map: Map<{}>, callback: (key: string) => T | undefined): T | undefined;
export function forEachKey<T>(map: UnderscoreEscapedMap<{}> | Map<{}>, callback: (key: string & __String) => T | undefined): T | undefined {
export function forEachKey<T>(map: ReadonlyUnderscoreEscapedMap<{}>, callback: (key: __String) => T | undefined): T | undefined;
export function forEachKey<T>(map: ReadonlyMap<{}>, callback: (key: string) => T | undefined): T | undefined;
export function forEachKey<T>(map: ReadonlyUnderscoreEscapedMap<{}> | ReadonlyMap<{}>, callback: (key: string & __String) => T | undefined): T | undefined {
const iterator = map.keys();
for (let { value: key, done } = iterator.next(); !done; { value: key, done } = iterator.next()) {
const result = callback(key as string & __String);
@@ -1045,8 +1019,8 @@ namespace ts {
}
/** Copy entries from `source` to `target`. */
export function copyEntries<T>(source: UnderscoreEscapedMap<T>, target: UnderscoreEscapedMap<T>): void;
export function copyEntries<T>(source: Map<T>, target: Map<T>): void;
export function copyEntries<T>(source: ReadonlyUnderscoreEscapedMap<T>, target: UnderscoreEscapedMap<T>): void;
export function copyEntries<T>(source: ReadonlyMap<T>, target: Map<T>): void;
export function copyEntries<T, U extends UnderscoreEscapedMap<T> | Map<T>>(source: U, target: U): void {
(source as Map<T>).forEach((value, key) => {
(target as Map<T>).set(key, value);
@@ -1102,9 +1076,9 @@ namespace ts {
* the same key with the given 'makeKey' function, then the element with the higher
* index in the array will be the one associated with the produced key.
*/
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
export function arrayToMap<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<T>;
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
const result = createMap<T | U>();
for (const value of array) {
result.set(makeKey(value), makeValue ? makeValue(value) : value);
@@ -1117,15 +1091,15 @@ namespace ts {
*
* @param array the array of input elements.
*/
export function arrayToSet(array: string[]): Map<true>;
export function arrayToSet<T>(array: T[], makeKey: (value: T) => string): Map<true>;
export function arrayToSet(array: any[], makeKey?: (value: any) => string): Map<true> {
export function arrayToSet(array: ReadonlyArray<string>): Map<true>;
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<true>;
export function arrayToSet(array: ReadonlyArray<any>, makeKey?: (value: any) => string): Map<true> {
return arrayToMap<any, true>(array, makeKey || (s => s), () => true);
}
export function cloneMap(map: SymbolTable): SymbolTable;
export function cloneMap<T>(map: Map<T>): Map<T>;
export function cloneMap<T>(map: Map<T> | SymbolTable): Map<T> | SymbolTable {
export function cloneMap<T>(map: ReadonlyMap<T>): Map<T>;
export function cloneMap<T>(map: ReadonlyMap<T> | SymbolTable): Map<T> | SymbolTable {
const clone = createMap<T>();
copyEntries(map as Map<T>, clone);
return clone;
@@ -1202,7 +1176,7 @@ namespace ts {
/**
* Tests whether a value is an array.
*/
export function isArray(value: any): value is any[] {
export function isArray(value: any): value is ReadonlyArray<any> {
return Array.isArray ? Array.isArray(value) : value instanceof Array;
}
@@ -1600,10 +1574,21 @@ namespace ts {
return path && !isRootedDiskPath(path) && path.indexOf("://") !== -1;
}
/* @internal */
export function pathIsRelative(path: string): boolean {
return /^\.\.?($|[\\/])/.test(path);
}
export function isExternalModuleNameRelative(moduleName: string): boolean {
// TypeScript 1.0 spec (April 2014): 11.2.1
// An external module name is "relative" if the first term is "." or "..".
return /^\.\.?($|[\\/])/.test(moduleName);
// Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module.
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
}
/** @deprecated Use `!isExternalModuleNameRelative(moduleName)` instead. */
export function moduleHasNonRelativeName(moduleName: string): boolean {
return !isExternalModuleNameRelative(moduleName);
}
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
@@ -1672,7 +1657,7 @@ namespace ts {
return getNormalizedPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory));
}
export function getNormalizedPathFromPathComponents(pathComponents: string[]) {
export function getNormalizedPathFromPathComponents(pathComponents: ReadonlyArray<string>) {
if (pathComponents && pathComponents.length) {
return pathComponents[0] + pathComponents.slice(1).join(directorySeparator);
}
@@ -1874,7 +1859,7 @@ namespace ts {
}
/* @internal */
export function fileExtensionIsOneOf(path: string, extensions: string[]): boolean {
export function fileExtensionIsOneOf(path: string, extensions: ReadonlyArray<string>): boolean {
for (const extension of extensions) {
if (fileExtensionIs(path, extension)) {
return true;
@@ -1899,7 +1884,7 @@ namespace ts {
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
export function getRegularExpressionForWildcard(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
if (!patterns || !patterns.length) {
return undefined;
@@ -1911,7 +1896,7 @@ namespace ts {
return `^(${pattern})${terminator}`;
}
function getRegularExpressionsForWildcards(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
function getRegularExpressionsForWildcards(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}
@@ -2016,21 +2001,21 @@ namespace ts {
}
export interface FileSystemEntries {
files: string[];
directories: string[];
files: ReadonlyArray<string>;
directories: ReadonlyArray<string>;
}
export interface FileMatcherPatterns {
/** One pattern for each "include" spec. */
includeFilePatterns: string[];
includeFilePatterns: ReadonlyArray<string>;
/** One pattern matching one of any of the "include" specs. */
includeFilePattern: string;
includeDirectoryPattern: string;
excludePattern: string;
basePaths: string[];
basePaths: ReadonlyArray<string>;
}
export function getFileMatcherPatterns(path: string, excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
export function getFileMatcherPatterns(path: string, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
const absolutePath = combinePaths(currentDirectory, path);
@@ -2044,7 +2029,7 @@ namespace ts {
};
}
export function matchFiles(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
export function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
@@ -2064,7 +2049,7 @@ namespace ts {
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
}
return flatten(results);
return flatten<string>(results);
function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
let { files, directories } = getFileSystemEntries(path);
@@ -2108,7 +2093,7 @@ namespace ts {
/**
* Computes the unique non-wildcard base paths amongst the provided include patterns.
*/
function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) {
function getBasePaths(path: string, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean) {
// Storage for our results in the form of literal paths (e.g. the paths as written by the user).
const basePaths: string[] = [path];
@@ -2180,13 +2165,13 @@ namespace ts {
/**
* List of supported extensions in order of file resolution precedence.
*/
export const supportedTypeScriptExtensions = [Extension.Ts, Extension.Tsx, Extension.Dts];
export const supportedTypeScriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
export const supportedTypescriptExtensionsForExtractExtension = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJavascriptExtensions = [Extension.Js, Extension.Jsx];
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
const allSupportedExtensions = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]): string[] {
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;
@@ -2208,7 +2193,7 @@ namespace ts {
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
}
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]) {
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>) {
if (!fileName) { return false; }
for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) {
@@ -2232,7 +2217,7 @@ namespace ts {
Lowest = DeclarationAndJavaScriptFiles,
}
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
export function getExtensionPriority(path: string, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
if (fileExtensionIs(path, supportedExtensions[i])) {
return adjustExtensionPriority(<ExtensionPriority>i, supportedExtensions);
@@ -2247,7 +2232,7 @@ namespace ts {
/**
* Adjusts an extension priority to be the highest priority within the same range.
*/
export function adjustExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
export function adjustExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.TypeScriptFiles;
}
@@ -2256,12 +2241,13 @@ namespace ts {
}
else {
return supportedExtensions.length;
} }
}
}
/**
* Gets the next lowest extension priority for a given priority.
*/
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.DeclarationAndJavaScriptFiles;
}
@@ -2306,7 +2292,7 @@ namespace ts {
function Symbol(this: Symbol, flags: SymbolFlags, name: __String) {
this.flags = flags;
this.name = name;
this.escapedName = name;
this.declarations = undefined;
}
@@ -2450,7 +2436,7 @@ namespace ts {
* (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
*/
/* @internal */
export function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
export function matchPatternOrExact(patternStrings: ReadonlyArray<string>, candidate: string): string | Pattern | undefined {
const patterns: Pattern[] = [];
for (const patternString of patternStrings) {
const pattern = tryParsePattern(patternString);
@@ -2483,7 +2469,7 @@ namespace ts {
/** Return the object corresponding to the best pattern to match `candidate`. */
/* @internal */
export function findBestPatternMatch<T>(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
export function findBestPatternMatch<T>(values: ReadonlyArray<T>, getPattern: (value: T) => Pattern, candidate: string): T | undefined {
let matchedValue: T | undefined = undefined;
// use length of prefix as betterness criteria
let longestMatchPrefixLength = -1;
@@ -2539,7 +2525,7 @@ namespace ts {
Debug.fail(`File ${path} has unknown extension.`);
}
export function tryGetExtensionFromPath(path: string): Extension | undefined {
return find(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
return find<Extension>(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
}
export function isCheckJsEnabledForFile(sourceFile: SourceFile, compilerOptions: CompilerOptions) {
+7 -7
View File
@@ -211,7 +211,7 @@ namespace ts {
decreaseIndent = newWriter.decreaseIndent;
}
function writeAsynchronousModuleElements(nodes: Node[]) {
function writeAsynchronousModuleElements(nodes: ReadonlyArray<Node>) {
const oldWriter = writer;
forEach(nodes, declaration => {
let nodeToCheck: Node;
@@ -374,13 +374,13 @@ namespace ts {
}
}
function emitLines(nodes: Node[]) {
function emitLines(nodes: ReadonlyArray<Node>) {
for (const node of nodes) {
emit(node);
}
}
function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
function emitSeparatedList(nodes: ReadonlyArray<Node>, separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
let currentWriterPos = writer.getTextPos();
for (const node of nodes) {
if (!canEmitFn || canEmitFn(node)) {
@@ -393,7 +393,7 @@ namespace ts {
}
}
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
function emitCommaList(nodes: ReadonlyArray<Node>, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn);
}
@@ -1007,7 +1007,7 @@ namespace ts {
return node.parent.kind === SyntaxKind.MethodDeclaration && hasModifier(node.parent, ModifierFlags.Private);
}
function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
function emitTypeParameters(typeParameters: ReadonlyArray<TypeParameterDeclaration>) {
function emitTypeParameter(node: TypeParameterDeclaration) {
increaseIndent();
emitJsDocComments(node);
@@ -1109,7 +1109,7 @@ namespace ts {
}
}
function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
function emitHeritageClause(typeReferences: ReadonlyArray<ExpressionWithTypeArguments>, isImplementsList: boolean) {
if (typeReferences) {
write(isImplementsList ? " implements " : " extends ");
emitCommaList(typeReferences, emitTypeOfTypeReference);
@@ -1164,7 +1164,7 @@ namespace ts {
if (baseTypeNode && !isEntityNameExpression(baseTypeNode.expression)) {
tempVarName = baseTypeNode.expression.kind === SyntaxKind.NullKeyword ?
"null" :
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.text}_base`, {
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.escapedText}_base`, {
diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
errorNode: baseTypeNode,
typeName: node.name
+30 -15
View File
@@ -2064,7 +2064,7 @@
"category": "Error",
"code": 2679
},
"A 'this' parameter must be the first parameter.": {
"A '{0}' parameter must be the first parameter.": {
"category": "Error",
"code": 2680
},
@@ -2192,6 +2192,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",
@@ -2658,7 +2662,7 @@
"category": "Message",
"code": 6015
},
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
"Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
"category": "Message",
"code": 6016
},
@@ -3455,6 +3459,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
@@ -3463,6 +3471,22 @@
"category": "Error",
"code": 8016
},
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
},
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
"category": "Error",
"code": 8018
},
"Report errors in .js files.": {
"category": "Message",
"code": 8019
},
"JSDoc types can only be used inside documentation comments.": {
"category": "Error",
"code": 8020
},
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error",
"code": 9002
@@ -3637,6 +3661,10 @@
"category": "Message",
"code": 90025
},
"Rewrite as the indexed access type '{0}'.": {
"category": "Message",
"code": 90026
},
"Convert function to an ES2015 class": {
"category": "Message",
@@ -3645,18 +3673,5 @@
"Convert function '{0}' to class": {
"category": "Message",
"code": 95002
},
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
},
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
"category": "Error",
"code": 8018
},
"Report errors in .js files.": {
"category": "Message",
"code": 8019
}
}
+7 -5
View File
@@ -1346,7 +1346,9 @@ namespace ts {
emitExpression(node.left);
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
emitLeadingCommentsOfPosition(node.operatorToken.pos);
writeTokenNode(node.operatorToken);
emitTrailingCommentsOfPosition(node.operatorToken.end);
increaseIndentIf(indentAfterOperator, " ");
emitExpression(node.right);
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
@@ -2228,7 +2230,7 @@ namespace ts {
* Emits any prologue directives at the start of a Statement list, returning the
* number of prologue directives written to the output.
*/
function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean, seenPrologueDirectives?: Map<true>): number {
function emitPrologueDirectives(statements: ReadonlyArray<Node>, startWithNewLine?: boolean, seenPrologueDirectives?: Map<true>): number {
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
if (isPrologueDirective(statement)) {
@@ -2761,7 +2763,7 @@ namespace ts {
return generateName(node);
}
else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) {
return unescapeLeadingUnderscores(node.text);
return unescapeLeadingUnderscores(node.escapedText);
}
else if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
return getTextOfNode((<StringLiteral>node).textSourceNode, includeTrivia);
@@ -2917,8 +2919,8 @@ namespace ts {
*/
function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
const expr = getExternalModuleName(node);
const baseName = expr.kind === SyntaxKind.StringLiteral ?
makeIdentifierFromModuleName((<LiteralExpression>expr).text) : "module";
const baseName = isStringLiteral(expr) ?
makeIdentifierFromModuleName(expr.text) : "module";
return makeUniqueName(baseName);
}
@@ -2981,7 +2983,7 @@ namespace ts {
case GeneratedIdentifierKind.Loop:
return makeTempVariableName(TempFlags._i);
case GeneratedIdentifierKind.Unique:
return makeUniqueName(unescapeLeadingUnderscores(name.text));
return makeUniqueName(unescapeLeadingUnderscores(name.escapedText));
}
Debug.fail("Unsupported GeneratedIdentifierKind.");
+344 -117
View File
File diff suppressed because it is too large Load Diff
+6 -14
View File
@@ -13,12 +13,6 @@ namespace ts {
return compilerOptions.traceResolution && host.trace !== undefined;
}
/** Array that is only intended to be pushed to, never read. */
/* @internal */
export interface Push<T> {
push(value: T): void;
}
/**
* Result of trying to resolve a module.
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
@@ -54,10 +48,6 @@ namespace ts {
};
}
export function moduleHasNonRelativeName(moduleName: string): boolean {
return !(isRootedDiskPath(moduleName) || isExternalModuleNameRelative(moduleName));
}
interface ModuleResolutionState {
host: ModuleResolutionHost;
compilerOptions: CompilerOptions;
@@ -266,6 +256,8 @@ namespace ts {
for (const typeDirectivePath of host.getDirectories(root)) {
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
// See `createNotNeededPackageJSON` in the types-publisher` repo.
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
if (!isNotNeededPackage) {
@@ -318,7 +310,7 @@ namespace ts {
}
function getOrCreateCacheForModuleName(nonRelativeModuleName: string) {
if (!moduleHasNonRelativeName(nonRelativeModuleName)) {
if (isExternalModuleNameRelative(nonRelativeModuleName)) {
return undefined;
}
let perModuleNameCache = moduleNameToDirectoryMap.get(nonRelativeModuleName);
@@ -535,7 +527,7 @@ namespace ts {
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
}
else {
@@ -711,7 +703,7 @@ namespace ts {
return toSearchResult({ resolved, isExternalLibraryImport: false });
}
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
if (traceEnabled) {
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
}
@@ -1024,7 +1016,7 @@ namespace ts {
}
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
// Climb up parent directories looking for a module.
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host);
+526 -652
View File
File diff suppressed because it is too large Load Diff
+48 -32
View File
@@ -3,7 +3,6 @@
/// <reference path="core.ts" />
namespace ts {
const emptyArray: any[] = [];
const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/;
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
@@ -332,6 +331,7 @@ namespace ts {
const categoryColor = getCategoryFormat(diagnostic.category);
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`;
output += sys.newLine;
}
return output;
}
@@ -441,13 +441,13 @@ namespace ts {
const supportedExtensions = getSupportedExtensions(options);
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
const hasEmitBlockingDiagnostics = createMap<boolean>();
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression;
let moduleResolutionCache: ModuleResolutionCache;
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
if (host.resolveModuleNames) {
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => {
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
return resolved as ResolvedModuleFull;
@@ -460,22 +460,22 @@ namespace ts {
else {
moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x));
const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache).resolvedModule;
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(moduleNames, containingFile, loader);
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(checkAllDefined(moduleNames), containingFile, loader);
}
let resolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[], containingFile: string) => ResolvedTypeReferenceDirective[];
if (host.resolveTypeReferenceDirectives) {
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(checkAllDefined(typeDirectiveNames), containingFile);
}
else {
const loader = (typesRef: string, containingFile: string) => resolveTypeReferenceDirective(typesRef, containingFile, options, host).resolvedTypeReferenceDirective;
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(typeReferenceDirectiveNames, containingFile, loader);
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader);
}
const filesByName = createMap<SourceFile | undefined>();
// stores 'filename -> file association' ignoring case
// used to track cases when two file names differ only in casing
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createMap<SourceFile>() : undefined;
const structuralIsReused = tryReuseStructureFromOldProgram();
if (structuralIsReused !== StructureIsReused.Completely) {
@@ -556,6 +556,10 @@ namespace ts {
return program;
function toPath(fileName: string): Path {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
function getCommonSourceDirectory() {
if (commonSourceDirectory === undefined) {
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary));
@@ -934,7 +938,7 @@ namespace ts {
}
function isEmitBlocked(emitFileName: string): boolean {
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
return hasEmitBlockingDiagnostics.has(toPath(emitFileName));
}
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
@@ -993,7 +997,7 @@ namespace ts {
}
function getSourceFile(fileName: string): SourceFile {
return getSourceFileByPath(toPath(fileName, currentDirectory, getCanonicalFileName));
return getSourceFileByPath(toPath(fileName));
}
function getSourceFileByPath(path: Path): SourceFile {
@@ -1192,10 +1196,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;
@@ -1385,8 +1393,8 @@ namespace ts {
const isExternalModuleFile = isExternalModule(file);
// file.imports may not be undefined if there exists dynamic import
let imports: LiteralExpression[];
let moduleAugmentations: LiteralExpression[];
let imports: StringLiteral[];
let moduleAugmentations: StringLiteral[];
let ambientModules: string[];
// If we are importing helpers, we need to add a synthetic reference to resolve the
@@ -1421,35 +1429,36 @@ namespace ts {
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportDeclaration:
const moduleNameExpr = getExternalModuleName(node);
if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) {
if (!moduleNameExpr || !isStringLiteral(moduleNameExpr)) {
break;
}
if (!(<LiteralExpression>moduleNameExpr).text) {
if (!moduleNameExpr.text) {
break;
}
// TypeScript 1.0 spec (April 2014): 12.1.6
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
// only through top - level external module names. Relative external module names are not permitted.
if (!inAmbientModule || !isExternalModuleNameRelative((<LiteralExpression>moduleNameExpr).text)) {
(imports || (imports = [])).push(<LiteralExpression>moduleNameExpr);
if (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) {
(imports || (imports = [])).push(moduleNameExpr);
}
break;
case SyntaxKind.ModuleDeclaration:
if (isAmbientModule(<ModuleDeclaration>node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
const moduleName = <LiteralExpression>(<ModuleDeclaration>node).name;
const moduleName = <StringLiteral>(<ModuleDeclaration>node).name; // TODO: GH#17347
const nameText = ts.getTextOfIdentifierOrLiteral(moduleName);
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
// This will happen in two cases:
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
// immediately nested in top level ambient module declaration .
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(moduleName.text))) {
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
(moduleAugmentations || (moduleAugmentations = [])).push(moduleName);
}
else if (!inAmbientModule) {
if (file.isDeclarationFile) {
// for global .d.ts files record name of ambient module
(ambientModules || (ambientModules = [])).push(moduleName.text);
(ambientModules || (ambientModules = [])).push(nameText);
}
// An AmbientExternalModuleDeclaration declares an external module.
// This type of declaration is permitted only in the global module.
@@ -1484,7 +1493,7 @@ namespace ts {
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName)));
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)));
}
function getSourceFileFromReferenceWorker(
@@ -1528,7 +1537,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, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd),
(diagnostic, ...args) => {
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
@@ -1597,13 +1606,14 @@ namespace ts {
file.path = path;
if (host.useCaseSensitiveFileNames()) {
const pathLowerCase = path.toLowerCase();
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(path);
const existingFile = filesByNameIgnoreCase.get(pathLowerCase);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
}
else {
filesByNameIgnoreCase.set(path, file);
filesByNameIgnoreCase.set(pathLowerCase, file);
}
}
@@ -1750,7 +1760,7 @@ namespace ts {
modulesWithElidedImports.set(file.path, true);
}
else if (shouldAddFile) {
const path = toPath(resolvedFileName, currentDirectory, getCanonicalFileName);
const path = toPath(resolvedFileName);
const pos = skipTrivia(file.text, file.imports[i].pos);
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
}
@@ -1969,7 +1979,7 @@ namespace ts {
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
if (!options.noEmit && !options.suppressOutputPathCheck) {
const emitHost = getEmitHost();
const emitFilesSeen = createFileMap<boolean>(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : key => key);
const emitFilesSeen = createMap<true>();
forEachEmittedFile(emitHost, (emitFileNames) => {
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
@@ -1977,9 +1987,9 @@ namespace ts {
}
// Verify that all the emit files are unique and don't overwrite input files
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: FileMap<boolean>) {
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: Map<true>) {
if (emitFileName) {
const emitFilePath = toPath(emitFileName, currentDirectory, getCanonicalFileName);
const emitFilePath = toPath(emitFileName);
// Report error if the output overwrites input file
if (filesByName.has(emitFilePath)) {
let chain: DiagnosticMessageChain;
@@ -1991,13 +2001,14 @@ namespace ts {
blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
}
const emitFileKey = !host.useCaseSensitiveFileNames() ? emitFilePath.toLocaleLowerCase() : emitFilePath;
// Report error if multiple files write into same file
if (emitFilesSeen.contains(emitFilePath)) {
if (emitFilesSeen.has(emitFileKey)) {
// Already seen the same emit file - report error
blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
}
else {
emitFilesSeen.set(emitFilePath, true);
emitFilesSeen.set(emitFileKey, true);
}
}
}
@@ -2089,7 +2100,7 @@ namespace ts {
}
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
programDiagnostics.add(diag);
}
}
@@ -2121,4 +2132,9 @@ namespace ts {
return options.allowJs ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
}
}
function checkAllDefined(names: string[]): string[] {
Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names));
return names;
}
}
File diff suppressed because one or more lines are too long
+28 -9
View File
@@ -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,
@@ -23,7 +35,7 @@ namespace ts {
newLine: string;
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string;
readFile(path: string, encoding?: string): string | undefined;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
/**
@@ -39,7 +51,7 @@ namespace ts {
getExecutingFilePath(): string;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
/**
* This should be cryptographically secure.
@@ -97,10 +109,10 @@ namespace ts {
directoryExists(path: string): boolean;
createDirectory(path: string): void;
resolvePath(path: string): string;
readFile(path: string): string;
readFile(path: string): string | undefined;
writeFile(path: string, contents: string): void;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, basePaths?: ReadonlyArray<string>, excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
realpath(path: string): string;
@@ -196,15 +208,22 @@ namespace ts {
if (platform === "win32" || platform === "win64") {
return false;
}
// convert current file name to upper case / lower case and check if file exists
// (guards against cases when name is already all uppercase or lowercase)
return !fileExists(__filename.toUpperCase()) || !fileExists(__filename.toLowerCase());
// If this file exists under a different case, we must be case-insensitve.
return !fileExists(swapCase(__filename));
}
/** Convert all lowercase chars to uppercase, and vice-versa */
function swapCase(s: string): string {
return s.replace(/\w/g, (ch) => {
const up = ch.toUpperCase();
return ch === up ? ch.toLowerCase() : up;
});
}
const platform: string = _os.platform();
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
function readFile(fileName: string, _encoding?: string): string {
function readFile(fileName: string, _encoding?: string): string | undefined {
if (!fileExists(fileName)) {
return undefined;
}
@@ -287,7 +306,7 @@ namespace ts {
}
}
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[], depth?: number): string[] {
function readDirectory(path: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries);
}
+2 -2
View File
@@ -415,7 +415,7 @@ namespace ts {
return createElementAccess(value, argumentExpression);
}
else {
const name = createIdentifier(unescapeLeadingUnderscores(propertyName.text));
const name = createIdentifier(unescapeLeadingUnderscores(propertyName.escapedText));
return createPropertyAccess(value, name);
}
}
@@ -492,7 +492,7 @@ namespace ts {
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`
*/
function createRestCall(context: TransformationContext, value: Expression, elements: BindingOrAssignmentElement[], computedTempVariables: Expression[], location: TextRange): Expression {
function createRestCall(context: TransformationContext, value: Expression, elements: ReadonlyArray<BindingOrAssignmentElement>, computedTempVariables: ReadonlyArray<Expression>, location: TextRange): Expression {
context.requestEmitHelper(restHelper);
const propertyNames: Expression[] = [];
let computedTempVariableOffset = 0;
+15 -15
View File
@@ -647,7 +647,7 @@ namespace ts {
if (isGeneratedIdentifier(node)) {
return node;
}
if (node.text !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
if (node.escapedText !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
return node;
}
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = createUniqueName("arguments"));
@@ -661,7 +661,7 @@ namespace ts {
// - break/continue is non-labeled and located in non-converted loop/switch statement
const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
const canUseBreakOrContinue =
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(unescapeLeadingUnderscores(node.label.text))) ||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(unescapeLeadingUnderscores(node.label.escapedText))) ||
(!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
if (!canUseBreakOrContinue) {
@@ -679,12 +679,12 @@ namespace ts {
}
else {
if (node.kind === SyntaxKind.BreakStatement) {
labelMarker = `break-${node.label.text}`;
setLabeledJump(convertedLoopState, /*isBreak*/ true, unescapeLeadingUnderscores(node.label.text), labelMarker);
labelMarker = `break-${node.label.escapedText}`;
setLabeledJump(convertedLoopState, /*isBreak*/ true, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
}
else {
labelMarker = `continue-${node.label.text}`;
setLabeledJump(convertedLoopState, /*isBreak*/ false, unescapeLeadingUnderscores(node.label.text), labelMarker);
labelMarker = `continue-${node.label.escapedText}`;
setLabeledJump(convertedLoopState, /*isBreak*/ false, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
}
}
let returnExpression: Expression = createLiteral(labelMarker);
@@ -1963,7 +1963,7 @@ namespace ts {
updated,
setTextRange(
createNodeArray(
prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true)
prependCaptureNewTargetIfNeeded(updated.statements as MutableNodeArray<Statement>, node, /*copyOnWrite*/ true)
),
/*location*/ updated.statements
)
@@ -2236,11 +2236,11 @@ namespace ts {
}
function recordLabel(node: LabeledStatement) {
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.text), true);
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), true);
}
function resetLabel(node: LabeledStatement) {
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.text), false);
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), false);
}
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
@@ -3053,7 +3053,7 @@ namespace ts {
else {
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
const outParamName = createUniqueName("out_" + unescapeLeadingUnderscores(name.text));
const outParamName = createUniqueName("out_" + unescapeLeadingUnderscores(name.escapedText));
loopOutParameters.push({ originalName: name, outParamName });
}
}
@@ -3199,7 +3199,7 @@ namespace ts {
function addStatementToStartOfBlock(block: Block, statement: Statement): Block {
const transformedStatements = visitNodes(block.statements, visitor, isStatement);
return updateBlock(block, [statement].concat(transformedStatements));
return updateBlock(block, [statement, ...transformedStatements]);
}
/**
@@ -3579,7 +3579,7 @@ namespace ts {
// Map spans of spread expressions into their expressions and spans of other
// expressions into an array literal.
const numElements = elements.length;
const segments = flatten(
const segments = flatten<Expression>(
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
)
@@ -3591,7 +3591,7 @@ namespace ts {
if (isCallExpression(firstSegment)
&& isIdentifier(firstSegment.expression)
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
&& firstSegment.expression.text === "___spread") {
&& firstSegment.expression.escapedText === "___spread") {
return segments[0];
}
}
@@ -3842,7 +3842,7 @@ namespace ts {
}
function visitMetaProperty(node: MetaProperty) {
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target") {
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") {
if (hierarchyFacts & HierarchyFacts.ComputedPropertyName) {
hierarchyFacts |= HierarchyFacts.NewTargetInComputedPropertyName;
}
@@ -4067,7 +4067,7 @@ namespace ts {
}
const expression = (<SpreadElement>callArgument).expression;
return isIdentifier(expression) && expression.text === "arguments";
return isIdentifier(expression) && expression.escapedText === "arguments";
}
}
+1 -1
View File
@@ -369,7 +369,7 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(unescapeLeadingUnderscores(node.name.text)),
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
node
);
}
+1 -1
View File
@@ -111,7 +111,7 @@ namespace ts {
* @param name An Identifier
*/
function trySubstituteReservedName(name: Identifier) {
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(unescapeLeadingUnderscores(name.text)) : undefined);
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(unescapeLeadingUnderscores(name.escapedText)) : undefined);
if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
return setTextRange(createLiteral(name), name);
}
+2 -2
View File
@@ -156,7 +156,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] {
function chunkObjectLiteralElements(elements: ReadonlyArray<ObjectLiteralElement>): Expression[] {
let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[];
const objects: Expression[] = [];
for (const e of elements) {
@@ -776,7 +776,7 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(unescapeLeadingUnderscores(node.name.text)),
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
node
);
}
+9 -9
View File
@@ -1176,7 +1176,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function transformAndEmitStatements(statements: Statement[], start = 0) {
function transformAndEmitStatements(statements: ReadonlyArray<Statement>, start = 0) {
const numStatements = statements.length;
for (let i = start; i < numStatements; i++) {
transformAndEmitStatement(statements[i]);
@@ -1635,14 +1635,14 @@ namespace ts {
}
function transformAndEmitContinueStatement(node: ContinueStatement): void {
const label = findContinueTarget(node.label ? unescapeLeadingUnderscores(node.label.text) : undefined);
const label = findContinueTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
Debug.assert(label > 0, "Expected continue statment to point to a valid Label.");
emitBreak(label, /*location*/ node);
}
function visitContinueStatement(node: ContinueStatement): Statement {
if (inStatementContainingYield) {
const label = findContinueTarget(node.label && unescapeLeadingUnderscores(node.label.text));
const label = findContinueTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
if (label > 0) {
return createInlineBreak(label, /*location*/ node);
}
@@ -1652,14 +1652,14 @@ namespace ts {
}
function transformAndEmitBreakStatement(node: BreakStatement): void {
const label = findBreakTarget(node.label ? unescapeLeadingUnderscores(node.label.text) : undefined);
const label = findBreakTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
Debug.assert(label > 0, "Expected break statment to point to a valid Label.");
emitBreak(label, /*location*/ node);
}
function visitBreakStatement(node: BreakStatement): Statement {
if (inStatementContainingYield) {
const label = findBreakTarget(node.label && unescapeLeadingUnderscores(node.label.text));
const label = findBreakTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
if (label > 0) {
return createInlineBreak(label, /*location*/ node);
}
@@ -1838,7 +1838,7 @@ namespace ts {
// /*body*/
// .endlabeled
// .mark endLabel
beginLabeledBlock(unescapeLeadingUnderscores(node.label.text));
beginLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
transformAndEmitEmbeddedStatement(node.statement);
endLabeledBlock();
}
@@ -1849,7 +1849,7 @@ namespace ts {
function visitLabeledStatement(node: LabeledStatement) {
if (inStatementContainingYield) {
beginScriptLabeledBlock(unescapeLeadingUnderscores(node.label.text));
beginScriptLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
}
node = visitEachChild(node, visitor, context);
@@ -1950,7 +1950,7 @@ namespace ts {
}
function substituteExpressionIdentifier(node: Identifier) {
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(unescapeLeadingUnderscores(node.text))) {
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(unescapeLeadingUnderscores(node.escapedText))) {
const original = getOriginalNode(node);
if (isIdentifier(original) && original.parent) {
const declaration = resolver.getReferencedValueDeclaration(original);
@@ -2123,7 +2123,7 @@ namespace ts {
hoistVariableDeclaration(variable.name);
}
else {
const text = unescapeLeadingUnderscores((<Identifier>variable.name).text);
const text = unescapeLeadingUnderscores((<Identifier>variable.name).escapedText);
name = declareLocal(text);
if (!renamedCatchVariables) {
renamedCatchVariables = createMap<boolean>();
+6 -6
View File
@@ -77,7 +77,7 @@ namespace ts {
return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node);
}
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[], isChild: boolean, location: TextRange) {
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray<JsxChild>, isChild: boolean, location: TextRange) {
const tagName = getTagName(node);
let objectProperties: Expression;
const attrs = node.attributes.properties;
@@ -88,7 +88,7 @@ namespace ts {
else {
// Map spans of JsxAttribute nodes into object literals and spans
// of JsxSpreadAttribute nodes into expressions.
const segments = flatten(
const segments = flatten<Expression | ObjectLiteralExpression>(
spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread
? map(attrs, transformJsxSpreadAttributeToExpression)
: createObjectLiteral(map(attrs, transformJsxAttributeToObjectLiteralElement))
@@ -252,8 +252,8 @@ namespace ts {
}
else {
const name = (<JsxOpeningLikeElement>node).tagName;
if (isIdentifier(name) && isIntrinsicJsxName(name.text)) {
return createLiteral(unescapeLeadingUnderscores(name.text));
if (isIdentifier(name) && isIntrinsicJsxName(name.escapedText)) {
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
else {
return createExpressionFromEntityName(name);
@@ -268,11 +268,11 @@ namespace ts {
*/
function getAttributeName(node: JsxAttribute): StringLiteral | Identifier {
const name = node.name;
if (/^[A-Za-z_]\w*$/.test(unescapeLeadingUnderscores(name.text))) {
if (/^[A-Za-z_]\w*$/.test(unescapeLeadingUnderscores(name.escapedText))) {
return name;
}
else {
return createLiteral(unescapeLeadingUnderscores(name.text));
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
}
+2 -2
View File
@@ -924,7 +924,7 @@ namespace ts {
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, importCallExpressionVisitor),
node.members
visitNodes(node.members, importCallExpressionVisitor)
),
node
),
@@ -1225,7 +1225,7 @@ namespace ts {
*/
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration): Statement[] | undefined {
const name = getDeclarationName(decl);
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.text));
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
if (exportSpecifiers) {
for (const exportSpecifier of exportSpecifiers) {
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name);
+7 -7
View File
@@ -324,7 +324,7 @@ namespace ts {
const exportedNames: ObjectLiteralElementLike[] = [];
if (moduleInfo.exportedNames) {
for (const exportedLocalName of moduleInfo.exportedNames) {
if (exportedLocalName.text === "default") {
if (exportedLocalName.escapedText === "default") {
continue;
}
@@ -353,7 +353,7 @@ namespace ts {
// write name of indirectly exported entry, i.e. 'export {x} from ...'
exportedNames.push(
createPropertyAssignment(
createLiteral(unescapeLeadingUnderscores((element.name || element.propertyName).text)),
createLiteral(unescapeLeadingUnderscores((element.name || element.propertyName).escapedText)),
createTrue()
)
);
@@ -504,10 +504,10 @@ namespace ts {
for (const e of (<ExportDeclaration>entry).exportClause.elements) {
properties.push(
createPropertyAssignment(
createLiteral(unescapeLeadingUnderscores(e.name.text)),
createLiteral(unescapeLeadingUnderscores(e.name.escapedText)),
createElementAccess(
parameterName,
createLiteral(unescapeLeadingUnderscores((e.propertyName || e.name).text))
createLiteral(unescapeLeadingUnderscores((e.propertyName || e.name).escapedText))
)
)
);
@@ -1028,7 +1028,7 @@ namespace ts {
let excludeName: string;
if (exportSelf) {
statements = appendExportStatement(statements, decl.name, getLocalName(decl));
excludeName = unescapeLeadingUnderscores(decl.name.text);
excludeName = unescapeLeadingUnderscores(decl.name.escapedText);
}
statements = appendExportsOfDeclaration(statements, decl, excludeName);
@@ -1080,10 +1080,10 @@ namespace ts {
}
const name = getDeclarationName(decl);
const exportSpecifiers = moduleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.text));
const exportSpecifiers = moduleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
if (exportSpecifiers) {
for (const exportSpecifier of exportSpecifiers) {
if (exportSpecifier.name.text !== excludeName) {
if (exportSpecifier.name.escapedText !== excludeName) {
statements = appendExportStatement(statements, exportSpecifier.name, name);
}
}
+16 -16
View File
@@ -522,7 +522,7 @@ namespace ts {
return parameter.decorators !== undefined && parameter.decorators.length > 0;
}
function getClassFacts(node: ClassDeclaration, staticProperties: PropertyDeclaration[]) {
function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray<PropertyDeclaration>) {
let facts = ClassFacts.None;
if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties;
if (getClassExtendsHeritageClauseElement(node)) facts |= ClassFacts.HasExtendsClause;
@@ -1051,7 +1051,7 @@ namespace ts {
*
* @param node The constructor node.
*/
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ParameterDeclaration[] {
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray<ParameterDeclaration> {
return filter(node.parameters, isParameterWithPropertyAssignment);
}
@@ -1104,7 +1104,7 @@ namespace ts {
* @param node The class node.
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
*/
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): PropertyDeclaration[] {
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
}
@@ -1144,7 +1144,7 @@ namespace ts {
* @param properties An array of property declarations to transform.
* @param receiver The receiver on which each property should be assigned.
*/
function addInitializedPropertyStatements(statements: Statement[], properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
for (const property of properties) {
const statement = createStatement(transformInitializedProperty(property, receiver));
setSourceMapRange(statement, moveRangePastModifiers(property));
@@ -1159,7 +1159,7 @@ namespace ts {
* @param properties An array of property declarations to transform.
* @param receiver The receiver on which each property should be assigned.
*/
function generateInitializedPropertyExpressions(properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
const expressions: Expression[] = [];
for (const property of properties) {
const expression = transformInitializedProperty(property, receiver);
@@ -1194,7 +1194,7 @@ namespace ts {
* @param isStatic A value indicating whether to retrieve static or instance members of
* the class.
*/
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ClassElement[] {
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<ClassElement> {
return filter(node.members, isStatic ? isStaticDecoratedClassElement : isInstanceDecoratedClassElement);
}
@@ -1233,8 +1233,8 @@ namespace ts {
* A structure describing the decorators for a class element.
*/
interface AllDecorators {
decorators: Decorator[];
parameters?: Decorator[][];
decorators: ReadonlyArray<Decorator>;
parameters?: ReadonlyArray<ReadonlyArray<Decorator>>;
}
/**
@@ -1244,7 +1244,7 @@ namespace ts {
* @param node The function-like node.
*/
function getDecoratorsOfParameters(node: FunctionLikeDeclaration) {
let decorators: Decorator[][];
let decorators: ReadonlyArray<Decorator>[];
if (node) {
const parameters = node.parameters;
for (let i = 0; i < parameters.length; i++) {
@@ -1692,7 +1692,7 @@ namespace ts {
const numParameters = parameters.length;
for (let i = 0; i < numParameters; i++) {
const parameter = parameters[i];
if (i === 0 && isIdentifier(parameter.name) && parameter.name.text === "this") {
if (i === 0 && isIdentifier(parameter.name) && parameter.name.escapedText === "this") {
continue;
}
if (parameter.dotDotDotToken) {
@@ -1841,7 +1841,7 @@ namespace ts {
for (const typeNode of node.types) {
const serializedIndividual = serializeTypeNode(typeNode);
if (isIdentifier(serializedIndividual) && serializedIndividual.text === "Object") {
if (isIdentifier(serializedIndividual) && serializedIndividual.escapedText === "Object") {
// One of the individual is global object, return immediately
return serializedIndividual;
}
@@ -1851,7 +1851,7 @@ namespace ts {
// Different types
if (!isIdentifier(serializedUnion) ||
!isIdentifier(serializedIndividual) ||
serializedUnion.text !== serializedIndividual.text) {
serializedUnion.escapedText !== serializedIndividual.escapedText) {
return createIdentifier("Object");
}
}
@@ -2007,7 +2007,7 @@ namespace ts {
: (<ComputedPropertyName>name).expression;
}
else if (isIdentifier(name)) {
return createLiteral(unescapeLeadingUnderscores(name.text));
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
else {
return getSynthesizedClone(name);
@@ -2644,7 +2644,7 @@ namespace ts {
* on symbol names.
*/
function recordEmittedDeclarationInScope(node: Node) {
const name = node.symbol && node.symbol.name;
const name = node.symbol && node.symbol.escapedName;
if (name) {
if (!currentScopeFirstDeclarationsOfName) {
currentScopeFirstDeclarationsOfName = createUnderscoreEscapedMap<Node>();
@@ -2662,7 +2662,7 @@ namespace ts {
*/
function isFirstEmittedDeclarationInScope(node: Node) {
if (currentScopeFirstDeclarationsOfName) {
const name = node.symbol && node.symbol.name;
const name = node.symbol && node.symbol.escapedName;
if (name) {
return currentScopeFirstDeclarationsOfName.get(name) === node;
}
@@ -3210,7 +3210,7 @@ namespace ts {
function getClassAliasIfNeeded(node: ClassDeclaration) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeLeadingUnderscores(node.name.text) : "default");
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeLeadingUnderscores(node.name.escapedText) : "default");
classAliases[getOriginalNodeId(node)] = classAlias;
hoistVariableDeclaration(classAlias);
return classAlias;
+9 -9
View File
@@ -58,9 +58,9 @@ namespace ts {
else {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
if (!uniqueExports.get(unescapeLeadingUnderscores(specifier.name.text))) {
if (!uniqueExports.get(unescapeLeadingUnderscores(specifier.name.escapedText))) {
const name = specifier.propertyName || specifier.name;
exportSpecifiers.add(unescapeLeadingUnderscores(name.text), specifier);
exportSpecifiers.add(unescapeLeadingUnderscores(name.escapedText), specifier);
const decl = resolver.getReferencedImportDeclaration(name)
|| resolver.getReferencedValueDeclaration(name);
@@ -69,7 +69,7 @@ namespace ts {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
uniqueExports.set(unescapeLeadingUnderscores(specifier.name.text), true);
uniqueExports.set(unescapeLeadingUnderscores(specifier.name.escapedText), true);
exportedNames = append(exportedNames, specifier.name);
}
}
@@ -103,9 +103,9 @@ namespace ts {
else {
// export function x() { }
const name = (<FunctionDeclaration>node).name;
if (!uniqueExports.get(unescapeLeadingUnderscores(name.text))) {
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(unescapeLeadingUnderscores(name.text), true);
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
exportedNames = append(exportedNames, name);
}
}
@@ -124,9 +124,9 @@ namespace ts {
else {
// export class x { }
const name = (<ClassDeclaration>node).name;
if (!uniqueExports.get(unescapeLeadingUnderscores(name.text))) {
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(unescapeLeadingUnderscores(name.text), true);
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
exportedNames = append(exportedNames, name);
}
}
@@ -158,8 +158,8 @@ namespace ts {
}
}
else if (!isGeneratedIdentifier(decl.name)) {
if (!uniqueExports.get(unescapeLeadingUnderscores(decl.name.text))) {
uniqueExports.set(unescapeLeadingUnderscores(decl.name.text), true);
if (!uniqueExports.get(unescapeLeadingUnderscores(decl.name.escapedText))) {
uniqueExports.set(unescapeLeadingUnderscores(decl.name.escapedText), true);
exportedNames = append(exportedNames, decl.name);
}
}
+3 -1
View File
@@ -61,7 +61,7 @@ namespace ts {
}
function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void {
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine + sys.newLine);
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine);
}
function reportWatchDiagnostic(diagnostic: Diagnostic) {
@@ -665,6 +665,8 @@ namespace ts {
}
}
ts.setStackTraceLimit();
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
+116 -162
View File
@@ -8,13 +8,10 @@ namespace ts {
[index: string]: T;
}
/** ES6 Map interface. */
export interface Map<T> {
/** ES6 Map interface, only read methods included. */
export interface ReadonlyMap<T> {
get(key: string): T | undefined;
has(key: string): boolean;
set(key: string, value: T): this;
delete(key: string): boolean;
clear(): void;
forEach(action: (value: T, key: string) => void): void;
readonly size: number;
keys(): Iterator<string>;
@@ -22,26 +19,27 @@ namespace ts {
entries(): Iterator<[string, T]>;
}
/** ES6 Map interface. */
export interface Map<T> extends ReadonlyMap<T> {
set(key: string, value: T): this;
delete(key: string): boolean;
clear(): void;
}
/** ES6 Iterator type. */
export interface Iterator<T> {
next(): { value: T, done: false } | { value: never, done: true };
}
/** Array that is only intended to be pushed to, never read. */
export interface Push<T> {
push(...values: T[]): void;
}
// branded string type used to store absolute, normalized and canonicalized paths
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
export interface FileMap<T> {
get(fileName: Path): T;
set(fileName: Path, value: T): void;
contains(fileName: Path): boolean;
remove(fileName: Path): void;
forEachValue(f: (key: Path, v: T) => void): void;
getKeys(): Path[];
clear(): void;
}
export interface TextRange {
pos: number;
end: number;
@@ -359,19 +357,11 @@ namespace ts {
JSDocAllType,
// The ? type
JSDocUnknownType,
JSDocArrayType,
JSDocUnionType,
JSDocTupleType,
JSDocNullableType,
JSDocNonNullableType,
JSDocRecordType,
JSDocRecordMember,
JSDocTypeReference,
JSDocOptionalType,
JSDocFunctionType,
JSDocVariadicType,
JSDocConstructorType,
JSDocThisType,
JSDocComment,
JSDocTag,
JSDocAugmentsTag,
@@ -383,7 +373,6 @@ namespace ts {
JSDocTypedefTag,
JSDocPropertyTag,
JSDocTypeLiteral,
JSDocLiteralType,
// Synthesized list
SyntaxList,
@@ -425,9 +414,9 @@ namespace ts {
LastBinaryOperator = CaretEqualsToken,
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocLiteralType,
LastJSDocNode = JSDocTypeLiteral,
FirstJSDocTagNode = JSDocTag,
LastJSDocTagNode = JSDocLiteralType
LastJSDocTagNode = JSDocTypeLiteral
}
export const enum NodeFlags {
@@ -462,6 +451,7 @@ namespace ts {
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
/* @internal */
PossiblyContainsDynamicImport = 1 << 19,
JSDoc = 1 << 20, // If node was parsed inside jsdoc
BlockScoped = Let | Const,
@@ -521,25 +511,28 @@ namespace ts {
flags: NodeFlags;
/* @internal */ modifierFlagsCache?: ModifierFlags;
/* @internal */ transformFlags?: TransformFlags;
decorators?: NodeArray<Decorator>; // Array of decorators (in document order)
modifiers?: ModifiersArray; // Array of modifiers
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node
/* @internal */ jsDocCache?: (JSDoc | JSDocTag)[]; // All JSDoc that applies to the node, including parent docs and @param tags
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
/* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
/* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
decorators?: NodeArray<Decorator>; // Array of decorators (in document order)
modifiers?: ModifiersArray; // Array of modifiers
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node
/* @internal */ jsDocCache?: ReadonlyArray<JSDocTag>; // Cache for getJSDocTags
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
/* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
/* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
}
export interface NodeArray<T extends Node> extends Array<T>, TextRange {
/* @internal */
export type MutableNodeArray<T extends Node> = NodeArray<T> & T[];
export interface NodeArray<T extends Node> extends ReadonlyArray<T>, TextRange {
hasTrailingComma?: boolean;
/* @internal */ transformFlags?: TransformFlags;
}
@@ -587,15 +580,16 @@ namespace ts {
export interface Identifier extends PrimaryExpression {
kind: SyntaxKind.Identifier;
/**
* Text of identifier (with escapes converted to characters).
* If the identifier begins with two underscores, this will begin with three.
* Prefer to use `id.unescapedText`. (Note: This is available only in services, not internally to the TypeScript compiler.)
* Text of identifier, but if the identifier begins with two underscores, this will begin with three.
*/
text: __String;
escapedText: __String;
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
/*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier.
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics.
/*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id.<T>
}
// Transient identifier node (marked by id === -1)
@@ -615,6 +609,7 @@ namespace ts {
kind: SyntaxKind.QualifiedName;
left: EntityName;
right: Identifier;
/*@internal*/ jsdocDotPos?: number; // QualifiedName occurs in JSDoc-style generic: Id1.Id2.<T>
}
export type EntityName = Identifier | QualifiedName;
@@ -691,7 +686,7 @@ namespace ts {
kind: SyntaxKind.Parameter;
parent?: SignatureDeclaration;
dotDotDotToken?: DotDotDotToken; // Present on rest parameter
name: BindingName; // Declared parameter name
name: BindingName; // Declared parameter name.
questionToken?: QuestionToken; // Present on optional parameter
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
@@ -706,7 +701,7 @@ namespace ts {
initializer?: Expression; // Optional initializer
}
export interface TSPropertySignature extends TypeElement {
export interface PropertySignature extends TypeElement {
kind: SyntaxKind.PropertySignature;
name: PropertyName; // Declared property name
questionToken?: QuestionToken; // Present on optional property
@@ -714,16 +709,6 @@ namespace ts {
initializer?: Expression; // Optional initializer
}
export interface JSDocPropertySignature extends TypeElement {
kind: SyntaxKind.JSDocRecordMember;
name: PropertyName; // Declared property name
questionToken?: QuestionToken; // Present on optional property
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
export type PropertySignature = TSPropertySignature | JSDocPropertySignature;
export interface PropertyDeclaration extends ClassElement {
kind: SyntaxKind.PropertyDeclaration;
questionToken?: QuestionToken; // Present for use with reporting a grammar error
@@ -776,10 +761,11 @@ namespace ts {
// SyntaxKind.ShorthandPropertyAssignment
// SyntaxKind.EnumMember
// SyntaxKind.JSDocPropertyTag
// SyntaxKind.JSDocParameterTag
export interface VariableLikeDeclaration extends NamedDeclaration {
propertyName?: PropertyName;
dotDotDotToken?: DotDotDotToken;
name: DeclarationName;
name?: DeclarationName; // May be missing for ParameterDeclaration, see comment there
questionToken?: QuestionToken;
type?: TypeNode;
initializer?: Expression;
@@ -933,7 +919,7 @@ namespace ts {
kind: SyntaxKind.ConstructorType;
}
export type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference;
export type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
export interface TypeReferenceNode extends TypeNode {
kind: SyntaxKind.TypeReference;
@@ -2052,9 +2038,9 @@ namespace ts {
}
// represents a top level: { type } expression in a JSDoc comment.
export interface JSDocTypeExpression extends Node {
export interface JSDocTypeExpression extends TypeNode {
kind: SyntaxKind.JSDocTypeExpression;
type: JSDocType;
type: TypeNode;
}
export interface JSDocType extends TypeNode {
@@ -2069,80 +2055,31 @@ namespace ts {
kind: SyntaxKind.JSDocUnknownType;
}
export interface JSDocArrayType extends JSDocType {
kind: SyntaxKind.JSDocArrayType;
elementType: JSDocType;
}
export interface JSDocUnionType extends JSDocType {
kind: SyntaxKind.JSDocUnionType;
types: NodeArray<JSDocType>;
}
export interface JSDocTupleType extends JSDocType {
kind: SyntaxKind.JSDocTupleType;
types: NodeArray<JSDocType>;
}
export interface JSDocNonNullableType extends JSDocType {
kind: SyntaxKind.JSDocNonNullableType;
type: JSDocType;
type: TypeNode;
}
export interface JSDocNullableType extends JSDocType {
kind: SyntaxKind.JSDocNullableType;
type: JSDocType;
}
export interface JSDocRecordType extends JSDocType {
kind: SyntaxKind.JSDocRecordType;
literal: TypeLiteralNode;
}
export interface JSDocTypeReference extends JSDocType {
kind: SyntaxKind.JSDocTypeReference;
name: EntityName;
typeArguments: NodeArray<JSDocType>;
type: TypeNode;
}
export interface JSDocOptionalType extends JSDocType {
kind: SyntaxKind.JSDocOptionalType;
type: JSDocType;
type: TypeNode;
}
export interface JSDocFunctionType extends JSDocType, SignatureDeclaration {
kind: SyntaxKind.JSDocFunctionType;
parameters: NodeArray<ParameterDeclaration>;
type: JSDocType;
}
export interface JSDocVariadicType extends JSDocType {
kind: SyntaxKind.JSDocVariadicType;
type: JSDocType;
type: TypeNode;
}
export interface JSDocConstructorType extends JSDocType {
kind: SyntaxKind.JSDocConstructorType;
type: JSDocType;
}
export interface JSDocThisType extends JSDocType {
kind: SyntaxKind.JSDocThisType;
type: JSDocType;
}
export interface JSDocLiteralType extends JSDocType {
kind: SyntaxKind.JSDocLiteralType;
literal: LiteralTypeNode;
}
export type JSDocTypeReferencingNode = JSDocThisType | JSDocConstructorType | JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
export interface JSDocRecordMember extends JSDocPropertySignature {
kind: SyntaxKind.JSDocRecordMember;
name: Identifier | StringLiteral | NumericLiteral;
type?: JSDocType;
}
export type JSDocTypeReferencingNode = JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
export interface JSDoc extends Node {
kind: SyntaxKind.JSDocComment;
@@ -2190,38 +2127,32 @@ namespace ts {
kind: SyntaxKind.JSDocTypedefTag;
fullName?: JSDocNamespaceDeclaration | Identifier;
name?: Identifier;
typeExpression?: JSDocTypeExpression;
jsDocTypeLiteral?: JSDocTypeLiteral;
typeExpression?: JSDocTypeExpression | JSDocTypeLiteral;
}
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
export interface JSDocPropertyLikeTag extends JSDocTag, Declaration {
parent: JSDoc;
kind: SyntaxKind.JSDocPropertyTag;
name: Identifier;
/** the parameter name, if provided *before* the type (TypeScript-style) */
preParameterName?: Identifier;
/** the parameter name, if provided *after* the type (JSDoc-standard) */
postParameterName?: Identifier;
name: EntityName;
typeExpression: JSDocTypeExpression;
/** Whether the property name came before the type -- non-standard for JSDoc, but Typescript-like */
isNameFirst: boolean;
isBracketed: boolean;
}
export interface JSDocPropertyTag extends JSDocPropertyLikeTag {
kind: SyntaxKind.JSDocPropertyTag;
}
export interface JSDocParameterTag extends JSDocPropertyLikeTag {
kind: SyntaxKind.JSDocParameterTag;
}
export interface JSDocTypeLiteral extends JSDocType {
kind: SyntaxKind.JSDocTypeLiteral;
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
jsDocTypeTag?: JSDocTypeTag;
}
export interface JSDocParameterTag extends JSDocTag {
kind: SyntaxKind.JSDocParameterTag;
/** the parameter name, if provided *before* the type (TypeScript-style) */
preParameterName?: Identifier;
typeExpression?: JSDocTypeExpression;
/** the parameter name, if provided *after* the type (JSDoc-standard) */
postParameterName?: Identifier;
/** the parameter name, regardless of the location it was provided */
name: Identifier;
isBracketed: boolean;
/** If true, then this type literal represents an *array* of its type. */
isArrayType?: boolean;
}
export const enum FlowFlags {
@@ -2391,10 +2322,10 @@ namespace ts {
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<ResolvedModuleFull>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ imports: StringLiteral[];
/* @internal */ moduleAugmentations: StringLiteral[];
/* @internal */ imports: ReadonlyArray<StringLiteral>;
/* @internal */ moduleAugmentations: ReadonlyArray<StringLiteral>;
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
/* @internal */ ambientModuleNames: string[];
/* @internal */ ambientModuleNames: ReadonlyArray<string>;
/* @internal */ checkJsDirective: CheckJsDirective | undefined;
}
@@ -2418,7 +2349,7 @@ namespace ts {
export interface ParseConfigHost {
useCaseSensitiveFileNames: boolean;
readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[];
readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, depth: number): string[];
/**
* Gets a value indicating whether the specified path exists and is a file.
@@ -2426,11 +2357,11 @@ namespace ts {
*/
fileExists(path: string): boolean;
readFile(path: string): string;
readFile(path: string): string | undefined;
}
export interface WriteFileCallback {
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: SourceFile[]): void;
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: ReadonlyArray<SourceFile>): void;
}
export class OperationCanceledException { }
@@ -2597,6 +2528,7 @@ namespace ts {
* Returns `any` if the index is not valid.
*/
/* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type;
getNullableType(type: Type, flags: TypeFlags): Type;
getNonNullableType(type: Type): Type;
/** Note that the resulting nodes cannot be checked. */
@@ -2650,6 +2582,8 @@ namespace ts {
getAmbientModules(): Symbol[];
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
/** Unlike `tryGetMemberInModuleExports`, this includes properties of an `export =` value. */
/* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
@@ -2754,6 +2688,7 @@ namespace ts {
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
}
export const enum SymbolFormatFlags {
@@ -2902,13 +2837,11 @@ namespace ts {
TypeParameter = 1 << 18, // Type parameter
TypeAlias = 1 << 19, // Type alias
ExportValue = 1 << 20, // Exported value marker (see comment in declareModuleMember in binder)
ExportType = 1 << 21, // Exported type marker (see comment in declareModuleMember in binder)
ExportNamespace = 1 << 22, // Exported namespace marker (see comment in declareModuleMember in binder)
Alias = 1 << 23, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
Prototype = 1 << 24, // Prototype property (no source representation)
ExportStar = 1 << 25, // Export * declaration
Optional = 1 << 26, // Optional property
Transient = 1 << 27, // Transient symbol (created during type check)
Alias = 1 << 21, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
Prototype = 1 << 22, // Prototype property (no source representation)
ExportStar = 1 << 23, // Export * declaration
Optional = 1 << 24, // Optional property
Transient = 1 << 25, // Transient symbol (created during type check)
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
@@ -2953,7 +2886,6 @@ namespace ts {
BlockScoped = BlockScopedVariable | Class | Enum,
PropertyOrAccessor = Property | Accessor,
Export = ExportNamespace | ExportType | ExportValue,
ClassMember = Method | Accessor | Property,
@@ -2965,7 +2897,7 @@ namespace ts {
export interface Symbol {
flags: SymbolFlags; // Symbol flags
name: __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
@@ -3062,13 +2994,10 @@ namespace ts {
*/
export type __String = (string & { __escapedIdentifier: void }) | (void & { __escapedIdentifier: void }) | InternalSymbolName;
/** EscapedStringMap based on ES6 Map interface. */
export interface UnderscoreEscapedMap<T> {
/** ReadonlyMap where keys are `__String`s. */
export interface ReadonlyUnderscoreEscapedMap<T> {
get(key: __String): T | undefined;
has(key: __String): boolean;
set(key: __String, value: T): this;
delete(key: __String): boolean;
clear(): void;
forEach(action: (value: T, key: __String) => void): void;
readonly size: number;
keys(): Iterator<__String>;
@@ -3076,6 +3005,13 @@ namespace ts {
entries(): Iterator<[__String, T]>;
}
/** Map where keys are `__String`s. */
export interface UnderscoreEscapedMap<T> extends ReadonlyUnderscoreEscapedMap<T> {
set(key: __String, value: T): this;
delete(key: __String): boolean;
clear(): void;
}
/** SymbolTable based on ES6 Map interface. */
export type SymbolTable = UnderscoreEscapedMap<Symbol>;
@@ -3189,7 +3125,7 @@ namespace ts {
UnionOrIntersection = Union | Intersection,
StructuredType = Object | Union | Intersection,
StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess | Promised,
TypeVariable = TypeParameter | IndexedAccess,
TypeVariable = TypeParameter | IndexedAccess | Promised,
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
@@ -3499,11 +3435,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 */
@@ -3945,7 +3899,7 @@ namespace ts {
fileExists(fileName: string): boolean;
// readFile function is used to read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json'
// to determine location of bundled typings for node module
readFile(fileName: string): string;
readFile(fileName: string): string | undefined;
trace?(s: string): void;
directoryExists?(directoryName: string): boolean;
realpath?(path: string): string;
@@ -4360,7 +4314,7 @@ namespace ts {
*/
export type Visitor = (node: Node) => VisitResult<Node>;
export type VisitResult<T extends Node> = T | T[];
export type VisitResult<T extends Node> = T | T[] | undefined;
export interface Printer {
/**
+181 -191
View File
@@ -2,6 +2,9 @@
/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
export const emptyMap: ReadonlyMap<never> = createMap<never>();
export const externalHelpersModuleNameText = "tslib";
export interface ReferencePathMatchResult {
@@ -42,54 +45,55 @@ namespace ts {
string(): string;
}
// Pool writers to avoid needing to allocate them for every symbol we write.
const stringWriters: StringSymbolWriter[] = [];
export function getSingleLineStringWriter(): StringSymbolWriter {
if (stringWriters.length === 0) {
let str = "";
const stringWriter = createSingleLineStringWriter();
let stringWriterAcquired = false;
const writeText: (text: string) => void = text => str += text;
return {
string: () => str,
writeKeyword: writeText,
writeOperator: writeText,
writePunctuation: writeText,
writeSpace: writeText,
writeStringLiteral: writeText,
writeParameter: writeText,
writeProperty: writeText,
writeSymbol: writeText,
function createSingleLineStringWriter(): StringSymbolWriter {
let str = "";
// Completely ignore indentation for string writers. And map newlines to
// a single space.
writeLine: () => str += " ",
increaseIndent: noop,
decreaseIndent: noop,
clear: () => str = "",
trackSymbol: noop,
reportInaccessibleThisError: noop,
reportPrivateInBaseOfClassExpression: noop,
};
}
const writeText: (text: string) => void = text => str += text;
return {
string: () => str,
writeKeyword: writeText,
writeOperator: writeText,
writePunctuation: writeText,
writeSpace: writeText,
writeStringLiteral: writeText,
writeParameter: writeText,
writeProperty: writeText,
writeSymbol: writeText,
return stringWriters.pop();
// Completely ignore indentation for string writers. And map newlines to
// a single space.
writeLine: () => str += " ",
increaseIndent: noop,
decreaseIndent: noop,
clear: () => str = "",
trackSymbol: noop,
reportInaccessibleThisError: noop,
reportPrivateInBaseOfClassExpression: noop,
};
}
export function releaseStringWriter(writer: StringSymbolWriter) {
writer.clear();
stringWriters.push(writer);
export function usingSingleLineStringWriter(action: (writer: StringSymbolWriter) => void): string {
try {
Debug.assert(!stringWriterAcquired);
stringWriterAcquired = true;
action(stringWriter);
return stringWriter.string();
}
finally {
stringWriter.clear();
stringWriterAcquired = false;
}
}
export function getFullWidth(node: Node) {
return node.end - node.pos;
}
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
return !!(sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules.get(moduleNameText));
}
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModuleFull {
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules.get(moduleNameText) : undefined;
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModuleFull | undefined {
return sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules.get(moduleNameText);
}
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModuleFull): void {
@@ -121,7 +125,11 @@ namespace ts {
}
/* @internal */
export function hasChangesInResolutions<T>(names: string[], newResolutions: T[], oldResolutions: Map<T>, comparer: (oldResolution: T, newResolution: T) => boolean): boolean {
export function hasChangesInResolutions<T>(
names: ReadonlyArray<string>,
newResolutions: ReadonlyArray<T>,
oldResolutions: ReadonlyMap<T>,
comparer: (oldResolution: T, newResolution: T) => boolean): boolean {
Debug.assert(names.length === newResolutions.length);
for (let i = 0; i < names.length; i++) {
@@ -356,11 +364,11 @@ namespace ts {
}
/**
* @deprecated
* @deprecated Use `id.escapedText` to get the escaped text of an Identifier.
* @param identifier The identifier to escape
*/
export function escapeIdentifier(identifier: string): string {
return escapeLeadingUnderscores(identifier) as string;
return identifier;
}
// Make an identifier from an external module name by extracting the string after the last "/" and replacing
@@ -384,6 +392,11 @@ namespace ts {
((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(<ModuleDeclaration>node));
}
/* @internal */
export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration & { name: StringLiteral } {
return isModuleDeclaration(node) && isStringLiteral(node.name);
}
/** Given a symbol for a module, checks that it is a shorthand ambient module. */
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
@@ -478,7 +491,7 @@ namespace ts {
export function getTextOfPropertyName(name: PropertyName): __String {
switch (name.kind) {
case SyntaxKind.Identifier:
return (<Identifier>name).text;
return (<Identifier>name).escapedText;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return escapeLeadingUnderscores((<LiteralExpression>name).text);
@@ -494,7 +507,7 @@ namespace ts {
export function entityNameToString(name: EntityNameOrEntityNameExpression): string {
switch (name.kind) {
case SyntaxKind.Identifier:
return getFullWidth(name) === 0 ? unescapeLeadingUnderscores(name.text) : getTextOfNode(name);
return getFullWidth(name) === 0 ? unescapeLeadingUnderscores(name.escapedText) : getTextOfNode(name);
case SyntaxKind.QualifiedName:
return entityNameToString(name.left) + "." + entityNameToString(name.right);
case SyntaxKind.PropertyAccessExpression:
@@ -633,7 +646,8 @@ namespace ts {
const commentRanges = (node.kind === SyntaxKind.Parameter ||
node.kind === SyntaxKind.TypeParameter ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ArrowFunction) ?
node.kind === SyntaxKind.ArrowFunction ||
node.kind === SyntaxKind.ParenthesizedExpression) ?
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
getLeadingCommentRangesOfNodeFromText(node, text);
// True if the comment starts with '/**' but not if it is '/**/'
@@ -898,8 +912,8 @@ namespace ts {
return predicate && predicate.kind === TypePredicateKind.This;
}
export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string) {
return <PropertyAssignment[]>filter(objectLiteral.properties, property => {
export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string): ReadonlyArray<PropertyAssignment> {
return filter(objectLiteral.properties, (property): property is PropertyAssignment => {
if (property.kind === SyntaxKind.PropertyAssignment) {
const propName = getTextOfPropertyName(property.name);
return key === propName || (key2 && key2 === propName);
@@ -908,21 +922,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 {
@@ -1075,7 +1079,6 @@ namespace ts {
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
switch (node.kind) {
case SyntaxKind.TypeReference:
case SyntaxKind.JSDocTypeReference:
return (<TypeReferenceNode>node).typeName;
case SyntaxKind.ExpressionWithTypeArguments:
@@ -1286,6 +1289,10 @@ namespace ts {
return node && !!(node.flags & NodeFlags.JavaScriptFile);
}
export function isInJSDoc(node: Node): boolean {
return node && !!(node.flags & NodeFlags.JSDoc);
}
/**
* Returns true if the node is a CallExpression to the identifier 'require' with
* exactly one argument (of the form 'require("name")').
@@ -1297,7 +1304,7 @@ namespace ts {
}
const { expression, arguments: args } = callExpression as CallExpression;
if (expression.kind !== SyntaxKind.Identifier || (expression as Identifier).text !== "require") {
if (expression.kind !== SyntaxKind.Identifier || (expression as Identifier).escapedText !== "require") {
return false;
}
@@ -1332,11 +1339,11 @@ namespace ts {
}
export function isExportsIdentifier(node: Node) {
return isIdentifier(node) && node.text === "exports";
return isIdentifier(node) && node.escapedText === "exports";
}
export function isModuleExportsPropertyAccessExpression(node: Node) {
return isPropertyAccessExpression(node) && isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
return isPropertyAccessExpression(node) && isIdentifier(node.expression) && node.expression.escapedText === "module" && node.name.escapedText === "exports";
}
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
@@ -1352,11 +1359,11 @@ namespace ts {
const lhs = <PropertyAccessExpression>expr.left;
if (lhs.expression.kind === SyntaxKind.Identifier) {
const lhsId = <Identifier>lhs.expression;
if (lhsId.text === "exports") {
if (lhsId.escapedText === "exports") {
// exports.name = expr
return SpecialPropertyAssignmentKind.ExportsProperty;
}
else if (lhsId.text === "module" && lhs.name.text === "exports") {
else if (lhsId.escapedText === "module" && lhs.name.escapedText === "exports") {
// module.exports = expr
return SpecialPropertyAssignmentKind.ModuleExports;
}
@@ -1374,10 +1381,10 @@ namespace ts {
if (innerPropertyAccess.expression.kind === SyntaxKind.Identifier) {
// module.exports.name = expr
const innerPropertyAccessIdentifier = <Identifier>innerPropertyAccess.expression;
if (innerPropertyAccessIdentifier.text === "module" && innerPropertyAccess.name.text === "exports") {
if (innerPropertyAccessIdentifier.escapedText === "module" && innerPropertyAccess.name.escapedText === "exports") {
return SpecialPropertyAssignmentKind.ExportsProperty;
}
if (innerPropertyAccess.name.text === "prototype") {
if (innerPropertyAccess.name.escapedText === "prototype") {
return SpecialPropertyAssignmentKind.PrototypeProperty;
}
}
@@ -1441,43 +1448,42 @@ namespace ts {
export function isJSDocConstructSignature(node: Node) {
return node.kind === SyntaxKind.JSDocFunctionType &&
(<JSDocFunctionType>node).parameters.length > 0 &&
(<JSDocFunctionType>node).parameters[0].type.kind === SyntaxKind.JSDocConstructorType;
(node as JSDocFunctionType).parameters.length > 0 &&
(node as JSDocFunctionType).parameters[0].name &&
((node as JSDocFunctionType).parameters[0].name as Identifier).escapedText === "new";
}
export function getCommentsFromJSDoc(node: Node): string[] {
return map(getJSDocs(node), doc => doc.comment);
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean {
return !!getFirstJSDocTag(node, SyntaxKind.JSDocParameterTag);
}
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration) {
const parameterTags = getJSDocTags(node, SyntaxKind.JSDocParameterTag);
return parameterTags && parameterTags.length > 0;
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag | undefined {
const tags = getJSDocTags(node);
return find(tags, doc => doc.kind === kind);
}
function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] {
return flatMap(getJSDocs(node), doc =>
doc.kind === SyntaxKind.JSDocComment
? filter((doc as JSDoc).tags, tag => tag.kind === kind)
: doc.kind === kind && doc);
}
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag {
return node && firstOrUndefined(getJSDocTags(node, kind));
}
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
export function getAllJSDocs(node: Node): (JSDoc | JSDocTag)[] {
if (isJSDocTypedefTag(node)) {
return [node.parent];
}
return getJSDocCommentsAndTags(node);
}
let cache: (JSDoc | JSDocTag)[] = node.jsDocCache;
if (!cache) {
getJSDocsWorker(node);
node.jsDocCache = cache;
export function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined {
let tags = node.jsDocCache;
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
if (tags === undefined) {
node.jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
}
return cache;
return tags;
}
function getJSDocsWorker(node: Node) {
function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
let result: Array<JSDoc | JSDocTag> | undefined;
getJSDocCommentsAndTagsWorker(node);
return result || emptyArray;
function getJSDocCommentsAndTagsWorker(node: Node): void {
const parent = node.parent;
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
// /**
@@ -1496,7 +1502,7 @@ namespace ts {
isVariableOfVariableDeclarationStatement ? parent.parent :
undefined;
if (variableStatementNode) {
getJSDocsWorker(variableStatementNode);
getJSDocCommentsAndTagsWorker(variableStatementNode);
}
// Also recognize when the node is the RHS of an assignment expression
@@ -1506,70 +1512,64 @@ namespace ts {
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
parent.parent.kind === SyntaxKind.ExpressionStatement;
if (isSourceOfAssignmentExpressionStatement) {
getJSDocsWorker(parent.parent);
getJSDocCommentsAndTagsWorker(parent.parent);
}
const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration &&
parent && parent.kind === SyntaxKind.ModuleDeclaration;
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
if (isModuleDeclaration || isPropertyAssignmentExpression) {
getJSDocsWorker(parent);
getJSDocCommentsAndTagsWorker(parent);
}
// Pull parameter comments from declaring function as well
if (node.kind === SyntaxKind.Parameter) {
cache = concatenate(cache, getJSDocParameterTags(node as ParameterDeclaration));
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
}
if (isVariableLike(node) && node.initializer) {
cache = concatenate(cache, node.initializer.jsDoc);
result = addRange(result, node.initializer.jsDoc);
}
cache = concatenate(cache, node.jsDoc);
result = addRange(result, node.jsDoc);
}
}
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] {
const func = param.parent;
const tags = getJSDocTags(func, SyntaxKind.JSDocParameterTag) as JSDocParameterTag[];
if (!param.name) {
// this is an anonymous jsdoc param from a `function(type1, type2): type3` specification
const i = func.parameters.indexOf(param);
const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag);
if (paramTags && 0 <= i && i < paramTags.length) {
return [paramTags[i]];
}
}
else if (param.name.kind === SyntaxKind.Identifier) {
const name = (param.name as Identifier).text;
return filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && tag.name.text === name);
}
else {
// TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines
// But multi-line object types aren't supported yet either
return undefined;
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] | undefined {
if (param.name && isIdentifier(param.name)) {
const name = param.name.escapedText;
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name) as JSDocParameterTag[];
}
// a binding pattern doesn't have a name, so it's not possible to match it a jsdoc parameter, which is identified by name
return undefined;
}
/** Does the opposite of `getJSDocParameterTags`: given a JSDoc parameter, finds the parameter corresponding to it. */
export function getParameterFromJSDoc(node: JSDocParameterTag): ParameterDeclaration | undefined {
const name = node.name.text;
const grandParent = node.parent!.parent!;
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
if (!isFunctionLike(grandParent)) {
export function getParameterSymbolFromJSDoc(node: JSDocParameterTag): Symbol | undefined {
if (node.symbol) {
return node.symbol;
}
if (!isIdentifier(node.name)) {
return undefined;
}
return find(grandParent.parameters, p =>
p.name.kind === SyntaxKind.Identifier && p.name.text === name);
const name = node.name.escapedText;
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
const func = node.parent!.parent!;
if (!isFunctionLike(func)) {
return undefined;
}
const parameter = find(func.parameters, p =>
p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
return parameter && parameter.symbol;
}
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {
const name = node.name.text;
const name = node.name.escapedText;
const { typeParameters } = (node.parent.parent.parent as ts.SignatureDeclaration | ts.InterfaceDeclaration | ts.ClassDeclaration);
return find(typeParameters, p => p.name.text === name);
return find(typeParameters, p => p.name.escapedText === name);
}
export function getJSDocType(node: Node): JSDocType {
export function getJSDocType(node: Node): TypeNode {
let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
if (!tag && node.kind === SyntaxKind.Parameter) {
const paramTags = getJSDocParameterTags(node as ParameterDeclaration);
@@ -1593,7 +1593,7 @@ namespace ts {
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
}
export function getJSDocReturnType(node: Node): JSDocType {
export function getJSDocReturnType(node: Node): TypeNode {
const returnTag = getJSDocReturnTag(node);
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
}
@@ -1611,7 +1611,7 @@ namespace ts {
}
export function isRestParameter(node: ParameterDeclaration) {
if (node && (node.flags & NodeFlags.JavaScriptFile)) {
if (isInJavaScriptFile(node)) {
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType ||
forEach(getJSDocParameterTags(node),
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
@@ -1771,7 +1771,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;
@@ -1969,7 +1970,7 @@ namespace ts {
export function getPropertyNameForPropertyNameNode(name: DeclarationName): __String {
if (name.kind === SyntaxKind.Identifier) {
return name.text;
return name.escapedText;
}
if (name.kind === SyntaxKind.StringLiteral || name.kind === SyntaxKind.NumericLiteral) {
return escapeLeadingUnderscores(name.text);
@@ -1977,7 +1978,7 @@ namespace ts {
if (name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = name.expression;
if (isWellKnownSymbolSyntactically(nameExpression)) {
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.text;
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.escapedText;
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores(rightHandSideName));
}
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
@@ -1991,7 +1992,7 @@ namespace ts {
export function getTextOfIdentifierOrLiteral(node: Identifier | LiteralLikeNode) {
if (node) {
if (node.kind === SyntaxKind.Identifier) {
return unescapeLeadingUnderscores((node as Identifier).text);
return unescapeLeadingUnderscores((node as Identifier).escapedText);
}
if (node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
@@ -2006,7 +2007,7 @@ namespace ts {
export function getEscapedTextOfIdentifierOrLiteral(node: Identifier | LiteralLikeNode) {
if (node) {
if (node.kind === SyntaxKind.Identifier) {
return (node as Identifier).text;
return (node as Identifier).escapedText;
}
if (node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
@@ -2026,11 +2027,11 @@ namespace ts {
* Includes the word "Symbol" with unicode escapes
*/
export function isESSymbolIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "Symbol";
return node.kind === SyntaxKind.Identifier && (<Identifier>node).escapedText === "Symbol";
}
export function isPushOrUnshiftIdentifier(node: Identifier) {
return node.text === "push" || node.text === "unshift";
return node.escapedText === "push" || node.escapedText === "unshift";
}
export function isParameterDeclaration(node: VariableLikeDeclaration) {
@@ -2067,7 +2068,7 @@ namespace ts {
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
}
export function getOriginalSourceFiles(sourceFiles: SourceFile[]) {
export function getOriginalSourceFiles(sourceFiles: ReadonlyArray<SourceFile>) {
return sameMap(sourceFiles, getOriginalSourceFile);
}
@@ -2588,7 +2589,7 @@ namespace ts {
return combinePaths(newDirPath, sourceFilePath);
}
export function writeFile(host: EmitHost, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean, sourceFiles?: SourceFile[]) {
export function writeFile(host: EmitHost, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean, sourceFiles?: ReadonlyArray<SourceFile>) {
host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
}, sourceFiles);
@@ -2598,7 +2599,7 @@ namespace ts {
return getLineAndCharacterOfPosition(currentSourceFile, pos).line;
}
export function getLineOfLocalPositionFromLineMap(lineMap: number[], pos: number) {
export function getLineOfLocalPositionFromLineMap(lineMap: ReadonlyArray<number>, pos: number) {
return computeLineAndCharacterOfPosition(lineMap, pos).line;
}
@@ -2731,11 +2732,11 @@ namespace ts {
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): TypeParameterDeclaration[] {
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
if (node.typeParameters) {
return node.typeParameters;
}
if (node.flags & NodeFlags.JavaScriptFile) {
if (isInJavaScriptFile(node)) {
const templateTag = getJSDocTemplateTag(node);
return templateTag && templateTag.typeParameters;
}
@@ -2750,11 +2751,11 @@ namespace ts {
return parameter && getEffectiveTypeAnnotationNode(parameter);
}
export function emitNewLineBeforeLeadingComments(lineMap: number[], writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) {
export function emitNewLineBeforeLeadingComments(lineMap: ReadonlyArray<number>, writer: EmitTextWriter, node: TextRange, leadingComments: ReadonlyArray<CommentRange>) {
emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments);
}
export function emitNewLineBeforeLeadingCommentsOfPosition(lineMap: number[], writer: EmitTextWriter, pos: number, leadingComments: CommentRange[]) {
export function emitNewLineBeforeLeadingCommentsOfPosition(lineMap: ReadonlyArray<number>, writer: EmitTextWriter, pos: number, leadingComments: ReadonlyArray<CommentRange>) {
// If the leading comments start on different line than the start of node, write new line
if (leadingComments && leadingComments.length && pos !== leadingComments[0].pos &&
getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, leadingComments[0].pos)) {
@@ -2762,7 +2763,7 @@ namespace ts {
}
}
export function emitNewLineBeforeLeadingCommentOfPosition(lineMap: number[], writer: EmitTextWriter, pos: number, commentPos: number) {
export function emitNewLineBeforeLeadingCommentOfPosition(lineMap: ReadonlyArray<number>, writer: EmitTextWriter, pos: number, commentPos: number) {
// If the leading comments start on different line than the start of node, write new line
if (pos !== commentPos &&
getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, commentPos)) {
@@ -2770,8 +2771,15 @@ namespace ts {
}
}
export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], leadingSeparator: boolean, trailingSeparator: boolean, newLine: string,
writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void) {
export function emitComments(
text: string,
lineMap: ReadonlyArray<number>,
writer: EmitTextWriter,
comments: ReadonlyArray<CommentRange>,
leadingSeparator: boolean,
trailingSeparator: boolean,
newLine: string,
writeComment: (text: string, lineMap: ReadonlyArray<number>, writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void) {
if (comments && comments.length > 0) {
if (leadingSeparator) {
writer.write(" ");
@@ -2803,8 +2811,8 @@ namespace ts {
* Detached comment is a comment at the top of file or function body that is separated from
* the next statement by space.
*/
export function emitDetachedComments(text: string, lineMap: number[], writer: EmitTextWriter,
writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void,
export function emitDetachedComments(text: string, lineMap: ReadonlyArray<number>, writer: EmitTextWriter,
writeComment: (text: string, lineMap: ReadonlyArray<number>, writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void,
node: TextRange, newLine: string, removeComments: boolean) {
let leadingComments: CommentRange[];
let currentDetachedCommentInfo: { nodePos: number, detachedCommentEndPos: number };
@@ -2868,7 +2876,7 @@ namespace ts {
}
export function writeCommentRange(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
export function writeCommentRange(text: string, lineMap: ReadonlyArray<number>, writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
if (text.charCodeAt(commentPos + 1) === CharacterCodes.asterisk) {
const firstCommentLineAndCharacter = computeLineAndCharacterOfPosition(lineMap, commentPos);
const lineCount = lineMap.length;
@@ -3326,7 +3334,7 @@ namespace ts {
}
}
return stableSort(result, (x, y) => compareValues(x[0], y[0]));
return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
}
export function formatSyntaxKind(kind: SyntaxKind): string {
@@ -3590,6 +3598,15 @@ namespace ts {
}
return previous[previous.length - 1];
}
export function skipAlias(symbol: Symbol, checker: TypeChecker) {
return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
}
/** See comment on `declareModuleMember` in `binder.ts`. */
export function getCombinedLocalAndExportSymbolFlags(symbol: Symbol): SymbolFlags {
return symbol.exportSymbol ? symbol.exportSymbol.flags | symbol.flags : symbol.flags;
}
}
namespace ts {
@@ -3709,7 +3726,7 @@ namespace ts {
* This function will then merge those changes into a single change range valid between V1 and
* Vn.
*/
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
export function collapseTextChangeRangesAcrossMultipleVersions(changes: ReadonlyArray<TextChangeRange>): TextChangeRange {
if (changes.length === 0) {
return unchangedTextChangeRange;
}
@@ -3899,8 +3916,8 @@ namespace ts {
*/
export function validateLocaleAndSetLanguage(
locale: string,
sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string },
errors?: Diagnostic[]) {
sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string | undefined },
errors?: Push<Diagnostic>) {
const matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(locale.toLowerCase());
if (!matchResult) {
@@ -3919,7 +3936,7 @@ namespace ts {
trySetLanguageAndTerritory(language, /*territory*/ undefined, errors);
}
function trySetLanguageAndTerritory(language: string, territory: string, errors?: Diagnostic[]): boolean {
function trySetLanguageAndTerritory(language: string, territory: string, errors?: Push<Diagnostic>): boolean {
const compilerFilePath = normalizePath(sys.getExecutingFilePath());
const containingDirectoryPath = getDirectoryPath(compilerFilePath);
@@ -4024,18 +4041,21 @@ namespace ts {
/**
* Remove extra underscore from escaped identifier text content.
* @deprecated
* @deprecated Use `id.text` for the unescaped text.
* @param identifier The escaped identifier text.
* @returns The unescaped identifier text.
*/
export function unescapeIdentifier(id: string): string {
return unescapeLeadingUnderscores(id as __String);
return id;
}
export function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined {
if (!declaration) {
return undefined;
}
if (isJSDocPropertyLikeTag(declaration) && declaration.name.kind === SyntaxKind.QualifiedName) {
return declaration.name.right;
}
if (declaration.kind === SyntaxKind.BinaryExpression) {
const expr = declaration as BinaryExpression;
switch (getSpecialPropertyAssignmentKind(expr)) {
@@ -4642,18 +4662,6 @@ namespace ts {
return node.kind === SyntaxKind.JSDocUnknownType;
}
export function isJSDocArrayType(node: Node): node is JSDocArrayType {
return node.kind === SyntaxKind.JSDocArrayType;
}
export function isJSDocUnionType(node: Node): node is JSDocUnionType {
return node.kind === SyntaxKind.JSDocUnionType;
}
export function isJSDocTupleType(node: Node): node is JSDocTupleType {
return node.kind === SyntaxKind.JSDocTupleType;
}
export function isJSDocNullableType(node: Node): node is JSDocNullableType {
return node.kind === SyntaxKind.JSDocNullableType;
}
@@ -4662,18 +4670,6 @@ namespace ts {
return node.kind === SyntaxKind.JSDocNonNullableType;
}
export function isJSDocRecordType(node: Node): node is JSDocRecordType {
return node.kind === SyntaxKind.JSDocRecordType;
}
export function isJSDocRecordMember(node: Node): node is JSDocRecordMember {
return node.kind === SyntaxKind.JSDocRecordMember;
}
export function isJSDocTypeReference(node: Node): node is JSDocTypeReference {
return node.kind === SyntaxKind.JSDocTypeReference;
}
export function isJSDocOptionalType(node: Node): node is JSDocOptionalType {
return node.kind === SyntaxKind.JSDocOptionalType;
}
@@ -4686,14 +4682,6 @@ namespace ts {
return node.kind === SyntaxKind.JSDocVariadicType;
}
export function isJSDocConstructorType(node: Node): node is JSDocConstructorType {
return node.kind === SyntaxKind.JSDocConstructorType;
}
export function isJSDocThisType(node: Node): node is JSDocThisType {
return node.kind === SyntaxKind.JSDocThisType;
}
export function isJSDoc(node: Node): node is JSDoc {
return node.kind === SyntaxKind.JSDocComment;
}
@@ -4726,12 +4714,12 @@ namespace ts {
return node.kind === SyntaxKind.JSDocPropertyTag;
}
export function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral {
return node.kind === SyntaxKind.JSDocTypeLiteral;
export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
return node.kind === SyntaxKind.JSDocPropertyTag || node.kind === SyntaxKind.JSDocParameterTag;
}
export function isJSDocLiteralType(node: Node): node is JSDocLiteralType {
return node.kind === SyntaxKind.JSDocLiteralType;
export function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral {
return node.kind === SyntaxKind.JSDocTypeLiteral;
}
}
@@ -4766,7 +4754,7 @@ namespace ts {
// Node Arrays
/* @internal */
export function isNodeArray<T extends Node>(array: T[]): array is NodeArray<T> {
export function isNodeArray<T extends Node>(array: ReadonlyArray<T>): array is NodeArray<T> {
return array.hasOwnProperty("pos")
&& array.hasOwnProperty("end");
}
@@ -4883,6 +4871,7 @@ namespace ts {
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ConstructorType:
return true;
}
@@ -5108,6 +5097,7 @@ namespace ts {
|| kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.SuperKeyword
|| kind === SyntaxKind.ImportKeyword
|| kind === SyntaxKind.NonNullExpression
|| kind === SyntaxKind.MetaProperty;
}
+6 -6
View File
@@ -86,7 +86,7 @@ namespace ts {
return nodes;
}
let updated: NodeArray<T>;
let updated: MutableNodeArray<T>;
// Ensure start and count have valid values
const length = nodes.length;
@@ -901,7 +901,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
function extractSingleNode(nodes: Node[]): Node {
function extractSingleNode(nodes: ReadonlyArray<Node>): Node {
Debug.assert(nodes.length <= 1, "Too many nodes written to output.");
return singleOrUndefined(nodes);
}
@@ -1421,13 +1421,13 @@ namespace ts {
/**
* Merges generated lexical declarations into a new statement list.
*/
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement>;
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: ReadonlyArray<Statement>): NodeArray<Statement>;
/**
* Appends generated lexical declarations to an array of statements.
*/
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[];
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) {
export function mergeLexicalEnvironment(statements: Statement[], declarations: ReadonlyArray<Statement>): Statement[];
export function mergeLexicalEnvironment(statements: Statement[] | NodeArray<Statement>, declarations: ReadonlyArray<Statement>) {
if (!some(declarations)) {
return statements;
}
@@ -1442,7 +1442,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
export function liftToBlock(nodes: Node[]): Statement {
export function liftToBlock(nodes: ReadonlyArray<Node>): Statement {
Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block.");
return <Statement>singleOrUndefined(nodes) || createBlock(<NodeArray<Statement>>nodes);
}
+49 -28
View File
@@ -130,7 +130,7 @@ namespace FourSlash {
// 0 - cancelled
// >0 - not cancelled
// <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled
private static NotCanceled: number = -1;
private static readonly NotCanceled: number = -1;
private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled;
public isCancellationRequested(): boolean {
@@ -219,7 +219,7 @@ namespace FourSlash {
// Add input file which has matched file name with the given reference-file path.
// This is necessary when resolveReference flag is specified
private addMatchedInputFile(referenceFilePath: string, extensions: string[]) {
private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray<string>) {
const inputFiles = this.inputFiles;
const languageServiceAdapterHost = this.languageServiceAdapterHost;
if (!extensions) {
@@ -605,7 +605,7 @@ namespace FourSlash {
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
}
else if (ts.isArray(arg0)) {
const pairs: [string | string[], string | string[]][] = arg0;
const pairs: ReadonlyArray<[string | string[], string | string[]]> = arg0;
for (const [start, end] of pairs) {
this.verifyGoToXPlain(start, end, getDefs);
}
@@ -949,6 +949,22 @@ namespace FourSlash {
this.verifySymbol(symbol, declarationRanges);
}
public symbolsInScope(range: Range): ts.Symbol[] {
const node = this.goToAndGetNode(range);
return this.getChecker().getSymbolsInScope(node, ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace);
}
public verifyTypeOfSymbolAtLocation(range: Range, symbol: ts.Symbol, expected: string): void {
const node = this.goToAndGetNode(range);
const checker = this.getChecker();
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
const actual = checker.typeToString(type);
if (actual !== expected) {
this.raiseError(`Expected: '${expected}', actual: '${actual}'`);
}
}
private verifyReferencesAre(expectedReferences: Range[]) {
const actualReferences = this.getReferencesAtCaret() || [];
@@ -1790,7 +1806,14 @@ namespace FourSlash {
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
const editDelta = edit.newText.length - edit.span.length;
if (offsetStart <= this.currentCaretPosition) {
this.currentCaretPosition += editDelta;
if (offsetEnd <= this.currentCaretPosition) {
// The entirety of the edit span falls before the caret position, shift the caret accordingly
this.currentCaretPosition += editDelta;
}
else {
// The span being replaced includes the caret position, place the caret at the beginning of the span
this.currentCaretPosition = offsetStart;
}
}
runningOffset += editDelta;
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
@@ -2320,35 +2343,25 @@ namespace FourSlash {
* @param fileName Path to file where error should be retrieved from.
*/
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => {
return {
start: diagnostic.start,
length: diagnostic.length,
code: diagnostic.code
};
});
const dedupedDiagnositcs = ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties);
let actions: ts.CodeAction[] = undefined;
for (const diagnostic of dedupedDiagnositcs) {
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => ({
start: diagnostic.start,
length: diagnostic.length,
code: diagnostic.code
}));
return ts.flatMap(ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties), diagnostic => {
if (errorCode && errorCode !== diagnostic.code) {
continue;
return;
}
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code], this.formatCodeSettings);
if (newActions && newActions.length) {
actions = actions ? actions.concat(newActions) : newActions;
}
}
return actions;
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code], this.formatCodeSettings);
});
}
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.`);
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" }`);
}
index = 0;
}
@@ -2373,7 +2386,7 @@ namespace FourSlash {
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
if (!codeFixes || codeFixes.length === 0) {
if (codeFixes.length === 0) {
if (expectedTextArray.length !== 0) {
this.raiseError("No codefixes returned.");
}
@@ -2392,7 +2405,7 @@ namespace FourSlash {
const sortedActualArray = actualTextArray.sort();
if (!ts.arrayIsEqualTo(sortedExpectedArray, sortedActualArray)) {
this.raiseError(
`Actual text array doesn't match expected text array. \nActual: \n"${sortedActualArray.join("\n\n")}"\n---\nExpected: \n'${sortedExpectedArray.join("\n\n")}'`);
`Actual text array doesn't match expected text array. \nActual: \n'${sortedActualArray.join("\n\n")}'\n---\nExpected: \n'${sortedExpectedArray.join("\n\n")}'`);
}
}
@@ -2702,11 +2715,11 @@ namespace FourSlash {
public verifyCodeFixAvailable(negative: boolean) {
const codeFix = this.getCodeFixActions(this.activeFile.fileName);
if (negative && codeFix) {
if (negative && codeFix.length) {
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
}
if (!(negative || codeFix)) {
if (!(negative || codeFix.length)) {
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
}
}
@@ -3426,6 +3439,10 @@ namespace FourSlashInterface {
public markerByName(s: string): FourSlash.Marker {
return this.state.getMarkerByName(s);
}
public symbolsInScope(range: FourSlash.Range): ts.Symbol[] {
return this.state.symbolsInScope(range);
}
}
export class GoTo {
@@ -3694,6 +3711,10 @@ namespace FourSlashInterface {
this.state.verifySymbolAtLocation(startRange, declarationRanges);
}
public typeOfSymbolAtLocation(range: FourSlash.Range, symbol: ts.Symbol, expected: string) {
this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected);
}
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
this.state.verifyReferencesOf(start, references);
}
+4 -4
View File
@@ -479,7 +479,7 @@ namespace Harness {
getCurrentDirectory(): string;
useCaseSensitiveFileNames(): boolean;
resolvePath(path: string): string;
readFile(path: string): string;
readFile(path: string): string | undefined;
writeFile(path: string, contents: string): void;
directoryName(path: string): string;
getDirectories(path: string): string[];
@@ -493,7 +493,7 @@ namespace Harness {
args(): string[];
getExecutingFilePath(): string;
exit(exitCode?: number): void;
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[], depth?: number): string[];
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
tryEnableSourceMapsForHost?(): void;
getEnvironmentVariable?(name: string): string;
}
@@ -719,7 +719,7 @@ namespace Harness {
}
});
export function readFile(file: string) {
export function readFile(file: string): string | undefined {
const response = Http.getFileFromServerSync(serverRoot + file);
if (response.status === 200) {
return response.responseText;
@@ -976,7 +976,7 @@ namespace Harness {
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => newLine,
fileExists: fileName => fileMap.has(toPath(fileName)),
readFile: (fileName: string): string => {
readFile(fileName: string): string | undefined {
const file = fileMap.get(toPath(fileName));
if (ts.endsWith(fileName, "json")) {
// strip comments
+4 -4
View File
@@ -108,7 +108,7 @@ namespace Harness.LanguageService {
}
class DefaultHostCancellationToken implements ts.HostCancellationToken {
public static Instance = new DefaultHostCancellationToken();
public static readonly Instance = new DefaultHostCancellationToken();
public isCancellationRequested() {
return false;
@@ -208,14 +208,14 @@ namespace Harness.LanguageService {
const script = this.getScriptSnapshot(fileName);
return script !== undefined;
}
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
return ts.matchFiles(path, extensions, exclude, include,
/*useCaseSensitiveFileNames*/ false,
this.getCurrentDirectory(),
depth,
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
}
readFile(path: string): string {
readFile(path: string): string | undefined {
const snapshot = this.getScriptSnapshot(path);
return snapshot.getText(0, snapshot.getLength());
}
@@ -619,7 +619,7 @@ namespace Harness.LanguageService {
this.writeMessage(message);
}
readFile(fileName: string): string {
readFile(fileName: string): string | undefined {
if (fileName.indexOf(Harness.Compiler.defaultLibFileName) >= 0) {
fileName = Harness.Compiler.defaultLibFileName;
}
+4 -4
View File
@@ -64,11 +64,11 @@ interface IOLog {
}[];
directoriesRead: {
path: string,
extensions: string[],
exclude: string[],
include: string[],
extensions: ReadonlyArray<string>,
exclude: ReadonlyArray<string>,
include: ReadonlyArray<string>,
depth: number,
result: string[]
result: ReadonlyArray<string>,
}[];
}
+1 -1
View File
@@ -289,7 +289,7 @@ class ProjectRunner extends RunnerBase {
return Harness.IO.fileExists(getFileNameInTheProjectTest(fileName));
}
function readFile(fileName: string): string {
function readFile(fileName: string): string | undefined {
return Harness.IO.readFile(getFileNameInTheProjectTest(fileName));
}
+3 -4
View File
@@ -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));
@@ -238,10 +239,8 @@ namespace RWC {
}
class RWCRunner extends RunnerBase {
private static sourcePath = "internal/cases/rwc/";
public enumerateTestFiles() {
return Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
return Harness.IO.listFiles("internal/cases/rwc/", /.+\.json$/);
}
public kind(): TestRunnerKind {
+6 -6
View File
@@ -4,19 +4,19 @@
/* tslint:disable:no-null-keyword */
class Test262BaselineRunner extends RunnerBase {
private static basePath = "internal/cases/test262";
private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
private static helperFile: Harness.Compiler.TestFile = {
private static readonly basePath = "internal/cases/test262";
private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
private static readonly helperFile: Harness.Compiler.TestFile = {
unitName: Test262BaselineRunner.helpersFilePath,
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath),
};
private static testFileExtensionRegex = /\.js$/;
private static options: ts.CompilerOptions = {
private static readonly testFileExtensionRegex = /\.js$/;
private static readonly options: ts.CompilerOptions = {
allowNonTsExtensions: true,
target: ts.ScriptTarget.Latest,
module: ts.ModuleKind.CommonJS
};
private static baselineOptions: Harness.Baseline.BaselineOptions = {
private static readonly baselineOptions: Harness.Baseline.BaselineOptions = {
Subfolder: "test262",
Baselinefolder: "internal/baselines"
};
-5
View File
@@ -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",
+9 -11
View File
@@ -44,8 +44,8 @@ namespace ts {
parsesCorrectly("functionType1", "{function()}");
parsesCorrectly("functionType2", "{function(string, boolean)}");
parsesCorrectly("functionReturnType1", "{function(string, boolean)}");
parsesCorrectly("thisType1", "{this:a.b}");
parsesCorrectly("newType1", "{new:a.b}");
parsesCorrectly("thisType1", "{function(this:a.b)}");
parsesCorrectly("newType1", "{function(new:a.b)}");
parsesCorrectly("variadicType", "{...number}");
parsesCorrectly("optionalType", "{number=}");
parsesCorrectly("optionalNullable", "{?=}");
@@ -54,7 +54,7 @@ namespace ts {
parsesCorrectly("typeReference3", "{a.function}");
parsesCorrectly("arrayType1", "{a[]}");
parsesCorrectly("arrayType2", "{a[][]}");
parsesCorrectly("arrayType3", "{a[][]=}");
parsesCorrectly("arrayType3", "{(a[][])=}");
parsesCorrectly("keyword1", "{var}");
parsesCorrectly("keyword2", "{null}");
parsesCorrectly("keyword3", "{undefined}");
@@ -62,6 +62,12 @@ namespace ts {
parsesCorrectly("tupleType1", "{[number]}");
parsesCorrectly("tupleType2", "{[number,string]}");
parsesCorrectly("tupleType3", "{[number,string,boolean]}");
parsesCorrectly("tupleTypeWithTrailingComma", "{[number,]}");
parsesCorrectly("typeOfType", "{typeof M}");
parsesCorrectly("tsConstructorType", "{new () => string}");
parsesCorrectly("tsFunctionType", "{() => string}");
parsesCorrectly("typeArgumentsNotFollowingDot", "{a<>}");
parsesCorrectly("functionTypeWithTrailingComma", "{function(a,)}");
});
describe("parsesIncorrectly", () => {
@@ -69,21 +75,13 @@ namespace ts {
parsesIncorrectly("unionTypeWithTrailingBar", "{(a|)}");
parsesIncorrectly("unionTypeWithoutTypes", "{()}");
parsesIncorrectly("nullableTypeWithoutType", "{!}");
parsesIncorrectly("functionTypeWithTrailingComma", "{function(a,)}");
parsesIncorrectly("thisWithoutType", "{this:}");
parsesIncorrectly("newWithoutType", "{new:}");
parsesIncorrectly("variadicWithoutType", "{...}");
parsesIncorrectly("optionalWithoutType", "{=}");
parsesIncorrectly("allWithType", "{*foo}");
parsesIncorrectly("typeArgumentsNotFollowingDot", "{a<>}");
parsesIncorrectly("emptyTypeArguments", "{a.<>}");
parsesIncorrectly("typeArgumentsWithTrailingComma", "{a.<a,>}");
parsesIncorrectly("tsFunctionType", "{() => string}");
parsesIncorrectly("tsConstructoType", "{new () => string}");
parsesIncorrectly("typeOfType", "{typeof M}");
parsesIncorrectly("namedParameter", "{function(a: number)}");
parsesIncorrectly("tupleTypeWithComma", "{[,]}");
parsesIncorrectly("tupleTypeWithTrailingComma", "{[number,]}");
parsesIncorrectly("tupleTypeWithLeadingComma", "{[,number]}");
});
});
+1 -1
View File
@@ -56,7 +56,7 @@ namespace ts {
else {
return { readFile, fileExists: path => map.has(path) };
}
function readFile(path: string): string {
function readFile(path: string): string | undefined {
const file = map.get(path);
return file && file.content;
}
+1 -1
View File
@@ -9,7 +9,7 @@ namespace ts.server {
newLine: "\n",
useCaseSensitiveFileNames: true,
write(s): void { lastWrittenToHost = s; },
readFile(): string { return void 0; },
readFile: () => undefined,
writeFile: noop,
resolvePath(): string { return void 0; },
fileExists: () => false,
+4 -4
View File
@@ -11,7 +11,7 @@ namespace ts {
return find(n);
function find(node: Node): Node {
if (isDeclaration(node) && node.name && isIdentifier(node.name) && node.name.text === name) {
if (isDeclaration(node) && node.name && isIdentifier(node.name) && node.name.escapedText === name) {
return node;
}
else {
@@ -67,12 +67,12 @@ namespace ts {
}
function flattenNodes(n: Node) {
const data: (Node | NodeArray<any>)[] = [];
const data: (Node | NodeArray<Node>)[] = [];
walk(n);
return data;
function walk(n: Node | Node[]): void {
data.push(<any>n);
function walk(n: Node | NodeArray<Node>): void {
data.push(n);
return isArray(n) ? forEach(n, walk) : forEachChild(n, walk, walk);
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ namespace ts {
context.enableSubstitution(SyntaxKind.Identifier);
context.onSubstituteNode = (hint, node) => {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression && node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "undefined") {
if (hint === EmitHint.Expression && isIdentifier(node) && node.escapedText === "undefined") {
node = createPartiallyEmittedExpression(
addSyntheticTrailingComment(
setTextRange(
@@ -26,7 +26,7 @@ namespace ts {
context.enableSubstitution(SyntaxKind.Identifier);
context.onSubstituteNode = (hint, node) => {
node = previousOnSubstituteNode(hint, node);
if (node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "oldName") {
if (isIdentifier(node) && node.escapedText === "oldName") {
node = setTextRange(createIdentifier("newName"), node);
}
return node;
+51 -9
View File
@@ -438,24 +438,22 @@ namespace ts.projectSystem {
}
}
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, (dir) => {
const result: FileSystemEntries = {
directories: [],
files: []
};
const directories: string[] = [];
const files: string[] = [];
const dirEntry = this.fs.get(this.toPath(dir));
if (isFolder(dirEntry)) {
dirEntry.entries.forEach((entry) => {
if (isFolder(entry)) {
result.directories.push(entry.fullPath);
directories.push(entry.fullPath);
}
else if (isFile(entry)) {
result.files.push(entry.fullPath);
files.push(entry.fullPath);
}
});
}
return result;
return { directories, files };
});
}
@@ -563,7 +561,7 @@ namespace ts.projectSystem {
}
clearOutput() {
this.output.length = 0;
clear(this.output);
}
readonly readFile = (s: string) => (<File>this.fs.get(this.toPath(s))).content;
@@ -2334,6 +2332,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", () => {
+43 -5
View File
@@ -44,6 +44,18 @@ namespace ts.projectSystem {
});
}
function trackingLogger(): { log(message: string): void, finish(): string[] } {
const logs: string[] = [];
return {
log(message) {
logs.push(message);
},
finish() {
return logs;
}
};
}
import typingsName = TI.typingsName;
describe("local module", () => {
@@ -1015,6 +1027,8 @@ namespace ts.projectSystem {
});
describe("discover typings", () => {
const emptySafeList = emptyMap;
it("should use mappings from safe list", () => {
const app = {
path: "/a/b/app.js",
@@ -1028,10 +1042,17 @@ namespace ts.projectSystem {
path: "/a/b/chroma.min.js",
content: ""
};
const cache = createMap<string>();
const safeList = createMapFromTemplate({ jquery: "jquery", chroma: "chroma-js" });
const host = createServerHost([app, jquery, chroma]);
const result = JsTyping.discoverTypings(host, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, []);
const logger = trackingLogger();
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"]);
});
@@ -1044,7 +1065,12 @@ namespace ts.projectSystem {
const cache = createMap<string>();
for (const name of JsTyping.nodeCoreModuleList) {
const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, [name, "somename"]);
const logger = trackingLogger();
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, [name, "somename"]);
assert.deepEqual(logger.finish(), [
'Inferred typings from unresolved imports: ["node","somename"]',
'Result: {"cachedTypingPaths":[],"newTypingNames":["node","somename"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
]);
assert.deepEqual(result.newTypingNames.sort(), ["node", "somename"]);
}
});
@@ -1060,7 +1086,12 @@ namespace ts.projectSystem {
};
const host = createServerHost([f, node]);
const cache = createMapFromTemplate<string>({ "node": node.path });
const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, ["fs", "bar"]);
const logger = trackingLogger();
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"]);
assert.deepEqual(logger.finish(), [
'Inferred typings from unresolved imports: ["node","bar"]',
'Result: {"cachedTypingPaths":["/a/b/node.d.ts"],"newTypingNames":["bar"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
]);
assert.deepEqual(result.cachedTypingPaths, [node.path]);
assert.deepEqual(result.newTypingNames, ["bar"]);
});
@@ -1080,7 +1111,14 @@ namespace ts.projectSystem {
};
const host = createServerHost([app, a, b]);
const cache = createMap<string>();
const result = JsTyping.discoverTypings(host, [app.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, /*unresolvedImports*/ []);
const logger = trackingLogger();
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, {
cachedTypingPaths: [],
newTypingNames: ["a"], // But not "b"
+4 -8
View File
@@ -7,8 +7,7 @@ namespace ts {
}
function lineColToPosition(lineIndex: server.LineIndex, line: number, col: number) {
const lineInfo = lineIndex.lineNumberToInfo(line);
return (lineInfo.offset + col - 1);
return lineIndex.absolutePositionOfStartOfLine(line) + (col - 1);
}
function validateEdit(lineIndex: server.LineIndex, sourceText: string, position: number, deleteLength: number, insertString: string): void {
@@ -298,20 +297,17 @@ and grew 1cm per day`;
it("Line/offset from pos", () => {
for (let i = 0; i < iterationCount; i++) {
const lp = lineIndex.charOffsetToLineNumberAndPos(rsa[i]);
const lp = lineIndex.positionToLineOffset(rsa[i]);
const lac = ts.computeLineAndCharacterOfPosition(lineMap, rsa[i]);
assert.equal(lac.line + 1, lp.line, "Line number mismatch " + (lac.line + 1) + " " + lp.line + " " + i);
assert.equal(lac.character, (lp.offset), "Charachter offset mismatch " + lac.character + " " + lp.offset + " " + i);
assert.equal(lac.character, lp.offset - 1, "Character offset mismatch " + lac.character + " " + (lp.offset - 1) + " " + i);
}
});
it("Start pos from line", () => {
for (let i = 0; i < iterationCount; i++) {
for (let j = 0; j < lines.length; j++) {
const lineInfo = lineIndex.lineNumberToInfo(j + 1);
const lineIndexOffset = lineInfo.offset;
const lineMapOffset = lineMap[j];
assert.equal(lineIndexOffset, lineMapOffset);
assert.equal(lineIndex.absolutePositionOfStartOfLine(j + 1), lineMap[j]);
}
}
});
+2 -2
View File
@@ -209,14 +209,14 @@ namespace Utils {
}
}
readFile(path: string): string {
readFile(path: string): string | undefined {
const value = this.traversePath(path);
if (value && value.isFile()) {
return value.content.content;
}
}
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number) {
readDirectory(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, depth: number) {
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, depth, (path: string) => this.getAccessibleFileSystemEntries(path));
}
}
+15 -72
View File
@@ -203,57 +203,27 @@ namespace ts.server {
}
class ModuleBuilderFileInfo extends BuilderFileInfo {
references: ModuleBuilderFileInfo[] = [];
referencedBy: ModuleBuilderFileInfo[] = [];
references = createSortedArray<ModuleBuilderFileInfo>();
readonly referencedBy = createSortedArray<ModuleBuilderFileInfo>();
scriptVersionForReferences: string;
static compareFileInfos(lf: ModuleBuilderFileInfo, rf: ModuleBuilderFileInfo): number {
const l = lf.scriptInfo.fileName;
const r = rf.scriptInfo.fileName;
return (l < r ? -1 : (l > r ? 1 : 0));
}
static addToReferenceList(array: ModuleBuilderFileInfo[], fileInfo: ModuleBuilderFileInfo) {
if (array.length === 0) {
array.push(fileInfo);
return;
}
const insertIndex = binarySearch(array, fileInfo, ModuleBuilderFileInfo.compareFileInfos);
if (insertIndex < 0) {
array.splice(~insertIndex, 0, fileInfo);
}
}
static removeFromReferenceList(array: ModuleBuilderFileInfo[], fileInfo: ModuleBuilderFileInfo) {
if (!array || array.length === 0) {
return;
}
if (array[0] === fileInfo) {
array.splice(0, 1);
return;
}
const removeIndex = binarySearch(array, fileInfo, ModuleBuilderFileInfo.compareFileInfos);
if (removeIndex >= 0) {
array.splice(removeIndex, 1);
}
static compareFileInfos(lf: ModuleBuilderFileInfo, rf: ModuleBuilderFileInfo): Comparison {
return compareStrings(lf.scriptInfo.fileName, rf.scriptInfo.fileName);
}
addReferencedBy(fileInfo: ModuleBuilderFileInfo): void {
ModuleBuilderFileInfo.addToReferenceList(this.referencedBy, fileInfo);
insertSorted(this.referencedBy, fileInfo, ModuleBuilderFileInfo.compareFileInfos);
}
removeReferencedBy(fileInfo: ModuleBuilderFileInfo): void {
ModuleBuilderFileInfo.removeFromReferenceList(this.referencedBy, fileInfo);
removeSorted(this.referencedBy, fileInfo, ModuleBuilderFileInfo.compareFileInfos);
}
removeFileReferences() {
for (const reference of this.references) {
reference.removeReferencedBy(this);
}
this.references = [];
clear(this.references);
}
}
@@ -270,16 +240,13 @@ namespace ts.server {
super.clear();
}
private getReferencedFileInfos(fileInfo: ModuleBuilderFileInfo): ModuleBuilderFileInfo[] {
private getReferencedFileInfos(fileInfo: ModuleBuilderFileInfo): SortedArray<ModuleBuilderFileInfo> {
if (!fileInfo.isExternalModuleOrHasOnlyAmbientExternalModules()) {
return [];
return createSortedArray();
}
const referencedFilePaths = this.project.getReferencedFiles(fileInfo.scriptInfo.path);
if (referencedFilePaths.length > 0) {
return map(referencedFilePaths, f => this.getOrCreateFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos);
}
return [];
return toSortedArray(referencedFilePaths.map(f => this.getOrCreateFileInfo(f)), ModuleBuilderFileInfo.compareFileInfos);
}
protected ensureFileInfoIfInProject(_scriptInfo: ScriptInfo) {
@@ -319,39 +286,15 @@ namespace ts.server {
const newReferences = this.getReferencedFileInfos(fileInfo);
const oldReferences = fileInfo.references;
let oldIndex = 0;
let newIndex = 0;
while (oldIndex < oldReferences.length && newIndex < newReferences.length) {
const oldReference = oldReferences[oldIndex];
const newReference = newReferences[newIndex];
const compare = ModuleBuilderFileInfo.compareFileInfos(oldReference, newReference);
if (compare < 0) {
enumerateInsertsAndDeletes(newReferences, oldReferences,
/*inserted*/ newReference => newReference.addReferencedBy(fileInfo),
/*deleted*/ oldReference => {
// New reference is greater then current reference. That means
// the current reference doesn't exist anymore after parsing. So delete
// references.
oldReference.removeReferencedBy(fileInfo);
oldIndex++;
}
else if (compare > 0) {
// A new reference info. Add it.
newReference.addReferencedBy(fileInfo);
newIndex++;
}
else {
// Equal. Go to next
oldIndex++;
newIndex++;
}
}
// Clean old references
for (let i = oldIndex; i < oldReferences.length; i++) {
oldReferences[i].removeReferencedBy(fileInfo);
}
// Update new references
for (let i = newIndex; i < newReferences.length; i++) {
newReferences[i].addReferencedBy(fileInfo);
}
},
/*compare*/ ModuleBuilderFileInfo.compareFileInfos);
fileInfo.references = newReferences;
fileInfo.scriptVersionForReferences = fileInfo.scriptInfo.getLatestVersion();
+1 -1
View File
@@ -227,7 +227,7 @@ namespace ts.server {
}));
}
getFormattingEditsForRange(file: string, start: number, end: number, _options: ts.FormatCodeOptions): ts.TextChange[] {
getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): ts.TextChange[] {
const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset(file, start, end);
+17 -20
View File
@@ -45,7 +45,7 @@ namespace ts.server {
* Any compiler options that might contain paths will be taken out.
* Enum compiler options will be converted to strings.
*/
readonly compilerOptions: ts.CompilerOptions;
readonly compilerOptions: CompilerOptions;
// "extends", "files", "include", or "exclude" will be undefined if an external config is used.
// Otherwise, we will use "true" if the property is present and "false" if it is missing.
readonly extends: boolean | undefined;
@@ -201,7 +201,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) {
const result = projects.reduce<T[]>((previous, current) => concatenate(previous, action(current)), []).sort(comparer);
const result = flatMap(projects, action).sort(comparer);
return projects.length > 1 ? deduplicate(result, areEqual) : result;
}
@@ -239,10 +239,7 @@ namespace ts.server {
const fileNamePropertyReader: FilePropertyReader<string> = {
getFileName: x => x,
getScriptKind: _ => undefined,
hasMixedContent: (fileName, extraFileExtensions) => {
const mixedContentExtensions = ts.map(ts.filter(extraFileExtensions, item => item.isMixedContent), item => item.extension);
return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension));
}
hasMixedContent: (fileName, extraFileExtensions) => some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)),
};
const externalFilePropertyReader: FilePropertyReader<protocol.ExternalFile> = {
@@ -373,7 +370,7 @@ namespace ts.server {
private readonly throttledOperations: ThrottledOperations;
private readonly hostConfiguration: HostConfiguration;
private static safelist: SafeList = defaultTypeSafeList;
private safelist: SafeList = defaultTypeSafeList;
private changedFiles: ScriptInfo[];
@@ -633,7 +630,7 @@ namespace ts.server {
// If a change was made inside "folder/file", node will trigger the callback twice:
// one with the fileName being "folder/file", and the other one with "folder".
// We don't respond to the second one.
if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) {
if (fileName && !isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) {
return;
}
@@ -703,15 +700,15 @@ namespace ts.server {
switch (project.projectKind) {
case ProjectKind.External:
removeItemFromSet(this.externalProjects, <ExternalProject>project);
unorderedRemoveItem(this.externalProjects, <ExternalProject>project);
this.projectToSizeMap.delete((project as ExternalProject).externalProjectName);
break;
case ProjectKind.Configured:
removeItemFromSet(this.configuredProjects, <ConfiguredProject>project);
unorderedRemoveItem(this.configuredProjects, <ConfiguredProject>project);
this.projectToSizeMap.delete((project as ConfiguredProject).canonicalConfigFilePath);
break;
case ProjectKind.Inferred:
removeItemFromSet(this.inferredProjects, <InferredProject>project);
unorderedRemoveItem(this.inferredProjects, <InferredProject>project);
break;
}
}
@@ -790,7 +787,7 @@ namespace ts.server {
// to the disk, and the server's version of the file can be out of sync.
info.close();
removeItemFromSet(this.openFiles, info);
unorderedRemoveItem(this.openFiles, info);
// collect all projects that should be removed
let projectsToRemove: Project[];
@@ -940,7 +937,7 @@ namespace ts.server {
this.logger.info("Open files: ");
for (const rootFile of this.openFiles) {
this.logger.info(rootFile.fileName);
this.logger.info(`\t${rootFile.fileName}`);
}
this.logger.endGroup();
@@ -1082,7 +1079,7 @@ namespace ts.server {
configFileName: configFileName(),
projectType: project instanceof server.ExternalProject ? "external" : "configured",
languageServiceEnabled: project.languageServiceEnabled,
version: ts.version,
version,
};
this.eventHandler({ eventName: ProjectInfoTelemetryEvent, data });
@@ -1092,7 +1089,7 @@ namespace ts.server {
}
const configFilePath = project instanceof server.ConfiguredProject && project.getConfigFilePath();
const base = ts.getBaseFileName(configFilePath);
const base = getBaseFileName(configFilePath);
return base === "tsconfig.json" || base === "jsconfig.json" ? base : "other";
}
@@ -1617,13 +1614,13 @@ namespace ts.server {
}
/** Makes a filename safe to insert in a RegExp */
private static filenameEscapeRegexp = /[-\/\\^$*+?.()|[\]{}]/g;
private static readonly filenameEscapeRegexp = /[-\/\\^$*+?.()|[\]{}]/g;
private static escapeFilenameForRegex(filename: string) {
return filename.replace(this.filenameEscapeRegexp, "\\$&");
}
resetSafeList(): void {
ProjectService.safelist = defaultTypeSafeList;
this.safelist = defaultTypeSafeList;
}
loadSafeList(fileName: string): void {
@@ -1633,7 +1630,7 @@ namespace ts.server {
raw[k].match = new RegExp(raw[k].match as {} as string, "i");
}
// raw is now fixed and ready
ProjectService.safelist = raw;
this.safelist = raw;
}
applySafeList(proj: protocol.ExternalProject): void {
@@ -1644,8 +1641,8 @@ namespace ts.server {
const normalizedNames = rootFiles.map(f => normalizeSlashes(f.fileName));
for (const name of Object.keys(ProjectService.safelist)) {
const rule = ProjectService.safelist[name];
for (const name of Object.keys(this.safelist)) {
const rule = this.safelist[name];
for (const root of normalizedNames) {
if (rule.match.test(root)) {
this.logger.info(`Excluding files based on rule ${name}`);
+9 -9
View File
@@ -3,8 +3,8 @@
/// <reference path="scriptInfo.ts" />
namespace ts.server {
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost {
private compilationSettings: ts.CompilerOptions;
export class LSHost implements LanguageServiceHost, ModuleResolutionHost {
private compilationSettings: CompilerOptions;
private readonly resolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
private readonly resolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
private readonly getCanonicalFileName: (fileName: string) => string;
@@ -17,7 +17,7 @@ namespace ts.server {
constructor(private readonly host: ServerHost, private project: Project, private readonly cancellationToken: HostCancellationToken) {
this.cancellationToken = new ThrottledCancellationToken(cancellationToken, project.projectService.throttleWaitMilliseconds);
this.getCanonicalFileName = ts.createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
this.getCanonicalFileName = createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
if (host.trace) {
this.trace = s => host.trace(s);
@@ -29,7 +29,7 @@ namespace ts.server {
: undefined;
const primaryResult = resolveModuleName(moduleName, containingFile, compilerOptions, host);
// return result immediately only if it is .ts, .tsx or .d.ts
if (moduleHasNonRelativeName(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension)) && globalCache !== undefined) {
if (!isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension)) && globalCache !== undefined) {
// otherwise try to load typings from @types
// create different collection of failed lookup locations for second pass
@@ -99,7 +99,7 @@ namespace ts.server {
}
}
ts.Debug.assert(resolution !== undefined);
Debug.assert(resolution !== undefined);
resolvedModules.push(getResult(resolution));
}
@@ -177,7 +177,7 @@ namespace ts.server {
return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilationSettings));
}
getScriptSnapshot(filename: string): ts.IScriptSnapshot {
getScriptSnapshot(filename: string): IScriptSnapshot {
const scriptInfo = this.project.getScriptInfoLSHost(filename);
if (scriptInfo) {
return scriptInfo.getSnapshot();
@@ -217,7 +217,7 @@ namespace ts.server {
return !this.project.isWatchedMissingFile(path) && this.host.fileExists(file);
}
readFile(fileName: string): string {
readFile(fileName: string): string | undefined {
return this.host.readFile(fileName);
}
@@ -225,7 +225,7 @@ namespace ts.server {
return this.host.directoryExists(path);
}
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
return this.host.readDirectory(path, extensions, exclude, include, depth);
}
@@ -238,7 +238,7 @@ namespace ts.server {
this.resolvedTypeReferenceDirectives.delete(info.path);
}
setCompilationSettings(opt: ts.CompilerOptions) {
setCompilationSettings(opt: CompilerOptions) {
if (changesAffectModuleResolution(this.compilationSettings, opt)) {
this.resolvedModuleNames.clear();
this.resolvedTypeReferenceDirectives.clear();
+22 -20
View File
@@ -105,7 +105,7 @@ namespace ts.server {
export abstract class Project {
private rootFiles: ScriptInfo[] = [];
private rootFilesMap: Map<ScriptInfo> = createMap<ScriptInfo>();
private program: ts.Program;
private program: Program;
private externalFiles: SortedReadonlyArray<string>;
private missingFilesMap: Map<FileWatcher> = createMap<FileWatcher>();
@@ -180,14 +180,14 @@ namespace ts.server {
private readonly projectName: string,
readonly projectKind: ProjectKind,
readonly projectService: ProjectService,
private documentRegistry: ts.DocumentRegistry,
private documentRegistry: DocumentRegistry,
hasExplicitListOfFiles: boolean,
languageServiceEnabled: boolean,
private compilerOptions: CompilerOptions,
public compileOnSaveEnabled: boolean) {
if (!this.compilerOptions) {
this.compilerOptions = ts.getDefaultCompilerOptions();
this.compilerOptions = getDefaultCompilerOptions();
this.compilerOptions.allowNonTsExtensions = true;
this.compilerOptions.allowJs = true;
}
@@ -201,7 +201,7 @@ namespace ts.server {
this.lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken);
this.lsHost.setCompilationSettings(this.compilerOptions);
this.languageService = ts.createLanguageService(this.lsHost, this.documentRegistry);
this.languageService = createLanguageService(this.lsHost, this.documentRegistry);
if (!languageServiceEnabled) {
this.disableLanguageService();
@@ -554,7 +554,7 @@ namespace ts.server {
for (const sourceFile of this.program.getSourceFiles()) {
this.extractUnresolvedImportsFromSourceFile(sourceFile, result);
}
this.lastCachedUnresolvedImportsList = toSortedReadonlyArray(result);
this.lastCachedUnresolvedImportsList = toSortedArray(result);
}
unresolvedImports = this.lastCachedUnresolvedImportsList;
@@ -690,7 +690,7 @@ namespace ts.server {
}
let strBuilder = "";
for (const file of this.program.getSourceFiles()) {
strBuilder += `${file.fileName}\n`;
strBuilder += `\t${file.fileName}\n`;
}
return strBuilder;
}
@@ -783,7 +783,7 @@ namespace ts.server {
// We need to use a set here since the code can contain the same import twice,
// but that will only be one dependency.
// To avoid invernal conversion, the key of the referencedFiles map must be of type Path
const referencedFiles = createMap<boolean>();
const referencedFiles = createMap<true>();
if (sourceFile.imports && sourceFile.imports.length > 0) {
const checker: TypeChecker = this.program.getTypeChecker();
for (const importName of sourceFile.imports) {
@@ -837,7 +837,7 @@ namespace ts.server {
*/
export class InferredProject extends Project {
private static newName = (() => {
private static readonly newName = (() => {
let nextId = 1;
return () => {
const id = nextId;
@@ -875,7 +875,7 @@ namespace ts.server {
// Used to keep track of what directories are watched for this project
directoriesWatchedForTsconfig: string[] = [];
constructor(projectService: ProjectService, documentRegistry: ts.DocumentRegistry, compilerOptions: CompilerOptions) {
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions) {
super(InferredProject.newName(),
ProjectKind.Inferred,
projectService,
@@ -936,9 +936,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[] = [];
@@ -948,7 +948,7 @@ namespace ts.server {
constructor(configFileName: NormalizedPath,
projectService: ProjectService,
documentRegistry: ts.DocumentRegistry,
documentRegistry: DocumentRegistry,
hasExplicitListOfFiles: boolean,
compilerOptions: CompilerOptions,
private wildcardDirectories: Map<WatchDirectoryFlags>,
@@ -1057,7 +1057,7 @@ namespace ts.server {
}
getExternalFiles(): SortedReadonlyArray<string> {
return toSortedReadonlyArray(flatMap(this.plugins, plugin => {
return toSortedArray(flatMap(this.plugins, plugin => {
if (typeof plugin.getExternalFiles !== "function") return;
try {
return plugin.getExternalFiles(this);
@@ -1134,10 +1134,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();
}
@@ -1152,7 +1154,7 @@ namespace ts.server {
}
getEffectiveTypeRoots() {
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
return getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
}
}
@@ -1164,7 +1166,7 @@ namespace ts.server {
private typeAcquisition: TypeAcquisition;
constructor(public externalProjectName: string,
projectService: ProjectService,
documentRegistry: ts.DocumentRegistry,
documentRegistry: DocumentRegistry,
compilerOptions: CompilerOptions,
languageServiceEnabled: boolean,
public compileOnSaveEnabled: boolean,
+1 -1
View File
@@ -640,7 +640,7 @@ namespace ts.server.protocol {
}
/**
* 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.
*/
export interface Location {
line: number;
+14 -33
View File
@@ -61,7 +61,7 @@ namespace ts.server {
: ScriptSnapshot.fromString(this.getOrLoadText());
}
public getLineInfo(line: number) {
public getLineInfo(line: number): AbsolutePositionAndLineText {
return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line);
}
/**
@@ -72,19 +72,12 @@ namespace ts.server {
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 ts.createTextSpanFromBounds(start, end);
return createTextSpanFromBounds(start, end);
}
const index = this.svc.getSnapshot().index;
const lineInfo = index.lineNumberToInfo(line + 1);
let len: number;
if (lineInfo.leaf) {
len = lineInfo.leaf.text.length;
}
else {
const nextLineInfo = index.lineNumberToInfo(line + 2);
len = nextLineInfo.offset - lineInfo.offset;
}
return ts.createTextSpan(lineInfo.offset, len);
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
return createTextSpan(absolutePosition, len);
}
/**
@@ -93,27 +86,19 @@ namespace ts.server {
*/
lineOffsetToPosition(line: number, offset: number): number {
if (!this.svc) {
return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1);
return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1, this.text);
}
const index = this.svc.getSnapshot().index;
const lineInfo = index.lineNumberToInfo(line);
// TODO: assert this offset is actually on the line
return (lineInfo.offset + offset - 1);
return this.svc.getSnapshot().index.absolutePositionOfStartOfLine(line) + (offset - 1);
}
/**
* @param line 1-based index
* @param offset 1-based index
*/
positionToLineOffset(position: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
if (!this.svc) {
const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position);
return { line: line + 1, offset: character + 1 };
}
const index = this.svc.getSnapshot().index;
const lineOffset = index.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
return this.svc.getSnapshot().index.positionToLineOffset(position);
}
private getFileText(tempFileName?: string) {
@@ -162,7 +147,7 @@ namespace ts.server {
* All projects that include this file
*/
readonly containingProjects: Project[] = [];
private formatCodeSettings: ts.FormatCodeSettings;
private formatCodeSettings: FormatCodeSettings;
readonly path: Path;
private fileWatcher: FileWatcher;
@@ -247,7 +232,7 @@ namespace ts.server {
}
break;
default:
removeItemFromSet(this.containingProjects, project);
unorderedRemoveItem(this.containingProjects, project);
break;
}
}
@@ -257,7 +242,7 @@ namespace ts.server {
// detach is unnecessary since we'll clean the list of containing projects anyways
p.removeFile(this, /*detachFromProjects*/ false);
}
this.containingProjects.length = 0;
clear(this.containingProjects);
}
getDefaultProject() {
@@ -334,7 +319,7 @@ namespace ts.server {
}
}
getLineInfo(line: number) {
getLineInfo(line: number): AbsolutePositionAndLineText {
return this.textStorage.getLineInfo(line);
}
@@ -364,11 +349,7 @@ namespace ts.server {
return this.textStorage.lineOffsetToPosition(line, offset);
}
/**
* @param line 1-based index
* @param offset 1-based index
*/
positionToLineOffset(position: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
return this.textStorage.positionToLineOffset(position);
}
+105 -126
View File
@@ -8,15 +8,13 @@ namespace ts.server {
export interface LineCollection {
charCount(): number;
lineCount(): number;
isLeaf(): boolean;
isLeaf(): this is LineLeaf;
walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker): void;
}
export interface ILineInfo {
line: number;
offset: number;
text?: string;
leaf?: LineLeaf;
export interface AbsolutePositionAndLineText {
absolutePosition: number;
lineText: string | undefined;
}
export enum CharRangeSection {
@@ -97,22 +95,20 @@ namespace ts.server {
}
// path at least length two (root and leaf)
let insertionNode = <LineNode>this.startPath[this.startPath.length - 2];
const leafNode = <LineLeaf>this.startPath[this.startPath.length - 1];
const len = lines.length;
if (len > 0) {
if (lines.length > 0) {
leafNode.text = lines[0];
if (len > 1) {
let insertedNodes = <LineCollection[]>new Array(len - 1);
if (lines.length > 1) {
let insertedNodes = <LineCollection[]>new Array(lines.length - 1);
let startNode = <LineCollection>leafNode;
for (let i = 1; i < lines.length; i++) {
insertedNodes[i - 1] = new LineLeaf(lines[i]);
}
let pathIndex = this.startPath.length - 2;
while (pathIndex >= 0) {
insertionNode = <LineNode>this.startPath[pathIndex];
const insertionNode = <LineNode>this.startPath[pathIndex];
insertedNodes = insertionNode.insertAt(startNode, insertedNodes);
pathIndex--;
startNode = insertionNode;
@@ -134,6 +130,7 @@ namespace ts.server {
}
}
else {
const insertionNode = <LineNode>this.startPath[this.startPath.length - 2];
// no content for leaf node, so delete it
insertionNode.remove(leafNode);
for (let j = this.startPath.length - 2; j >= 0; j--) {
@@ -251,7 +248,7 @@ namespace ts.server {
}
getTextChangeRange() {
return ts.createTextChangeRange(ts.createTextSpan(this.pos, this.deleteLen),
return createTextChangeRange(createTextSpan(this.pos, this.deleteLen),
this.insertedText ? this.insertedText.length : 0);
}
}
@@ -281,9 +278,9 @@ namespace ts.server {
// REVIEW: can optimize by coalescing simple edits
edit(pos: number, deleteLen: number, insertedText?: string) {
this.changes.push(new TextChange(pos, deleteLen, insertedText));
if ((this.changes.length > ScriptVersionCache.changeNumberThreshold) ||
(deleteLen > ScriptVersionCache.changeLengthThreshold) ||
(insertedText && (insertedText.length > ScriptVersionCache.changeLengthThreshold))) {
if (this.changes.length > ScriptVersionCache.changeNumberThreshold ||
deleteLen > ScriptVersionCache.changeLengthThreshold ||
insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold) {
this.getSnapshot();
}
}
@@ -340,21 +337,21 @@ namespace ts.server {
getTextChangesBetweenVersions(oldVersion: number, newVersion: number) {
if (oldVersion < newVersion) {
if (oldVersion >= this.minVersion) {
const textChangeRanges: ts.TextChangeRange[] = [];
const textChangeRanges: TextChangeRange[] = [];
for (let i = oldVersion + 1; i <= newVersion; i++) {
const snap = this.versions[this.versionToIndex(i)];
for (const textChange of snap.changesSincePreviousVersion) {
textChangeRanges.push(textChange.getTextChangeRange());
}
}
return ts.collapseTextChangeRangesAcrossMultipleVersions(textChangeRanges);
return collapseTextChangeRangesAcrossMultipleVersions(textChangeRanges);
}
else {
return undefined;
}
}
else {
return ts.unchangedTextChangeRange;
return unchangedTextChangeRange;
}
}
@@ -368,7 +365,7 @@ namespace ts.server {
}
}
export class LineIndexSnapshot implements ts.IScriptSnapshot {
export class LineIndexSnapshot implements IScriptSnapshot {
constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: ReadonlyArray<TextChange> = emptyArray) {
}
@@ -380,10 +377,10 @@ namespace ts.server {
return this.index.root.charCount();
}
getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange {
getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange {
if (oldSnapshot instanceof LineIndexSnapshot && this.cache === oldSnapshot.cache) {
if (this.version <= oldSnapshot.version) {
return ts.unchangedTextChangeRange;
return unchangedTextChangeRange;
}
else {
return this.cache.getTextChangesBetweenVersions(oldSnapshot.version, this.version);
@@ -397,22 +394,27 @@ namespace ts.server {
// set this to true to check each edit for accuracy
checkEdits = false;
charOffsetToLineNumberAndPos(charOffset: number) {
return this.root.charOffsetToLineNumberAndPos(1, charOffset);
absolutePositionOfStartOfLine(oneBasedLine: number): number {
return this.lineNumberToInfo(oneBasedLine).absolutePosition;
}
lineNumberToInfo(lineNumber: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
const { oneBasedLine, zeroBasedColumn } = this.root.charOffsetToLineInfo(1, position);
return { line: oneBasedLine, offset: zeroBasedColumn + 1 };
}
private positionToColumnAndLineText(position: number): { zeroBasedColumn: number, lineText: string } {
return this.root.charOffsetToLineInfo(1, position);
}
lineNumberToInfo(oneBasedLine: number): AbsolutePositionAndLineText {
const lineCount = this.root.lineCount();
if (lineNumber <= lineCount) {
const lineInfo = this.root.lineNumberToInfo(lineNumber, 0);
lineInfo.line = lineNumber;
return lineInfo;
if (oneBasedLine <= lineCount) {
const { position, leaf } = this.root.lineNumberToInfo(oneBasedLine, 0);
return { absolutePosition: position, lineText: leaf && leaf.text };
}
else {
return {
line: lineNumber,
offset: this.root.charCount()
};
return { absolutePosition: this.root.charCount(), lineText: undefined };
}
}
@@ -468,12 +470,9 @@ namespace ts.server {
return !walkFns.done;
}
edit(pos: number, deleteLength: number, newText?: string) {
function editFlat(source: string, s: number, dl: number, nt = "") {
return source.substring(0, s) + nt + source.substring(s + dl, source.length);
}
edit(pos: number, deleteLength: number, newText?: string): LineIndex {
if (this.root.charCount() === 0) {
// TODO: assert deleteLength === 0
Debug.assert(deleteLength === 0); // Can't delete from empty document
if (newText !== undefined) {
this.load(LineIndex.linesFromText(newText).lines);
return this;
@@ -482,7 +481,8 @@ namespace ts.server {
else {
let checkText: string;
if (this.checkEdits) {
checkText = editFlat(this.getText(0, this.root.charCount()), pos, deleteLength, newText);
const source = this.getText(0, this.root.charCount());
checkText = source.slice(0, pos) + newText + source.slice(pos + deleteLength);
}
const walker = new EditWalker();
let suppressTrailingText = false;
@@ -502,63 +502,44 @@ namespace ts.server {
else if (deleteLength > 0) {
// check whether last characters deleted are line break
const e = pos + deleteLength;
const lineInfo = this.charOffsetToLineNumberAndPos(e);
if ((lineInfo && (lineInfo.offset === 0))) {
const { zeroBasedColumn, lineText } = this.positionToColumnAndLineText(e);
if (zeroBasedColumn === 0) {
// move range end just past line that will merge with previous line
deleteLength += lineInfo.text.length;
deleteLength += lineText.length;
// store text by appending to end of insertedText
if (newText) {
newText = newText + lineInfo.text;
}
else {
newText = lineInfo.text;
}
newText = newText ? newText + lineText : lineText;
}
}
if (pos < this.root.charCount()) {
this.root.walk(pos, deleteLength, walker);
walker.insertLines(newText, suppressTrailingText);
}
this.root.walk(pos, deleteLength, walker);
walker.insertLines(newText, suppressTrailingText);
if (this.checkEdits) {
const updatedText = this.getText(0, this.root.charCount());
const updatedText = walker.lineIndex.getText(0, walker.lineIndex.getLength());
Debug.assert(checkText === updatedText, "buffer edit mismatch");
}
return walker.lineIndex;
}
}
static buildTreeFromBottom(nodes: LineCollection[]): LineNode {
const nodeCount = Math.ceil(nodes.length / lineCollectionCapacity);
const interiorNodes: LineNode[] = [];
private static buildTreeFromBottom(nodes: LineCollection[]): LineNode {
if (nodes.length < lineCollectionCapacity) {
return new LineNode(nodes);
}
const interiorNodes = new Array<LineNode>(Math.ceil(nodes.length / lineCollectionCapacity));
let nodeIndex = 0;
for (let i = 0; i < nodeCount; i++) {
interiorNodes[i] = new LineNode();
let charCount = 0;
let lineCount = 0;
for (let j = 0; j < lineCollectionCapacity; j++) {
if (nodeIndex < nodes.length) {
interiorNodes[i].add(nodes[nodeIndex]);
charCount += nodes[nodeIndex].charCount();
lineCount += nodes[nodeIndex].lineCount();
}
else {
break;
}
nodeIndex++;
}
interiorNodes[i].totalChars = charCount;
interiorNodes[i].totalLines = lineCount;
}
if (interiorNodes.length === 1) {
return interiorNodes[0];
}
else {
return this.buildTreeFromBottom(interiorNodes);
for (let i = 0; i < interiorNodes.length; i++) {
const end = Math.min(nodeIndex + lineCollectionCapacity, nodes.length);
interiorNodes[i] = new LineNode(nodes.slice(nodeIndex, end));
nodeIndex = end;
}
return this.buildTreeFromBottom(interiorNodes);
}
static linesFromText(text: string) {
const lineMap = ts.computeLineStarts(text);
const lineMap = computeLineStarts(text);
if (lineMap.length === 0) {
return { lines: <string[]>[], lineMap };
@@ -583,7 +564,10 @@ namespace ts.server {
export class LineNode implements LineCollection {
totalChars = 0;
totalLines = 0;
children: LineCollection[] = [];
constructor(private readonly children: LineCollection[] = []) {
if (children.length) this.updateCounts();
}
isLeaf() {
return false;
@@ -598,7 +582,7 @@ namespace ts.server {
}
}
execWalk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker, childIndex: number, nodeType: CharRangeSection) {
private execWalk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker, childIndex: number, nodeType: CharRangeSection) {
if (walkFns.pre) {
walkFns.pre(rangeStart, rangeLength, this.children[childIndex], this, nodeType);
}
@@ -614,7 +598,7 @@ namespace ts.server {
return walkFns.done;
}
skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: ILineIndexWalker, nodeType: CharRangeSection) {
private skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: ILineIndexWalker, nodeType: CharRangeSection) {
if (walkFns.pre && (!walkFns.done)) {
walkFns.pre(relativeStart, relativeLength, this.children[childIndex], this, nodeType);
walkFns.goSubtree = true;
@@ -624,16 +608,14 @@ namespace ts.server {
walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) {
// assume (rangeStart < this.totalChars) && (rangeLength <= this.totalChars)
let childIndex = 0;
let child = this.children[0];
let childCharCount = child.charCount();
let childCharCount = this.children[childIndex].charCount();
// find sub-tree containing start
let adjustedStart = rangeStart;
while (adjustedStart >= childCharCount) {
this.skipChild(adjustedStart, rangeLength, childIndex, walkFns, CharRangeSection.PreStart);
adjustedStart -= childCharCount;
childIndex++;
child = this.children[childIndex];
childCharCount = child.charCount();
childCharCount = this.children[childIndex].charCount();
}
// Case I: both start and end of range in same subtree
if ((adjustedStart + rangeLength) <= childCharCount) {
@@ -648,7 +630,7 @@ namespace ts.server {
}
let adjustedLength = rangeLength - (childCharCount - adjustedStart);
childIndex++;
child = this.children[childIndex];
const child = this.children[childIndex];
childCharCount = child.charCount();
while (adjustedLength > childCharCount) {
if (this.execWalk(0, childCharCount, walkFns, childIndex, CharRangeSection.Mid)) {
@@ -656,8 +638,7 @@ namespace ts.server {
}
adjustedLength -= childCharCount;
childIndex++;
child = this.children[childIndex];
childCharCount = child.charCount();
childCharCount = this.children[childIndex].charCount();
}
if (adjustedLength > 0) {
if (this.execWalk(0, adjustedLength, walkFns, childIndex, CharRangeSection.End)) {
@@ -676,90 +657,88 @@ namespace ts.server {
}
}
charOffsetToLineNumberAndPos(lineNumber: number, charOffset: number): ILineInfo {
const childInfo = this.childFromCharOffset(lineNumber, charOffset);
// 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 {
line: lineNumber,
offset: charOffset,
oneBasedLine: lineNumberAccumulator,
zeroBasedColumn: relativePosition,
lineText: undefined,
};
}
else if (childInfo.childIndex < this.children.length) {
if (childInfo.child.isLeaf()) {
return {
line: childInfo.lineNumber,
offset: childInfo.charOffset,
text: (<LineLeaf>(childInfo.child)).text,
leaf: (<LineLeaf>(childInfo.child))
oneBasedLine: childInfo.lineNumberAccumulator,
zeroBasedColumn: childInfo.relativePosition,
lineText: childInfo.child.text,
};
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.charOffsetToLineNumberAndPos(childInfo.lineNumber, childInfo.charOffset);
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
}
}
else {
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
return { line: this.lineCount(), offset: lineInfo.leaf.charCount() };
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
}
}
lineNumberToInfo(lineNumber: number, charOffset: number): ILineInfo {
const childInfo = this.childFromLineNumber(lineNumber, charOffset);
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
if (!childInfo.child) {
return {
line: lineNumber,
offset: charOffset
};
return { position: positionAccumulator, leaf: undefined };
}
else if (childInfo.child.isLeaf()) {
return {
line: lineNumber,
offset: childInfo.charOffset,
text: (<LineLeaf>(childInfo.child)).text,
leaf: (<LineLeaf>(childInfo.child))
};
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.lineNumberToInfo(childInfo.relativeLineNumber, childInfo.charOffset);
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
}
}
childFromLineNumber(lineNumber: number, charOffset: number) {
/**
* Input line number is relative to the start of this node.
* 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 relativeLineNumber = lineNumber;
let i: number;
let len: number;
for (i = 0, len = this.children.length; i < len; i++) {
for (i = 0; i < this.children.length; i++) {
child = this.children[i];
const childLineCount = child.lineCount();
if (childLineCount >= relativeLineNumber) {
if (childLineCount >= relativeOneBasedLine) {
break;
}
else {
relativeLineNumber -= childLineCount;
charOffset += child.charCount();
relativeOneBasedLine -= childLineCount;
positionAccumulator += child.charCount();
}
}
return { child, childIndex: i, relativeLineNumber, charOffset };
return { child, relativeOneBasedLine, positionAccumulator };
}
childFromCharOffset(lineNumber: number, charOffset: number) {
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() > charOffset) {
if (child.charCount() > relativePosition) {
break;
}
else {
charOffset -= child.charCount();
lineNumber += child.lineCount();
relativePosition -= child.charCount();
lineNumberAccumulator += child.lineCount();
}
}
return { child, childIndex: i, charOffset, lineNumber };
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
}
private splitAfter(childIndex: number) {
+22 -8
View File
@@ -138,7 +138,7 @@ namespace ts.server {
terminal: false,
});
class Logger implements ts.server.Logger {
class Logger implements server.Logger {
private fd = -1;
private seq = 0;
private inGroup = false;
@@ -200,7 +200,7 @@ namespace ts.server {
msg(s: string, type: Msg.Types = Msg.Err) {
if (this.fd >= 0 || this.traceToConsole) {
s = s + "\n";
s = `[${nowString()}] ${s}\n`;
const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " ");
if (this.firstInGroup) {
s = prefix + s;
@@ -222,6 +222,12 @@ namespace ts.server {
}
}
// E.g. "12:34:56.789"
function nowString() {
const d = new Date();
return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
}
class NodeTypingsInstaller implements ITypingsInstaller {
private installer: NodeChildProcess;
private installerPidReported = false;
@@ -526,12 +532,18 @@ namespace ts.server {
if (err) {
watchedFile.callback(watchedFile.fileName, FileWatcherEventKind.Changed);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = stats.mtime;
const eventKind = watchedFile.mtime.getTime() === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
watchedFile.callback(watchedFile.fileName, eventKind);
else {
const oldTime = watchedFile.mtime.getTime();
const newTime = stats.mtime.getTime();
if (oldTime !== newTime) {
watchedFile.mtime = stats.mtime;
const eventKind = oldTime === 0
? FileWatcherEventKind.Created
: newTime === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
watchedFile.callback(watchedFile.fileName, eventKind);
}
}
});
}
@@ -745,6 +757,8 @@ namespace ts.server {
validateLocaleAndSetLanguage(localeStr, sys);
}
setStackTraceLimit();
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation);
const npmLocation = findArgument(Arguments.NpmLocation);
+82 -100
View File
@@ -49,7 +49,7 @@ namespace ts.server {
interface FileStart {
file: string;
start: ILineInfo;
start: protocol.Location;
}
function compareNumber(a: number, b: number) {
@@ -72,28 +72,28 @@ namespace ts.server {
}
}
function formatDiag(fileName: NormalizedPath, project: Project, diag: ts.Diagnostic): protocol.Diagnostic {
function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic): protocol.Diagnostic {
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName);
return {
start: scriptInfo.positionToLineOffset(diag.start),
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n"),
text: flattenDiagnosticMessageText(diag.messageText, "\n"),
code: diag.code,
category: DiagnosticCategory[diag.category].toLowerCase(),
source: diag.source
};
}
function convertToILineInfo(lineAndCharacter: LineAndCharacter): ILineInfo {
function convertToLocation(lineAndCharacter: LineAndCharacter): protocol.Location {
return { line: lineAndCharacter.line + 1, offset: lineAndCharacter.character + 1 };
}
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: false): protocol.Diagnostic;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
const start = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start));
const end = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = ts.flattenDiagnosticMessageText(diag.messageText, "\n");
function formatConfigFileDiag(diag: Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
function formatConfigFileDiag(diag: Diagnostic, includeFileName: false): protocol.Diagnostic;
function formatConfigFileDiag(diag: Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
const start = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start));
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
@@ -162,19 +162,13 @@ namespace ts.server {
* Represents operation that can schedule its next step to be executed later.
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
*/
class MultistepOperation {
class MultistepOperation implements NextStep {
private requestId: number;
private timerHandle: any;
private immediateId: any;
private completed = true;
private readonly next: NextStep;
constructor(private readonly operationHost: MultistepOperationHost) {
this.next = {
immediate: action => this.immediate(action),
delay: (ms, action) => this.delay(ms, action)
};
}
constructor(private readonly operationHost: MultistepOperationHost) {}
public startNew(action: (next: NextStep) => void) {
this.complete();
@@ -194,7 +188,7 @@ namespace ts.server {
this.setImmediateId(undefined);
}
private immediate(action: () => void) {
public immediate(action: () => void) {
const requestId = this.requestId;
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id");
this.setImmediateId(this.operationHost.getServerHost().setImmediate(() => {
@@ -203,7 +197,7 @@ namespace ts.server {
}));
}
private delay(ms: number, action: () => void) {
public delay(ms: number, action: () => void) {
const requestId = this.requestId;
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id");
this.setTimerHandle(this.operationHost.getServerHost().setTimeout(() => {
@@ -219,7 +213,7 @@ namespace ts.server {
stop = true;
}
else {
action(this.next);
action(this);
}
}
catch (e) {
@@ -389,8 +383,8 @@ namespace ts.server {
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
}
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ts.Diagnostic[]) {
const bakedDiags = ts.map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: Diagnostic[]) {
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
const ev: protocol.ConfigFileDiagnosticEvent = {
seq: 0,
type: "event",
@@ -555,8 +549,8 @@ namespace ts.server {
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
code: d.code,
startLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start + d.length))
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
});
}
@@ -615,7 +609,7 @@ namespace ts.server {
return {
file: def.fileName,
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan))
};
});
}
@@ -639,7 +633,7 @@ namespace ts.server {
return {
file: def.fileName,
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan))
};
});
}
@@ -657,7 +651,7 @@ namespace ts.server {
return {
file: fileName,
start: scriptInfo.positionToLineOffset(textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan))
end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan))
};
});
}
@@ -681,7 +675,7 @@ namespace ts.server {
const { fileName, isWriteAccess, textSpan, isInString } = occurrence;
const scriptInfo = project.getScriptInfo(fileName);
const start = scriptInfo.positionToLineOffset(textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan));
const result: protocol.OccurrencesResponseItem = {
start,
end,
@@ -731,7 +725,7 @@ namespace ts.server {
return documentHighlights;
}
function convertToDocumentHighlightsItem(documentHighlights: ts.DocumentHighlights): ts.server.protocol.DocumentHighlightsItem {
function convertToDocumentHighlightsItem(documentHighlights: DocumentHighlights): protocol.DocumentHighlightsItem {
const { fileName, highlightSpans } = documentHighlights;
const scriptInfo = project.getScriptInfo(fileName);
@@ -740,10 +734,10 @@ namespace ts.server {
highlightSpans: highlightSpans.map(convertHighlightSpan)
};
function convertHighlightSpan(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan {
function convertHighlightSpan(highlightSpan: HighlightSpan): protocol.HighlightSpan {
const { textSpan, kind } = highlightSpan;
const start = scriptInfo.positionToLineOffset(textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan));
return { start, end, kind };
}
}
@@ -786,7 +780,7 @@ namespace ts.server {
const scriptInfo = this.projectService.getScriptInfo(args.file);
projects = scriptInfo.containingProjects;
}
// ts.filter handles case when 'projects' is undefined
// filter handles case when 'projects' is undefined
projects = filter(projects, p => p.languageServiceEnabled);
if (!projects || !projects.length) {
return Errors.ThrowNoProject();
@@ -839,28 +833,29 @@ namespace ts.server {
return <protocol.FileSpan>{
file: location.fileName,
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
end: locationScriptInfo.positionToLineOffset(ts.textSpanEnd(location.textSpan)),
end: locationScriptInfo.positionToLineOffset(textSpanEnd(location.textSpan)),
};
});
},
compareRenameLocation,
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
);
const locs = fileSpans.reduce<protocol.SpanGroup[]>((accum, cur) => {
const locs: protocol.SpanGroup[] = [];
for (const cur of fileSpans) {
let curFileAccum: protocol.SpanGroup;
if (accum.length > 0) {
curFileAccum = accum[accum.length - 1];
if (locs.length > 0) {
curFileAccum = locs[locs.length - 1];
if (curFileAccum.file !== cur.file) {
curFileAccum = undefined;
}
}
if (!curFileAccum) {
curFileAccum = { file: cur.file, locs: [] };
accum.push(curFileAccum);
locs.push(curFileAccum);
}
curFileAccum.locs.push({ start: cur.start, end: cur.end });
return accum;
}, []);
}
return { info: renameInfo, locs };
}
@@ -920,10 +915,10 @@ namespace ts.server {
return undefined;
}
const displayString = ts.displayPartsToString(nameInfo.displayParts);
const displayString = displayPartsToString(nameInfo.displayParts);
const nameSpan = nameInfo.textSpan;
const nameColStart = scriptInfo.positionToLineOffset(nameSpan.start).offset;
const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, ts.textSpanEnd(nameSpan));
const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan));
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
projects,
(project: Project) => {
@@ -936,12 +931,12 @@ namespace ts.server {
const refScriptInfo = project.getScriptInfo(ref.fileName);
const start = refScriptInfo.positionToLineOffset(ref.textSpan.start);
const refLineSpan = refScriptInfo.lineToTextSpan(start.line - 1);
const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
return {
file: ref.fileName,
start,
lineText,
end: refScriptInfo.positionToLineOffset(ts.textSpanEnd(ref.textSpan)),
end: refScriptInfo.positionToLineOffset(textSpanEnd(ref.textSpan)),
isWriteAccess: ref.isWriteAccess,
isDefinition: ref.isDefinition
};
@@ -1064,14 +1059,14 @@ namespace ts.server {
}
if (simplifiedResult) {
const displayString = ts.displayPartsToString(quickInfo.displayParts);
const docString = ts.displayPartsToString(quickInfo.documentation);
const displayString = displayPartsToString(quickInfo.displayParts);
const docString = displayPartsToString(quickInfo.documentation);
return {
kind: quickInfo.kind,
kindModifiers: quickInfo.kindModifiers,
start: scriptInfo.positionToLineOffset(quickInfo.textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(quickInfo.textSpan)),
end: scriptInfo.positionToLineOffset(textSpanEnd(quickInfo.textSpan)),
displayString,
documentation: docString,
tags: quickInfo.tags || []
@@ -1131,32 +1126,29 @@ namespace ts.server {
// only to the previous line. If all this is true, then
// add edits necessary to properly indent the current line.
if ((args.key === "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) {
const lineInfo = scriptInfo.getLineInfo(args.line);
if (lineInfo && (lineInfo.leaf) && (lineInfo.leaf.text)) {
const lineText = lineInfo.leaf.text;
if (lineText.search("\\S") < 0) {
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
let hasIndent = 0;
let i: number, len: number;
for (i = 0, len = lineText.length; i < len; i++) {
if (lineText.charAt(i) === " ") {
hasIndent++;
}
else if (lineText.charAt(i) === "\t") {
hasIndent += formatOptions.tabSize;
}
else {
break;
}
const { lineText, absolutePosition } = scriptInfo.getLineInfo(args.line);
if (lineText && lineText.search("\\S") < 0) {
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
let hasIndent = 0;
let i: number, len: number;
for (i = 0, len = lineText.length; i < len; i++) {
if (lineText.charAt(i) === " ") {
hasIndent++;
}
// i points to the first non whitespace character
if (preferredIndent !== hasIndent) {
const firstNoWhiteSpacePosition = lineInfo.offset + i;
edits.push({
span: ts.createTextSpanFromBounds(lineInfo.offset, firstNoWhiteSpacePosition),
newText: formatting.getIndentationString(preferredIndent, formatOptions)
});
else if (lineText.charAt(i) === "\t") {
hasIndent += formatOptions.tabSize;
}
else {
break;
}
}
// i points to the first non whitespace character
if (preferredIndent !== hasIndent) {
const firstNoWhiteSpacePosition = absolutePosition + i;
edits.push({
span: createTextSpanFromBounds(absolutePosition, firstNoWhiteSpacePosition),
newText: formatting.getIndentationString(preferredIndent, formatOptions)
});
}
}
}
@@ -1168,7 +1160,7 @@ namespace ts.server {
return edits.map((edit) => {
return {
start: scriptInfo.positionToLineOffset(edit.span.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(edit.span)),
end: scriptInfo.positionToLineOffset(textSpanEnd(edit.span)),
newText: edit.newText ? edit.newText : ""
};
});
@@ -1186,15 +1178,13 @@ namespace ts.server {
return undefined;
}
if (simplifiedResult) {
return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => {
return mapDefined(completions.entries, entry => {
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
const convertedSpan: protocol.TextSpan =
replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan });
const convertedSpan = replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan };
}
return result;
}, []).sort((a, b) => ts.compareStrings(a.name, b.name));
}).sort((a, b) => compareStrings(a.name, b.name));
}
else {
return completions;
@@ -1206,13 +1196,8 @@ namespace ts.server {
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const position = this.getPosition(args, scriptInfo);
return args.entryNames.reduce((accum: protocol.CompletionEntryDetails[], entryName: string) => {
const details = project.getLanguageService().getCompletionEntryDetails(file, position, entryName);
if (details) {
accum.push(details);
}
return accum;
}, []);
return mapDefined(args.entryNames, entryName =>
project.getLanguageService().getCompletionEntryDetails(file, position, entryName));
}
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): protocol.CompileOnSaveAffectedFileListSingleProject[] {
@@ -1277,14 +1262,11 @@ namespace ts.server {
}
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
const checkList = fileNames.reduce((accum: PendingErrorCheck[], uncheckedFileName: string) => {
const checkList = mapDefined(fileNames, uncheckedFileName => {
const fileName = toNormalizedPath(uncheckedFileName);
const project = this.projectService.getDefaultProjectForFile(fileName, /*refreshInferredProjects*/ true);
if (project) {
accum.push({ fileName, project });
}
return accum;
}, []);
return project && { fileName, project };
});
if (checkList.length > 0) {
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
@@ -1329,11 +1311,11 @@ namespace ts.server {
if (!fileName) {
return;
}
const file = ts.normalizePath(fileName);
const file = normalizePath(fileName);
this.projectService.closeClientFile(file);
}
private decorateNavigationBarItems(items: ts.NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] {
private decorateNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] {
return map(items, item => ({
text: item.text,
kind: item.kind,
@@ -1354,7 +1336,7 @@ namespace ts.server {
: items;
}
private decorateNavigationTree(tree: ts.NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree {
private decorateNavigationTree(tree: NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree {
return {
text: tree.text,
kind: tree.kind,
@@ -1367,7 +1349,7 @@ namespace ts.server {
private decorateSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
return {
start: scriptInfo.positionToLineOffset(span.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(span))
end: scriptInfo.positionToLineOffset(textSpanEnd(span))
};
}
@@ -1397,7 +1379,7 @@ namespace ts.server {
return navItems.map((navItem) => {
const scriptInfo = project.getScriptInfo(navItem.fileName);
const start = scriptInfo.positionToLineOffset(navItem.textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(navItem.textSpan));
const end = scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan));
const bakedItem: protocol.NavtoItem = {
name: navItem.name,
kind: navItem.kind,
@@ -1462,7 +1444,7 @@ namespace ts.server {
}
private getSupportedCodeFixes(): string[] {
return ts.getSupportedCodeFixes();
return getSupportedCodeFixes();
}
private isLocation(locationOrSpan: protocol.FileLocationOrRangeRequestArgs): locationOrSpan is protocol.FileLocationRequestArgs {
@@ -1493,7 +1475,7 @@ namespace ts.server {
return project.getLanguageService().getApplicableRefactors(file, position || textRange);
}
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): ts.RefactorEditInfo | protocol.RefactorEditInfo {
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo {
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const { position, textRange } = this.extractPositionAndRange(args, scriptInfo);
@@ -1514,7 +1496,7 @@ namespace ts.server {
if (simplifiedResult) {
const file = result.renameFilename;
let location: ILineInfo | undefined = undefined;
let location: protocol.Location | undefined;
if (file !== undefined && result.renameLocation !== undefined) {
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file));
location = renameScriptInfo.positionToLineOffset(result.renameLocation);
@@ -1662,7 +1644,7 @@ namespace ts.server {
getCanonicalFileName(fileName: string) {
const name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
return ts.normalizePath(name);
return normalizePath(name);
}
exit() {
+10 -6
View File
@@ -20,8 +20,12 @@ declare namespace ts.server {
require?(initialPath: string, moduleName: string): RequireResult;
}
export interface SortedArray<T> extends Array<T> {
" __sortedArrayBrand": any;
}
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
" __sortedReadonlyArrayBrand": any;
" __sortedArrayBrand": any;
}
export interface TypingInstallerRequest {
@@ -31,9 +35,9 @@ declare namespace ts.server {
export interface DiscoverTypings extends TypingInstallerRequest {
readonly fileNames: string[];
readonly projectRootPath: ts.Path;
readonly compilerOptions: ts.CompilerOptions;
readonly typeAcquisition: ts.TypeAcquisition;
readonly projectRootPath: Path;
readonly compilerOptions: CompilerOptions;
readonly typeAcquisition: TypeAcquisition;
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly cachePath?: string;
readonly kind: "discover";
@@ -63,8 +67,8 @@ declare namespace ts.server {
}
export interface SetTypings extends ProjectResponse {
readonly typeAcquisition: ts.TypeAcquisition;
readonly compilerOptions: ts.CompilerOptions;
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: string[];
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly kind: ActionSet;
+1 -1
View File
@@ -110,7 +110,7 @@ namespace ts.server {
this.perProjectCache.set(projectName, {
compilerOptions,
typeAcquisition,
typings: toSortedReadonlyArray(newTypings),
typings: toSortedArray(newTypings),
unresolvedImports,
poisoned: false
});
@@ -85,6 +85,7 @@ namespace ts.server.typingsInstaller {
private readonly missingTypingsSet: Map<true> = createMap<true>();
private readonly knownCachesSet: Map<true> = createMap<true>();
private readonly projectWatchers: Map<FileWatcher[]> = createMap<FileWatcher[]>();
private safeList: JsTyping.SafeList | undefined;
readonly pendingRunRequests: PendingRequest[] = [];
private installRunCount = 1;
@@ -93,10 +94,10 @@ namespace ts.server.typingsInstaller {
abstract readonly typesRegistry: Map<void>;
constructor(
readonly installTypingHost: InstallTypingHost,
readonly globalCachePath: string,
readonly safeListPath: Path,
readonly throttleLimit: number,
protected readonly installTypingHost: InstallTypingHost,
private readonly globalCachePath: string,
private readonly safeListPath: Path,
private readonly throttleLimit: number,
protected readonly log = nullLog) {
if (this.log.isEnabled()) {
this.log.writeLine(`Global cache location '${globalCachePath}', safe file path '${safeListPath}'`);
@@ -143,11 +144,15 @@ namespace ts.server.typingsInstaller {
this.processCacheLocation(req.cachePath);
}
if (this.safeList === undefined) {
this.safeList = JsTyping.loadSafeList(this.installTypingHost, this.safeListPath);
}
const discoverTypingsResult = JsTyping.discoverTypings(
this.installTypingHost,
this.log.isEnabled() ? this.log.writeLine : undefined,
req.fileNames,
req.projectRootPath,
this.safeListPath,
this.safeList,
this.packageNameToTypingLocation,
req.typeAcquisition,
req.unresolvedImports);
+73 -54
View File
@@ -9,7 +9,7 @@ namespace ts.server {
verbose
}
export const emptyArray: ReadonlyArray<any> = [];
export const emptyArray: SortedReadonlyArray<never> = createSortedArray<never>();
export interface Logger {
close(): void;
@@ -77,7 +77,7 @@ namespace ts.server {
tabSize: 4,
newLineCharacter: host.newLine || "\n",
convertTabsToSpaces: true,
indentStyle: ts.IndentStyle.Smart,
indentStyle: IndentStyle.Smart,
insertSpaceAfterConstructor: false,
insertSpaceAfterCommaDelimiter: true,
insertSpaceAfterSemicolonInForStatements: true,
@@ -103,24 +103,6 @@ namespace ts.server {
}
}
export function removeItemFromSet<T>(items: T[], itemToRemove: T) {
if (items.length === 0) {
return;
}
const index = items.indexOf(itemToRemove);
if (index < 0) {
return;
}
if (index === items.length - 1) {
// last item - pop it
items.pop();
}
else {
// non-last item - replace it with the last one
items[index] = items.pop();
}
}
export type NormalizedPath = string & { __normalizedPathTag: any };
export function toNormalizedPath(fileName: string): NormalizedPath {
@@ -190,40 +172,8 @@ namespace ts.server {
return `/dev/null/inferredProject${counter}*`;
}
export function toSortedReadonlyArray(arr: string[]): SortedReadonlyArray<string> {
arr.sort();
return <any>arr;
}
export function enumerateInsertsAndDeletes<T>(a: SortedReadonlyArray<T>, b: SortedReadonlyArray<T>, inserted: (item: T) => void, deleted: (item: T) => void, compare?: (a: T, b: T) => Comparison) {
compare = compare || ts.compareValues;
let aIndex = 0;
let bIndex = 0;
const aLen = a.length;
const bLen = b.length;
while (aIndex < aLen && bIndex < bLen) {
const aItem = a[aIndex];
const bItem = b[bIndex];
const compareResult = compare(aItem, bItem);
if (compareResult === Comparison.LessThan) {
inserted(aItem);
aIndex++;
}
else if (compareResult === Comparison.GreaterThan) {
deleted(bItem);
bIndex++;
}
else {
aIndex++;
bIndex++;
}
}
while (aIndex < aLen) {
inserted(a[aIndex++]);
}
while (bIndex < bLen) {
deleted(b[bIndex++]);
}
export function createSortedArray<T>(): SortedArray<T> {
return [] as SortedArray<T>;
}
export class ThrottledOperations {
@@ -273,4 +223,73 @@ 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);
return;
}
const insertIndex = binarySearch(array, insert, compare);
if (insertIndex < 0) {
array.splice(~insertIndex, 0, insert);
}
}
export function removeSorted<T>(array: SortedArray<T>, remove: T, compare: Comparer<T>): void {
if (!array || array.length === 0) {
return;
}
if (array[0] === remove) {
array.splice(0, 1);
return;
}
const removeIndex = binarySearch(array, remove, compare);
if (removeIndex >= 0) {
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 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++]);
}
}
}
+9 -9
View File
@@ -557,7 +557,7 @@ namespace ts {
// Only bother calling into the typechecker if this is an identifier that
// could possibly resolve to a type name. This makes classification run
// in a third of the time it would normally take.
if (classifiableNames.has(identifier.text)) {
if (classifiableNames.has(identifier.escapedText)) {
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
const type = classifySymbol(symbol, getMeaningFromLocation(node));
@@ -755,10 +755,10 @@ namespace ts {
return;
function processJSDocParameterTag(tag: JSDocParameterTag) {
if (tag.preParameterName) {
pushCommentRange(pos, tag.preParameterName.pos - pos);
pushClassification(tag.preParameterName.pos, tag.preParameterName.end - tag.preParameterName.pos, ClassificationType.parameterName);
pos = tag.preParameterName.end;
if (tag.isNameFirst) {
pushCommentRange(pos, tag.name.pos - pos);
pushClassification(tag.name.pos, tag.name.end - tag.name.pos, ClassificationType.parameterName);
pos = tag.name.end;
}
if (tag.typeExpression) {
@@ -767,10 +767,10 @@ namespace ts {
pos = tag.typeExpression.end;
}
if (tag.postParameterName) {
pushCommentRange(pos, tag.postParameterName.pos - pos);
pushClassification(tag.postParameterName.pos, tag.postParameterName.end - tag.postParameterName.pos, ClassificationType.parameterName);
pos = tag.postParameterName.end;
if (!tag.isNameFirst) {
pushCommentRange(pos, tag.name.pos - pos);
pushClassification(tag.name.pos, tag.name.end - tag.name.pos, ClassificationType.parameterName);
pos = tag.name.end;
}
}
}
@@ -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()
}];
}
});
}
@@ -32,7 +32,7 @@ namespace ts.codefix {
}
}
// If all fails, add an extra new line immediatlly before the error span.
// If all fails, add an extra new line immediately before the error span.
return {
span: { start: position, length: 0 },
newText: `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`
@@ -67,4 +67,4 @@ namespace ts.codefix {
}]
}];
}
}
}
+40
View File
@@ -0,0 +1,40 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments.code],
getCodeActions: getActionsForJSDocTypes
});
function getActionsForJSDocTypes(context: CodeFixContext): CodeAction[] | undefined {
const sourceFile = context.sourceFile;
const node = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false);
const decl = ts.findAncestor(node, n => n.kind === SyntaxKind.VariableDeclaration);
if (!decl) return;
const checker = context.program.getTypeChecker();
const jsdocType = (decl as VariableDeclaration).type;
const original = getTextOfNode(jsdocType);
const type = checker.getTypeFromTypeNode(jsdocType);
const actions = [createAction(jsdocType, sourceFile.fileName, original, checker.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation))];
if (jsdocType.kind === SyntaxKind.JSDocNullableType) {
// for nullable types, suggest the flow-compatible `T | null | undefined`
// in addition to the jsdoc/closure-compatible `T | null`
const replacementWithUndefined = checker.typeToString(checker.getNullableType(type, TypeFlags.Undefined), /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation);
actions.push(createAction(jsdocType, sourceFile.fileName, original, replacementWithUndefined));
}
return actions;
}
function createAction(declaration: TypeNode, fileName: string, original: string, replacement: string): CodeAction {
return {
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [original, replacement]),
changes: [{
fileName,
textChanges: [{
span: { start: declaration.getStart(), length: declaration.getWidth() },
newText: replacement
}]
}],
};
}
}
+2 -1
View File
@@ -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);
}
+28 -24
View File
@@ -25,15 +25,15 @@ namespace ts.codefix {
return [deleteNode(token.parent)];
default:
return [deleteDefault()];
return deleteDefault();
}
function deleteDefault() {
function deleteDefault(): CodeAction[] | undefined {
if (isDeclarationName(token)) {
return deleteNode(token.parent);
return [deleteNode(token.parent)];
}
else if (isLiteralComputedPropertyDeclarationName(token)) {
return deleteNode(token.parent.parent);
return [deleteNode(token.parent.parent)];
}
else {
return undefined;
@@ -87,20 +87,16 @@ namespace ts.codefix {
case SyntaxKind.ImportSpecifier:
const namedImports = <NamedImports>parent.parent;
if (namedImports.elements.length === 1) {
// Only 1 import and it is unused. So the entire declaration should be removed.
const importSpec = getAncestor(identifier, SyntaxKind.ImportDeclaration);
return [deleteNode(importSpec)];
return deleteNamedImportBinding(namedImports);
}
else {
// delete import specifier
return [deleteNodeInList(parent)];
}
// handle case where "import d, * as ns from './file'"
// or "'import {a, b as ns} from './file'"
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
const importClause = <ImportClause>parent;
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
if (!importClause.namedBindings) { // |import d from './file'|
const importDecl = getAncestor(importClause, SyntaxKind.ImportDeclaration);
return [deleteNode(importDecl)];
}
@@ -118,22 +114,30 @@ namespace ts.codefix {
}
case SyntaxKind.NamespaceImport:
const namespaceImport = <NamespaceImport>parent;
if (namespaceImport.name === identifier && !(<ImportClause>namespaceImport.parent).name) {
const importDecl = getAncestor(namespaceImport, SyntaxKind.ImportDeclaration);
return [deleteNode(importDecl)];
}
else {
const previousToken = getTokenAtPosition(sourceFile, namespaceImport.pos - 1, /*includeJsDocComment*/ false);
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, textChanges.Position.FullStart);
return [deleteRange({ pos: startPosition, end: namespaceImport.end })];
}
return [deleteRange(namespaceImport)];
}
return deleteNamedImportBinding(<NamespaceImport>parent);
default:
return [deleteDefault()];
return deleteDefault();
}
}
function deleteNamedImportBinding(namedBindings: NamedImportBindings): CodeAction[] | undefined {
if ((<ImportClause>namedBindings.parent).name) {
// Delete named imports while preserving the default import
// import d|, * as ns| from './file'
// import d|, { a }| from './file'
const previousToken = getTokenAtPosition(sourceFile, namedBindings.pos - 1, /*includeJsDocComment*/ false);
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
return [deleteRange({ pos: previousToken.getStart(), end: namedBindings.end })];
}
return undefined;
}
else {
// Delete the entire import declaration
// |import * as ns from './file'|
// |import { a } from './file'|
const importDecl = getAncestor(namedBindings, SyntaxKind.ImportDeclaration);
return [deleteNode(importDecl)];
}
}
+2
View File
@@ -1,3 +1,4 @@
/// <reference path="correctQualifiedNameToIndexedAccessType.ts" />
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
/// <reference path="fixAddMissingMember.ts" />
/// <reference path="fixSpelling.ts" />
@@ -7,6 +8,7 @@
/// <reference path="fixExtendsInterfaceBecomesImplements.ts" />
/// <reference path="fixForgottenThisPropertyAccess.ts" />
/// <reference path='fixUnusedIdentifier.ts' />
/// <reference path='fixJSDocTypes.ts' />
/// <reference path='importFixes.ts' />
/// <reference path='disableJsDiagnostics.ts' />
/// <reference path='helpers.ts' />
+10 -4
View File
@@ -35,7 +35,7 @@ namespace ts.codefix {
*/
export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker): Node[] {
const classMembers = classDeclaration.symbol.members;
const missingMembers = possiblyMissingSymbols.filter(symbol => !classMembers.has(symbol.name));
const missingMembers = possiblyMissingSymbols.filter(symbol => !classMembers.has(symbol.escapedName));
let newNodes: Node[] = [];
for (const symbol of missingMembers) {
@@ -186,7 +186,7 @@ namespace ts.codefix {
return parameters;
}
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
function createMethodImplementingSignatures(signatures: ReadonlyArray<Signature>, name: PropertyName, optional: boolean, modifiers: ReadonlyArray<Modifier> | undefined): MethodDeclaration {
/** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments,
* this is one of them.
@@ -205,7 +205,7 @@ namespace ts.codefix {
}
}
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.getUnescapedName());
const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.name);
const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, minArgumentCount, /*addAnyType*/ true);
@@ -231,7 +231,13 @@ namespace ts.codefix {
/*returnType*/ undefined);
}
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
export function createStubbedMethod(
modifiers: ReadonlyArray<Modifier>,
name: PropertyName,
optional: boolean,
typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined,
parameters: ReadonlyArray<ParameterDeclaration>,
returnType: TypeNode | undefined) {
return createMethod(
/*decorators*/ undefined,
modifiers,
+109 -34
View File
@@ -148,7 +148,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));
symbolName = symbol.getUnescapedName();
symbolName = symbol.name;
}
else {
Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here");
@@ -171,15 +171,18 @@ namespace ts.codefix {
const defaultExport = checker.tryGetMemberInModuleExports("default", moduleSymbol);
if (defaultExport) {
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
if (localSymbol && localSymbol.name === name && checkSymbolHasMeaning(localSymbol, currentTokenMeaning)) {
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));
}
}
// "default" is a keyword and not a legal identifier for the import, so we don't expect it here
Debug.assert(name !== "default");
// check exports with the same name
const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExports(name, moduleSymbol);
const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExportsAndProperties(name, moduleSymbol);
if (exportSymbolWithIdenticalName && checkSymbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) {
const symbolId = getUniqueSymbolId(exportSymbolWithIdenticalName);
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name));
@@ -222,10 +225,7 @@ namespace ts.codefix {
}
function getUniqueSymbolId(symbol: Symbol) {
if (symbol.flags & SymbolFlags.Alias) {
return getSymbolId(checker.getAliasedSymbol(symbol));
}
return getSymbolId(symbol);
return getSymbolId(skipAlias(symbol, checker));
}
function checkSymbolHasMeaning(symbol: Symbol, meaning: SemanticMeaning) {
@@ -504,45 +504,120 @@ namespace ts.codefix {
return undefined;
}
const indexOfNodeModules = moduleFileName.indexOf("node_modules");
if (indexOfNodeModules < 0) {
const parts = getNodeModulePathParts(moduleFileName);
if (!parts) {
return undefined;
}
let relativeFileName: string;
if (sourceDirectory.indexOf(moduleFileName.substring(0, indexOfNodeModules - 1)) === 0) {
// if node_modules folder is in this folder or any of its parent folder, no need to keep it.
relativeFileName = moduleFileName.substring(indexOfNodeModules + 13 /* "node_modules\".length */);
}
else {
relativeFileName = getRelativePath(moduleFileName, sourceDirectory);
}
// Simplify the full file path to something that can be resolved by Node.
relativeFileName = removeFileExtension(relativeFileName);
if (endsWith(relativeFileName, "/index")) {
relativeFileName = getDirectoryPath(relativeFileName);
}
else {
try {
const moduleDirectory = getDirectoryPath(moduleFileName);
const packageJsonContent = JSON.parse(context.host.readFile(combinePaths(moduleDirectory, "package.json")));
// If the module could be imported by a directory name, use that directory's name
let moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
// Get a path that's relative to node_modules or the importing file's path
moduleSpecifier = getNodeResolvablePath(moduleSpecifier);
// If the module was found in @types, get the actual Node package name
return getPackageNameFromAtTypesDirectory(moduleSpecifier);
function getDirectoryOrExtensionlessFileName(path: string): string {
// If the file is the main module, it can be imported by the package name
const packageRootPath = path.substring(0, parts.packageRootIndex);
const packageJsonPath = combinePaths(packageRootPath, "package.json");
if (context.host.fileExists(packageJsonPath)) {
const packageJsonContent = JSON.parse(context.host.readFile(packageJsonPath));
if (packageJsonContent) {
const mainFile = packageJsonContent.main || packageJsonContent.typings;
if (mainFile) {
const mainExportFile = toPath(mainFile, moduleDirectory, getCanonicalFileName);
if (removeFileExtension(mainExportFile) === removeFileExtension(moduleFileName)) {
relativeFileName = getDirectoryPath(relativeFileName);
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
if (mainFileRelative) {
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
if (mainExportFile === getCanonicalFileName(path)) {
return packageRootPath;
}
}
}
}
catch (e) { }
// We still have a file name - remove the extension
const fullModulePathWithoutExtension = removeFileExtension(path);
// If the file is /index, it can be imported by its directory name
if (getCanonicalFileName(fullModulePathWithoutExtension.substring(parts.fileNameIndex)) === "/index") {
return fullModulePathWithoutExtension.substring(0, parts.fileNameIndex);
}
return fullModulePathWithoutExtension;
}
return getPackageNameFromAtTypesDirectory(relativeFileName);
function getNodeResolvablePath(path: string): string {
const basePath = path.substring(0, parts.topLevelNodeModulesIndex);
if (sourceDirectory.indexOf(basePath) === 0) {
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
return path.substring(parts.topLevelPackageNameIndex + 1);
}
else {
return getRelativePath(path, sourceDirectory);
}
}
}
}
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/[@scope/otherpackage/@otherscope/node_modules/]package/[subdirectory/]file.js
// Returns indices: ^ ^ ^ ^
let topLevelNodeModulesIndex = 0;
let topLevelPackageNameIndex = 0;
let packageRootIndex = 0;
let fileNameIndex = 0;
const enum States {
BeforeNodeModules,
NodeModules,
Scope,
PackageContent
}
let partStart = 0;
let partEnd = 0;
let state = States.BeforeNodeModules;
while (partEnd >= 0) {
partStart = partEnd;
partEnd = fullPath.indexOf("/", partStart + 1);
switch (state) {
case States.BeforeNodeModules:
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
topLevelNodeModulesIndex = partStart;
topLevelPackageNameIndex = partEnd;
state = States.NodeModules;
}
break;
case States.NodeModules:
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) {
state = States.NodeModules;
}
else {
state = States.PackageContent;
}
break;
}
}
fileNameIndex = partStart;
return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined;
}
function getPathRelativeToRootDirs(path: string, rootDirs: string[]) {
for (const rootDir of rootDirs) {
const relativeName = getRelativePathIfInDirectory(path, rootDir);
@@ -568,7 +643,7 @@ namespace ts.codefix {
function getRelativePath(path: string, directoryPath: string) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
return moduleHasNonRelativeName(relativePath) ? "./" + relativePath : relativePath;
return !pathIsRelative(relativePath) ? "./" + relativePath : relativePath;
}
}
+124 -126
View File
@@ -57,11 +57,11 @@ namespace ts.Completions {
if (isSourceFileJavaScript(sourceFile)) {
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log);
addRange(entries, getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target));
getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target, entries);
}
else {
if ((!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
return undefined;
return undefined;
}
getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log);
@@ -79,40 +79,41 @@ namespace ts.Completions {
return { isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, entries };
}
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map<true>, target: ScriptTarget): CompletionEntry[] {
const entries: CompletionEntry[] = [];
const nameTable = getNameTable(sourceFile);
nameTable.forEach((pos, name) => {
function getJavaScriptCompletionEntries(
sourceFile: SourceFile,
position: number,
uniqueNames: Map<true>,
target: ScriptTarget,
entries: Push<CompletionEntry>): void {
getNameTable(sourceFile).forEach((pos, name) => {
// Skip identifiers produced only from the current location
if (pos === position) {
return;
}
const realName = unescapeLeadingUnderscores(name);
if (!uniqueNames.get(realName)) {
uniqueNames.set(realName, true);
const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true);
if (displayName) {
const entry = {
name: displayName,
kind: ScriptElementKind.warning,
kindModifiers: "",
sortText: "1"
};
entries.push(entry);
}
if (uniqueNames.has(realName)) {
return;
}
uniqueNames.set(realName, true);
const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true);
if (displayName) {
entries.push({
name: displayName,
kind: ScriptElementKind.warning,
kindModifiers: "",
sortText: "1"
});
}
});
return entries;
}
function createCompletionEntry(symbol: Symbol, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget): CompletionEntry {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
const displayName = getCompletionEntryDisplayNameForSymbol(typeChecker, symbol, target, performCharacterChecks, location);
const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks);
if (!displayName) {
return undefined;
}
@@ -141,7 +142,7 @@ namespace ts.Completions {
const entry = createCompletionEntry(symbol, location, performCharacterChecks, typeChecker, target);
if (entry) {
const id = entry.name;
if (!uniqueNames.get(id)) {
if (!uniqueNames.has(id)) {
entries.push(entry);
uniqueNames.set(id, true);
}
@@ -307,7 +308,7 @@ namespace ts.Completions {
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined);
if (symbol) {
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
@@ -341,20 +342,14 @@ namespace ts.Completions {
return undefined;
}
export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol {
export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol | undefined {
// Compute all the completion symbols again.
const completionData = getCompletionData(typeChecker, log, sourceFile, position);
if (completionData) {
const { symbols, location } = completionData;
// Find the symbol with the matching entry name.
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
return forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
}
return undefined;
// Find the symbol with the matching entry name.
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
return completionData && forEach(completionData.symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined);
}
interface CompletionData {
@@ -369,7 +364,7 @@ namespace ts.Completions {
}
type Request = { kind: "JsDocTagName" } | { kind: "JsDocTag" } | { kind: "JsDocParameterName", tag: JSDocParameterTag };
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData {
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData | undefined {
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
let request: Request | undefined;
@@ -425,7 +420,7 @@ namespace ts.Completions {
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
request = { kind: "JsDocTagName" };
}
if (isTagWithTypeExpression(tag) && tag.typeExpression) {
if (isTagWithTypeExpression(tag) && tag.typeExpression && tag.typeExpression.kind === SyntaxKind.JSDocTypeExpression) {
currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ true);
if (!currentToken ||
(!isDeclarationName(currentToken) &&
@@ -601,58 +596,60 @@ namespace ts.Completions {
isNewIdentifierLocation = false;
// Since this is qualified name check its a type node location
const isTypeLocation = isPartOfTypeNode(node.parent) || insideJsDocTagTypeExpression;
const isTypeLocation = insideJsDocTagTypeExpression || isPartOfTypeNode(node.parent);
const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration(node);
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) {
if (isEntityName(node)) {
let symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
symbol = skipAlias(symbol, typeChecker);
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Alias) {
symbol = typeChecker.getAliasedSymbol(symbol);
}
if (symbol && symbol.flags & SymbolFlags.HasExports) {
// Extract module or enum members
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName());
const isValidTypeAccess = (symbol: Symbol) => symbolCanbeReferencedAtTypeLocation(symbol);
const isValidAccess = isRhsOfImportDeclaration ?
// Any kind is allowed when dotting off namespace in internal import equals declaration
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
forEach(exportedSymbols, symbol => {
if (isValidAccess(symbol)) {
symbols.push(symbol);
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
// Extract module or enum members
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name);
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
const isValidAccess = isRhsOfImportDeclaration ?
// Any kind is allowed when dotting off namespace in internal import equals declaration
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
for (const symbol of exportedSymbols) {
if (isValidAccess(symbol)) {
symbols.push(symbol);
}
}
});
// If the module is merged with a value, we must get the type of the class and add its propertes (for inherited static methods).
if (!isTypeLocation && symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration)) {
addTypeProperties(typeChecker.getTypeOfSymbolAtLocation(symbol, node));
}
return;
}
}
}
if (!isTypeLocation) {
const type = typeChecker.getTypeAtLocation(node);
addTypeProperties(type);
addTypeProperties(typeChecker.getTypeAtLocation(node));
}
}
function addTypeProperties(type: Type) {
if (type) {
// Filter private properties
for (const symbol of type.getApparentProperties()) {
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName())) {
symbols.push(symbol);
}
// Filter private properties
for (const symbol of type.getApparentProperties()) {
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name)) {
symbols.push(symbol);
}
}
if (isJavaScriptFile && type.flags & TypeFlags.Union) {
// In javascript files, for union types, we don't just get the members that
// the individual types have in common, we also include all the members that
// each individual type has. This is because we're going to add all identifiers
// anyways. So we might as well elevate the members that were at least part
// of the individual types to a higher status since we know what they are.
const unionType = <UnionType>type;
for (const elementType of unionType.types) {
addTypeProperties(elementType);
}
if (isJavaScriptFile && type.flags & TypeFlags.Union) {
// In javascript files, for union types, we don't just get the members that
// the individual types have in common, we also include all the members that
// each individual type has. This is because we're going to add all identifiers
// anyways. So we might as well elevate the members that were at least part
// of the individual types to a higher status since we know what they are.
const unionType = <UnionType>type;
for (const elementType of unionType.types) {
addTypeProperties(elementType);
}
}
}
@@ -777,12 +774,12 @@ namespace ts.Completions {
(!isContextTokenValueLocation(contextToken) &&
(isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)))) {
// Its a type, but you can reach it by namespace.type as well
return symbolCanbeReferencedAtTypeLocation(symbol);
return symbolCanBeReferencedAtTypeLocation(symbol);
}
}
// expressions are value space (which includes the value namespaces)
return !!(symbol.flags & SymbolFlags.Value);
return !!(getCombinedLocalAndExportSymbolFlags(symbol) & SymbolFlags.Value);
});
}
@@ -812,21 +809,21 @@ namespace ts.Completions {
}
}
function symbolCanbeReferencedAtTypeLocation(symbol: Symbol): boolean {
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol): boolean {
symbol = symbol.exportSymbol || symbol;
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Alias) {
symbol = typeChecker.getAliasedSymbol(symbol);
}
symbol = skipAlias(symbol, typeChecker);
if (symbol.flags & SymbolFlags.Type) {
return true;
}
if (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule)) {
if (symbol.flags & SymbolFlags.Module) {
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
// If the exported symbols contains type,
// symbol can be referenced at locations where type is allowed
return forEach(exportedSymbols, symbolCanbeReferencedAtTypeLocation);
return forEach(exportedSymbols, symbolCanBeReferencedAtTypeLocation);
}
}
@@ -966,7 +963,7 @@ namespace ts.Completions {
isMemberCompletion = true;
let typeMembers: Symbol[];
let existingMembers: Declaration[];
let existingMembers: ReadonlyArray<Declaration>;
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
// We are completing on contextual types, but may also include properties
@@ -1003,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;
}
}
@@ -1096,14 +1093,14 @@ namespace ts.Completions {
}
}
const implementedInterfaceTypePropertySymbols = (classElementModifierFlags & ModifierFlags.Static) ?
undefined :
flatMap(implementsTypeNodes, typeNode => typeChecker.getPropertiesOfType(typeChecker.getTypeAtLocation(typeNode)));
emptyArray :
flatMap(implementsTypeNodes || emptyArray, typeNode => typeChecker.getPropertiesOfType(typeChecker.getTypeAtLocation(typeNode)));
// List of property symbols of base type that are not private and already implemented
symbols = filterClassMembersList(
baseClassTypeToGetPropertiesFrom ?
typeChecker.getPropertiesOfType(baseClassTypeToGetPropertiesFrom) :
undefined,
emptyArray,
implementedInterfaceTypePropertySymbols,
classLikeDeclaration.members,
classElementModifierFlags);
@@ -1446,7 +1443,7 @@ namespace ts.Completions {
* @returns Symbols to be suggested at an import/export clause, barring those whose named imports/exports
* do not occur at the current position and have not otherwise been typed.
*/
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] {
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ReadonlyArray<ImportOrExportSpecifier>): Symbol[] {
const existingImportsOrExports = createUnderscoreEscapedMap<boolean>();
for (const element of namedImportsOrExports) {
@@ -1456,14 +1453,14 @@ namespace ts.Completions {
}
const name = element.propertyName || element.name;
existingImportsOrExports.set(name.text, true);
existingImportsOrExports.set(name.escapedText, true);
}
if (existingImportsOrExports.size === 0) {
return filter(exportsOfModule, e => e.name !== "default");
return filter(exportsOfModule, e => e.escapedName !== "default");
}
return filter(exportsOfModule, e => e.name !== "default" && !existingImportsOrExports.get(e.name));
return filter(exportsOfModule, e => e.escapedName !== "default" && !existingImportsOrExports.get(e.escapedName));
}
/**
@@ -1472,7 +1469,7 @@ namespace ts.Completions {
* @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations
* do not occur at the current position and have not otherwise been typed.
*/
function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: ReadonlyArray<Declaration>): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
return contextualMemberSymbols;
}
@@ -1499,7 +1496,7 @@ namespace ts.Completions {
if (m.kind === SyntaxKind.BindingElement && (<BindingElement>m).propertyName) {
// include only identifiers in completion list
if ((<BindingElement>m).propertyName.kind === SyntaxKind.Identifier) {
existingName = (<Identifier>(<BindingElement>m).propertyName).text;
existingName = (<Identifier>(<BindingElement>m).propertyName).escapedText;
}
}
else {
@@ -1513,7 +1510,7 @@ namespace ts.Completions {
existingMemberNames.set(existingName, true);
}
return filter(contextualMemberSymbols, m => !existingMemberNames.get(m.name));
return filter(contextualMemberSymbols, m => !existingMemberNames.get(m.escapedName));
}
/**
@@ -1521,7 +1518,11 @@ namespace ts.Completions {
*
* @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags
*/
function filterClassMembersList(baseSymbols: Symbol[], implementingTypeSymbols: Symbol[], existingMembers: ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] {
function filterClassMembersList(
baseSymbols: ReadonlyArray<Symbol>,
implementingTypeSymbols: ReadonlyArray<Symbol>,
existingMembers: ReadonlyArray<ClassElement>,
currentClassElementModifierFlags: ModifierFlags): Symbol[] {
const existingMemberNames = createUnderscoreEscapedMap<boolean>();
for (const m of existingMembers) {
// Ignore omitted expressions for missing members
@@ -1556,13 +1557,21 @@ namespace ts.Completions {
}
}
return concatenate(
filter(baseSymbols, baseProperty => isValidProperty(baseProperty, ModifierFlags.Private)),
filter(implementingTypeSymbols, implementingProperty => isValidProperty(implementingProperty, ModifierFlags.NonPublicAccessibilityModifier))
);
const result: Symbol[] = [];
addPropertySymbols(baseSymbols, ModifierFlags.Private);
addPropertySymbols(implementingTypeSymbols, ModifierFlags.NonPublicAccessibilityModifier);
return result;
function addPropertySymbols(properties: ReadonlyArray<Symbol>, inValidModifierFlags: ModifierFlags) {
for (const property of properties) {
if (isValidProperty(property, inValidModifierFlags)) {
result.push(property);
}
}
}
function isValidProperty(propertySymbol: Symbol, inValidModifierFlags: ModifierFlags) {
return !existingMemberNames.get(propertySymbol.name) &&
return !existingMemberNames.get(propertySymbol.escapedName) &&
propertySymbol.getDeclarations() &&
!(getDeclarationModifierFlagsFromSymbol(propertySymbol) & inValidModifierFlags);
}
@@ -1583,11 +1592,11 @@ namespace ts.Completions {
}
if (attr.kind === SyntaxKind.JsxAttribute) {
seenNames.set((<JsxAttribute>attr).name.text, true);
seenNames.set((<JsxAttribute>attr).name.escapedText, true);
}
}
return filter(symbols, a => !seenNames.get(a.name));
return filter(symbols, a => !seenNames.get(a.escapedName));
}
function isCurrentlyEditingNode(node: Node): boolean {
@@ -1598,22 +1607,23 @@ namespace ts.Completions {
/**
* Get the name to be display in completion from a given symbol.
*
* @return undefined if the name is of external module otherwise a name with striped of any quote
* @return undefined if the name is of external module
*/
function getCompletionEntryDisplayNameForSymbol(typeChecker: TypeChecker, symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean, location: Node): string {
const displayName: string = getDeclaredName(typeChecker, symbol, location);
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string | undefined {
const name = symbol.name;
if (!name) return undefined;
if (displayName) {
const firstCharCode = displayName.charCodeAt(0);
// First check of the displayName is not external module; if it is an external module, it is not valid entry
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
// First check of the displayName is not external module; if it is an external module, it is not valid entry
if (symbol.flags & SymbolFlags.Namespace) {
const firstCharCode = name.charCodeAt(0);
if (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote) {
// If the symbol is external module, don't show it in the completion list
// (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
return undefined;
}
}
return getCompletionEntryDisplayName(displayName, target, performCharacterChecks);
return getCompletionEntryDisplayName(name, target, performCharacterChecks);
}
/**
@@ -1621,24 +1631,12 @@ namespace ts.Completions {
* and checking whether the name is valid identifier name.
*/
function getCompletionEntryDisplayName(name: string, target: ScriptTarget, performCharacterChecks: boolean): string {
if (!name) {
return undefined;
}
name = stripQuotes(name);
if (!name) {
return undefined;
}
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
// invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
// e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
// We, thus, need to check if whatever was inside the quotes is actually a valid identifier name.
if (performCharacterChecks) {
if (!isIdentifierText(name, target)) {
return undefined;
}
if (performCharacterChecks && !isIdentifierText(name, target)) {
return undefined;
}
return name;

Some files were not shown because too many files have changed in this diff Show More