mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into improve_type_arguments_parser_1
This commit is contained in:
+57
-35
@@ -24,10 +24,9 @@ const baselineAccept = require("./scripts/build/baselineAccept");
|
||||
const cmdLineOptions = require("./scripts/build/options");
|
||||
const exec = require("./scripts/build/exec");
|
||||
const browserify = require("./scripts/build/browserify");
|
||||
const debounce = require("./scripts/build/debounce");
|
||||
const prepend = require("./scripts/build/prepend");
|
||||
const { removeSourceMaps } = require("./scripts/build/sourcemaps");
|
||||
const { CancelSource, CancelError } = require("./scripts/build/cancellation");
|
||||
const { CancellationTokenSource, CancelError, delay, Semaphore } = require("prex");
|
||||
const { libraryTargets, generateLibs } = require("./scripts/build/lib");
|
||||
const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests");
|
||||
|
||||
@@ -534,57 +533,80 @@ gulp.task(
|
||||
["watch-diagnostics", "watch-lib"].concat(useCompilerDeps),
|
||||
() => project.watch(tsserverProject, { typescript: useCompiler }));
|
||||
|
||||
gulp.task(
|
||||
"watch-local",
|
||||
/*help*/ false,
|
||||
["watch-lib", "watch-tsc", "watch-services", "watch-server"]);
|
||||
|
||||
gulp.task(
|
||||
"watch-runner",
|
||||
/*help*/ false,
|
||||
useCompilerDeps,
|
||||
() => project.watch(testRunnerProject, { typescript: useCompiler }));
|
||||
|
||||
const watchPatterns = [
|
||||
runJs,
|
||||
typescriptDts,
|
||||
tsserverlibraryDts
|
||||
];
|
||||
gulp.task(
|
||||
"watch-local",
|
||||
"Watches for changes to projects in src/ (but does not execute tests).",
|
||||
["watch-lib", "watch-tsc", "watch-services", "watch-server", "watch-runner", "watch-lssl"]);
|
||||
|
||||
gulp.task(
|
||||
"watch",
|
||||
"Watches for changes to the build inputs for built/local/run.js, then executes runtests-parallel.",
|
||||
"Watches for changes to the build inputs for built/local/run.js, then runs tests.",
|
||||
["build-rules", "watch-runner", "watch-services", "watch-lssl"],
|
||||
() => {
|
||||
/** @type {CancelSource | undefined} */
|
||||
let runTestsSource;
|
||||
const sem = new Semaphore(1);
|
||||
|
||||
const fn = debounce(() => {
|
||||
runTests().catch(error => {
|
||||
if (error instanceof CancelError) {
|
||||
log.warn("Operation was canceled");
|
||||
}
|
||||
else {
|
||||
log.error(error);
|
||||
}
|
||||
});
|
||||
}, /*timeout*/ 100, { max: 500 });
|
||||
|
||||
gulp.watch(watchPatterns, () => project.wait().then(fn));
|
||||
gulp.watch([runJs, typescriptDts, tsserverlibraryDts], () => {
|
||||
runTests();
|
||||
});
|
||||
|
||||
// NOTE: gulp.watch is far too slow when watching tests/cases/**/* as it first enumerates *every* file
|
||||
const testFilePattern = /(\.ts|[\\/]tsconfig\.json)$/;
|
||||
fs.watch("tests/cases", { recursive: true }, (_, file) => {
|
||||
if (testFilePattern.test(file)) project.wait().then(fn);
|
||||
if (testFilePattern.test(file)) runTests();
|
||||
});
|
||||
|
||||
function runTests() {
|
||||
if (runTestsSource) runTestsSource.cancel();
|
||||
runTestsSource = new CancelSource();
|
||||
return cmdLineOptions.tests || cmdLineOptions.failed
|
||||
? runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true, runTestsSource.token)
|
||||
: runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ true, runTestsSource.token);
|
||||
}
|
||||
async function runTests() {
|
||||
try {
|
||||
// Ensure only one instance of the test runner is running at any given time.
|
||||
if (sem.count > 0) {
|
||||
await sem.wait();
|
||||
try {
|
||||
// Wait for any concurrent recompilations to complete...
|
||||
try {
|
||||
await delay(100);
|
||||
while (project.hasRemainingWork()) {
|
||||
await project.waitForWorkToComplete();
|
||||
await delay(500);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof CancelError) return;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// cancel any pending or active test run if a new recompilation is triggered
|
||||
const source = new CancellationTokenSource();
|
||||
project.waitForWorkToStart().then(() => {
|
||||
source.cancel();
|
||||
});
|
||||
|
||||
if (cmdLineOptions.tests || cmdLineOptions.failed) {
|
||||
await runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true, source.token);
|
||||
}
|
||||
else {
|
||||
await runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ true, source.token);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
sem.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof CancelError) {
|
||||
log.warn("Operation was canceled");
|
||||
}
|
||||
else {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
gulp.task("clean-built", /*help*/ false, [`clean:${diagnosticInformationMapTs}`], () => del(["built"]));
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
"mocha": "latest",
|
||||
"mocha-fivemat-progress-reporter": "latest",
|
||||
"plugin-error": "latest",
|
||||
"prex": "^0.4.3",
|
||||
"q": "latest",
|
||||
"remove-internal": "^2.9.2",
|
||||
"run-sequence": "latest",
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// @ts-check
|
||||
const symSource = Symbol("CancelToken.source");
|
||||
const symToken = Symbol("CancelSource.token");
|
||||
const symCancellationRequested = Symbol("CancelSource.cancellationRequested");
|
||||
const symCancellationCallbacks = Symbol("CancelSource.cancellationCallbacks");
|
||||
|
||||
class CancelSource {
|
||||
constructor() {
|
||||
this[symCancellationRequested] = false;
|
||||
this[symCancellationCallbacks] = [];
|
||||
}
|
||||
|
||||
/** @type {CancelToken} */
|
||||
get token() {
|
||||
return this[symToken] || (this[symToken] = new CancelToken(this));
|
||||
}
|
||||
|
||||
cancel() {
|
||||
if (!this[symCancellationRequested]) {
|
||||
this[symCancellationRequested] = true;
|
||||
for (const callback of this[symCancellationCallbacks]) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.CancelSource = CancelSource;
|
||||
|
||||
class CancelToken {
|
||||
/**
|
||||
* @param {CancelSource} source
|
||||
*/
|
||||
constructor(source) {
|
||||
if (source[symToken]) return source[symToken];
|
||||
this[symSource] = source;
|
||||
}
|
||||
|
||||
/** @type {boolean} */
|
||||
get cancellationRequested() {
|
||||
return this[symSource][symCancellationRequested];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {() => void} callback
|
||||
*/
|
||||
subscribe(callback) {
|
||||
const source = this[symSource];
|
||||
if (source[symCancellationRequested]) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
source[symCancellationCallbacks].push(callback);
|
||||
|
||||
return {
|
||||
unsubscribe() {
|
||||
const index = source[symCancellationCallbacks].indexOf(callback);
|
||||
if (index !== -1) source[symCancellationCallbacks].splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.CancelToken = CancelToken;
|
||||
|
||||
class CancelError extends Error {
|
||||
constructor(message = "Operation was canceled") {
|
||||
super(message);
|
||||
this.name = "CancelError";
|
||||
}
|
||||
}
|
||||
exports.CancelError = CancelError;
|
||||
+17
-12
@@ -3,7 +3,7 @@ const cp = require("child_process");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const isWin = /^win/.test(process.platform);
|
||||
const chalk = require("./chalk");
|
||||
const { CancelToken, CancelError } = require("./cancellation");
|
||||
const { CancellationToken, CancelError } = require("prex");
|
||||
|
||||
module.exports = exec;
|
||||
|
||||
@@ -15,31 +15,36 @@ module.exports = exec;
|
||||
*
|
||||
* @typedef ExecOptions
|
||||
* @property {boolean} [ignoreExitCode]
|
||||
* @property {CancelToken} [cancelToken]
|
||||
* @property {import("prex").CancellationToken} [cancelToken]
|
||||
*/
|
||||
function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
|
||||
log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const { ignoreExitCode, cancelToken = CancellationToken.none } = options;
|
||||
cancelToken.throwIfCancellationRequested();
|
||||
|
||||
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
|
||||
const subshellFlag = isWin ? "/c" : "-c";
|
||||
const command = isWin ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
|
||||
const ex = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
|
||||
const subscription = options.cancelToken && options.cancelToken.subscribe(() => {
|
||||
ex.kill("SIGINT");
|
||||
ex.kill("SIGTERM");
|
||||
|
||||
log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
|
||||
const registration = cancelToken.register(() => {
|
||||
log(`${chalk.red("killing")} '${chalk.green(cmd)} ${args.join(" ")}'...`);
|
||||
proc.kill("SIGINT");
|
||||
proc.kill("SIGTERM");
|
||||
reject(new CancelError());
|
||||
});
|
||||
ex.on("exit", exitCode => {
|
||||
subscription && subscription.unsubscribe();
|
||||
if (exitCode === 0 || options.ignoreExitCode) {
|
||||
proc.on("exit", exitCode => {
|
||||
registration.unregister();
|
||||
if (exitCode === 0 || ignoreExitCode) {
|
||||
resolve({ exitCode });
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Process exited with code: ${exitCode}`));
|
||||
}
|
||||
});
|
||||
ex.on("error", error => {
|
||||
subscription && subscription.unsubscribe();
|
||||
proc.on("error", error => {
|
||||
registration.unregister();
|
||||
reject(error);
|
||||
});
|
||||
}));
|
||||
|
||||
+56
-23
@@ -3,6 +3,8 @@ const path = require("path");
|
||||
const fs = require("fs");
|
||||
const gulp = require("./gulp");
|
||||
const gulpif = require("gulp-if");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const chalk = require("./chalk");
|
||||
const sourcemaps = require("gulp-sourcemaps");
|
||||
const merge2 = require("merge2");
|
||||
const tsc = require("gulp-typescript");
|
||||
@@ -12,7 +14,12 @@ const ts = require("../../lib/typescript");
|
||||
const del = require("del");
|
||||
const needsUpdate = require("./needsUpdate");
|
||||
const mkdirp = require("./mkdirp");
|
||||
const prettyTime = require("pretty-hrtime");
|
||||
const { reportDiagnostics } = require("./diagnostics");
|
||||
const { CountdownEvent, ManualResetEvent } = require("prex");
|
||||
|
||||
const workStartedEvent = new ManualResetEvent();
|
||||
const countdown = new CountdownEvent(0);
|
||||
|
||||
class CompilationGulp extends gulp.Gulp {
|
||||
/**
|
||||
@@ -20,15 +27,39 @@ class CompilationGulp extends gulp.Gulp {
|
||||
*/
|
||||
fork(verbose) {
|
||||
const child = new ForkedGulp(this.tasks);
|
||||
if (verbose) {
|
||||
child.on("task_start", e => gulp.emit("task_start", e));
|
||||
child.on("task_stop", e => gulp.emit("task_stop", e));
|
||||
child.on("task_err", e => gulp.emit("task_err", e));
|
||||
child.on("task_not_found", e => gulp.emit("task_not_found", e));
|
||||
child.on("task_recursion", e => gulp.emit("task_recursion", e));
|
||||
}
|
||||
child.on("task_start", e => {
|
||||
if (countdown.remainingCount === 0) {
|
||||
countdown.reset(1);
|
||||
workStartedEvent.set();
|
||||
workStartedEvent.reset();
|
||||
}
|
||||
else {
|
||||
countdown.add();
|
||||
}
|
||||
if (verbose) {
|
||||
log('Starting', `'${chalk.cyan(e.task)}' ${chalk.gray(`(${countdown.remainingCount} remaining)`)}...`);
|
||||
}
|
||||
});
|
||||
child.on("task_stop", e => {
|
||||
countdown.signal();
|
||||
if (verbose) {
|
||||
log('Finished', `'${chalk.cyan(e.task)}' after ${chalk.magenta(prettyTime(/** @type {*}*/(e).hrDuration))} ${chalk.gray(`(${countdown.remainingCount} remaining)`)}`);
|
||||
}
|
||||
});
|
||||
child.on("task_err", e => {
|
||||
countdown.signal();
|
||||
if (verbose) {
|
||||
log(`'${chalk.cyan(e.task)}' ${chalk.red("errored after")} ${chalk.magenta(prettyTime(/** @type {*}*/(e).hrDuration))} ${chalk.gray(`(${countdown.remainingCount} remaining)`)}`);
|
||||
log(e.err ? e.err.stack : e.message);
|
||||
}
|
||||
});
|
||||
return child;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
start() {
|
||||
throw new Error("Not supported, use fork.");
|
||||
}
|
||||
}
|
||||
|
||||
class ForkedGulp extends gulp.Gulp {
|
||||
@@ -211,24 +242,26 @@ exports.flatten = flatten;
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves when all pending build tasks have completed
|
||||
* @param {import("prex").CancellationToken} [token]
|
||||
*/
|
||||
function wait() {
|
||||
return new Promise(resolve => {
|
||||
if (compilationGulp.allDone()) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
const onDone = () => {
|
||||
compilationGulp.removeListener("onDone", onDone);
|
||||
compilationGulp.removeListener("err", onDone);
|
||||
resolve();
|
||||
};
|
||||
compilationGulp.on("stop", onDone);
|
||||
compilationGulp.on("err", onDone);
|
||||
}
|
||||
});
|
||||
function waitForWorkToComplete(token) {
|
||||
return countdown.wait(token);
|
||||
}
|
||||
exports.wait = wait;
|
||||
exports.waitForWorkToComplete = waitForWorkToComplete;
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves when all pending build tasks have completed
|
||||
* @param {import("prex").CancellationToken} [token]
|
||||
*/
|
||||
function waitForWorkToStart(token) {
|
||||
return workStartedEvent.wait(token);
|
||||
}
|
||||
exports.waitForWorkToStart = waitForWorkToStart;
|
||||
|
||||
function getRemainingWork() {
|
||||
return countdown.remainingCount > 0;
|
||||
}
|
||||
exports.hasRemainingWork = getRemainingWork;
|
||||
|
||||
/**
|
||||
* Resolve a TypeScript specifier into a fully-qualified module specifier and any requisite dependencies.
|
||||
|
||||
@@ -8,6 +8,7 @@ const mkdirP = require("./mkdirp");
|
||||
const cmdLineOptions = require("./options");
|
||||
const exec = require("./exec");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const { CancellationToken } = require("prex");
|
||||
const mochaJs = require.resolve("mocha/bin/_mocha");
|
||||
|
||||
exports.localBaseline = "tests/baselines/local/";
|
||||
@@ -21,9 +22,9 @@ exports.localTest262Baseline = "internal/baselines/test262/local";
|
||||
* @param {string} defaultReporter
|
||||
* @param {boolean} runInParallel
|
||||
* @param {boolean} watchMode
|
||||
* @param {InstanceType<typeof import("./cancellation").CancelToken>} [cancelToken]
|
||||
* @param {import("prex").CancellationToken} [cancelToken]
|
||||
*/
|
||||
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken) {
|
||||
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken = CancellationToken.none) {
|
||||
let testTimeout = cmdLineOptions.timeout;
|
||||
let tests = cmdLineOptions.tests;
|
||||
const lintFlag = cmdLineOptions.lint;
|
||||
@@ -37,6 +38,7 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
|
||||
const keepFailed = cmdLineOptions.keepFailed;
|
||||
if (!cmdLineOptions.dirty) {
|
||||
await cleanTestDirs();
|
||||
cancelToken.throwIfCancellationRequested();
|
||||
}
|
||||
|
||||
if (fs.existsSync(testConfigFile)) {
|
||||
|
||||
+22
-24
@@ -236,8 +236,9 @@ namespace ts {
|
||||
if (symbolFlags & SymbolFlags.Value) {
|
||||
const { valueDeclaration } = symbol;
|
||||
if (!valueDeclaration ||
|
||||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
|
||||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
|
||||
// other kinds of value declarations take precedence over modules
|
||||
// other kinds of value declarations take precedence over modules and assignment declarations
|
||||
symbol.valueDeclaration = node;
|
||||
}
|
||||
}
|
||||
@@ -373,7 +374,8 @@ namespace ts {
|
||||
// prototype symbols like methods.
|
||||
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
|
||||
}
|
||||
else {
|
||||
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.JSContainer)) {
|
||||
// JSContainers are allowed to merge with variables, no matter what other flags they have.
|
||||
if (isNamedDeclaration(node)) {
|
||||
node.name.parent = node;
|
||||
}
|
||||
@@ -733,6 +735,8 @@ namespace ts {
|
||||
return isNarrowingBinaryExpression(<BinaryExpression>expr);
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
return (<PrefixUnaryExpression>expr).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((<PrefixUnaryExpression>expr).operand);
|
||||
case SyntaxKind.TypeOfExpression:
|
||||
return isNarrowingExpression((<TypeOfExpression>expr).expression);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1729,10 +1733,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindBlockScopedVariableDeclaration(node: Declaration) {
|
||||
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
|
||||
}
|
||||
|
||||
function delayedBindJSDocTypedefTag() {
|
||||
if (!delayedTypeAliases) {
|
||||
return;
|
||||
@@ -2078,8 +2078,8 @@ namespace ts {
|
||||
if (isInJavaScriptFile(node) &&
|
||||
file.commonJsModuleIndicator &&
|
||||
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
|
||||
!lookupSymbolForNameWorker(container, "module" as __String)) {
|
||||
declareSymbol(container.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
|
||||
!lookupSymbolForNameWorker(blockScopeContainer, "module" as __String)) {
|
||||
declareSymbol(file.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
|
||||
SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes);
|
||||
}
|
||||
break;
|
||||
@@ -2510,11 +2510,10 @@ namespace ts {
|
||||
|
||||
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
|
||||
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
|
||||
const isToplevelNamespaceableInitializer = isBinaryExpression(propertyAccess.parent)
|
||||
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile &&
|
||||
!!getJavascriptInitializer(getInitializerOfBinaryExpression(propertyAccess.parent), isPrototypeAccess(propertyAccess.parent.left))
|
||||
const isToplevel = isBinaryExpression(propertyAccess.parent)
|
||||
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
|
||||
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
|
||||
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevel) {
|
||||
// make symbols or add declarations for intermediate containers
|
||||
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
|
||||
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
|
||||
@@ -2537,12 +2536,10 @@ namespace ts {
|
||||
(namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
|
||||
(namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
|
||||
|
||||
// Declare the method/property
|
||||
const jsContainerFlag = isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0;
|
||||
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!);
|
||||
const symbolFlags = (isMethod ? SymbolFlags.Method : SymbolFlags.Property) | jsContainerFlag;
|
||||
const symbolExcludes = (isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes) & ~jsContainerFlag;
|
||||
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, symbolFlags, symbolExcludes);
|
||||
const includes = isMethod ? SymbolFlags.Method : SymbolFlags.Property;
|
||||
const excludes = isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes;
|
||||
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.JSContainer, excludes & ~SymbolFlags.JSContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2573,7 +2570,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getParentOfBinaryExpression(expr: BinaryExpression) {
|
||||
function getParentOfBinaryExpression(expr: Node) {
|
||||
while (isBinaryExpression(expr.parent)) {
|
||||
expr = expr.parent;
|
||||
}
|
||||
@@ -2660,8 +2657,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!isBindingPattern(node.name)) {
|
||||
const isEnum = !!getJSDocEnumTag(node);
|
||||
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
|
||||
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
|
||||
if (isBlockOrCatchScoped(node)) {
|
||||
bindBlockScopedVariableDeclaration(node);
|
||||
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable | enumFlags, SymbolFlags.BlockScopedVariableExcludes | enumExcludes);
|
||||
}
|
||||
else if (isParameterDeclaration(node)) {
|
||||
// It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
|
||||
@@ -2676,7 +2676,7 @@ namespace ts {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
|
||||
}
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes);
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable | enumFlags, SymbolFlags.FunctionScopedVariableExcludes | enumExcludes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2804,9 +2804,7 @@ namespace ts {
|
||||
// report error on class declarations
|
||||
node.kind === SyntaxKind.ClassDeclaration ||
|
||||
// report error on instantiated modules or const-enums only modules if preserveConstEnums is set
|
||||
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node)) ||
|
||||
// report error on regular enums and const enums if preserveConstEnums is set
|
||||
(isEnumDeclaration(node) && (!isEnumConst(node) || options.preserveConstEnums));
|
||||
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node));
|
||||
|
||||
if (reportError) {
|
||||
currentFlow = reportedUnreachableFlow;
|
||||
@@ -2851,7 +2849,7 @@ namespace ts {
|
||||
// As opposed to a pure declaration like an `interface`
|
||||
function isExecutableStatement(s: Statement): boolean {
|
||||
// Don't remove statements that can validly be used before they appear.
|
||||
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
|
||||
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) &&
|
||||
// `var x;` may declare a variable used above
|
||||
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
|
||||
}
|
||||
|
||||
+753
-400
File diff suppressed because it is too large
Load Diff
@@ -62,9 +62,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
/* @internal */
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
// CommandLine only options
|
||||
const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
@@ -78,6 +76,27 @@ namespace ts {
|
||||
shortName: "?",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "preserveWatchOutput",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: false,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
shortName: "w",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
},
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
// CommandLine only options
|
||||
...commonOptionsWithBuild,
|
||||
{
|
||||
name: "all",
|
||||
type: "boolean",
|
||||
@@ -125,21 +144,6 @@ namespace ts {
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
|
||||
},
|
||||
{
|
||||
name: "preserveWatchOutput",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: false,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
shortName: "w",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
},
|
||||
|
||||
// Basic
|
||||
{
|
||||
@@ -754,6 +758,38 @@ namespace ts {
|
||||
}
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const buildOpts: CommandLineOption[] = [
|
||||
...commonOptionsWithBuild,
|
||||
{
|
||||
name: "verbose",
|
||||
shortName: "v",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Enable_verbose_logging,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "dry",
|
||||
shortName: "d",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "force",
|
||||
shortName: "f",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "clean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Delete_the_outputs_of_all_projects,
|
||||
type: "boolean"
|
||||
}
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const typeAcquisitionDeclarations: CommandLineOption[] = [
|
||||
{
|
||||
@@ -815,10 +851,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getOptionNameMap(): OptionNameMap {
|
||||
if (optionNameMapCache) {
|
||||
return optionNameMapCache;
|
||||
}
|
||||
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function createOptionNameMap(optionDeclarations: ReadonlyArray<CommandLineOption>): OptionNameMap {
|
||||
const optionNameMap = createMap<CommandLineOption>();
|
||||
const shortOptionNames = createMap<string>();
|
||||
forEach(optionDeclarations, option => {
|
||||
@@ -828,8 +865,7 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
optionNameMapCache = { optionNameMap, shortOptionNames };
|
||||
return optionNameMapCache;
|
||||
return { optionNameMap, shortOptionNames };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -979,7 +1015,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
@@ -992,6 +1033,58 @@ namespace ts {
|
||||
return optionNameMap.get(optionName);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface ParsedBuildCommand {
|
||||
buildOptions: BuildOptions;
|
||||
projects: string[];
|
||||
errors: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function parseBuildCommand(args: string[]): ParsedBuildCommand {
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
let errors: Diagnostic[] | undefined;
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
projects.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
projects.push(".");
|
||||
}
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
}
|
||||
|
||||
return { buildOptions, projects, errors: errors || emptyArray };
|
||||
}
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
|
||||
|
||||
+4
-10
@@ -789,11 +789,8 @@ namespace ts {
|
||||
* @param comparer An optional `Comparer` used to sort entries before comparison, though the
|
||||
* result will remain in the original order in `array`.
|
||||
*/
|
||||
export function deduplicate<T>(array: ReadonlyArray<T>, equalityComparer?: EqualityComparer<T>, comparer?: Comparer<T>): T[];
|
||||
export function deduplicate<T>(array: ReadonlyArray<T> | undefined, equalityComparer?: EqualityComparer<T>, comparer?: Comparer<T>): T[] | undefined;
|
||||
export function deduplicate<T>(array: ReadonlyArray<T> | undefined, equalityComparer: EqualityComparer<T>, comparer?: Comparer<T>): T[] | undefined {
|
||||
return !array ? undefined :
|
||||
array.length === 0 ? [] :
|
||||
export function deduplicate<T>(array: ReadonlyArray<T>, equalityComparer: EqualityComparer<T>, comparer?: Comparer<T>): T[] {
|
||||
return array.length === 0 ? [] :
|
||||
array.length === 1 ? array.slice() :
|
||||
comparer ? deduplicateRelational(array, equalityComparer, comparer) :
|
||||
deduplicateEquality(array, equalityComparer);
|
||||
@@ -802,10 +799,7 @@ namespace ts {
|
||||
/**
|
||||
* Deduplicates an array that has already been sorted.
|
||||
*/
|
||||
function deduplicateSorted<T>(array: ReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): T[];
|
||||
function deduplicateSorted<T>(array: ReadonlyArray<T> | undefined, comparer: EqualityComparer<T> | Comparer<T>): T[] | undefined;
|
||||
function deduplicateSorted<T>(array: ReadonlyArray<T> | undefined, comparer: EqualityComparer<T> | Comparer<T>): T[] | undefined {
|
||||
if (!array) return undefined;
|
||||
function deduplicateSorted<T>(array: ReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): T[] {
|
||||
if (array.length === 0) return [];
|
||||
|
||||
let last = array[0];
|
||||
@@ -1272,7 +1266,7 @@ namespace ts {
|
||||
if (!left || !right) return false;
|
||||
for (const key in left) {
|
||||
if (hasOwnProperty.call(left, key)) {
|
||||
if (!hasOwnProperty.call(right, key) === undefined) return false;
|
||||
if (!hasOwnProperty.call(right, key)) return false;
|
||||
if (!equalityComparer(left[key], right[key])) return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,6 +991,22 @@
|
||||
"category": "Error",
|
||||
"code": 1345
|
||||
},
|
||||
"This parameter is not allowed with 'use strict' directive.": {
|
||||
"category": "Error",
|
||||
"code": 1346
|
||||
},
|
||||
"'use strict' directive cannot be used with non-simple parameter list.": {
|
||||
"category": "Error",
|
||||
"code": 1347
|
||||
},
|
||||
"Non-simple parameter declared here.": {
|
||||
"category": "Error",
|
||||
"code": 1348
|
||||
},
|
||||
"'use strict' directive used here.": {
|
||||
"category": "Error",
|
||||
"code": 1349
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@@ -2437,6 +2453,10 @@
|
||||
"category": "Error",
|
||||
"code": 2732
|
||||
},
|
||||
"Index '{0}' is out-of-bounds in tuple of length {1}.": {
|
||||
"category": "Error",
|
||||
"code": 2733
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -2892,10 +2912,15 @@
|
||||
"category": "Error",
|
||||
"code": 5070
|
||||
},
|
||||
"Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs'.": {
|
||||
"Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs', 'amd', 'es2015' or 'esNext'.": {
|
||||
"category": "Error",
|
||||
"code": 5071
|
||||
},
|
||||
"Unknown build option '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -1780,7 +1780,9 @@ namespace ts {
|
||||
|
||||
function emitExpressionStatement(node: ExpressionStatement) {
|
||||
emitExpression(node.expression);
|
||||
if (!isJsonSourceFile(currentSourceFile)) {
|
||||
// Emit semicolon in non json files
|
||||
// or if json file that created synthesized expression(eg.define expression statement when --out and amd code generation)
|
||||
if (!isJsonSourceFile(currentSourceFile) || nodeIsSynthesized(node.expression)) {
|
||||
writeSemicolon();
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -3894,6 +3894,20 @@ namespace ts {
|
||||
return statementOffset;
|
||||
}
|
||||
|
||||
export function findUseStrictPrologue(statements: ReadonlyArray<Statement>): Statement | undefined {
|
||||
for (const statement of statements) {
|
||||
if (isPrologueDirective(statement)) {
|
||||
if (isUseStrictPrologue(statement)) {
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function startsWithUseStrict(statements: ReadonlyArray<Statement>) {
|
||||
const firstStatement = firstOrUndefined(statements);
|
||||
return firstStatement !== undefined
|
||||
@@ -3907,18 +3921,7 @@ namespace ts {
|
||||
* @param statements An array of statements
|
||||
*/
|
||||
export function ensureUseStrict(statements: NodeArray<Statement>): NodeArray<Statement> {
|
||||
let foundUseStrict = false;
|
||||
for (const statement of statements) {
|
||||
if (isPrologueDirective(statement)) {
|
||||
if (isUseStrictPrologue(statement as ExpressionStatement)) {
|
||||
foundUseStrict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const foundUseStrict = findUseStrictPrologue(statements);
|
||||
|
||||
if (!foundUseStrict) {
|
||||
return setTextRange(
|
||||
|
||||
+125
-152
@@ -1,8 +1,52 @@
|
||||
// Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
|
||||
/* @internal */
|
||||
namespace ts.moduleSpecifiers {
|
||||
export interface ModuleSpecifierPreferences {
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
const enum RelativePreference { Relative, NonRelative, Auto }
|
||||
// See UserPreferences#importPathEnding
|
||||
const enum Ending { Minimal, Index, JsExtension }
|
||||
|
||||
// Processed preferences
|
||||
interface Preferences {
|
||||
readonly relativePreference: RelativePreference;
|
||||
readonly ending: Ending;
|
||||
}
|
||||
|
||||
function getPreferences({ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences {
|
||||
return {
|
||||
relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : RelativePreference.Auto,
|
||||
ending: getEnding(),
|
||||
};
|
||||
function getEnding(): Ending {
|
||||
switch (importModuleSpecifierEnding) {
|
||||
case "minimal": return Ending.Minimal;
|
||||
case "index": return Ending.Index;
|
||||
case "js": return Ending.JsExtension;
|
||||
default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
|
||||
return {
|
||||
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
|
||||
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateModuleSpecifier(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
oldImportSpecifier: string,
|
||||
): string | undefined {
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferencesForUpdate(compilerOptions, oldImportSpecifier));
|
||||
if (res === oldImportSpecifier) return undefined;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Note: importingSourceFile is just for usesJsExtensionOnImports
|
||||
@@ -13,158 +57,98 @@ namespace ts.moduleSpecifiers {
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences = {},
|
||||
preferences: UserPreferences = {},
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): string {
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferences(preferences, compilerOptions, importingSourceFile));
|
||||
}
|
||||
|
||||
export function getModuleSpecifierForDeclarationFile(
|
||||
moduleSymbol: Symbol,
|
||||
function getModuleSpecifierWorker(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
preferences: Preferences
|
||||
): string {
|
||||
const isBundle = (compilerOptions.out || compilerOptions.outFile);
|
||||
if (isBundle && host.getCommonSourceDirectory) {
|
||||
// For declaration bundles, we need to generate absolute paths relative to the common source dir for imports,
|
||||
// just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this
|
||||
// using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative
|
||||
// specifier preference
|
||||
compilerOptions = {
|
||||
...compilerOptions,
|
||||
baseUrl: host.getCommonSourceDirectory(),
|
||||
};
|
||||
}
|
||||
const preferences: ModuleSpecifierPreferences = { importModuleSpecifierPreference: isBundle ? "non-relative" : "relative" };
|
||||
return first(first(getModuleSpecifiers(moduleSymbol, compilerOptions, importingSourceFile, host, host.getSourceFiles ? host.getSourceFiles() : [importingSourceFile], preferences, redirectTargetsMap)));
|
||||
const info = getInfo(importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions)) ||
|
||||
getLocalModuleSpecifier(toFileName, info, compilerOptions, preferences);
|
||||
}
|
||||
|
||||
// For each symlink/original for a module, returns a list of ways to import that file.
|
||||
// Returns an import for each symlink and for the realpath.
|
||||
export function getModuleSpecifiers(
|
||||
moduleSymbol: Symbol,
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
userPreferences: UserPreferences,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): ReadonlyArray<ReadonlyArray<string>> {
|
||||
): ReadonlyArray<string> {
|
||||
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
|
||||
if (ambient) return [[ambient]];
|
||||
if (ambient) return [ambient];
|
||||
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.path, host);
|
||||
if (!files) {
|
||||
return Debug.fail("Files list must be present to resolve symlinks in specifier resolution");
|
||||
}
|
||||
const info = getInfo(importingSourceFile.path, host);
|
||||
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
|
||||
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
|
||||
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
|
||||
getLocalModuleSpecifiers(moduleFileName, info, compilerOptions, preferences));
|
||||
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
|
||||
const global = mapDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions));
|
||||
return global.length ? global : modulePaths.map(moduleFileName => getLocalModuleSpecifier(moduleFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
interface Info {
|
||||
readonly moduleResolutionKind: ModuleResolutionKind;
|
||||
readonly addJsExtension: boolean;
|
||||
readonly getCanonicalFileName: GetCanonicalFileName;
|
||||
readonly sourceDirectory: Path;
|
||||
}
|
||||
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
|
||||
function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
|
||||
function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
|
||||
const sourceDirectory = getDirectoryPath(importingSourceFileName);
|
||||
return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory };
|
||||
return { getCanonicalFileName, sourceDirectory };
|
||||
}
|
||||
|
||||
function getGlobalModuleSpecifier(
|
||||
moduleFileName: string,
|
||||
{ addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
compilerOptions: CompilerOptions,
|
||||
) {
|
||||
return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|
||||
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory);
|
||||
}
|
||||
|
||||
function getLocalModuleSpecifiers(
|
||||
moduleFileName: string,
|
||||
{ moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
compilerOptions: CompilerOptions,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
): ReadonlyArray<string> {
|
||||
function getLocalModuleSpecifier(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): string {
|
||||
const { baseUrl, paths, rootDirs } = compilerOptions;
|
||||
|
||||
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
|
||||
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
|
||||
return [relativePath];
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
|
||||
if (!baseUrl || relativePreference === RelativePreference.Relative) {
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName);
|
||||
if (!relativeToBaseUrl) {
|
||||
return [relativePath];
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
|
||||
if (paths) {
|
||||
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
if (fromPaths) {
|
||||
return [fromPaths];
|
||||
}
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions);
|
||||
const fromPaths = paths && tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
const nonRelative = fromPaths === undefined ? importRelativeToBaseUrl : fromPaths;
|
||||
|
||||
if (relativePreference === RelativePreference.NonRelative) {
|
||||
return nonRelative;
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference === "non-relative") {
|
||||
return [importRelativeToBaseUrl];
|
||||
if (relativePreference !== RelativePreference.Auto) Debug.assertNever(relativePreference);
|
||||
|
||||
// Prefer a relative import over a baseUrl import if it has fewer components.
|
||||
return isPathRelativeToParent(nonRelative) || countPathComponents(relativePath) < countPathComponents(nonRelative) ? relativePath : nonRelative;
|
||||
}
|
||||
|
||||
function countPathComponents(path: string): number {
|
||||
let count = 0;
|
||||
for (let i = startsWith(path, "./") ? 2 : 0; i < path.length; i++) {
|
||||
if (path.charCodeAt(i) === CharacterCodes.slash) count++;
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
|
||||
|
||||
if (isPathRelativeToParent(relativeToBaseUrl)) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
/*
|
||||
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/a/b
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../../foo/bar
|
||||
getRelativePathNParents(relativePath) = 2
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
2 < 2 = false
|
||||
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/foo/a
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../a
|
||||
getRelativePathNParents(relativePath) = 1
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
1 < 2 = true
|
||||
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
|
||||
*/
|
||||
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
|
||||
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
|
||||
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
|
||||
return count;
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
|
||||
}
|
||||
|
||||
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
|
||||
@@ -232,15 +216,6 @@ namespace ts.moduleSpecifiers {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getRelativePathNParents(relativePath: string): number {
|
||||
const components = getPathComponents(relativePath);
|
||||
if (components[0] || components.length === 1) return 0;
|
||||
for (let i = 1; i < components.length; i++) {
|
||||
if (components[i] !== "..") return i - 1;
|
||||
}
|
||||
return components.length - 1;
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
|
||||
const decl = find(moduleSymbol.declarations,
|
||||
d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name)))
|
||||
@@ -283,37 +258,8 @@ namespace ts.moduleSpecifiers {
|
||||
return removeFileExtension(relativePath);
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
moduleFileName: string,
|
||||
addJsExtension: boolean,
|
||||
): string | undefined {
|
||||
const roots = getEffectiveTypeRoots(options, host);
|
||||
return firstDefined(roots, unNormalizedTypeRoot => {
|
||||
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
|
||||
if (startsWith(moduleFileName, typeRoot)) {
|
||||
// For a type definition, we can strip `/index` even with classic resolution.
|
||||
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(
|
||||
options: CompilerOptions,
|
||||
moduleFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
sourceDirectory: Path,
|
||||
): string | undefined {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
// nothing to do here
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
|
||||
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
|
||||
|
||||
if (!parts) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -325,8 +271,12 @@ namespace ts.moduleSpecifiers {
|
||||
// Get a path that's relative to node_modules or the importing file's path
|
||||
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
|
||||
if (!startsWith(sourceDirectory, getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)))) return undefined;
|
||||
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
|
||||
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
|
||||
const packageName = getPackageNameFromAtTypesDirectory(nodeModulesDirectoryName);
|
||||
// For classic resolution, only allow importing from node_modules/@types, not other node_modules
|
||||
return getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs && packageName === nodeModulesDirectoryName ? undefined : packageName;
|
||||
|
||||
function getDirectoryOrExtensionlessFileName(path: string): string {
|
||||
// If the file is the main module, it can be imported by the package name
|
||||
@@ -440,13 +390,36 @@ namespace ts.moduleSpecifiers {
|
||||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
|
||||
function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions): string {
|
||||
if (fileExtensionIs(fileName, Extension.Json)) return fileName;
|
||||
const noExtension = removeFileExtension(fileName);
|
||||
return addJsExtension
|
||||
? noExtension + ".js"
|
||||
: moduleResolutionKind === ModuleResolutionKind.NodeJs
|
||||
? removeSuffix(noExtension, "/index")
|
||||
: noExtension;
|
||||
switch (ending) {
|
||||
case Ending.Minimal:
|
||||
return removeSuffix(noExtension, "/index");
|
||||
case Ending.Index:
|
||||
return noExtension;
|
||||
case Ending.JsExtension:
|
||||
return noExtension + getJavaScriptExtensionForFile(fileName, options);
|
||||
default:
|
||||
return Debug.assertNever(ending);
|
||||
}
|
||||
}
|
||||
|
||||
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
case Extension.Dts:
|
||||
return Extension.Js;
|
||||
case Extension.Tsx:
|
||||
return options.jsx === JsxEmit.Preserve ? Extension.Jsx : Extension.Js;
|
||||
case Extension.Js:
|
||||
case Extension.Jsx:
|
||||
case Extension.Json:
|
||||
return ext;
|
||||
default:
|
||||
return Debug.assertNever(ext);
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
|
||||
+13
-4
@@ -86,6 +86,7 @@ namespace ts {
|
||||
visitNodes(cbNode, cbNodes, node.modifiers) ||
|
||||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
|
||||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
|
||||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).exclamationToken) ||
|
||||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
|
||||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
@@ -156,6 +157,7 @@ namespace ts {
|
||||
visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) ||
|
||||
visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
|
||||
visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
|
||||
visitNode(cbNode, (<FunctionLikeDeclaration>node).exclamationToken) ||
|
||||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
|
||||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
|
||||
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
|
||||
@@ -515,7 +517,7 @@ namespace ts {
|
||||
performance.mark("beforeParse");
|
||||
let result: SourceFile;
|
||||
if (languageVersion === ScriptTarget.JSON) {
|
||||
result = Parser.parseJsonText(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes);
|
||||
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON);
|
||||
}
|
||||
else {
|
||||
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
|
||||
@@ -689,8 +691,12 @@ namespace ts {
|
||||
if (scriptKind === ScriptKind.JSON) {
|
||||
const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
|
||||
convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
|
||||
result.referencedFiles = emptyArray;
|
||||
result.typeReferenceDirectives = emptyArray;
|
||||
result.libReferenceDirectives = emptyArray;
|
||||
result.amdDependencies = emptyArray;
|
||||
result.hasNoDefaultLib = false;
|
||||
result.pragmas = emptyMap;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2377,8 +2383,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseJSDocType(): TypeNode {
|
||||
scanner.setInJSDocType(true);
|
||||
const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
let type = parseTypeOrTypePredicate();
|
||||
scanner.setInJSDocType(false);
|
||||
if (dotdotdot) {
|
||||
const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType;
|
||||
variadic.type = type;
|
||||
@@ -4713,8 +4721,10 @@ namespace ts {
|
||||
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
|
||||
const tokenIsIdentifier = isIdentifier();
|
||||
node.name = parsePropertyName();
|
||||
// Disallowing of optional property assignments happens in the grammar checker.
|
||||
// Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
|
||||
(<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
(<MethodDeclaration>node).exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
|
||||
|
||||
if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
|
||||
return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken);
|
||||
}
|
||||
@@ -6858,7 +6868,7 @@ namespace ts {
|
||||
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
skipWhitespaceOrAsterisk();
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
@@ -7760,7 +7770,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;
|
||||
|
||||
/*@internal*/
|
||||
|
||||
+56
-62
@@ -67,19 +67,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
|
||||
return createCompilerHostWorker(options, setParentNodes);
|
||||
}
|
||||
/*@internal*/
|
||||
// TODO(shkamat): update this after reworking ts build API
|
||||
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
||||
const existingDirectories = createMap<boolean>();
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
|
||||
let text: string | undefined;
|
||||
try {
|
||||
performance.mark("beforeIORead");
|
||||
text = sys.readFile(fileName, options.charset);
|
||||
text = system.readFile(fileName, options.charset);
|
||||
performance.mark("afterIORead");
|
||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||
}
|
||||
@@ -97,7 +102,7 @@ namespace ts {
|
||||
if (existingDirectories.has(directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
if (system.directoryExists(directoryPath)) {
|
||||
existingDirectories.set(directoryPath, true);
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +113,7 @@ namespace ts {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
system.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +124,8 @@ namespace ts {
|
||||
outputFingerprints = createMap<OutputFingerprint>();
|
||||
}
|
||||
|
||||
const hash = sys.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
const hash = system.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
|
||||
if (mtimeBefore) {
|
||||
const fingerprint = outputFingerprints.get(fileName);
|
||||
@@ -133,9 +138,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
|
||||
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
|
||||
outputFingerprints.set(fileName, {
|
||||
hash,
|
||||
@@ -149,11 +154,11 @@ namespace ts {
|
||||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
|
||||
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
|
||||
writeFileIfUpdated(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
else {
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
@@ -167,32 +172,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDefaultLibLocation(): string {
|
||||
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
|
||||
const newLine = getNewLineCharacter(options, () => system.newLine);
|
||||
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
writeFile,
|
||||
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => sys.getDirectories(path),
|
||||
fileExists: fileName => system.fileExists(fileName),
|
||||
readFile: fileName => system.readFile(fileName),
|
||||
trace: (s: string) => system.write(s + newLine),
|
||||
directoryExists: directoryName => system.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => system.getDirectories(path),
|
||||
realpath,
|
||||
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
|
||||
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
|
||||
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
|
||||
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
|
||||
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -951,8 +953,11 @@ namespace ts {
|
||||
// If we change our policy of rechecking failed lookups on each program create,
|
||||
// we should adjust the value returned here.
|
||||
function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string, oldProgramState: OldProgramState): boolean {
|
||||
if (!oldProgramState.program) {
|
||||
return false;
|
||||
}
|
||||
const resolutionToFile = getResolvedModule(oldProgramState.oldSourceFile!, moduleName); // TODO: GH#18217
|
||||
const resolvedFile = resolutionToFile && oldProgramState.program && oldProgramState.program.getSourceFile(resolutionToFile.resolvedFileName);
|
||||
const resolvedFile = resolutionToFile && oldProgramState.program.getSourceFile(resolutionToFile.resolvedFileName);
|
||||
if (resolutionToFile && resolvedFile && !resolvedFile.externalModuleIndicator) {
|
||||
// In the old program, we resolved to an ambient module that was in the same
|
||||
// place as we expected to find an actual module file.
|
||||
@@ -960,16 +965,11 @@ namespace ts {
|
||||
// because the normal module resolution algorithm will find this anyway.
|
||||
return false;
|
||||
}
|
||||
const ambientModule = oldProgramState.program && oldProgramState.program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(moduleName);
|
||||
if (!(ambientModule && ambientModule.declarations)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// at least one of declarations should come from non-modified source file
|
||||
const firstUnmodifiedFile = forEach(ambientModule.declarations, d => {
|
||||
const f = getSourceFileOfNode(d);
|
||||
return !contains(oldProgramState.modifiedFilePaths, f.path) && f;
|
||||
});
|
||||
const firstUnmodifiedFile = oldProgramState.program.getSourceFiles().find(
|
||||
f => !contains(oldProgramState.modifiedFilePaths, f.path) && contains(f.ambientModuleNames, moduleName)
|
||||
);
|
||||
|
||||
if (!firstUnmodifiedFile) {
|
||||
return false;
|
||||
@@ -1178,7 +1178,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
if (resolveTypeReferenceDirectiveNamesWorker) {
|
||||
const typesReferenceDirectives = map(newSourceFile.typeReferenceDirectives, x => x.fileName);
|
||||
// We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
|
||||
const typesReferenceDirectives = map(newSourceFile.typeReferenceDirectives, ref => ref.fileName.toLocaleLowerCase());
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFilePath);
|
||||
// ensure that types resolutions are still correct
|
||||
const resolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, resolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo);
|
||||
@@ -1257,8 +1258,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getProjectReferences() {
|
||||
if (!resolvedProjectReferences) return;
|
||||
|
||||
return resolvedProjectReferences;
|
||||
}
|
||||
|
||||
@@ -2319,27 +2318,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
|
||||
const fileNames: string[] = [];
|
||||
for (const file of sourceFiles) {
|
||||
if (!file.isDeclarationFile) {
|
||||
fileNames.push(file.fileName);
|
||||
}
|
||||
}
|
||||
const fileNames = mapDefined(sourceFiles, file => file.isDeclarationFile ? undefined : file.fileName);
|
||||
return computeCommonSourceDirectoryOfFilenames(fileNames, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean {
|
||||
function checkSourceFilesBelongToPath(sourceFiles: ReadonlyArray<SourceFile>, rootDirectory: string): boolean {
|
||||
let allFilesBelongToPath = true;
|
||||
if (sourceFiles) {
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2439,12 +2431,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
// List of collected files is complete; validate exhautiveness if this is a project with a file list
|
||||
if (options.composite && rootNames.length < files.length) {
|
||||
const normalizedRootNames = rootNames.map(r => normalizePath(r).toLowerCase());
|
||||
const sourceFiles = files.filter(f => !f.isDeclarationFile).map(f => normalizePath(f.path).toLowerCase());
|
||||
for (const file of sourceFiles) {
|
||||
if (normalizedRootNames.every(r => r !== file)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern, file));
|
||||
if (options.composite) {
|
||||
const sourceFiles = files.filter(f => !f.isDeclarationFile);
|
||||
if (rootNames.length < sourceFiles.length) {
|
||||
const normalizedRootNames = rootNames.map(r => normalizePath(r).toLowerCase());
|
||||
for (const file of sourceFiles.map(f => normalizePath(f.path).toLowerCase())) {
|
||||
if (normalizedRootNames.indexOf(file) === -1) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2556,9 +2550,9 @@ namespace ts {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule");
|
||||
}
|
||||
// Any emit other than common js is error
|
||||
else if (getEmitModuleKind(options) !== ModuleKind.CommonJS) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs, "resolveJsonModule", "module");
|
||||
// Any emit other than common js, amd, es2015 or esnext is error
|
||||
else if (!hasJsonModuleEmitEnabled(options)) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, "resolveJsonModule", "module");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ namespace ts {
|
||||
setScriptTarget(scriptTarget: ScriptTarget): void;
|
||||
setLanguageVariant(variant: LanguageVariant): void;
|
||||
setTextPos(textPos: number): void;
|
||||
/* @internal */
|
||||
setInJSDocType(inType: boolean): void;
|
||||
// Invokes the provided callback then unconditionally restores the scanner to the state it
|
||||
// was in immediately prior to invoking the callback. The result of invoking the callback
|
||||
// is returned from this function.
|
||||
@@ -825,6 +827,8 @@ namespace ts {
|
||||
let tokenValue!: string;
|
||||
let tokenFlags: TokenFlags;
|
||||
|
||||
let inJSDocType = 0;
|
||||
|
||||
setText(text, start, length);
|
||||
|
||||
return {
|
||||
@@ -856,6 +860,7 @@ namespace ts {
|
||||
setLanguageVariant,
|
||||
setOnError,
|
||||
setTextPos,
|
||||
setInJSDocType,
|
||||
tryScan,
|
||||
lookAhead,
|
||||
scanRange,
|
||||
@@ -1352,6 +1357,7 @@ namespace ts {
|
||||
function scan(): SyntaxKind {
|
||||
startPos = pos;
|
||||
tokenFlags = 0;
|
||||
let asteriskSeen = false;
|
||||
while (true) {
|
||||
tokenPos = pos;
|
||||
if (pos >= end) {
|
||||
@@ -1392,6 +1398,24 @@ namespace ts {
|
||||
case CharacterCodes.verticalTab:
|
||||
case CharacterCodes.formFeed:
|
||||
case CharacterCodes.space:
|
||||
case CharacterCodes.nonBreakingSpace:
|
||||
case CharacterCodes.ogham:
|
||||
case CharacterCodes.enQuad:
|
||||
case CharacterCodes.emQuad:
|
||||
case CharacterCodes.enSpace:
|
||||
case CharacterCodes.emSpace:
|
||||
case CharacterCodes.threePerEmSpace:
|
||||
case CharacterCodes.fourPerEmSpace:
|
||||
case CharacterCodes.sixPerEmSpace:
|
||||
case CharacterCodes.figureSpace:
|
||||
case CharacterCodes.punctuationSpace:
|
||||
case CharacterCodes.thinSpace:
|
||||
case CharacterCodes.hairSpace:
|
||||
case CharacterCodes.zeroWidthSpace:
|
||||
case CharacterCodes.narrowNoBreakSpace:
|
||||
case CharacterCodes.mathematicalSpace:
|
||||
case CharacterCodes.ideographicSpace:
|
||||
case CharacterCodes.byteOrderMark:
|
||||
if (skipTrivia) {
|
||||
pos++;
|
||||
continue;
|
||||
@@ -1449,6 +1473,11 @@ namespace ts {
|
||||
return pos += 2, token = SyntaxKind.AsteriskAsteriskToken;
|
||||
}
|
||||
pos++;
|
||||
if (inJSDocType && !asteriskSeen && (tokenFlags & TokenFlags.PrecedingLineBreak)) {
|
||||
// decoration at the start of a JSDoc comment line
|
||||
asteriskSeen = true;
|
||||
continue;
|
||||
}
|
||||
return token = SyntaxKind.AsteriskToken;
|
||||
case CharacterCodes.plus:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.plus) {
|
||||
@@ -2088,5 +2117,9 @@ namespace ts {
|
||||
tokenValue = undefined!;
|
||||
tokenFlags = 0;
|
||||
}
|
||||
|
||||
function setInJSDocType(inType: boolean) {
|
||||
inJSDocType += inType ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,7 +971,7 @@ namespace ts {
|
||||
}
|
||||
case SyntaxKind.FunctionDeclaration: {
|
||||
// Generators lose their generator-ness, excepting their return type
|
||||
return cleanup(updateFunctionDeclaration(
|
||||
const clean = cleanup(updateFunctionDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
ensureModifiers(input, isPrivate),
|
||||
@@ -982,6 +982,21 @@ namespace ts {
|
||||
ensureType(input, input.type),
|
||||
/*body*/ undefined
|
||||
));
|
||||
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
|
||||
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
|
||||
if (!isPropertyAccessExpression(p.valueDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
|
||||
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
|
||||
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
|
||||
});
|
||||
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
|
||||
return [clean, namespaceDecl];
|
||||
}
|
||||
else {
|
||||
return clean;
|
||||
}
|
||||
}
|
||||
case SyntaxKind.ModuleDeclaration: {
|
||||
needsDeclare = false;
|
||||
@@ -1309,12 +1324,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration;
|
||||
function canHaveLiteralInitializer(node: Node): node is CanHaveLiteralInitializer {
|
||||
function canHaveLiteralInitializer(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
return !hasModifier(node, ModifierFlags.Private);
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -2060,14 +2060,11 @@ namespace ts {
|
||||
setTextRange(declarationList, node);
|
||||
setCommentRange(declarationList, node);
|
||||
|
||||
// If the first or last declaration is a binding pattern, we need to modify
|
||||
// the source map range for the declaration list.
|
||||
if (node.transformFlags & TransformFlags.ContainsBindingPattern
|
||||
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(last(node.declarations).name))) {
|
||||
// If the first or last declaration is a binding pattern, we need to modify
|
||||
// the source map range for the declaration list.
|
||||
const firstDeclaration = firstOrUndefined(declarations);
|
||||
if (firstDeclaration) {
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, last(declarations).end));
|
||||
}
|
||||
setSourceMapRange(declarationList, getRangeUnion(declarations));
|
||||
}
|
||||
|
||||
return declarationList;
|
||||
@@ -2075,6 +2072,17 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function getRangeUnion(declarations: ReadonlyArray<Node>): TextRange {
|
||||
// declarations may not be sorted by position.
|
||||
// pos should be the minimum* position over all nodes (that's not -1), end should be the maximum end over all nodes.
|
||||
let pos = -1, end = -1;
|
||||
for (const node of declarations) {
|
||||
pos = pos === -1 ? node.pos : node.pos === -1 ? pos : Math.min(pos, node.pos);
|
||||
end = Math.max(end, node.end);
|
||||
}
|
||||
return createRange(pos, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether we should emit an explicit initializer for a variable
|
||||
* declaration in a `let` declaration list.
|
||||
|
||||
@@ -53,7 +53,10 @@ namespace ts {
|
||||
* @param node The SourceFile node.
|
||||
*/
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile || !(isEffectiveExternalModule(node, compilerOptions) || node.transformFlags & TransformFlags.ContainsDynamicImport)) {
|
||||
if (node.isDeclarationFile ||
|
||||
!(isEffectiveExternalModule(node, compilerOptions) ||
|
||||
node.transformFlags & TransformFlags.ContainsDynamicImport ||
|
||||
(isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && (compilerOptions.out || compilerOptions.outFile)))) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -117,6 +120,7 @@ namespace ts {
|
||||
function transformAMDModule(node: SourceFile) {
|
||||
const define = createIdentifier("define");
|
||||
const moduleName = tryGetModuleNameFromFile(node, host, compilerOptions);
|
||||
const jsonSourceFile = isJsonSourceFile(node) && node;
|
||||
|
||||
// An AMD define function has the following shape:
|
||||
//
|
||||
@@ -158,7 +162,7 @@ namespace ts {
|
||||
// Add the dependency array argument:
|
||||
//
|
||||
// ["require", "exports", module1", "module2", ...]
|
||||
createArrayLiteral([
|
||||
createArrayLiteral(jsonSourceFile ? emptyArray : [
|
||||
createLiteral("require"),
|
||||
createLiteral("exports"),
|
||||
...aliasedModuleNames,
|
||||
@@ -168,7 +172,9 @@ namespace ts {
|
||||
// Add the module body function argument:
|
||||
//
|
||||
// function (require, exports, module1, module2) ...
|
||||
createFunctionExpression(
|
||||
jsonSourceFile ?
|
||||
jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression : createObjectLiteral() :
|
||||
createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
/*name*/ undefined,
|
||||
|
||||
+413
-407
File diff suppressed because it is too large
Load Diff
+37
-26
@@ -739,6 +739,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface ComputedPropertyName extends Node {
|
||||
parent: Declaration;
|
||||
kind: SyntaxKind.ComputedPropertyName;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -883,6 +884,7 @@ namespace ts {
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
// used when ObjectLiteralExpression is used in ObjectAssignmentPattern
|
||||
// it is grammar error to appear in actual object initializer
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
@@ -941,6 +943,7 @@ namespace ts {
|
||||
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
body?: Block | Expression;
|
||||
}
|
||||
|
||||
@@ -2632,7 +2635,7 @@ namespace ts {
|
||||
/* @internal */ ambientModuleNames: ReadonlyArray<string>;
|
||||
/* @internal */ checkJsDirective?: CheckJsDirective;
|
||||
/* @internal */ version: string;
|
||||
/* @internal */ pragmas: PragmaMap;
|
||||
/* @internal */ pragmas: ReadonlyPragmaMap;
|
||||
/* @internal */ localJsxNamespace?: __String;
|
||||
/* @internal */ localJsxFactory?: EntityName;
|
||||
|
||||
@@ -3097,6 +3100,10 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
|
||||
/* @internal */ getTypePredicateOfSignature(signature: Signature): TypePredicate;
|
||||
/**
|
||||
* An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
* and an external module with no 'export =' declaration resolves to the module itself.
|
||||
*/
|
||||
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
|
||||
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
|
||||
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
|
||||
@@ -3114,6 +3121,8 @@ namespace ts {
|
||||
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
|
||||
*/
|
||||
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
|
||||
|
||||
/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3374,7 +3383,9 @@ namespace ts {
|
||||
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
|
||||
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
|
||||
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
|
||||
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
|
||||
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
|
||||
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): Expression;
|
||||
@@ -3433,8 +3444,8 @@ namespace ts {
|
||||
|
||||
Enum = RegularEnum | ConstEnum,
|
||||
Variable = FunctionScopedVariable | BlockScopedVariable,
|
||||
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
|
||||
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias | JSContainer,
|
||||
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
|
||||
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | JSContainer,
|
||||
Namespace = ValueModule | NamespaceModule | Enum,
|
||||
Module = ValueModule | NamespaceModule,
|
||||
Accessor = GetAccessor | SetAccessor,
|
||||
@@ -3455,7 +3466,7 @@ namespace ts {
|
||||
InterfaceExcludes = Type & ~(Interface | Class),
|
||||
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
|
||||
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
|
||||
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),
|
||||
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule | JSContainer),
|
||||
NamespaceModuleExcludes = 0,
|
||||
MethodExcludes = Value & ~Method,
|
||||
GetAccessorExcludes = Value & ~SetAccessor,
|
||||
@@ -4167,9 +4178,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const enum InferenceFlags {
|
||||
None = 0, // No special inference behaviors
|
||||
InferUnionTypes = 1 << 0, // Infer union types for disjoint candidates (otherwise unknownType)
|
||||
NoDefault = 1 << 1, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
|
||||
AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType)
|
||||
NoDefault = 1 << 0, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
|
||||
AnyDefault = 1 << 1, // Infer anyType for no inferences (otherwise emptyObjectType)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4715,16 +4725,6 @@ namespace ts {
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface UpToDateHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
getModifiedTime(fileName: string): Date | undefined;
|
||||
getUnchangedTime?(fileName: string): Date | undefined;
|
||||
getLastStatus?(fileName: string): UpToDateStatus | undefined;
|
||||
setLastStatus?(fileName: string, status: UpToDateStatus): void;
|
||||
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
|
||||
}
|
||||
|
||||
export interface ModuleResolutionHost {
|
||||
// TODO: GH#18217 Optional methods frequently used as non-optional
|
||||
|
||||
@@ -4855,10 +4855,6 @@ namespace ts {
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
createHash?(data: string): string;
|
||||
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -5343,8 +5339,6 @@ namespace ts {
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
fileExists?(path: string): boolean;
|
||||
readFile?(path: string): string | undefined;
|
||||
getSourceFiles?(): ReadonlyArray<SourceFile>; // Used for cached resolutions to find symlinks without traversing the fs (again)
|
||||
getCommonSourceDirectory?(): string;
|
||||
}
|
||||
|
||||
// Note: this used to be deprecated in our public API, but is still used internally
|
||||
@@ -5357,7 +5351,7 @@ namespace ts {
|
||||
reportInaccessibleThisError?(): void;
|
||||
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
|
||||
reportInaccessibleUniqueSymbolError?(): void;
|
||||
moduleResolverHost?: ModuleSpecifierResolutionHost;
|
||||
moduleResolverHost?: EmitHost;
|
||||
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
|
||||
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
|
||||
}
|
||||
@@ -5596,15 +5590,32 @@ namespace ts {
|
||||
/* @internal */
|
||||
export type PragmaPsuedoMapEntry = {[K in keyof PragmaPsuedoMap]: {name: K, args: PragmaPsuedoMap[K]}}[keyof PragmaPsuedoMap];
|
||||
|
||||
/* @internal */
|
||||
export interface ReadonlyPragmaMap extends ReadonlyMap<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
|
||||
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
|
||||
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A strongly-typed es6 map of pragma entries, the values of which are either a single argument
|
||||
* value (if only one was found), or an array of multiple argument values if the pragma is present
|
||||
* in multiple places
|
||||
*/
|
||||
/* @internal */
|
||||
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
|
||||
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]>, ReadonlyPragmaMap {
|
||||
set<TKey extends keyof PragmaPsuedoMap>(key: TKey, value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][]): this;
|
||||
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
|
||||
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
+129
-37
@@ -16,7 +16,7 @@ namespace ts {
|
||||
namespace ts {
|
||||
export const emptyArray: never[] = [] as never[];
|
||||
export const resolvingEmptyArray: never[] = [] as never[];
|
||||
export const emptyMap: ReadonlyMap<never> = createMap<never>();
|
||||
export const emptyMap = createMap<never>() as ReadonlyMap<never> & ReadonlyPragmaMap;
|
||||
export const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap<never> = emptyMap as ReadonlyUnderscoreEscapedMap<never>;
|
||||
|
||||
export const externalHelpersModuleNameText = "tslib";
|
||||
@@ -490,12 +490,23 @@ namespace ts {
|
||||
return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia);
|
||||
}
|
||||
|
||||
function isJSDocTypeExpressionOrChild(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.JSDocTypeExpression || (node.parent && isJSDocTypeExpressionOrChild(node.parent));
|
||||
}
|
||||
|
||||
export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string {
|
||||
if (nodeIsMissing(node)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end);
|
||||
let text = sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end);
|
||||
|
||||
if (isJSDocTypeExpressionOrChild(node)) {
|
||||
// strip space + asterisk at line start
|
||||
text = text.replace(/(^|\r?\n|\r)\s*\*\s*/g, "$1");
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function getTextOfNode(node: Node, includeTrivia = false): string {
|
||||
@@ -911,6 +922,10 @@ namespace ts {
|
||||
return !!(getCombinedModifierFlags(node) & ModifierFlags.Const);
|
||||
}
|
||||
|
||||
export function isDeclarationReadonly(declaration: Declaration): boolean {
|
||||
return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration));
|
||||
}
|
||||
|
||||
export function isVarConst(node: VariableDeclaration | VariableDeclarationList): boolean {
|
||||
return !!(getCombinedNodeFlags(node) & NodeFlags.Const);
|
||||
}
|
||||
@@ -1762,6 +1777,10 @@ namespace ts {
|
||||
return decl;
|
||||
}
|
||||
|
||||
export function isAssignmentDeclaration(decl: Declaration) {
|
||||
return isBinaryExpression(decl) || isPropertyAccessExpression(decl) || isIdentifier(decl);
|
||||
}
|
||||
|
||||
/** Get the initializer, taking into account defaulted Javascript initializers */
|
||||
export function getEffectiveInitializer(node: HasExpressionInitializer) {
|
||||
if (isInJavaScriptFile(node) && node.initializer &&
|
||||
@@ -2112,6 +2131,10 @@ namespace ts {
|
||||
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
|
||||
break;
|
||||
}
|
||||
if (node.kind === SyntaxKind.TypeParameter) {
|
||||
result = addRange(result, getJSDocTypeParameterTags(node as TypeParameterDeclaration));
|
||||
break;
|
||||
}
|
||||
node = getNextJSDocCommentLocation(node);
|
||||
}
|
||||
return result || emptyArray;
|
||||
@@ -2331,6 +2354,13 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function skipParenthesesUp(node: Node): Node {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
node = node.parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
|
||||
export function isDeleteTarget(node: Node): boolean {
|
||||
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
|
||||
@@ -2354,29 +2384,33 @@ namespace ts {
|
||||
}
|
||||
|
||||
// See GH#16030
|
||||
export function isAnyDeclarationName(name: Node): boolean {
|
||||
export function getDeclarationFromName(name: Node): Declaration | undefined {
|
||||
const parent = name.parent;
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral: {
|
||||
const parent = name.parent;
|
||||
case SyntaxKind.NumericLiteral:
|
||||
if (isComputedPropertyName(parent)) return parent.parent;
|
||||
// falls through
|
||||
|
||||
case SyntaxKind.Identifier:
|
||||
if (isDeclaration(parent)) {
|
||||
return parent.name === name;
|
||||
return parent.name === name ? parent : undefined;
|
||||
}
|
||||
else if (isQualifiedName(name.parent)) {
|
||||
const tag = name.parent.parent;
|
||||
return isJSDocParameterTag(tag) && tag.name === name.parent;
|
||||
else if (isQualifiedName(parent)) {
|
||||
const tag = parent.parent;
|
||||
return isJSDocParameterTag(tag) && tag.name === parent ? tag : undefined;
|
||||
}
|
||||
else {
|
||||
const binExp = name.parent.parent;
|
||||
const binExp = parent.parent;
|
||||
return isBinaryExpression(binExp) &&
|
||||
getSpecialPropertyAssignmentKind(binExp) !== SpecialPropertyAssignmentKind.None &&
|
||||
(binExp.left.symbol || binExp.symbol) &&
|
||||
getNameOfDeclaration(binExp) === name;
|
||||
getNameOfDeclaration(binExp) === name
|
||||
? binExp
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3736,7 +3770,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
|
||||
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): node is ExpressionWithTypeArguments {
|
||||
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
|
||||
}
|
||||
|
||||
@@ -4030,7 +4064,8 @@ namespace ts {
|
||||
* @param pos The start position.
|
||||
* @param end The end position.
|
||||
*/
|
||||
export function createRange(pos: number, end: number): TextRange {
|
||||
export function createRange(pos: number, end: number = pos): TextRange {
|
||||
Debug.assert(end >= pos || end === -1);
|
||||
return { pos, end };
|
||||
}
|
||||
|
||||
@@ -4206,6 +4241,8 @@ namespace ts {
|
||||
if (!parent) return AccessKind.Read;
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return accessKind(parent);
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression;
|
||||
@@ -4217,13 +4254,35 @@ namespace ts {
|
||||
: AccessKind.Read;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent);
|
||||
case SyntaxKind.PropertyAssignment: {
|
||||
const parentAccess = accessKind(parent.parent);
|
||||
// In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
|
||||
return node === (parent as PropertyAssignment).name ? reverseAccessKind(parentAccess) : parentAccess;
|
||||
}
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
// Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
|
||||
return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return accessKind(parent);
|
||||
default:
|
||||
return AccessKind.Read;
|
||||
}
|
||||
|
||||
function writeOrReadWrite(): AccessKind {
|
||||
// If grandparent is not an ExpressionStatement, this is used as an expression in addition to having a side effect.
|
||||
return parent.parent && parent.parent.kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
return parent.parent && skipParenthesesUp(parent.parent).kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
}
|
||||
}
|
||||
function reverseAccessKind(a: AccessKind): AccessKind {
|
||||
switch (a) {
|
||||
case AccessKind.Read:
|
||||
return AccessKind.Write;
|
||||
case AccessKind.Write:
|
||||
return AccessKind.Read;
|
||||
case AccessKind.ReadWrite:
|
||||
return AccessKind.ReadWrite;
|
||||
default:
|
||||
return Debug.assertNever(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4470,12 +4529,6 @@ namespace ts {
|
||||
return { start, length };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createTextRange(pos: number, end: number = pos): TextRange {
|
||||
Debug.assert(end >= pos);
|
||||
return { pos, end };
|
||||
}
|
||||
|
||||
export function createTextSpanFromBounds(start: number, end: number) {
|
||||
return createTextSpan(start, end - start);
|
||||
}
|
||||
@@ -4853,13 +4906,13 @@ namespace ts {
|
||||
if (isDeclaration(hostNode)) {
|
||||
return getDeclarationIdentifier(hostNode);
|
||||
}
|
||||
// Covers remaining cases
|
||||
// Covers remaining cases (returning undefined if none match).
|
||||
switch (hostNode.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
if (hostNode.declarationList && hostNode.declarationList.declarations[0]) {
|
||||
return getDeclarationIdentifier(hostNode.declarationList.declarations[0]);
|
||||
}
|
||||
return undefined;
|
||||
break;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
const expr = hostNode.expression;
|
||||
switch (expr.kind) {
|
||||
@@ -4871,9 +4924,7 @@ namespace ts {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
return undefined;
|
||||
break;
|
||||
case SyntaxKind.ParenthesizedExpression: {
|
||||
return getDeclarationIdentifier(hostNode.expression);
|
||||
}
|
||||
@@ -4881,10 +4932,8 @@ namespace ts {
|
||||
if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) {
|
||||
return getDeclarationIdentifier(hostNode.statement);
|
||||
}
|
||||
return undefined;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.assertNever(hostNode, "Found typedef tag attached to node which it should not be!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4963,15 +5012,14 @@ namespace ts {
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* @remarks Returns any JSDoc param tag whose name matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
* For binding patterns, parameter tags are matched by position.
|
||||
*/
|
||||
export function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> {
|
||||
if (param.name) {
|
||||
@@ -4992,6 +5040,22 @@ namespace ts {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSDoc type parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc template tag whose names match the provided
|
||||
* parameter, whether a template tag on a containing function
|
||||
* expression, or a template tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the template
|
||||
* tag on the containing function expression would be first.
|
||||
*/
|
||||
export function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag> {
|
||||
const name = param.name.escapedText;
|
||||
return getJSDocTags(param.parent).filter((tag): tag is JSDocTemplateTag =>
|
||||
isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
@@ -5120,7 +5184,20 @@ namespace ts {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
}
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
}
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const decls = getJSDocTypeParameterDeclarations(node);
|
||||
if (decls.length) {
|
||||
return decls;
|
||||
}
|
||||
const typeTag = getJSDocType(node);
|
||||
if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
|
||||
return typeTag.typeParameters;
|
||||
}
|
||||
}
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
|
||||
@@ -6960,6 +7037,18 @@ namespace ts {
|
||||
return moduleResolution;
|
||||
}
|
||||
|
||||
export function hasJsonModuleEmitEnabled(options: CompilerOptions) {
|
||||
switch (getEmitModuleKind(options)) {
|
||||
case ModuleKind.CommonJS:
|
||||
case ModuleKind.AMD:
|
||||
case ModuleKind.ES2015:
|
||||
case ModuleKind.ESNext:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function unreachableCodeIsError(options: CompilerOptions): boolean {
|
||||
return options.allowUnreachableCode === false;
|
||||
}
|
||||
@@ -7293,8 +7382,6 @@ namespace ts {
|
||||
if (pathComponents.length === 0) return "";
|
||||
|
||||
const root = pathComponents[0] && ensureTrailingDirectorySeparator(pathComponents[0]);
|
||||
if (pathComponents.length === 1) return root;
|
||||
|
||||
return root + pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
|
||||
@@ -7898,6 +7985,7 @@ namespace ts {
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJavaScriptAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
@@ -7923,6 +8011,10 @@ namespace ts {
|
||||
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
+34
-26
@@ -27,12 +27,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nonClearingMessageCodes: number[] = [
|
||||
Diagnostics.Found_1_error_Watching_for_file_changes.code,
|
||||
Diagnostics.Found_0_errors_Watching_for_file_changes.code
|
||||
];
|
||||
|
||||
/**
|
||||
* @returns Whether the screen was cleared.
|
||||
*/
|
||||
@@ -41,7 +35,7 @@ namespace ts {
|
||||
!options.preserveWatchOutput &&
|
||||
!options.extendedDiagnostics &&
|
||||
!options.diagnostics &&
|
||||
!contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
system.clearScreen();
|
||||
return true;
|
||||
}
|
||||
@@ -174,6 +168,17 @@ namespace ts {
|
||||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
return {
|
||||
onWatchStatusChange,
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the watch compiler host that can be extended with config file or root file names and options host
|
||||
*/
|
||||
@@ -186,7 +191,7 @@ namespace ts {
|
||||
host; // tslint:disable-line no-unused-expression (TODO: `host` is unused!)
|
||||
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
|
||||
const writeFileName = (s: string) => system.write(s + system.newLine);
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
const { onWatchStatusChange, watchFile, watchDirectory, setTimeout, clearTimeout } = createWatchHost(system, reportWatchStatus);
|
||||
return {
|
||||
useCaseSensitiveFileNames,
|
||||
getNewLine: () => system.newLine,
|
||||
@@ -200,10 +205,10 @@ namespace ts {
|
||||
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
|
||||
realpath: system.realpath && (path => system.realpath!(path)),
|
||||
getEnvironmentVariable: system.getEnvironmentVariable && (name => system.getEnvironmentVariable(name)),
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop,
|
||||
watchFile,
|
||||
watchDirectory,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
trace: s => system.write(s),
|
||||
onWatchStatusChange,
|
||||
createDirectory: path => system.createDirectory(path),
|
||||
@@ -224,10 +229,10 @@ namespace ts {
|
||||
|
||||
const reportSummary = (errorCount: number) => {
|
||||
if (errorCount === 1) {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
else {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -270,7 +275,21 @@ namespace ts {
|
||||
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
export interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
// TODO: GH#18217 Optional methods are frequently asserted
|
||||
|
||||
/**
|
||||
@@ -279,8 +298,6 @@ namespace ts {
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
// Only for testing
|
||||
/*@internal*/
|
||||
@@ -323,15 +340,6 @@ namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
|
||||
/** Internal interface used to wire emit through same host */
|
||||
|
||||
@@ -374,5 +374,41 @@ namespace fakes {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost {
|
||||
diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
reportDiagnostic(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
clearDiagnostics() {
|
||||
this.diagnostics.length = 0;
|
||||
}
|
||||
|
||||
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
|
||||
const actual = this.diagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = ts.createDiagnosticReporter(ts.sys);
|
||||
ts.sys.write(header + "\r\n");
|
||||
for (const d of this.diagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -908,8 +908,8 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, sourceDisplay: undefined }
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, source, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, source: undefined, sourceDisplay: undefined }
|
||||
: expected;
|
||||
|
||||
if (actual.insertText !== insertText) {
|
||||
@@ -927,6 +927,7 @@ namespace FourSlash {
|
||||
|
||||
assert.equal(actual.hasAction, hasAction);
|
||||
assert.equal(actual.isRecommended, isRecommended);
|
||||
assert.equal(actual.source, source);
|
||||
|
||||
if (text) {
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
|
||||
@@ -4789,6 +4790,7 @@ namespace FourSlashInterface {
|
||||
|
||||
export type ExpectedCompletionEntry = string | {
|
||||
readonly name: string,
|
||||
readonly source?: string,
|
||||
readonly insertText?: string,
|
||||
readonly replacementSpan?: FourSlash.Range,
|
||||
readonly hasAction?: boolean, // If not specified, will assert that this is false.
|
||||
|
||||
@@ -620,14 +620,14 @@ interface Array<T> {}`
|
||||
}
|
||||
}
|
||||
|
||||
removeFile(filePath: string) {
|
||||
deleteFile(filePath: string) {
|
||||
const path = this.toFullPath(filePath);
|
||||
const currentEntry = this.fs.get(path) as FsFile;
|
||||
Debug.assert(isFsFile(currentEntry));
|
||||
this.removeFileOrFolder(currentEntry, returnFalse);
|
||||
}
|
||||
|
||||
removeFolder(folderPath: string, recursive?: boolean) {
|
||||
deleteFolder(folderPath: string, recursive?: boolean) {
|
||||
const path = this.toFullPath(folderPath);
|
||||
const currentEntry = this.fs.get(path) as FsFolder;
|
||||
Debug.assert(isFsFolder(currentEntry));
|
||||
@@ -635,7 +635,7 @@ interface Array<T> {}`
|
||||
const subEntries = currentEntry.entries.slice();
|
||||
subEntries.forEach(fsEntry => {
|
||||
if (isFsFolder(fsEntry)) {
|
||||
this.removeFolder(fsEntry.fullPath, recursive);
|
||||
this.deleteFolder(fsEntry.fullPath, recursive);
|
||||
}
|
||||
else {
|
||||
this.removeFileOrFolder(fsEntry, returnFalse);
|
||||
@@ -766,6 +766,14 @@ interface Array<T> {}`
|
||||
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
setModifiedTime(s: string, date: Date) {
|
||||
const path = this.toFullPath(s);
|
||||
const fsEntry = this.fs.get(path);
|
||||
if (fsEntry) {
|
||||
fsEntry.modifiedTime = date;
|
||||
}
|
||||
}
|
||||
|
||||
readFile(s: string): string | undefined {
|
||||
const fsEntry = this.getRealFile(this.toFullPath(s));
|
||||
return fsEntry ? fsEntry.content : undefined;
|
||||
|
||||
Vendored
+10
@@ -1378,6 +1378,16 @@ type Extract<T, U> = T extends U ? T : never;
|
||||
*/
|
||||
type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
|
||||
/**
|
||||
* Obtain the parameters of a function type in a tuple
|
||||
*/
|
||||
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
|
||||
|
||||
/**
|
||||
* Obtain the parameters of a constructor function type in a tuple
|
||||
*/
|
||||
type ConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;
|
||||
|
||||
/**
|
||||
* Obtain the return type of a function type
|
||||
*/
|
||||
|
||||
Vendored
+2
-2
@@ -11,7 +11,7 @@ interface ReadonlyArray<T> {
|
||||
* thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
flatMap<U, This = undefined> (
|
||||
callback: (this: This, value: T, index: number, array: T[]) => U|U[],
|
||||
callback: (this: This, value: T, index: number, array: T[]) => U|ReadonlyArray<U>,
|
||||
thisArg?: This
|
||||
): U[]
|
||||
|
||||
@@ -125,7 +125,7 @@ interface Array<T> {
|
||||
* thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
flatMap<U, This = undefined> (
|
||||
callback: (this: This, value: T, index: number, array: T[]) => U|U[],
|
||||
callback: (this: This, value: T, index: number, array: T[]) => U|ReadonlyArray<U>,
|
||||
thisArg?: This
|
||||
): U[]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ namespace ts.server {
|
||||
|
||||
// tslint:disable variable-name
|
||||
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
|
||||
export const SurveyReady = "surveyReady";
|
||||
export const LargeFileReferencedEvent = "largeFileReferenced";
|
||||
export const ConfigFileDiagEvent = "configFileDiag";
|
||||
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
|
||||
@@ -17,6 +18,11 @@ namespace ts.server {
|
||||
data: { openFiles: string[]; };
|
||||
}
|
||||
|
||||
export interface SurveyReady {
|
||||
eventName: typeof SurveyReady;
|
||||
data: { surveyId: string; };
|
||||
}
|
||||
|
||||
export interface LargeFileReferencedEvent {
|
||||
eventName: typeof LargeFileReferencedEvent;
|
||||
data: { file: string; fileSize: number; maxFileSize: number; };
|
||||
@@ -98,7 +104,7 @@ namespace ts.server {
|
||||
readonly checkJs: boolean;
|
||||
}
|
||||
|
||||
export type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
|
||||
export type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
|
||||
|
||||
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
|
||||
|
||||
@@ -218,9 +224,15 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function convertUserPreferences(preferences: protocol.UserPreferences): UserPreferences {
|
||||
const { lazyConfiguredProjectsFromExternalProject, ...userPreferences } = preferences;
|
||||
return userPreferences;
|
||||
}
|
||||
|
||||
export interface HostConfiguration {
|
||||
formatCodeOptions: FormatCodeSettings;
|
||||
preferences: UserPreferences;
|
||||
preferences: protocol.UserPreferences;
|
||||
hostInfo: string;
|
||||
extraFileExtensions?: FileExtensionInfo[];
|
||||
}
|
||||
@@ -456,6 +468,9 @@ namespace ts.server {
|
||||
/** Tracks projects that we have already sent telemetry for. */
|
||||
private readonly seenProjects = createMap<true>();
|
||||
|
||||
/** Tracks projects that we have already sent survey events for. */
|
||||
private readonly seenSurveyProjects = createMap<true>();
|
||||
|
||||
/*@internal*/
|
||||
readonly watchFactory: WatchFactory<WatchType, Project>;
|
||||
|
||||
@@ -472,7 +487,7 @@ namespace ts.server {
|
||||
this.globalPlugins = opts.globalPlugins || emptyArray;
|
||||
this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray;
|
||||
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
|
||||
this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(this.getExecutingFilePath(), "../typesMap.json") : opts.typesMapLocation;
|
||||
this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation;
|
||||
this.syntaxOnly = opts.syntaxOnly;
|
||||
|
||||
Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService");
|
||||
@@ -657,6 +672,14 @@ namespace ts.server {
|
||||
this.eventHandler(event);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
sendSurveyReadyEvent(surveyId: string) {
|
||||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
this.eventHandler({ eventName: SurveyReady, data: { surveyId } });
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
sendLargeFileReferencedEvent(file: string, fileSize: number) {
|
||||
if (!this.eventHandler) {
|
||||
@@ -802,7 +825,7 @@ namespace ts.server {
|
||||
return info && info.getFormatCodeSettings() || this.hostConfiguration.formatCodeOptions;
|
||||
}
|
||||
|
||||
getPreferences(file: NormalizedPath): UserPreferences {
|
||||
getPreferences(file: NormalizedPath): protocol.UserPreferences {
|
||||
const info = this.getScriptInfoForNormalizedPath(file);
|
||||
return info && info.getPreferences() || this.hostConfiguration.preferences;
|
||||
}
|
||||
@@ -811,7 +834,7 @@ namespace ts.server {
|
||||
return this.hostConfiguration.formatCodeOptions;
|
||||
}
|
||||
|
||||
getHostPreferences(): UserPreferences {
|
||||
getHostPreferences(): protocol.UserPreferences {
|
||||
return this.hostConfiguration.preferences;
|
||||
}
|
||||
|
||||
@@ -1471,6 +1494,20 @@ namespace ts.server {
|
||||
return project;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
sendSurveyReady(project: ExternalProject | ConfiguredProject): void {
|
||||
if (this.seenSurveyProjects.has(project.projectName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.getCompilerOptions().checkJs !== undefined) {
|
||||
const name = "checkJs";
|
||||
this.logger.info(`Survey ${name} is ready`);
|
||||
this.sendSurveyReadyEvent(name);
|
||||
this.seenSurveyProjects.set(project.projectName, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
sendProjectTelemetry(project: ExternalProject | ConfiguredProject): void {
|
||||
if (this.seenProjects.has(project.projectName)) {
|
||||
@@ -1561,6 +1598,13 @@ namespace ts.server {
|
||||
return project;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath) {
|
||||
const project = this.createAndLoadConfiguredProject(configFileName);
|
||||
project.updateGraph();
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the config file of the project, and update the project root file names.
|
||||
*/
|
||||
@@ -1979,7 +2023,19 @@ namespace ts.server {
|
||||
this.logger.info("Format host information updated");
|
||||
}
|
||||
if (args.preferences) {
|
||||
const { lazyConfiguredProjectsFromExternalProject } = this.hostConfiguration.preferences;
|
||||
this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences };
|
||||
if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) {
|
||||
// Load configured projects for external projects that are pending reload
|
||||
this.configuredProjects.forEach(project => {
|
||||
if (project.hasExternalProjectRef() &&
|
||||
project.pendingReload === ConfigFileProgramReloadLevel.Full &&
|
||||
!this.pendingProjectUpdates.has(project.getProjectName())) {
|
||||
this.loadConfiguredProject(project);
|
||||
project.updateGraph();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (args.extraFileExtensions) {
|
||||
this.hostConfiguration.extraFileExtensions = args.extraFileExtensions;
|
||||
@@ -2192,8 +2248,7 @@ namespace ts.server {
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
project = this.createAndLoadConfiguredProject(configFileName);
|
||||
project.updateGraph();
|
||||
project = this.createLoadAndUpdateConfiguredProject(configFileName);
|
||||
// Send the event only if the project got created as part of this open request and info is part of the project
|
||||
if (info.isOrphan()) {
|
||||
// Since the file isnt part of configured project, do not send config file info
|
||||
@@ -2633,7 +2688,9 @@ namespace ts.server {
|
||||
let project = this.findConfiguredProjectByProjectName(tsconfigFile);
|
||||
if (!project) {
|
||||
// errors are stored in the project, do not need to update the graph
|
||||
project = this.createConfiguredProjectWithDelayLoad(tsconfigFile);
|
||||
project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ?
|
||||
this.createConfiguredProjectWithDelayLoad(tsconfigFile) :
|
||||
this.createLoadAndUpdateConfiguredProject(tsconfigFile);
|
||||
}
|
||||
if (project && !contains(exisingConfigFiles, tsconfigFile)) {
|
||||
// keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project
|
||||
|
||||
@@ -1366,6 +1366,7 @@ namespace ts.server {
|
||||
result = super.updateGraph();
|
||||
}
|
||||
this.projectService.sendProjectTelemetry(this);
|
||||
this.projectService.sendSurveyReady(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1520,6 +1521,11 @@ namespace ts.server {
|
||||
) || false;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
hasExternalProjectRef() {
|
||||
return !!this.externalProjectRefCount;
|
||||
}
|
||||
|
||||
getEffectiveTypeRoots() {
|
||||
return getEffectiveTypeRoots(this.getCompilationSettings(), this.directoryStructureHost) || [];
|
||||
}
|
||||
@@ -1565,6 +1571,7 @@ namespace ts.server {
|
||||
updateGraph() {
|
||||
const result = super.updateGraph();
|
||||
this.projectService.sendProjectTelemetry(this);
|
||||
this.projectService.sendSurveyReady(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -1839,7 +1839,7 @@ namespace ts.server.protocol {
|
||||
* begin with prefix.
|
||||
*/
|
||||
export interface CompletionsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.Completions;
|
||||
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
|
||||
arguments: CompletionsRequestArgs;
|
||||
}
|
||||
|
||||
@@ -2436,6 +2436,18 @@ namespace ts.server.protocol {
|
||||
openFiles: string[];
|
||||
}
|
||||
|
||||
export type SurveyReadyEventName = "surveyReady";
|
||||
|
||||
export interface SurveyReadyEvent extends Event {
|
||||
event: SurveyReadyEventName;
|
||||
body: SurveyReadyEventBody;
|
||||
}
|
||||
|
||||
export interface SurveyReadyEventBody {
|
||||
/** Name of the survey. This is an internal machine- and programmer-friendly name */
|
||||
surveyId: string;
|
||||
}
|
||||
|
||||
export type LargeFileReferencedEventName = "largeFileReferenced";
|
||||
export interface LargeFileReferencedEvent extends Event {
|
||||
event: LargeFileReferencedEventName;
|
||||
@@ -2823,6 +2835,7 @@ namespace ts.server.protocol {
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
|
||||
export interface CompilerOptions {
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace ts.server {
|
||||
*/
|
||||
readonly containingProjects: Project[] = [];
|
||||
private formatSettings: FormatCodeSettings | undefined;
|
||||
private preferences: UserPreferences | undefined;
|
||||
private preferences: protocol.UserPreferences | undefined;
|
||||
|
||||
/* @internal */
|
||||
fileWatcher: FileWatcher | undefined;
|
||||
@@ -333,7 +333,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getFormatCodeSettings(): FormatCodeSettings | undefined { return this.formatSettings; }
|
||||
getPreferences(): UserPreferences | undefined { return this.preferences; }
|
||||
getPreferences(): protocol.UserPreferences | undefined { return this.preferences; }
|
||||
|
||||
attachToProject(project: Project): boolean {
|
||||
const isNew = !this.isAttached(project);
|
||||
@@ -432,7 +432,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void {
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void {
|
||||
if (formatSettings) {
|
||||
if (!this.formatSettings) {
|
||||
this.formatSettings = getDefaultFormatCodeSettings(this.host);
|
||||
|
||||
@@ -266,8 +266,6 @@ namespace ts.server {
|
||||
getValue: (path: Path) => T,
|
||||
projects: Projects,
|
||||
action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined,
|
||||
comparer?: (a: U, b: U) => number,
|
||||
areEqual?: (a: U, b: U) => boolean,
|
||||
): U[] {
|
||||
const outputs = flatMap(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
|
||||
if (!isArray(projects) && projects.symLinkedProjects) {
|
||||
@@ -276,10 +274,7 @@ namespace ts.server {
|
||||
outputs.push(...flatMap(projects, project => action(project, value)));
|
||||
});
|
||||
}
|
||||
|
||||
return comparer
|
||||
? sortAndDeduplicate(outputs, comparer, areEqual)
|
||||
: deduplicate(outputs, areEqual);
|
||||
return deduplicate(outputs, equateValues);
|
||||
}
|
||||
|
||||
function combineProjectOutputFromEveryProject<T>(projectService: ProjectService, action: (project: Project) => ReadonlyArray<T>, areEqual: (a: T, b: T) => boolean) {
|
||||
@@ -572,6 +567,10 @@ namespace ts.server {
|
||||
diagnostics: bakedDiags
|
||||
}, "configFileDiag");
|
||||
break;
|
||||
case SurveyReady:
|
||||
const { surveyId } = event.data;
|
||||
this.event<protocol.SurveyReadyEventBody>({ surveyId }, "surveyReady");
|
||||
break;
|
||||
case ProjectLanguageServiceStateEvent: {
|
||||
const eventName: protocol.ProjectLanguageServiceStateEventName = "projectLanguageServiceState";
|
||||
this.event<protocol.ProjectLanguageServiceStateEventBody>({
|
||||
@@ -1423,7 +1422,7 @@ namespace ts.server {
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(file, position, {
|
||||
...this.getPreferences(file),
|
||||
...convertUserPreferences(this.getPreferences(file)),
|
||||
triggerCharacter: args.triggerCharacter,
|
||||
includeExternalModuleExports: args.includeExternalModuleExports,
|
||||
includeInsertTextCompletions: args.includeInsertTextCompletions
|
||||
@@ -2352,7 +2351,7 @@ namespace ts.server {
|
||||
return this.projectService.getFormatCodeOptions(file);
|
||||
}
|
||||
|
||||
private getPreferences(file: NormalizedPath): UserPreferences {
|
||||
private getPreferences(file: NormalizedPath): protocol.UserPreferences {
|
||||
return this.projectService.getPreferences(file);
|
||||
}
|
||||
|
||||
@@ -2360,7 +2359,7 @@ namespace ts.server {
|
||||
return this.projectService.getHostFormatCodeOptions();
|
||||
}
|
||||
|
||||
private getHostPreferences(): UserPreferences {
|
||||
private getHostPreferences(): protocol.UserPreferences {
|
||||
return this.projectService.getHostPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,18 @@ namespace ts.codefix {
|
||||
|
||||
function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, context: CodeFixContextBase): void {
|
||||
// get the function declaration - returns a promise
|
||||
const functionToConvert: FunctionLikeDeclaration = getContainingFunction(getTokenAtPosition(sourceFile, position)) as FunctionLikeDeclaration;
|
||||
const tokenAtPosition = getTokenAtPosition(sourceFile, position);
|
||||
let functionToConvert: FunctionLikeDeclaration | undefined;
|
||||
|
||||
// if the parent of a FunctionLikeDeclaration is a variable declaration, the convertToAsync diagnostic will be reported on the variable name
|
||||
if (isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) &&
|
||||
tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer)) {
|
||||
functionToConvert = tokenAtPosition.parent.initializer;
|
||||
}
|
||||
else {
|
||||
functionToConvert = tryCast(getContainingFunction(getTokenAtPosition(sourceFile, position)), isFunctionLikeDeclaration);
|
||||
}
|
||||
|
||||
if (!functionToConvert) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace ts.codefix {
|
||||
return replacement[1];
|
||||
}
|
||||
else {
|
||||
changes.replaceRangeWithText(sourceFile, createTextRange(left.getStart(sourceFile), right.pos), "export default");
|
||||
changes.replaceRangeWithText(sourceFile, createRange(left.getStart(sourceFile), right.pos), "export default");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,27 +112,23 @@ namespace ts.codefix {
|
||||
|
||||
export function createMethodFromCallExpression(
|
||||
context: CodeFixContextBase,
|
||||
{ typeArguments, arguments: args, parent: parent }: CallExpression,
|
||||
call: CallExpression,
|
||||
methodName: string,
|
||||
inJs: boolean,
|
||||
makeStatic: boolean,
|
||||
preferences: UserPreferences,
|
||||
body: boolean,
|
||||
): MethodDeclaration {
|
||||
const { typeArguments, arguments: args, parent } = call;
|
||||
const checker = context.program.getTypeChecker();
|
||||
const types = map(args,
|
||||
arg => {
|
||||
let type = checker.getTypeAtLocation(arg);
|
||||
if (type === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
|
||||
type = checker.getBaseTypeOfLiteralType(type);
|
||||
return checker.typeToTypeNode(type);
|
||||
});
|
||||
const types = map(args, arg =>
|
||||
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
|
||||
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg))));
|
||||
const names = map(args, arg =>
|
||||
isIdentifier(arg) ? arg.text :
|
||||
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
|
||||
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
|
||||
const contextualType = checker.getContextualType(call);
|
||||
const returnType = inJs ? undefined : contextualType && checker.typeToTypeNode(contextualType, call) || createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
return createMethod(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
|
||||
@@ -142,7 +138,7 @@ namespace ts.codefix {
|
||||
/*typeParameters*/ inJs ? undefined : map(typeArguments, (_, i) =>
|
||||
createTypeParameterDeclaration(CharacterCodes.T + typeArguments!.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)),
|
||||
/*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs),
|
||||
/*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*type*/ returnType,
|
||||
body ? createStubbedMethodBody(preferences) : undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,14 +163,19 @@ namespace ts.codefix {
|
||||
position: number,
|
||||
preferences: UserPreferences,
|
||||
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getTypeChecker(), program.getSourceFiles());
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
|
||||
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
|
||||
// We sort the best codefixes first, so taking `first` is best for completions.
|
||||
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
|
||||
const fix = first(getFixForImport(exportInfos, symbolName, position, program, sourceFile, host, preferences));
|
||||
return { moduleSpecifier, codeAction: codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences)) };
|
||||
return { moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences))) };
|
||||
}
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
|
||||
function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction {
|
||||
return { description, changes, commands };
|
||||
}
|
||||
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
const result: SymbolExportInfo[] = [];
|
||||
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
|
||||
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
|
||||
@@ -178,10 +183,14 @@ namespace ts.codefix {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
|
||||
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol) });
|
||||
}
|
||||
|
||||
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
|
||||
if ((exported.escapedName === InternalSymbolName.Default || exported.name === symbolName) && skipAlias(exported, checker) === exportedSymbol) {
|
||||
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;
|
||||
result.push({ moduleSymbol, importKind: isDefaultExport ? ImportKind.Default : ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -274,14 +283,13 @@ namespace ts.codefix {
|
||||
preferences: UserPreferences,
|
||||
): ReadonlyArray<FixAddNewImport | FixUseImportType> {
|
||||
const isJs = isSourceFileJavaScript(sourceFile);
|
||||
const choicesForEachExportingModule = flatMap<SymbolExportInfo, ReadonlyArray<FixAddNewImport | FixUseImportType>>(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) => {
|
||||
const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap);
|
||||
return modulePathsGroups.map(group => group.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
|
||||
const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) =>
|
||||
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap)
|
||||
.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
|
||||
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
|
||||
exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
|
||||
});
|
||||
// Sort to keep the shortest paths first, but keep [relativePath, importRelativeToBaseUrl] groups together
|
||||
return flatten<FixAddNewImport | FixUseImportType>(choicesForEachExportingModule.sort((a, b) => first(a).moduleSpecifier.length - first(b).moduleSpecifier.length));
|
||||
// Sort to keep the shortest paths first
|
||||
return choicesForEachExportingModule.sort((a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
|
||||
}
|
||||
|
||||
function getFixesForAddImport(
|
||||
@@ -395,13 +403,9 @@ namespace ts.codefix {
|
||||
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// check the default export
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) {
|
||||
const info = getDefaultExportInfo(defaultExport, moduleSymbol, program);
|
||||
if (info && info.name === symbolName && symbolHasMeaning(info.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultExport, ImportKind.Default);
|
||||
}
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
|
||||
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
|
||||
}
|
||||
|
||||
// check exports with the same name
|
||||
@@ -413,7 +417,24 @@ namespace ts.codefix {
|
||||
return originalSymbolToExportInfos;
|
||||
}
|
||||
|
||||
function getDefaultExportInfo(defaultExport: Symbol, moduleSymbol: Symbol, program: Program): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
function getDefaultLikeExportInfo(
|
||||
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
|
||||
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
|
||||
if (!exported) return undefined;
|
||||
const { symbol, kind } = exported;
|
||||
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
|
||||
return info && { symbol, symbolForMeaning: info.symbolForMeaning, name: info.name, kind };
|
||||
}
|
||||
|
||||
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
|
||||
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
|
||||
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
|
||||
}
|
||||
|
||||
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
|
||||
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
|
||||
|
||||
@@ -421,11 +442,11 @@ namespace ts.codefix {
|
||||
if (name !== undefined) return { symbolForMeaning: defaultExport, name };
|
||||
|
||||
if (defaultExport.flags & SymbolFlags.Alias) {
|
||||
const aliased = program.getTypeChecker().getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfo(aliased, Debug.assertDefined(aliased.parent), program);
|
||||
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
|
||||
}
|
||||
else {
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!) };
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,17 +534,19 @@ namespace ts.codefix {
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) {
|
||||
return checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!);
|
||||
}
|
||||
else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.numberIndexContext || usageContext.stringIndexContext) {
|
||||
else if (usageContext.numberIndexContext) {
|
||||
return checker.createArrayType(recur(usageContext.numberIndexContext));
|
||||
}
|
||||
else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.stringIndexContext) {
|
||||
const members = createUnderscoreEscapedMap<Symbol>();
|
||||
const callSignatures: Signature[] = [];
|
||||
const constructSignatures: Signature[] = [];
|
||||
let stringIndexInfo: IndexInfo | undefined;
|
||||
let numberIndexInfo: IndexInfo | undefined;
|
||||
|
||||
if (usageContext.properties) {
|
||||
usageContext.properties.forEach((context, name) => {
|
||||
const symbol = checker.createSymbol(SymbolFlags.Property, name);
|
||||
symbol.type = getTypeFromUsageContext(context, checker) || checker.getAnyType();
|
||||
symbol.type = recur(context);
|
||||
members.set(name, symbol);
|
||||
});
|
||||
}
|
||||
@@ -561,19 +563,19 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
if (usageContext.numberIndexContext) {
|
||||
numberIndexInfo = checker.createIndexInfo(getTypeFromUsageContext(usageContext.numberIndexContext, checker) || checker.getAnyType(), /*isReadonly*/ false);
|
||||
}
|
||||
|
||||
if (usageContext.stringIndexContext) {
|
||||
stringIndexInfo = checker.createIndexInfo(getTypeFromUsageContext(usageContext.stringIndexContext, checker) || checker.getAnyType(), /*isReadonly*/ false);
|
||||
stringIndexInfo = checker.createIndexInfo(recur(usageContext.stringIndexContext), /*isReadonly*/ false);
|
||||
}
|
||||
|
||||
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); // TODO: GH#18217
|
||||
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function recur(innerContext: UsageContext): Type {
|
||||
return getTypeFromUsageContext(innerContext, checker) || checker.getAnyType();
|
||||
}
|
||||
}
|
||||
|
||||
function getParameterTypeFromCallContexts(parameterIndex: number, callContexts: CallContext[], isRestParameter: boolean, checker: TypeChecker) {
|
||||
|
||||
+35
-22
@@ -23,7 +23,8 @@ namespace ts.Completions {
|
||||
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
|
||||
|
||||
const enum KeywordCompletionFilters {
|
||||
None,
|
||||
None, // No keywords
|
||||
All, // Every possible keyword (TODO: This is never appropriate)
|
||||
ClassElementKeywords, // Keywords inside class body
|
||||
InterfaceElementKeywords, // Keywords inside interface body
|
||||
ConstructorParameterKeywords, // Keywords at constructor parameter
|
||||
@@ -143,21 +144,13 @@ namespace ts.Completions {
|
||||
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
|
||||
}
|
||||
|
||||
// TODO add filter for keyword based on type/value/namespace and also location
|
||||
|
||||
// Add all keywords if
|
||||
// - this is not a member completion list (all the keywords)
|
||||
// - other filters are enabled in required scenario so add those keywords
|
||||
const isMemberCompletion = isMemberCompletionKind(completionKind);
|
||||
if (keywordFilters !== KeywordCompletionFilters.None || !isMemberCompletion) {
|
||||
addRange(entries, getKeywordCompletions(keywordFilters));
|
||||
}
|
||||
addRange(entries, getKeywordCompletions(keywordFilters));
|
||||
|
||||
for (const literal of literals) {
|
||||
entries.push(createCompletionEntryForLiteral(literal));
|
||||
}
|
||||
|
||||
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion, isNewIdentifierLocation, entries };
|
||||
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion: isMemberCompletionKind(completionKind), isNewIdentifierLocation, entries };
|
||||
}
|
||||
|
||||
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
|
||||
@@ -271,6 +264,9 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function quote(text: string, preferences: UserPreferences): string {
|
||||
if (/^\d+$/.test(text)) {
|
||||
return text;
|
||||
}
|
||||
const quoted = JSON.stringify(text);
|
||||
switch (preferences.quotePreference) {
|
||||
case undefined:
|
||||
@@ -990,7 +986,10 @@ namespace ts.Completions {
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
// For `<div x=[|f/**/|]`, `parent` will be `x` and `previousToken.parent` will be `f` (which is its own JsxAttribute)
|
||||
if (parent !== previousToken.parent && !(parent as JsxAttribute).initializer) {
|
||||
// Note for `<div someBool f>` we don't want to treat this as a jsx inializer, instead it's the attribute name.
|
||||
if (parent !== previousToken.parent &&
|
||||
!(parent as JsxAttribute).initializer &&
|
||||
findChildOfKind(parent, SyntaxKind.EqualsToken, sourceFile)) {
|
||||
isJsxInitializer = previousToken as Identifier;
|
||||
}
|
||||
}
|
||||
@@ -1014,6 +1013,7 @@ namespace ts.Completions {
|
||||
tryGetGlobalSymbols();
|
||||
symbols = tagSymbols.concat(symbols);
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
keywordFilters = KeywordCompletionFilters.None;
|
||||
}
|
||||
else if (isStartingCloseTag) {
|
||||
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
||||
@@ -1022,6 +1022,7 @@ namespace ts.Completions {
|
||||
symbols = [tagSymbol];
|
||||
}
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
keywordFilters = KeywordCompletionFilters.None;
|
||||
}
|
||||
else {
|
||||
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
|
||||
@@ -1191,9 +1192,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function getGlobalCompletions(): void {
|
||||
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
|
||||
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
|
||||
}
|
||||
keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All;
|
||||
|
||||
// Get all entities in the current scope.
|
||||
completionKind = CompletionKind.Global;
|
||||
@@ -1378,6 +1377,14 @@ namespace ts.Completions {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolvedModuleSymbol !== moduleSymbol &&
|
||||
// Don't add another completion for `export =` of a symbol that's already global.
|
||||
// So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`.
|
||||
resolvedModuleSymbol.declarations.some(d => !!d.getSourceFile().externalModuleIndicator)) {
|
||||
symbols.push(resolvedModuleSymbol);
|
||||
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
|
||||
}
|
||||
|
||||
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
|
||||
// Don't add a completion for a re-export, only for the original.
|
||||
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
|
||||
@@ -1640,7 +1647,8 @@ namespace ts.Completions {
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
// Declaring new property/method/accessor
|
||||
isNewIdentifierLocation = true;
|
||||
keywordFilters = isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
|
||||
keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None :
|
||||
isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
|
||||
|
||||
// If you're in an interface you don't want to repeat things from super-interface. So just stop here.
|
||||
if (!isClassLike(decl)) return GlobalsSearch.Success;
|
||||
@@ -1678,14 +1686,16 @@ namespace ts.Completions {
|
||||
*/
|
||||
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern | undefined {
|
||||
if (contextToken) {
|
||||
const { parent } = contextToken;
|
||||
switch (contextToken.kind) {
|
||||
case SyntaxKind.OpenBraceToken: // const x = { |
|
||||
case SyntaxKind.CommaToken: // const x = { a: 0, |
|
||||
const parent = contextToken.parent;
|
||||
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
|
||||
return parent;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1862,10 +1872,8 @@ namespace ts.Completions {
|
||||
|
||||
case SyntaxKind.GetKeyword:
|
||||
case SyntaxKind.SetKeyword:
|
||||
if (isFromObjectTypeDeclaration(contextToken)) {
|
||||
return false;
|
||||
}
|
||||
// falls through
|
||||
return !isFromObjectTypeDeclaration(contextToken);
|
||||
|
||||
case SyntaxKind.ClassKeyword:
|
||||
case SyntaxKind.EnumKeyword:
|
||||
case SyntaxKind.InterfaceKeyword:
|
||||
@@ -1877,6 +1885,9 @@ namespace ts.Completions {
|
||||
case SyntaxKind.YieldKeyword:
|
||||
case SyntaxKind.TypeKeyword: // type htm|
|
||||
return true;
|
||||
|
||||
case SyntaxKind.AsteriskToken:
|
||||
return isFunctionLike(contextToken.parent) && !isMethodDeclaration(contextToken.parent);
|
||||
}
|
||||
|
||||
// If the previous token is keyword correspoding to class member completion keyword
|
||||
@@ -2116,6 +2127,8 @@ namespace ts.Completions {
|
||||
const kind = stringToToken(entry.name)!;
|
||||
switch (keywordFilter) {
|
||||
case KeywordCompletionFilters.None:
|
||||
return false;
|
||||
case KeywordCompletionFilters.All:
|
||||
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
|
||||
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
|
||||
case KeywordCompletionFilters.ClassElementKeywords:
|
||||
@@ -2228,7 +2241,7 @@ namespace ts.Completions {
|
||||
default:
|
||||
if (!isFromObjectTypeDeclaration(contextToken)) return undefined;
|
||||
const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword;
|
||||
return (isValidKeyword(contextToken.kind) || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
|
||||
return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
|
||||
? contextToken.parent.parent as ObjectTypeDeclaration : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ namespace ts.FindAllReferences {
|
||||
references: Entry[];
|
||||
}
|
||||
|
||||
export const enum DefinitionKind { Symbol, Label, Keyword, This, String }
|
||||
export type Definition =
|
||||
| { type: "symbol"; symbol: Symbol }
|
||||
| { type: "label"; node: Identifier }
|
||||
| { type: "keyword"; node: Node }
|
||||
| { type: "this"; node: Node }
|
||||
| { type: "string"; node: StringLiteral };
|
||||
| { readonly type: DefinitionKind.Symbol; readonly symbol: Symbol }
|
||||
| { readonly type: DefinitionKind.Label; readonly node: Identifier }
|
||||
| { readonly type: DefinitionKind.Keyword; readonly node: Node }
|
||||
| { readonly type: DefinitionKind.This; readonly node: Node }
|
||||
| { readonly type: DefinitionKind.String; readonly node: StringLiteral };
|
||||
|
||||
export type Entry = NodeEntry | SpanEntry;
|
||||
export interface NodeEntry {
|
||||
@@ -98,29 +99,29 @@ namespace ts.FindAllReferences {
|
||||
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo {
|
||||
const info = (() => {
|
||||
switch (def.type) {
|
||||
case "symbol": {
|
||||
case DefinitionKind.Symbol: {
|
||||
const { symbol } = def;
|
||||
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
|
||||
const name = displayParts.map(p => p.text).join("");
|
||||
return { node: symbol.declarations ? getNameOfDeclaration(first(symbol.declarations)) || first(symbol.declarations) : originalNode, name, kind, displayParts };
|
||||
}
|
||||
case "label": {
|
||||
case DefinitionKind.Label: {
|
||||
const { node } = def;
|
||||
return { node, name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] };
|
||||
}
|
||||
case "keyword": {
|
||||
case DefinitionKind.Keyword: {
|
||||
const { node } = def;
|
||||
const name = tokenToString(node.kind)!;
|
||||
return { node, name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] };
|
||||
}
|
||||
case "this": {
|
||||
case DefinitionKind.This: {
|
||||
const { node } = def;
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
const displayParts = symbol && SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(
|
||||
checker, symbol, node.getSourceFile(), getContainerNode(node), node).displayParts || [textPart("this")];
|
||||
return { node, name: "this", kind: ScriptElementKind.variableElement, displayParts };
|
||||
}
|
||||
case "string": {
|
||||
case DefinitionKind.String: {
|
||||
const { node } = def;
|
||||
return { node, name: node.text, kind: ScriptElementKind.variableElement, displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)] };
|
||||
}
|
||||
@@ -154,7 +155,7 @@ namespace ts.FindAllReferences {
|
||||
textSpan: getTextSpan(node, sourceFile),
|
||||
isWriteAccess: isWriteAccessForReference(node),
|
||||
isDefinition: node.kind === SyntaxKind.DefaultKeyword
|
||||
|| isAnyDeclarationName(node)
|
||||
|| !!getDeclarationFromName(node)
|
||||
|| isLiteralComputedPropertyDeclarationName(node),
|
||||
isInString,
|
||||
};
|
||||
@@ -223,7 +224,68 @@ namespace ts.FindAllReferences {
|
||||
|
||||
/** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */
|
||||
function isWriteAccessForReference(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.DefaultKeyword || isAnyDeclarationName(node) || isWriteAccess(node);
|
||||
const decl = getDeclarationFromName(node);
|
||||
return !!decl && declarationIsWriteAccess(decl) || node.kind === SyntaxKind.DefaultKeyword || isWriteAccess(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if 'decl' provides a value, as in `function f() {}`;
|
||||
* false if 'decl' is just a location for a future write, as in 'let x;'
|
||||
*/
|
||||
function declarationIsWriteAccess(decl: Declaration): boolean {
|
||||
// Consider anything in an ambient declaration to be a write access since it may be coming from JS.
|
||||
if (!!(decl.flags & NodeFlags.Ambient)) return true;
|
||||
|
||||
switch (decl.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.DefaultKeyword:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.ImportClause: // default import
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.NamespaceExportDeclaration:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.TypeParameter:
|
||||
return true;
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
// In `({ x: y } = 0);`, `x` is not a write access. (Won't call this function for `y`.)
|
||||
return !isArrayLiteralOrObjectLiteralDestructuringPattern((decl as PropertyAssignment).parent);
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return !!(decl as FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration).body;
|
||||
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return !!(decl as VariableDeclaration | PropertyDeclaration).initializer || isCatchClause(decl.parent);
|
||||
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return Debug.failBadSyntaxKind(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +375,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
}
|
||||
|
||||
return references.length ? [{ definition: { type: "symbol", symbol }, references }] : emptyArray;
|
||||
return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
|
||||
}
|
||||
|
||||
/** getReferencedSymbols for special node kinds. */
|
||||
@@ -524,7 +586,7 @@ namespace ts.FindAllReferences.Core {
|
||||
let references = this.symbolIdToReferences[symbolId];
|
||||
if (!references) {
|
||||
references = this.symbolIdToReferences[symbolId] = [];
|
||||
this.result.push({ definition: { type: "symbol", symbol: searchSymbol }, references });
|
||||
this.result.push({ definition: { type: DefinitionKind.Symbol, symbol: searchSymbol }, references });
|
||||
}
|
||||
return node => references.push(nodeEntry(node));
|
||||
}
|
||||
@@ -818,7 +880,7 @@ namespace ts.FindAllReferences.Core {
|
||||
const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, labelName, container), node =>
|
||||
// Only pick labels that are either the target label, or have a target that is the target label
|
||||
node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) ? nodeEntry(node) : undefined);
|
||||
return [{ definition: { type: "label", node: targetLabel }, references }];
|
||||
return [{ definition: { type: DefinitionKind.Label, node: targetLabel }, references }];
|
||||
}
|
||||
|
||||
function isValidReferencePosition(node: Node, searchSymbolName: string): boolean {
|
||||
@@ -850,7 +912,7 @@ namespace ts.FindAllReferences.Core {
|
||||
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation =>
|
||||
referenceLocation.kind === keywordKind ? nodeEntry(referenceLocation) : undefined);
|
||||
});
|
||||
return references.length ? [{ definition: { type: "keyword", node: references[0].node }, references }] : undefined;
|
||||
return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
|
||||
}
|
||||
|
||||
function getReferencesInSourceFile(sourceFile: SourceFile, search: Search, state: State, addReferencesHere = true): void {
|
||||
@@ -1292,7 +1354,7 @@ namespace ts.FindAllReferences.Core {
|
||||
return container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
|
||||
});
|
||||
|
||||
return [{ definition: { type: "symbol", symbol: searchSpaceNode.symbol }, references }];
|
||||
return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }];
|
||||
}
|
||||
|
||||
function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
|
||||
@@ -1355,8 +1417,9 @@ namespace ts.FindAllReferences.Core {
|
||||
});
|
||||
}).map(n => nodeEntry(n));
|
||||
|
||||
const thisParameter = firstDefined(references, r => isParameter(r.node.parent) ? r.node : undefined);
|
||||
return [{
|
||||
definition: { type: "this", node: thisOrSuperKeyword },
|
||||
definition: { type: DefinitionKind.This, node: thisParameter || thisOrSuperKeyword },
|
||||
references
|
||||
}];
|
||||
}
|
||||
@@ -1369,7 +1432,7 @@ namespace ts.FindAllReferences.Core {
|
||||
});
|
||||
|
||||
return [{
|
||||
definition: { type: "string", node },
|
||||
definition: { type: DefinitionKind.String, node },
|
||||
references
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ts {
|
||||
newFileOrDirPath: string,
|
||||
host: LanguageServiceHost,
|
||||
formatContext: formatting.FormatContext,
|
||||
preferences: UserPreferences,
|
||||
_preferences: UserPreferences,
|
||||
sourceMapper: SourceMapper,
|
||||
): ReadonlyArray<FileTextChanges> {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
@@ -15,7 +15,7 @@ namespace ts {
|
||||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace ts {
|
||||
newToOld: PathUpdater,
|
||||
host: LanguageServiceHost,
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
preferences: UserPreferences,
|
||||
): void {
|
||||
const allFiles = program.getSourceFiles();
|
||||
for (const sourceFile of allFiles) {
|
||||
@@ -156,7 +155,7 @@ namespace ts {
|
||||
|
||||
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
|
||||
return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text)))
|
||||
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences, program.redirectTargetsMap)
|
||||
? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), newImportFromPath, toImport.newFileName, host, allFiles, program.redirectTargetsMap, importLiteral.text)
|
||||
: undefined;
|
||||
});
|
||||
}
|
||||
@@ -210,7 +209,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) {
|
||||
for (const ref of sourceFile.referencedFiles) {
|
||||
for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162
|
||||
const updated = updateRef(ref.fileName);
|
||||
if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated);
|
||||
}
|
||||
@@ -222,7 +221,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createStringRange(node: StringLiteralLike, sourceFile: SourceFileLike): TextRange {
|
||||
return createTextRange(node.getStart(sourceFile) + 1, node.end - 1);
|
||||
return createRange(node.getStart(sourceFile) + 1, node.end - 1);
|
||||
}
|
||||
|
||||
function forEachProperty(objectLiteral: Expression, cb: (property: PropertyAssignment, propertyName: string) => void) {
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
|
||||
|
||||
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
|
||||
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorDeclaration(calledDeclaration))) {
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) {
|
||||
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration);
|
||||
// For a function, if this is the original function definition, return just sigInfo.
|
||||
// If this is the original constructor definition, parent is the class.
|
||||
@@ -319,4 +319,15 @@ namespace ts.GoToDefinition {
|
||||
// Don't go to a function type, go to the value having that type.
|
||||
return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d));
|
||||
}
|
||||
|
||||
function isConstructorLike(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace ts.SignatureHelp {
|
||||
const enum InvocationKind { Call, TypeArgs, Contextual }
|
||||
interface CallInvocation { readonly kind: InvocationKind.Call; readonly node: CallLikeExpression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Expression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Identifier; }
|
||||
interface ContextualInvocation {
|
||||
readonly kind: InvocationKind.Contextual;
|
||||
readonly signature: Signature;
|
||||
@@ -44,7 +44,7 @@ namespace ts.SignatureHelp {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// Extra syntactic and semantic filtering of signature help
|
||||
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
if (!candidateInfo) {
|
||||
@@ -53,11 +53,24 @@ namespace ts.SignatureHelp {
|
||||
return isSourceFileJavaScript(sourceFile) ? createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker =>
|
||||
candidateInfo.kind === CandidateOrTypeKind.Candidate
|
||||
? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker)
|
||||
: createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker));
|
||||
}
|
||||
|
||||
interface CandidateInfo { readonly candidates: ReadonlyArray<Signature>; readonly resolvedSignature: Signature; }
|
||||
function getCandidateInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | undefined {
|
||||
const enum CandidateOrTypeKind { Candidate, Type }
|
||||
interface CandidateInfo {
|
||||
readonly kind: CandidateOrTypeKind.Candidate;
|
||||
readonly candidates: ReadonlyArray<Signature>;
|
||||
readonly resolvedSignature: Signature;
|
||||
}
|
||||
interface TypeInfo {
|
||||
readonly kind: CandidateOrTypeKind.Type;
|
||||
readonly symbol: Symbol;
|
||||
}
|
||||
|
||||
function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined {
|
||||
switch (invocation.kind) {
|
||||
case InvocationKind.Call: {
|
||||
if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) {
|
||||
@@ -65,17 +78,21 @@ namespace ts.SignatureHelp {
|
||||
}
|
||||
const candidates: Signature[] = [];
|
||||
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
|
||||
return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature };
|
||||
}
|
||||
case InvocationKind.TypeArgs: {
|
||||
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
|
||||
const { called } = invocation;
|
||||
if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) {
|
||||
return undefined;
|
||||
}
|
||||
const candidates = getPossibleGenericSignatures(invocation.called, argumentCount, checker);
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
|
||||
const candidates = getPossibleGenericSignatures(called, argumentCount, checker);
|
||||
if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) };
|
||||
|
||||
const symbol = checker.getSymbolAtLocation(called);
|
||||
return symbol && { kind: CandidateOrTypeKind.Type, symbol };
|
||||
}
|
||||
case InvocationKind.Contextual:
|
||||
return { candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
default:
|
||||
return Debug.assertNever(invocation);
|
||||
}
|
||||
@@ -92,7 +109,7 @@ namespace ts.SignatureHelp {
|
||||
return !!containingList && contains(invocationChildren, containingList);
|
||||
}
|
||||
case SyntaxKind.LessThanToken:
|
||||
return lessThanFollowsCalledExpression(startingToken, sourceFile, node.expression);
|
||||
return containsPrecedingToken(startingToken, sourceFile, node.expression);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -114,12 +131,12 @@ namespace ts.SignatureHelp {
|
||||
}));
|
||||
}
|
||||
|
||||
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
|
||||
function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) {
|
||||
const precedingToken = Debug.assertDefined(
|
||||
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
|
||||
);
|
||||
|
||||
return rangeContainsRange(calledExpression, precedingToken);
|
||||
return rangeContainsRange(container, precedingToken);
|
||||
}
|
||||
|
||||
export interface ArgumentInfoForCompletions {
|
||||
@@ -457,6 +474,10 @@ namespace ts.SignatureHelp {
|
||||
return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called;
|
||||
}
|
||||
|
||||
function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node {
|
||||
return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
}
|
||||
|
||||
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
|
||||
function createSignatureHelpItems(
|
||||
candidates: ReadonlyArray<Signature>,
|
||||
@@ -465,7 +486,7 @@ namespace ts.SignatureHelp {
|
||||
sourceFile: SourceFile,
|
||||
typeChecker: TypeChecker,
|
||||
): SignatureHelpItems {
|
||||
const enclosingDeclaration = invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
|
||||
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
|
||||
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
|
||||
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
|
||||
@@ -480,11 +501,36 @@ namespace ts.SignatureHelp {
|
||||
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function createTypeHelpItems(
|
||||
symbol: Symbol,
|
||||
{ argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker
|
||||
): SignatureHelpItems | undefined {
|
||||
const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
if (!typeParameters) return undefined;
|
||||
const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)];
|
||||
return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function getTypeHelpItem(symbol: Symbol, typeParameters: ReadonlyArray<TypeParameter>, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const typeSymbolDisplay = symbolToDisplayParts(checker, symbol);
|
||||
|
||||
const printer = createPrinter({ removeComments: true });
|
||||
const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
|
||||
|
||||
const documentation = symbol.getDocumentationComment(checker);
|
||||
const tags = symbol.getJsDocTags();
|
||||
const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)];
|
||||
return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags };
|
||||
}
|
||||
|
||||
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
|
||||
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: ReadonlyArray<SymbolDisplayPart>, isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
|
||||
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
|
||||
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
|
||||
const separatorDisplayParts = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
const documentation = candidateSignature.getDocumentationComment(checker);
|
||||
const tags = candidateSignature.getJsDocTags();
|
||||
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
|
||||
@@ -545,6 +591,6 @@ namespace ts.SignatureHelp {
|
||||
const param = checker.typeParameterToDeclaration(typeParameter, enclosingDeclaration)!;
|
||||
printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer);
|
||||
});
|
||||
return { name: typeParameter.symbol.name, documentation: emptyArray, displayParts, isOptional: false };
|
||||
return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace ts {
|
||||
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] {
|
||||
program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
const diags: DiagnosticWithLocation[] = [];
|
||||
const checker = program.getDiagnosticsProducingTypeChecker();
|
||||
const checker = program.getTypeChecker();
|
||||
|
||||
if (sourceFile.commonJsModuleIndicator &&
|
||||
(programContainsEs6Modules(program) || compilerOptionsIndicateEs6Modules(program.getCompilerOptions())) &&
|
||||
@@ -115,11 +115,12 @@ namespace ts {
|
||||
|
||||
function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: DiagnosticWithLocation[]): void {
|
||||
|
||||
const functionType = node.type ? checker.getTypeFromTypeNode(node.type) : undefined;
|
||||
if (isAsyncFunction(node) || !node.body || !functionType) {
|
||||
if (isAsyncFunction(node) || !node.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
const functionType = checker.getTypeAtLocation(node);
|
||||
|
||||
const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call);
|
||||
const returnType = callSignatures.length ? checker.getReturnTypeOfSignature(callSignatures[0]) : undefined;
|
||||
|
||||
|
||||
@@ -611,7 +611,8 @@ namespace ts.SymbolDisplay {
|
||||
displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads"));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
documentation = signature.getDocumentationComment(typeChecker);
|
||||
const docComment = signature.getDocumentationComment(typeChecker);
|
||||
documentation = docComment.length === 0 ? undefined : docComment;
|
||||
tags = signature.getJsDocTags();
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public insertNodeAt(sourceFile: SourceFile, pos: number, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
this.replaceRange(sourceFile, createTextRange(pos), newNode, options);
|
||||
this.replaceRange(sourceFile, createRange(pos), newNode, options);
|
||||
}
|
||||
|
||||
private insertNodesAt(sourceFile: SourceFile, pos: number, newNodes: ReadonlyArray<Node>, options: ReplaceWithMultipleNodesOptions = {}): void {
|
||||
@@ -334,7 +334,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public insertText(sourceFile: SourceFile, pos: number, text: string): void {
|
||||
this.replaceRangeWithText(sourceFile, createTextRange(pos), text);
|
||||
this.replaceRangeWithText(sourceFile, createRange(pos), text);
|
||||
}
|
||||
|
||||
/** Prefer this over replacing a node with another that has a type annotation, as it avoids reformatting the other parts of the node. */
|
||||
@@ -456,7 +456,7 @@ namespace ts.textChanges {
|
||||
// check if previous statement ends with semicolon
|
||||
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
|
||||
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
|
||||
this.replaceRange(sourceFile, createTextRange(after.end), createToken(SyntaxKind.SemicolonToken));
|
||||
this.replaceRange(sourceFile, createRange(after.end), createToken(SyntaxKind.SemicolonToken));
|
||||
}
|
||||
}
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, after, {});
|
||||
@@ -595,7 +595,7 @@ namespace ts.textChanges {
|
||||
|
||||
// write separator and leading trivia of the next element as suffix
|
||||
const suffix = `${tokenToString(nextToken.kind)}${sourceFile.text.substring(nextToken.end, containingList[index + 1].getStart(sourceFile))}`;
|
||||
this.replaceRange(sourceFile, createTextRange(startPos, containingList[index + 1].getStart(sourceFile)), newNode, { prefix, suffix });
|
||||
this.replaceRange(sourceFile, createRange(startPos, containingList[index + 1].getStart(sourceFile)), newNode, { prefix, suffix });
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -629,7 +629,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
if (multilineList) {
|
||||
// insert separator immediately following the 'after' node to preserve comments in trailing trivia
|
||||
this.replaceRange(sourceFile, createTextRange(end), createToken(separator));
|
||||
this.replaceRange(sourceFile, createRange(end), createToken(separator));
|
||||
// use the same indentation as 'after' item
|
||||
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options);
|
||||
// insert element before the line break on the line that contains 'after' element
|
||||
@@ -637,10 +637,10 @@ namespace ts.textChanges {
|
||||
if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) {
|
||||
insertPos--;
|
||||
}
|
||||
this.replaceRange(sourceFile, createTextRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter });
|
||||
this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter });
|
||||
}
|
||||
else {
|
||||
this.replaceRange(sourceFile, createTextRange(end), newNode, { prefix: `${tokenToString(separator)} ` });
|
||||
this.replaceRange(sourceFile, createRange(end), newNode, { prefix: `${tokenToString(separator)} ` });
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -652,7 +652,7 @@ namespace ts.textChanges {
|
||||
const [openBraceEnd, closeBraceEnd] = getClassBraceEnds(cls, sourceFile);
|
||||
// For `class C { }` remove the whitespace inside the braces.
|
||||
if (positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile) && openBraceEnd !== closeBraceEnd - 1) {
|
||||
this.deleteRange(sourceFile, createTextRange(openBraceEnd, closeBraceEnd - 1));
|
||||
this.deleteRange(sourceFile, createRange(openBraceEnd, closeBraceEnd - 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,14 +233,6 @@ namespace ts {
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
/* @internal */
|
||||
export const emptyOptions = {};
|
||||
|
||||
|
||||
@@ -755,7 +755,7 @@ namespace ts {
|
||||
return result;
|
||||
|
||||
function find(n: Node): Node | undefined {
|
||||
if (isNonWhitespaceToken(n)) {
|
||||
if (isNonWhitespaceToken(n) && n.kind !== SyntaxKind.EndOfFileToken) {
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -786,16 +786,14 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n));
|
||||
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken || isJSDocCommentContainingNode(n));
|
||||
|
||||
// Here we know that none of child token nodes embrace the position,
|
||||
// the only known case is when position is at the end of the file.
|
||||
// Try to find the rightmost token in the file without filtering.
|
||||
// Namely we are skipping the check: 'position < node.end'
|
||||
if (children.length) {
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
|
||||
return candidate && findRightmostToken(candidate, sourceFile);
|
||||
}
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
|
||||
return candidate && findRightmostToken(candidate, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1048,7 +1046,7 @@ namespace ts {
|
||||
function nodeHasTokens(n: Node, sourceFile: SourceFileLike): boolean {
|
||||
// If we have a token or node that has a non-zero width, it must have tokens.
|
||||
// Note: getWidth() does not take trivia into account.
|
||||
return n.getWidth(sourceFile) !== 0;
|
||||
return n.kind === SyntaxKind.EndOfFileToken ? !!(n as EndOfFileToken).jsDoc : n.getWidth(sourceFile) !== 0;
|
||||
}
|
||||
|
||||
export function getNodeModifiers(node: Node): string {
|
||||
@@ -1165,7 +1163,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createTextRangeFromNode(node: Node, sourceFile: SourceFile): TextRange {
|
||||
return createTextRange(node.getStart(sourceFile), node.end);
|
||||
return createRange(node.getStart(sourceFile), node.end);
|
||||
}
|
||||
|
||||
export function createTextSpanFromRange(range: TextRange): TextSpan {
|
||||
@@ -1173,7 +1171,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createTextRangeFromSpan(span: TextSpan): TextRange {
|
||||
return createTextRange(span.start, span.start + span.length);
|
||||
return createRange(span.start, span.start + span.length);
|
||||
}
|
||||
|
||||
export function createTextChangeFromStartLength(start: number, length: number, newText: string): TextChange {
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"unittests/cancellableLanguageServiceOperations.ts",
|
||||
"unittests/commandLineParsing.ts",
|
||||
"unittests/compileOnSave.ts",
|
||||
"unittests/compilerCore.ts",
|
||||
"unittests/configurationExtension.ts",
|
||||
"unittests/convertCompilerOptionsFromJson.ts",
|
||||
"unittests/convertToAsyncFunction.ts",
|
||||
@@ -80,6 +81,7 @@
|
||||
"unittests/transform.ts",
|
||||
"unittests/transpile.ts",
|
||||
"unittests/tsbuild.ts",
|
||||
"unittests/tsbuildWatchMode.ts",
|
||||
"unittests/tsconfigParsing.ts",
|
||||
"unittests/tscWatchMode.ts",
|
||||
"unittests/versionCache.ts",
|
||||
|
||||
@@ -366,4 +366,120 @@ namespace ts {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseBuildOptions", () => {
|
||||
function assertParseResult(commandLine: string[], expectedParsedBuildCommand: ParsedBuildCommand) {
|
||||
const parsed = parseBuildCommand(commandLine);
|
||||
const parsedBuildOptions = JSON.stringify(parsed.buildOptions);
|
||||
const expectedBuildOptions = JSON.stringify(expectedParsedBuildCommand.buildOptions);
|
||||
assert.equal(parsedBuildOptions, expectedBuildOptions);
|
||||
|
||||
const parsedErrors = parsed.errors;
|
||||
const expectedErrors = expectedParsedBuildCommand.errors;
|
||||
assert.isTrue(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`);
|
||||
for (let i = 0; i < parsedErrors.length; i++) {
|
||||
const parsedError = parsedErrors[i];
|
||||
const expectedError = expectedErrors[i];
|
||||
assert.equal(parsedError.code, expectedError.code);
|
||||
assert.equal(parsedError.category, expectedError.category);
|
||||
assert.equal(parsedError.messageText, expectedError.messageText);
|
||||
}
|
||||
|
||||
const parsedProjects = parsed.projects;
|
||||
const expectedProjects = expectedParsedBuildCommand.projects;
|
||||
assert.deepEqual(parsedProjects, expectedProjects, `Expected projects: [${JSON.stringify(expectedProjects)}]. Actual projects: [${JSON.stringify(parsedProjects)}].`);
|
||||
}
|
||||
it("parse build without any options ", () => {
|
||||
// --lib es6 0.ts
|
||||
assertParseResult([],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["."],
|
||||
buildOptions: {}
|
||||
});
|
||||
});
|
||||
|
||||
it("Parse multiple options", () => {
|
||||
// --lib es5,es2015.symbol.wellknown 0.ts
|
||||
assertParseResult(["--verbose", "--force", "tests"],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["tests"],
|
||||
buildOptions: { verbose: true, force: true }
|
||||
});
|
||||
});
|
||||
|
||||
it("Parse option with invalid option ", () => {
|
||||
// --lib es5,invalidOption 0.ts
|
||||
assertParseResult(["--verbose", "--invalidOption"],
|
||||
{
|
||||
errors: [{
|
||||
messageText: "Unknown build option '--invalidOption'.",
|
||||
category: Diagnostics.Unknown_build_option_0.category,
|
||||
code: Diagnostics.Unknown_build_option_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined,
|
||||
}],
|
||||
projects: ["."],
|
||||
buildOptions: { verbose: true }
|
||||
});
|
||||
});
|
||||
|
||||
it("Parse multiple flags with input projects at the end", () => {
|
||||
// --lib es5,es2015.symbol.wellknown --target es5 0.ts
|
||||
assertParseResult(["--force", "--verbose", "src", "tests"],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["src", "tests"],
|
||||
buildOptions: { force: true, verbose: true }
|
||||
});
|
||||
});
|
||||
|
||||
it("Parse multiple flags with input projects in the middle", () => {
|
||||
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
|
||||
assertParseResult(["--force", "src", "tests", "--verbose"],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["src", "tests"],
|
||||
buildOptions: { force: true, verbose: true }
|
||||
});
|
||||
});
|
||||
|
||||
it("Parse multiple flags with input projects in the beginning", () => {
|
||||
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
|
||||
assertParseResult(["src", "tests", "--force", "--verbose"],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["src", "tests"],
|
||||
buildOptions: { force: true, verbose: true }
|
||||
});
|
||||
});
|
||||
|
||||
describe("Combining options that make no sense together", () => {
|
||||
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
|
||||
it(`--${flag1} and --${flag2} together is invalid`, () => {
|
||||
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
|
||||
assertParseResult([`--${flag1}`, `--${flag2}`],
|
||||
{
|
||||
errors: [{
|
||||
messageText: `Options '${flag1}' and '${flag2}' cannot be combined.`,
|
||||
category: Diagnostics.Options_0_and_1_cannot_be_combined.category,
|
||||
code: Diagnostics.Options_0_and_1_cannot_be_combined.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined,
|
||||
}],
|
||||
projects: ["."],
|
||||
buildOptions: { [flag1]: true, [flag2]: true }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
verifyInvalidCombination("clean", "force");
|
||||
verifyInvalidCombination("clean", "verbose");
|
||||
verifyInvalidCombination("clean", "watch");
|
||||
verifyInvalidCombination("watch", "dry");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace ts {
|
||||
describe("compilerCore", () => {
|
||||
describe("equalOwnProperties", () => {
|
||||
it("correctly equates objects", () => {
|
||||
assert.isTrue(equalOwnProperties({}, {}));
|
||||
assert.isTrue(equalOwnProperties({ a: 1 }, { a: 1 }));
|
||||
assert.isTrue(equalOwnProperties({ a: 1, b: 2 }, { b: 2, a: 1 }));
|
||||
});
|
||||
it("correctly identifies unmatched objects", () => {
|
||||
assert.isFalse(equalOwnProperties({}, { a: 1 }), "missing left property");
|
||||
assert.isFalse(equalOwnProperties({ a: 1 }, {}), "missing right property");
|
||||
assert.isFalse(equalOwnProperties({ a: 1 }, { a: 2 }), "differing property");
|
||||
});
|
||||
it("correctly identifies undefined vs hasOwnProperty", () => {
|
||||
assert.isFalse(equalOwnProperties({}, { a: undefined }), "missing left property");
|
||||
assert.isFalse(equalOwnProperties({ a: undefined }, {}), "missing right property");
|
||||
});
|
||||
it("truthiness", () => {
|
||||
const trythyTest = (l: any, r: any) => !!l === !!r;
|
||||
assert.isFalse(equalOwnProperties({}, { a: 1 }, trythyTest), "missing left truthy property");
|
||||
assert.isFalse(equalOwnProperties({}, { a: 0 }, trythyTest), "missing left falsey property");
|
||||
assert.isFalse(equalOwnProperties({ a: 1 }, {}, trythyTest), "missing right truthy property");
|
||||
assert.isFalse(equalOwnProperties({ a: 0 }, {}, trythyTest), "missing right falsey property");
|
||||
assert.isTrue(equalOwnProperties({ a: 1 }, { a: "foo" }, trythyTest), "valid equality");
|
||||
});
|
||||
it("all equal", () => {
|
||||
assert.isFalse(equalOwnProperties({}, { a: 1 }, () => true), "missing left property");
|
||||
assert.isFalse(equalOwnProperties({ a: 1 }, {}, () => true), "missing right property");
|
||||
assert.isTrue(equalOwnProperties({ a: 1 }, { a: 2 }, () => true), "valid equality");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -319,7 +319,7 @@ interface String { charAt: any; }
|
||||
interface Array<T> {}`
|
||||
};
|
||||
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage, includeLib?: boolean) {
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, diagnosticDescription: DiagnosticMessage, codeFixDescription: DiagnosticMessage, includeLib?: boolean) {
|
||||
const t = getTest(text);
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
@@ -361,12 +361,14 @@ interface Array<T> {}`
|
||||
};
|
||||
|
||||
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
|
||||
const diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === description.message);
|
||||
assert.isNotNull(diagnostic);
|
||||
const diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === diagnosticDescription.message);
|
||||
assert.exists(diagnostic);
|
||||
assert.equal(diagnostic!.start, context.span.start);
|
||||
assert.equal(diagnostic!.length, context.span.length);
|
||||
|
||||
const actions = codefix.getFixes(context);
|
||||
const action = find(actions, action => action.description === description.message)!;
|
||||
assert.isNotNull(action);
|
||||
const action = find(actions, action => action.description === codeFixDescription.message)!;
|
||||
assert.exists(action);
|
||||
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
@@ -423,6 +425,10 @@ interface Array<T> {}`
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_basic", `
|
||||
function [#|f|](): Promise<void>{
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}`);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_basicNoReturnTypeAnnotation", `
|
||||
function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}`);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_basicWithComments", `
|
||||
function [#|f|](): Promise<void>{
|
||||
@@ -436,6 +442,10 @@ function [#|f|](): Promise<void>{
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunction", `
|
||||
[#|():Promise<void> => {|]
|
||||
return fetch('https://typescriptlang.org').then(result => console.log(result));
|
||||
}`);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunctionNoAnnotation", `
|
||||
[#|() => {|]
|
||||
return fetch('https://typescriptlang.org').then(result => console.log(result));
|
||||
}`);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_Catch", `
|
||||
function [#|f|]():Promise<void> {
|
||||
@@ -1178,11 +1188,17 @@ function [#|f|]() {
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpression", `
|
||||
const [#|foo|] = function () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
});
|
||||
|
||||
function _testConvertToAsyncFunction(caption: string, text: string) {
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", Diagnostics.Convert_to_async_function, /*includeLib*/ true);
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", Diagnostics.This_may_be_converted_to_an_async_function, Diagnostics.Convert_to_async_function, /*includeLib*/ true);
|
||||
}
|
||||
|
||||
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
namespace ts {
|
||||
export function checkResolvedModule(expected: ResolvedModuleFull | undefined, actual: ResolvedModuleFull): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.isTrue(expected.extension === actual.extension, `'ext': expected '${expected.extension}' to be equal to '${actual.extension}'`);
|
||||
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
|
||||
export function checkResolvedModule(actual: ResolvedModuleFull | undefined, expected: ResolvedModuleFull | undefined): boolean {
|
||||
if (!expected) {
|
||||
if (actual) {
|
||||
assert.fail(actual, expected, "expected resolved module to be undefined");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
else if (!actual) {
|
||||
assert.fail(actual, expected, "expected resolved module to be defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert.isTrue(actual.resolvedFileName === expected.resolvedFileName, `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`);
|
||||
assert.isTrue(actual.extension === expected.extension, `'ext': expected '${actual.extension}' to be equal to '${expected.extension}'`);
|
||||
assert.isTrue(actual.isExternalLibraryImport === expected.isExternalLibraryImport, `'isExternalLibraryImport': expected '${actual.isExternalLibraryImport}' to be equal to '${expected.isExternalLibraryImport}'`);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModuleFull, expectedFailedLookupLocations: string[]): void {
|
||||
@@ -396,8 +403,12 @@ namespace ts {
|
||||
function testPreserveSymlinks(preserveSymlinks: boolean) {
|
||||
it(`preserveSymlinks: ${preserveSymlinks}`, () => {
|
||||
const realFileName = "/linked/index.d.ts";
|
||||
const symlinkFileName = "/app/node_modulex/linked/index.d.ts";
|
||||
const host = createModuleResolutionHost(/*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] });
|
||||
const symlinkFileName = "/app/node_modules/linked/index.d.ts";
|
||||
const host = createModuleResolutionHost(
|
||||
/*hasDirectoryExists*/ true,
|
||||
{ name: realFileName, symlinks: [symlinkFileName] },
|
||||
{ name: "/app/node_modules/linked/package.json", content: '{"version": "0.0.0", "main": "./index"}' },
|
||||
);
|
||||
const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host);
|
||||
const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName;
|
||||
checkResolvedModule(resolution.resolvedModule, createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/ true));
|
||||
|
||||
@@ -177,15 +177,10 @@ namespace ts {
|
||||
file.text = file.text.updateProgram(newProgramText);
|
||||
}
|
||||
|
||||
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.equal(expected.resolvedFileName, actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.equal(expected.primary, actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
function checkResolvedTypeDirective(actual: ResolvedTypeReferenceDirective, expected: ResolvedTypeReferenceDirective) {
|
||||
assert.equal(actual.resolvedFileName, expected.resolvedFileName, `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`);
|
||||
assert.equal(actual.primary, expected.primary, `'primary': expected '${actual.primary}' to be equal to '${expected.primary}'`);
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T> | undefined, getCache: (f: SourceFile) => Map<T> | undefined, entryChecker: (expected: T, original: T) => boolean): void {
|
||||
@@ -399,6 +394,30 @@ namespace ts {
|
||||
assert.isDefined(program2.getSourceFile("/a.ts")!.resolvedModules!.get("a"), "'a' is not an unresolved module after re-use");
|
||||
});
|
||||
|
||||
it("works with updated SourceFiles", () => {
|
||||
// adapted repro from https://github.com/Microsoft/TypeScript/issues/26166
|
||||
const files = [
|
||||
{ name: "/a.ts", text: SourceText.New("", "", 'import * as a from "a";a;') },
|
||||
{ name: "/types/zzz/index.d.ts", text: SourceText.New("", "", 'declare module "a" { }') },
|
||||
];
|
||||
const host = createTestCompilerHost(files, target);
|
||||
const options: CompilerOptions = { target, typeRoots: ["/types"] };
|
||||
const program1 = createProgram(["/a.ts"], options, host);
|
||||
let sourceFile = program1.getSourceFile("/a.ts")!;
|
||||
assert.isDefined(sourceFile, "'/a.ts' is included in the program");
|
||||
sourceFile = updateSourceFile(sourceFile, "'use strict';" + sourceFile.text, { newLength: "'use strict';".length, span: { start: 0, length: 0 } });
|
||||
assert.strictEqual(sourceFile.statements[2].getSourceFile(), sourceFile, "parent pointers are updated");
|
||||
const updateHost: TestCompilerHost = {
|
||||
...host,
|
||||
getSourceFile(fileName) {
|
||||
return fileName === sourceFile.fileName ? sourceFile : program1.getSourceFile(fileName);
|
||||
}
|
||||
};
|
||||
const program2 = createProgram(["/a.ts"], options, updateHost, program1);
|
||||
assert.isDefined(program2.getSourceFile("/a.ts")!.resolvedModules!.get("a"), "'a' is not an unresolved module after re-use");
|
||||
assert.strictEqual(sourceFile.statements[2].getSourceFile(), sourceFile, "parent pointers are not altered");
|
||||
});
|
||||
|
||||
it("resolved type directives cache follows type directives", () => {
|
||||
const files = [
|
||||
{ name: "/a.ts", text: SourceText.New("/// <reference types='typedefs'/>", "", "var x = $") },
|
||||
|
||||
@@ -1,32 +1,22 @@
|
||||
namespace ts {
|
||||
let currentTime = 100;
|
||||
let lastDiagnostics: Diagnostic[] = [];
|
||||
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiagnostic(d)
|
||||
};
|
||||
|
||||
export namespace Sample1 {
|
||||
tick();
|
||||
const projFs = loadProjectFromDisk("tests/projects/sample1");
|
||||
|
||||
const allExpectedOutputs = ["/src/tests/index.js",
|
||||
"/src/core/index.js", "/src/core/index.d.ts",
|
||||
"/src/logic/index.js", "/src/logic/index.d.ts"];
|
||||
"/src/core/index.js", "/src/core/index.d.ts", "/src/core/index.d.ts.map",
|
||||
"/src/logic/index.js", "/src/logic/index.js.map", "/src/logic/index.d.ts"];
|
||||
|
||||
describe("tsbuild - sanity check of clean build of 'sample1' project", () => {
|
||||
it("can build the sample project 'sample1' without error", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -37,12 +27,11 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - dry builds", () => {
|
||||
it("doesn't write any files in a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
host.assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
|
||||
// Check for outputs to not be written. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -51,28 +40,26 @@ namespace ts {
|
||||
});
|
||||
|
||||
it("indicates that it would skip builds during a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
let builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
tick();
|
||||
|
||||
clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
host.assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - clean builds", () => {
|
||||
it("removes all files it built", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
// Verify they exist
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -91,9 +78,9 @@ namespace ts {
|
||||
describe("tsbuild - force builds", () => {
|
||||
it("always builds under --force", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
let currentTime = time();
|
||||
checkOutputTimestamps(currentTime);
|
||||
@@ -116,14 +103,14 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - can detect when and what to rebuild", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
it("Builds the project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
@@ -135,10 +122,10 @@ namespace ts {
|
||||
|
||||
// All three projects are up to date
|
||||
it("Detects that all projects are up to date", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
|
||||
@@ -147,12 +134,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the leaf node (tests), only it should rebuild the last one
|
||||
it("Only builds the leaf node project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
@@ -162,12 +149,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the parent (without affecting types), should get fast downstream builds
|
||||
it("Detects type-only changes in upstream projects", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
|
||||
@@ -180,15 +167,13 @@ namespace ts {
|
||||
describe("tsbuild - downstream-blocked compilations", () => {
|
||||
it("won't build downstream projects if upstream projects have errors", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
// Induce an error in the middle project
|
||||
replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`);
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(
|
||||
host.assertDiagnosticMessages(
|
||||
Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
@@ -204,12 +189,11 @@ namespace ts {
|
||||
describe("tsbuild - project invalidation", () => {
|
||||
it("invalidates projects correctly", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Update a timestamp in the middle project
|
||||
tick();
|
||||
@@ -221,14 +205,14 @@ namespace ts {
|
||||
// Rebuild this project
|
||||
tick();
|
||||
builder.invalidateProject("/src/logic");
|
||||
builder.buildInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
// The file should be updated
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Build downstream projects should update 'tests', but not 'core'
|
||||
tick();
|
||||
builder.buildDependentInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
});
|
||||
@@ -240,11 +224,10 @@ namespace ts {
|
||||
|
||||
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, [configFile], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
host.assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
if (!expectedDiagnosticMessages.length) {
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -274,11 +257,11 @@ namespace ts {
|
||||
let fs: vfs.FileSystem | undefined;
|
||||
before(() => {
|
||||
fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
});
|
||||
after(() => {
|
||||
fs = undefined;
|
||||
@@ -293,25 +276,24 @@ namespace ts {
|
||||
describe("tsbuild - downstream prepend projects always get rebuilt", () => {
|
||||
it("", () => {
|
||||
const fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct");
|
||||
tick();
|
||||
replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola");
|
||||
tick();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("tsbuild - graph-ordering", () => {
|
||||
let host: fakes.CompilerHost | undefined;
|
||||
let host: fakes.SolutionBuilderHost | undefined;
|
||||
const deps: [string, string][] = [
|
||||
["A", "B"],
|
||||
["B", "C"],
|
||||
@@ -324,7 +306,7 @@ namespace ts {
|
||||
|
||||
before(() => {
|
||||
const fs = new vfs.FileSystem(false);
|
||||
host = new fakes.CompilerHost(fs);
|
||||
host = new fakes.SolutionBuilderHost(fs);
|
||||
writeProjects(fs, ["A", "B", "C", "D", "E", "F", "G"], deps);
|
||||
});
|
||||
|
||||
@@ -349,7 +331,7 @@ namespace ts {
|
||||
});
|
||||
|
||||
function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[]) {
|
||||
const builder = createSolutionBuilder(host!, buildHost, rootNames, { dry: true, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host!, rootNames, { dry: true, force: false, verbose: false });
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
@@ -404,30 +386,6 @@ namespace ts {
|
||||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
|
||||
const actual = lastDiagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDiagnostics() {
|
||||
lastDiagnostics = [];
|
||||
}
|
||||
|
||||
export function printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = createDiagnosticReporter(sys);
|
||||
sys.write(header + "\r\n");
|
||||
for (const d of lastDiagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
currentTime += 60_000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
|
||||
solutionBuilder.buildAllProjects();
|
||||
solutionBuilder.startWatching();
|
||||
return solutionBuilder;
|
||||
}
|
||||
|
||||
describe("tsbuild-watch program updates", () => {
|
||||
const projectsLocation = "/user/username/projects";
|
||||
const project = "sample1";
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
logic = "logic",
|
||||
tests = "tests",
|
||||
ui = "ui"
|
||||
}
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return {
|
||||
path: projectFilePath(subProject, baseFileName),
|
||||
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
|
||||
};
|
||||
}
|
||||
|
||||
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
|
||||
const tsconfig = projectFile(subProject, "tsconfig.json");
|
||||
const index = projectFile(subProject, "index.ts");
|
||||
if (!anotherModuleAndSomeDecl) {
|
||||
return [tsconfig, index];
|
||||
}
|
||||
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
|
||||
const someDecl = projectFile(SubProject.core, "some_decl.ts");
|
||||
return [tsconfig, index, anotherModule, someDecl];
|
||||
}
|
||||
|
||||
function getOutputFileNames(subProject: SubProject, baseFileNameWithoutExtension: string) {
|
||||
const file = projectFilePath(subProject, baseFileNameWithoutExtension);
|
||||
return [`${file}.js`, `${file}.d.ts`];
|
||||
}
|
||||
|
||||
type OutputFileStamp = [string, Date | undefined];
|
||||
function getOutputStamps(host: WatchedSystem, subProject: SubProject, baseFileNameWithoutExtension: string): OutputFileStamp[] {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
for (let i = 0; i < oldTimeStamps.length; i++) {
|
||||
const actual = actualStamps[i];
|
||||
const old = oldTimeStamps[i];
|
||||
if (contains(changedFiles, actual[0])) {
|
||||
assert.isTrue((actual[1] || 0) > (old[1] || 0), `${actual[0]} expected to written`);
|
||||
}
|
||||
else {
|
||||
assert.equal(actual[1], old[1], `${actual[0]} expected to not change`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
|
||||
const logic = subProjectFiles(SubProject.logic);
|
||||
const tests = subProjectFiles(SubProject.tests);
|
||||
const ui = subProjectFiles(SubProject.ui);
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode() {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return host;
|
||||
}
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const host = createSolutionInWatchMode();
|
||||
verifyChange(`${core[1].content}
|
||||
export class someClass { }`);
|
||||
|
||||
// Another change requeues and builds it
|
||||
verifyChange(core[1].content);
|
||||
|
||||
// Two changes together report only single time message: File change detected. Starting incremental compilation...
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
const change1 = `${core[1].content}
|
||||
export class someClass { }`;
|
||||
host.writeFile(core[1].path, change1);
|
||||
host.writeFile(core[1].path, `${change1}
|
||||
export class someClass2 { }`);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
|
||||
function verifyChange(coreContent: string) {
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
host.writeFile(core[1].path, coreContent);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
}
|
||||
|
||||
function verifyChangeAfterTimeout(outputFileStamps: OutputFileStamp[]) {
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedCore, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, changedTests, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
namespace ts.tscWatch {
|
||||
import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
type File = TestFSWithWatch.File;
|
||||
type SymLink = TestFSWithWatch.SymLink;
|
||||
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
import checkArray = TestFSWithWatch.checkArray;
|
||||
import libFile = TestFSWithWatch.libFile;
|
||||
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
export import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
export type File = TestFSWithWatch.File;
|
||||
export type SymLink = TestFSWithWatch.SymLink;
|
||||
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
export import checkArray = TestFSWithWatch.checkArray;
|
||||
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
|
||||
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
|
||||
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
|
||||
@@ -111,7 +110,7 @@ namespace ts.tscWatch {
|
||||
|
||||
function assertWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = getWatchDiagnosticWithoutDate(diagnostic);
|
||||
if (!disableConsoleClears && !contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
if (!disableConsoleClears && contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`);
|
||||
screenClears++;
|
||||
}
|
||||
@@ -137,7 +136,7 @@ namespace ts.tscWatch {
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@@ -148,7 +147,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
@@ -642,37 +642,54 @@ namespace ts.projectSystem {
|
||||
checkWatchedDirectories(host, [combinePaths(getDirectoryPath(appFile.path), nodeModulesAtTypes)], /*recursive*/ true);
|
||||
});
|
||||
|
||||
it("can handle tsconfig file name with difference casing", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
include: []
|
||||
})
|
||||
};
|
||||
describe("can handle tsconfig file name with difference casing", () => {
|
||||
function verifyConfigFileCasing(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
include: []
|
||||
})
|
||||
};
|
||||
|
||||
const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = createProjectService(host);
|
||||
const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path));
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: "/a/b/project.csproj",
|
||||
rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
options: {}
|
||||
const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path));
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: "/a/b/project.csproj",
|
||||
rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
}
|
||||
else {
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
}
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project is updated
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyConfigFileCasing(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project is updated
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyConfigFileCasing(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("create configured project without file list", () => {
|
||||
@@ -2846,7 +2863,7 @@ namespace ts.projectSystem {
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent || e.eventName === server.LargeFileReferencedEvent) {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent || e.eventName === server.LargeFileReferencedEvent || e.eventName === server.SurveyReady) {
|
||||
return;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
@@ -2950,45 +2967,56 @@ namespace ts.projectSystem {
|
||||
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);
|
||||
describe("deleting config file opened from the external project works", () => {
|
||||
function verifyDeletingConfigFile(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
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);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
const externalProject: protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { include: [] }
|
||||
};
|
||||
const externalProject: protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { include: [] }
|
||||
};
|
||||
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
const configProject = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(configProject, []); // Since no files opened from this project, its not loaded
|
||||
const configProject = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(configProject, lazyConfiguredProjectsFromExternalProject ?
|
||||
emptyArray : // Since no files opened from this project, its not loaded
|
||||
[libFile.path, configFile.path]);
|
||||
|
||||
host.reloadFS([libFile, site]);
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
host.reloadFS([libFile, site]);
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("Getting errors from closed script info does not throw exception (because of getting project from orphan script info)", () => {
|
||||
@@ -3298,49 +3326,64 @@ namespace ts.projectSystem {
|
||||
|
||||
});
|
||||
|
||||
it("includes deferred files in the project context", () => {
|
||||
const file1 = {
|
||||
path: "/a.deferred",
|
||||
content: "const a = 1;"
|
||||
};
|
||||
// Deferred extensions should not affect JS files.
|
||||
const file2 = {
|
||||
path: "/b.js",
|
||||
content: "const b = 1;"
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
describe("includes deferred files in the project context", () => {
|
||||
function verifyDeferredContext(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const file1 = {
|
||||
path: "/a.deferred",
|
||||
content: "const a = 1;"
|
||||
};
|
||||
// Deferred extensions should not affect JS files.
|
||||
const file2 = {
|
||||
path: "/b.js",
|
||||
content: "const b = 1;"
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, file2, tsconfig]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
const host = createServerHost([file1, file2, tsconfig]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
session.executeCommandSeq<protocol.ConfigureRequest>({
|
||||
command: protocol.CommandTypes.Configure,
|
||||
arguments: { preferences: { lazyConfiguredProjectsFromExternalProject } }
|
||||
});
|
||||
|
||||
// Configure the deferred extension.
|
||||
const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }];
|
||||
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
|
||||
session.executeCommand(configureHostRequest);
|
||||
// Configure the deferred extension.
|
||||
const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }];
|
||||
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
|
||||
session.executeCommand(configureHostRequest);
|
||||
|
||||
// Open external project
|
||||
const projectName = "/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([file1.path, file2.path, tsconfig.path]),
|
||||
options: {}
|
||||
// Open external project
|
||||
const projectName = "/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([file1.path, file2.path, tsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
// Assert
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
const configuredProject = configuredProjectAt(projectService, 0);
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
// configured project is just created and not yet loaded
|
||||
checkProjectActualFiles(configuredProject, emptyArray);
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProject, [file1.path, tsconfig.path]);
|
||||
|
||||
// Allow allowNonTsExtensions will be set to true for deferred extensions.
|
||||
assert.isTrue(configuredProject.getCompilerOptions().allowNonTsExtensions);
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyDeferredContext(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyDeferredContext(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
|
||||
// Assert
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
const configuredProject = configuredProjectAt(projectService, 0);
|
||||
// configured project is just created and not yet loaded
|
||||
checkProjectActualFiles(configuredProject, emptyArray);
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProject, [file1.path, tsconfig.path]);
|
||||
|
||||
// Allow allowNonTsExtensions will be set to true for deferred extensions.
|
||||
assert.isTrue(configuredProject.getCompilerOptions().allowNonTsExtensions);
|
||||
});
|
||||
|
||||
it("Orphan source files are handled correctly on watch trigger", () => {
|
||||
@@ -3496,6 +3539,121 @@ namespace ts.projectSystem {
|
||||
}
|
||||
});
|
||||
|
||||
function createSessionWithEventHandler(host: TestServerHost) {
|
||||
const surveyEvents: server.SurveyReady[] = [];
|
||||
const session = createSession(host, {
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.SurveyReady) {
|
||||
surveyEvents.push(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { session, verifySurveyReadyEvent };
|
||||
|
||||
function verifySurveyReadyEvent(numberOfEvents: number) {
|
||||
assert.equal(surveyEvents.length, numberOfEvents);
|
||||
const expectedEvents = numberOfEvents === 0 ? [] : [{
|
||||
eventName: server.SurveyReady,
|
||||
data: { surveyId: "checkJs" }
|
||||
}];
|
||||
assert.deepEqual(surveyEvents, expectedEvents);
|
||||
}
|
||||
}
|
||||
|
||||
it("doesn't log an event when checkJs isn't set", () => {
|
||||
const projectRoot = "/user/username/projects/project";
|
||||
const file: File = {
|
||||
path: `${projectRoot}/src/file.ts`,
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { } }),
|
||||
};
|
||||
const host = createServerHost([file, tsconfig]);
|
||||
const { session, verifySurveyReadyEvent } = createSessionWithEventHandler(host);
|
||||
const service = session.getProjectService();
|
||||
openFilesForSession([file], session);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(tsconfig.path)!;
|
||||
checkProjectActualFiles(project, [file.path, tsconfig.path]);
|
||||
|
||||
verifySurveyReadyEvent(0);
|
||||
});
|
||||
|
||||
it("logs an event when checkJs is set", () => {
|
||||
const projectRoot = "/user/username/projects/project";
|
||||
const file: File = {
|
||||
path: `${projectRoot}/src/file.ts`,
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { checkJs: true } }),
|
||||
};
|
||||
const host = createServerHost([file, tsconfig]);
|
||||
const { session, verifySurveyReadyEvent } = createSessionWithEventHandler(host);
|
||||
openFilesForSession([file], session);
|
||||
|
||||
verifySurveyReadyEvent(1);
|
||||
});
|
||||
|
||||
it("logs an event when checkJs is set, only the first time", () => {
|
||||
const projectRoot = "/user/username/projects/project";
|
||||
const file: File = {
|
||||
path: `${projectRoot}/src/file.ts`,
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const rando: File = {
|
||||
path: `/rando/calrissian.ts`,
|
||||
content: "export function f() { }"
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { checkJs: true } }),
|
||||
};
|
||||
const host = createServerHost([file, tsconfig]);
|
||||
const { session, verifySurveyReadyEvent } = createSessionWithEventHandler(host);
|
||||
openFilesForSession([file], session);
|
||||
|
||||
verifySurveyReadyEvent(1);
|
||||
|
||||
closeFilesForSession([file], session);
|
||||
openFilesForSession([rando], session);
|
||||
openFilesForSession([file], session);
|
||||
|
||||
verifySurveyReadyEvent(1);
|
||||
});
|
||||
|
||||
it("logs an event when checkJs is set after closing and reopening", () => {
|
||||
const projectRoot = "/user/username/projects/project";
|
||||
const file: File = {
|
||||
path: `${projectRoot}/src/file.ts`,
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const rando: File = {
|
||||
path: `/rando/calrissian.ts`,
|
||||
content: "export function f() { }"
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ }),
|
||||
};
|
||||
const host = createServerHost([file, tsconfig]);
|
||||
const { session, verifySurveyReadyEvent } = createSessionWithEventHandler(host);
|
||||
openFilesForSession([file], session);
|
||||
|
||||
verifySurveyReadyEvent(0);
|
||||
|
||||
closeFilesForSession([file], session);
|
||||
openFilesForSession([rando], session);
|
||||
host.writeFile(tsconfig.path, JSON.stringify({ compilerOptions: { checkJs: true } }));
|
||||
openFilesForSession([file], session);
|
||||
|
||||
verifySurveyReadyEvent(1);
|
||||
});
|
||||
|
||||
describe("CompileOnSaveAffectedFileListRequest with and without projectFileName in request", () => {
|
||||
const projectRoot = "/user/username/projects/myproject";
|
||||
const core: File = {
|
||||
@@ -3943,143 +4101,167 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem external projects", () => {
|
||||
it("correctly handling add/remove tsconfig - 1", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const f2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f1, f2]);
|
||||
const projectService = createProjectService(host);
|
||||
describe("correctly handling add/remove tsconfig - 1", () => {
|
||||
function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const f2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f1, f2]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
|
||||
// rename lib.ts to tsconfig.json
|
||||
host.reloadFS([f1, tsconfig]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, tsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
|
||||
// rename tsconfig.json back to lib.ts
|
||||
host.reloadFS([f1, f2]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
|
||||
// rename lib.ts to tsconfig.json
|
||||
host.reloadFS([f1, tsconfig]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, tsconfig.path]),
|
||||
options: {}
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
|
||||
// rename tsconfig.json back to lib.ts
|
||||
host.reloadFS([f1, f2]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
});
|
||||
|
||||
describe("correctly handling add/remove tsconfig - 2", () => {
|
||||
function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const cLib = {
|
||||
path: "/a/b/c/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const cTsconfig = {
|
||||
path: "/a/b/c/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const dLib = {
|
||||
path: "/a/b/d/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const dTsconfig = {
|
||||
path: "/a/b/d/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
it("correctly handling add/remove tsconfig - 2", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const cLib = {
|
||||
path: "/a/b/c/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const cTsconfig = {
|
||||
path: "/a/b/c/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const dLib = {
|
||||
path: "/a/b/d/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const dTsconfig = {
|
||||
path: "/a/b/d/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = createProjectService(host);
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove one config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove second config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// open two config files
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// close all projects - no projects should be opened
|
||||
projectService.closeExternalProject(projectName);
|
||||
projectService.checkNumberOfProjects({});
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove one config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove second config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// open two config files
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// close all projects - no projects should be opened
|
||||
projectService.closeExternalProject(projectName);
|
||||
projectService.checkNumberOfProjects({});
|
||||
});
|
||||
|
||||
it("correctly handles changes in lib section of config file", () => {
|
||||
@@ -4174,6 +4356,47 @@ namespace ts.projectSystem {
|
||||
assert.isTrue(project.hasOpenRef()); // f
|
||||
assert.isFalse(project.isClosed());
|
||||
});
|
||||
|
||||
it("handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({})
|
||||
};
|
||||
const projectFileName = "/a/b/project.csproj";
|
||||
const host = createServerHost([f1, config]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: true } });
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName,
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } });
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project, [config.path, f1.path]);
|
||||
|
||||
service.closeExternalProject(projectFileName);
|
||||
service.checkNumberOfProjects({});
|
||||
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName,
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project2 = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project2.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project2, [config.path, f1.path]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem prefer typings to js", () => {
|
||||
@@ -8257,7 +8480,7 @@ new C();`
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.removeFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
@@ -9173,7 +9396,7 @@ describe("Test Suite 1", () => {
|
||||
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
|
||||
|
||||
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
|
||||
host.removeFile(unitTest1.path);
|
||||
host.deleteFile(unitTest1.path);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
|
||||
|
||||
@@ -9210,6 +9433,187 @@ export function Test2() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem completions", () => {
|
||||
it("works", () => {
|
||||
const aTs: File = {
|
||||
path: "/a.ts",
|
||||
content: "export const foo = 0;",
|
||||
};
|
||||
const bTs: File = {
|
||||
path: "/b.ts",
|
||||
content: "foo",
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
const host = createServerHost([aTs, bTs, tsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs, bTs], session);
|
||||
|
||||
const requestLocation: protocol.FileLocationRequestArgs = {
|
||||
file: bTs.path,
|
||||
line: 1,
|
||||
offset: 3,
|
||||
};
|
||||
|
||||
const response = executeSessionRequest<protocol.CompletionsRequest, protocol.CompletionInfoResponse>(session, protocol.CommandTypes.CompletionInfo, {
|
||||
...requestLocation,
|
||||
includeExternalModuleExports: true,
|
||||
prefix: "foo",
|
||||
});
|
||||
const entry: protocol.CompletionEntry = {
|
||||
hasAction: true,
|
||||
insertText: undefined,
|
||||
isRecommended: undefined,
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
name: "foo",
|
||||
replacementSpan: undefined,
|
||||
sortText: "0",
|
||||
source: "/a",
|
||||
};
|
||||
assert.deepEqual<protocol.CompletionInfo | undefined>(response, {
|
||||
isGlobalCompletion: true,
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: false,
|
||||
entries: [entry],
|
||||
});
|
||||
|
||||
const detailsRequestArgs: protocol.CompletionDetailsRequestArgs = {
|
||||
...requestLocation,
|
||||
entryNames: [{ name: "foo", source: "/a" }],
|
||||
};
|
||||
|
||||
const detailsResponse = executeSessionRequest<protocol.CompletionDetailsRequest, protocol.CompletionDetailsResponse>(session, protocol.CommandTypes.CompletionDetails, detailsRequestArgs);
|
||||
const detailsCommon: protocol.CompletionEntryDetails & CompletionEntryDetails = {
|
||||
displayParts: [
|
||||
keywordPart(SyntaxKind.ConstKeyword),
|
||||
spacePart(),
|
||||
displayPart("foo", SymbolDisplayPartKind.localName),
|
||||
punctuationPart(SyntaxKind.ColonToken),
|
||||
spacePart(),
|
||||
displayPart("0", SymbolDisplayPartKind.stringLiteral),
|
||||
],
|
||||
documentation: emptyArray,
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
name: "foo",
|
||||
source: [{ text: "./a", kind: "text" }],
|
||||
tags: emptyArray,
|
||||
};
|
||||
assert.deepEqual<ReadonlyArray<protocol.CompletionEntryDetails> | undefined>(detailsResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
{
|
||||
description: `Import 'foo' from module "./a"`,
|
||||
changes: [
|
||||
{
|
||||
fileName: "/b.ts",
|
||||
textChanges: [
|
||||
{
|
||||
start: { line: 1, offset: 1 },
|
||||
end: { line: 1, offset: 1 },
|
||||
newText: 'import { foo } from "./a";\n\n',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
commands: undefined,
|
||||
},
|
||||
],
|
||||
...detailsCommon,
|
||||
},
|
||||
]);
|
||||
|
||||
interface CompletionDetailsFullRequest extends protocol.FileLocationRequest {
|
||||
readonly command: protocol.CommandTypes.CompletionDetailsFull;
|
||||
readonly arguments: protocol.CompletionDetailsRequestArgs;
|
||||
}
|
||||
interface CompletionDetailsFullResponse extends protocol.Response {
|
||||
readonly body?: ReadonlyArray<CompletionEntryDetails>;
|
||||
}
|
||||
const detailsFullResponse = executeSessionRequest<CompletionDetailsFullRequest, CompletionDetailsFullResponse>(session, protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs);
|
||||
assert.deepEqual<ReadonlyArray<CompletionEntryDetails> | undefined>(detailsFullResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
{
|
||||
description: `Import 'foo' from module "./a"`,
|
||||
changes: [
|
||||
{
|
||||
fileName: "/b.ts",
|
||||
textChanges: [createTextChange(createTextSpan(0, 0), 'import { foo } from "./a";\n\n')],
|
||||
},
|
||||
],
|
||||
commands: undefined,
|
||||
}
|
||||
],
|
||||
...detailsCommon,
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem typeReferenceDirectives", () => {
|
||||
it("when typeReferenceDirective contains UpperCasePackage", () => {
|
||||
const projectLocation = "/user/username/projects/myproject";
|
||||
const libProjectLocation = `${projectLocation}/lib`;
|
||||
const typeLib: File = {
|
||||
path: `${libProjectLocation}/@types/UpperCasePackage/index.d.ts`,
|
||||
content: `declare class BrokenTest {
|
||||
constructor(name: string, width: number, height: number, onSelect: Function);
|
||||
Name: string;
|
||||
SelectedFile: string;
|
||||
}`
|
||||
};
|
||||
const appLib: File = {
|
||||
path: `${libProjectLocation}/@app/lib/index.d.ts`,
|
||||
content: `/// <reference types="UpperCasePackage" />
|
||||
declare class TestLib {
|
||||
issue: BrokenTest;
|
||||
constructor();
|
||||
test(): void;
|
||||
}`
|
||||
};
|
||||
const testProjectLocation = `${projectLocation}/test`;
|
||||
const testFile: File = {
|
||||
path: `${testProjectLocation}/test.ts`,
|
||||
content: `class TestClass1 {
|
||||
|
||||
constructor() {
|
||||
var l = new TestLib();
|
||||
|
||||
}
|
||||
|
||||
public test2() {
|
||||
var x = new BrokenTest('',0,0,null);
|
||||
|
||||
}
|
||||
}`
|
||||
};
|
||||
const testConfig: File = {
|
||||
path: `${testProjectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "amd",
|
||||
typeRoots: ["../lib/@types", "../lib/@app"]
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const files = [typeLib, appLib, testFile, testConfig, libFile];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(testFile.path);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(testConfig.path)!;
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
host.writeFile(appLib.path, appLib.content.replace("test()", "test2()"));
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem project references", () => {
|
||||
const aTs: File = {
|
||||
path: "/a/a.ts",
|
||||
@@ -9297,7 +9701,7 @@ export function Test2() {
|
||||
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
|
||||
|
||||
// Testing what happens if we delete the original sources.
|
||||
host.removeFile(bTs.path);
|
||||
host.deleteFile(bTs.path);
|
||||
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
|
||||
+59
-13
@@ -13,7 +13,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
let reportDiagnostic = createDiagnosticReporter(sys);
|
||||
function updateReportDiagnostic(options: CompilerOptions) {
|
||||
function updateReportDiagnostic(options?: CompilerOptions) {
|
||||
if (shouldBePretty(options)) {
|
||||
reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
}
|
||||
@@ -23,8 +23,8 @@ namespace ts {
|
||||
return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY();
|
||||
}
|
||||
|
||||
function shouldBePretty(options: CompilerOptions) {
|
||||
if (typeof options.pretty === "undefined") {
|
||||
function shouldBePretty(options?: CompilerOptions) {
|
||||
if (!options || typeof options.pretty === "undefined") {
|
||||
return defaultIsPretty();
|
||||
}
|
||||
return options.pretty;
|
||||
@@ -54,15 +54,7 @@ namespace ts {
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const reportDiag = createDiagnosticReporter(sys, defaultIsPretty());
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiag(d)
|
||||
};
|
||||
const result = performBuild(args.slice(1), createCompilerHost({}), buildHost, sys);
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
@@ -172,6 +164,60 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const { buildOptions, projects: buildProjects, errors } = parseBuildCommand(args);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach(reportDiagnostic);
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
updateReportDiagnostic();
|
||||
const projects = mapDefined(buildProjects, project => {
|
||||
const fileName = resolvePath(sys.getCurrentDirectory(), project);
|
||||
const refPath = resolveProjectReferencePath(sys, { path: fileName });
|
||||
if (!sys.fileExists(refPath)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
return undefined;
|
||||
}
|
||||
return refPath;
|
||||
});
|
||||
|
||||
if (projects.length === 0) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
}
|
||||
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
const host = createCompilerHost(options);
|
||||
enableStatistics(options);
|
||||
@@ -205,7 +251,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createWatchStatusReporter(options: CompilerOptions) {
|
||||
function createWatchStatusReporter(options?: CompilerOptions) {
|
||||
return ts.createWatchStatusReporter(sys, shouldBePretty(options));
|
||||
}
|
||||
|
||||
|
||||
@@ -644,14 +644,18 @@ namespace ts.server {
|
||||
const cmdLineVerbosity = getLogLevel(findArgument("--logVerbosity"));
|
||||
const envLogOptions = parseLoggingEnvironmentString(process.env.TSS_LOG);
|
||||
|
||||
const logFileName = cmdLineLogFileName
|
||||
const unsubstitutedLogFileName = cmdLineLogFileName
|
||||
? stripQuotes(cmdLineLogFileName)
|
||||
: envLogOptions.logToFile
|
||||
? envLogOptions.file || (__dirname + "/.log" + process.pid.toString())
|
||||
: undefined;
|
||||
|
||||
const substitutedLogFileName = unsubstitutedLogFileName
|
||||
? unsubstitutedLogFileName.replace("PID", process.pid.toString())
|
||||
: undefined;
|
||||
|
||||
const logVerbosity = cmdLineVerbosity || envLogOptions.detailLevel;
|
||||
return new Logger(logFileName!, envLogOptions.traceToConsole!, logVerbosity!); // TODO: GH#18217
|
||||
return new Logger(substitutedLogFileName!, envLogOptions.traceToConsole!, logVerbosity!); // TODO: GH#18217
|
||||
}
|
||||
// This places log file in the directory containing editorServices.js
|
||||
// TODO: check that this location is writable
|
||||
@@ -920,7 +924,7 @@ namespace ts.server {
|
||||
setStackTraceLimit();
|
||||
|
||||
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation)!; // TODO: GH#18217
|
||||
const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(sys.getExecutingFilePath(), "../typesMap.json");
|
||||
const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json");
|
||||
const npmLocation = findArgument(Arguments.NpmLocation);
|
||||
|
||||
function parseStringArray(argName: string): ReadonlyArray<string> {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
|
||||
|
||||
==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ====
|
||||
==== tests/cases/compiler/abstractPropertyInConstructor.ts (4 errors) ====
|
||||
abstract class AbstractClass {
|
||||
constructor(str: string, other: AbstractClass) {
|
||||
this.method(parseInt(str));
|
||||
@@ -34,6 +35,11 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr
|
||||
|
||||
abstract method(num: number): void;
|
||||
|
||||
other = this.prop;
|
||||
~~~~
|
||||
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||
fn = () => this.prop;
|
||||
|
||||
method2() {
|
||||
this.prop = this.prop + "!";
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ abstract class AbstractClass {
|
||||
|
||||
abstract method(num: number): void;
|
||||
|
||||
other = this.prop;
|
||||
fn = () => this.prop;
|
||||
|
||||
method2() {
|
||||
this.prop = this.prop + "!";
|
||||
}
|
||||
@@ -42,6 +45,8 @@ class User {
|
||||
var AbstractClass = /** @class */ (function () {
|
||||
function AbstractClass(str, other) {
|
||||
var _this = this;
|
||||
this.other = this.prop;
|
||||
this.fn = function () { return _this.prop; };
|
||||
this.method(parseInt(str));
|
||||
var val = this.prop.toLowerCase();
|
||||
if (!str) {
|
||||
|
||||
@@ -67,8 +67,20 @@ abstract class AbstractClass {
|
||||
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
|
||||
>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 22, 20))
|
||||
|
||||
other = this.prop;
|
||||
>other : Symbol(AbstractClass.other, Decl(abstractPropertyInConstructor.ts, 22, 39))
|
||||
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
|
||||
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
|
||||
fn = () => this.prop;
|
||||
>fn : Symbol(AbstractClass.fn, Decl(abstractPropertyInConstructor.ts, 24, 22))
|
||||
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
|
||||
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
|
||||
method2() {
|
||||
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
|
||||
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
|
||||
|
||||
this.prop = this.prop + "!";
|
||||
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
@@ -81,31 +93,31 @@ abstract class AbstractClass {
|
||||
}
|
||||
|
||||
class User {
|
||||
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 27, 1))
|
||||
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 30, 1))
|
||||
|
||||
constructor(a: AbstractClass) {
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
|
||||
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
|
||||
|
||||
a.prop;
|
||||
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
|
||||
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
|
||||
|
||||
a.cb("hi");
|
||||
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
|
||||
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
|
||||
|
||||
a.method(12);
|
||||
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
|
||||
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
|
||||
|
||||
a.method2();
|
||||
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
|
||||
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
|
||||
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
|
||||
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
|
||||
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,19 @@ abstract class AbstractClass {
|
||||
>method : (num: number) => void
|
||||
>num : number
|
||||
|
||||
other = this.prop;
|
||||
>other : string
|
||||
>this.prop : string
|
||||
>this : this
|
||||
>prop : string
|
||||
|
||||
fn = () => this.prop;
|
||||
>fn : () => string
|
||||
>() => this.prop : () => string
|
||||
>this.prop : string
|
||||
>this : this
|
||||
>prop : string
|
||||
|
||||
method2() {
|
||||
>method2 : () => void
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(2,17): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(17,22): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(20,24): error TS1183: An implementation cannot be declared in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(29,9): error TS1066: In ambient enum declarations member initializer must be constant expression.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(34,11): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(34,13): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(35,19): error TS1183: An implementation cannot be declared in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(37,20): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/conformance/ambient/ambientErrors.ts(38,13): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
@@ -17,7 +17,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
|
||||
==== tests/cases/conformance/ambient/ambientErrors.ts (14 errors) ====
|
||||
// Ambient variable with an initializer
|
||||
declare var x = 4;
|
||||
~
|
||||
~
|
||||
!!! error TS1039: Initializers are not allowed in ambient contexts.
|
||||
|
||||
// Ambient functions with invalid overloads
|
||||
@@ -57,7 +57,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
|
||||
// Ambient module with initializers for values, bodies for functions / classes
|
||||
declare module M1 {
|
||||
var x = 3;
|
||||
~
|
||||
~
|
||||
!!! error TS1039: Initializers are not allowed in ambient contexts.
|
||||
function fn() { }
|
||||
~
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
tests/cases/compiler/ambientErrors1.ts(1,15): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/compiler/ambientErrors1.ts(1,17): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
|
||||
|
||||
==== tests/cases/compiler/ambientErrors1.ts (1 errors) ====
|
||||
declare var x = 4;
|
||||
~
|
||||
~
|
||||
!!! error TS1039: Initializers are not allowed in ambient contexts.
|
||||
@@ -1,5 +1,5 @@
|
||||
tests/cases/compiler/ambientStatement1.ts(2,6): error TS1036: Statements are not allowed in ambient contexts.
|
||||
tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
tests/cases/compiler/ambientStatement1.ts(4,22): error TS1039: Initializers are not allowed in ambient contexts.
|
||||
|
||||
|
||||
==== tests/cases/compiler/ambientStatement1.ts (2 errors) ====
|
||||
@@ -9,6 +9,6 @@ tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are
|
||||
!!! error TS1036: Statements are not allowed in ambient contexts.
|
||||
|
||||
export var v1 = () => false;
|
||||
~
|
||||
~~~~~~~~~~~
|
||||
!!! error TS1039: Initializers are not allowed in ambient contexts.
|
||||
}
|
||||
+79
-45
@@ -536,6 +536,7 @@ declare namespace ts {
|
||||
name?: Identifier | StringLiteral | NumericLiteral;
|
||||
}
|
||||
interface ComputedPropertyName extends Node {
|
||||
parent: Declaration;
|
||||
kind: SyntaxKind.ComputedPropertyName;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -632,6 +633,7 @@ declare namespace ts {
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
objectAssignmentInitializer?: Expression;
|
||||
}
|
||||
@@ -668,6 +670,7 @@ declare namespace ts {
|
||||
_functionLikeDeclarationBrand: any;
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
body?: Block | Expression;
|
||||
}
|
||||
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
|
||||
@@ -2060,28 +2063,28 @@ declare namespace ts {
|
||||
ModuleExports = 134217728,
|
||||
Enum = 384,
|
||||
Variable = 3,
|
||||
Value = 67216319,
|
||||
Type = 67901928,
|
||||
Value = 67220415,
|
||||
Type = 67897832,
|
||||
Namespace = 1920,
|
||||
Module = 1536,
|
||||
Accessor = 98304,
|
||||
FunctionScopedVariableExcludes = 67216318,
|
||||
BlockScopedVariableExcludes = 67216319,
|
||||
ParameterExcludes = 67216319,
|
||||
FunctionScopedVariableExcludes = 67220414,
|
||||
BlockScopedVariableExcludes = 67220415,
|
||||
ParameterExcludes = 67220415,
|
||||
PropertyExcludes = 0,
|
||||
EnumMemberExcludes = 68008959,
|
||||
FunctionExcludes = 67215791,
|
||||
FunctionExcludes = 67219887,
|
||||
ClassExcludes = 68008383,
|
||||
InterfaceExcludes = 67901832,
|
||||
InterfaceExcludes = 67897736,
|
||||
RegularEnumExcludes = 68008191,
|
||||
ConstEnumExcludes = 68008831,
|
||||
ValueModuleExcludes = 67215503,
|
||||
ValueModuleExcludes = 110735,
|
||||
NamespaceModuleExcludes = 0,
|
||||
MethodExcludes = 67208127,
|
||||
GetAccessorExcludes = 67150783,
|
||||
SetAccessorExcludes = 67183551,
|
||||
TypeParameterExcludes = 67639784,
|
||||
TypeAliasExcludes = 67901928,
|
||||
MethodExcludes = 67212223,
|
||||
GetAccessorExcludes = 67154879,
|
||||
SetAccessorExcludes = 67187647,
|
||||
TypeParameterExcludes = 67635688,
|
||||
TypeAliasExcludes = 67897832,
|
||||
AliasExcludes = 2097152,
|
||||
ModuleMember = 2623475,
|
||||
ExportHasLocal = 944,
|
||||
@@ -2690,9 +2693,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -2993,6 +2993,16 @@ declare namespace ts {
|
||||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
@@ -3202,17 +3212,27 @@ declare namespace ts {
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* @remarks Returns any JSDoc param tag whose name matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
* For binding patterns, parameter tags are matched by position.
|
||||
*/
|
||||
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag>;
|
||||
/**
|
||||
* Gets the JSDoc type parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc template tag whose names match the provided
|
||||
* parameter, whether a template tag on a containing function
|
||||
* expression, or a template tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the template
|
||||
* tag on the containing function expression would be first.
|
||||
*/
|
||||
function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag>;
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
@@ -4313,15 +4333,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4354,14 +4385,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
@@ -4637,14 +4660,6 @@ declare namespace ts {
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
@@ -6949,7 +6964,7 @@ declare namespace ts.server.protocol {
|
||||
* begin with prefix.
|
||||
*/
|
||||
interface CompletionsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.Completions;
|
||||
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
|
||||
arguments: CompletionsRequestArgs;
|
||||
}
|
||||
/**
|
||||
@@ -7461,6 +7476,15 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
openFiles: string[];
|
||||
}
|
||||
type SurveyReadyEventName = "surveyReady";
|
||||
interface SurveyReadyEvent extends Event {
|
||||
event: SurveyReadyEventName;
|
||||
body: SurveyReadyEventBody;
|
||||
}
|
||||
interface SurveyReadyEventBody {
|
||||
/** Name of the survey. This is an internal machine- and programmer-friendly name */
|
||||
surveyId: string;
|
||||
}
|
||||
type LargeFileReferencedEventName = "largeFileReferenced";
|
||||
interface LargeFileReferencedEvent extends Event {
|
||||
event: LargeFileReferencedEventName;
|
||||
@@ -7796,6 +7820,7 @@ declare namespace ts.server.protocol {
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
@@ -7927,14 +7952,14 @@ declare namespace ts.server {
|
||||
getSnapshot(): IScriptSnapshot;
|
||||
private ensureRealPath;
|
||||
getFormatCodeSettings(): FormatCodeSettings | undefined;
|
||||
getPreferences(): UserPreferences | undefined;
|
||||
getPreferences(): protocol.UserPreferences | undefined;
|
||||
attachToProject(project: Project): boolean;
|
||||
isAttached(project: Project): boolean;
|
||||
detachFromProject(project: Project): void;
|
||||
detachAllProjects(): void;
|
||||
getDefaultProject(): Project;
|
||||
registerFileUpdate(): void;
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void;
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void;
|
||||
getLatestVersion(): string;
|
||||
saveTo(fileName: string): void;
|
||||
reloadFromFile(tempFileName?: NormalizedPath): boolean;
|
||||
@@ -8202,6 +8227,7 @@ declare namespace ts.server {
|
||||
declare namespace ts.server {
|
||||
const maxProgramSizeForNonTsFiles: number;
|
||||
const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
|
||||
const SurveyReady = "surveyReady";
|
||||
const LargeFileReferencedEvent = "largeFileReferenced";
|
||||
const ConfigFileDiagEvent = "configFileDiag";
|
||||
const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
|
||||
@@ -8213,6 +8239,12 @@ declare namespace ts.server {
|
||||
openFiles: string[];
|
||||
};
|
||||
}
|
||||
interface SurveyReady {
|
||||
eventName: typeof SurveyReady;
|
||||
data: {
|
||||
surveyId: string;
|
||||
};
|
||||
}
|
||||
interface LargeFileReferencedEvent {
|
||||
eventName: typeof LargeFileReferencedEvent;
|
||||
data: {
|
||||
@@ -8291,7 +8323,7 @@ declare namespace ts.server {
|
||||
interface OpenFileInfo {
|
||||
readonly checkJs: boolean;
|
||||
}
|
||||
type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
|
||||
type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
|
||||
type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
|
||||
interface SafeList {
|
||||
[name: string]: {
|
||||
@@ -8312,7 +8344,7 @@ declare namespace ts.server {
|
||||
function convertScriptKindName(scriptKindName: protocol.ScriptKindName): ScriptKind.Unknown | ScriptKind.JS | ScriptKind.JSX | ScriptKind.TS | ScriptKind.TSX;
|
||||
interface HostConfiguration {
|
||||
formatCodeOptions: FormatCodeSettings;
|
||||
preferences: UserPreferences;
|
||||
preferences: protocol.UserPreferences;
|
||||
hostInfo: string;
|
||||
extraFileExtensions?: FileExtensionInfo[];
|
||||
}
|
||||
@@ -8410,6 +8442,8 @@ declare namespace ts.server {
|
||||
readonly syntaxOnly?: boolean;
|
||||
/** Tracks projects that we have already sent telemetry for. */
|
||||
private readonly seenProjects;
|
||||
/** Tracks projects that we have already sent survey events for. */
|
||||
private readonly seenSurveyProjects;
|
||||
constructor(opts: ProjectServiceOptions);
|
||||
toPath(fileName: string): Path;
|
||||
private loadTypesMap;
|
||||
@@ -8431,9 +8465,9 @@ declare namespace ts.server {
|
||||
*/
|
||||
private ensureProjectStructuresUptoDate;
|
||||
getFormatCodeOptions(file: NormalizedPath): FormatCodeSettings;
|
||||
getPreferences(file: NormalizedPath): UserPreferences;
|
||||
getPreferences(file: NormalizedPath): protocol.UserPreferences;
|
||||
getHostFormatCodeOptions(): FormatCodeSettings;
|
||||
getHostPreferences(): UserPreferences;
|
||||
getHostPreferences(): protocol.UserPreferences;
|
||||
private onSourceFileChanged;
|
||||
private handleDeletedFile;
|
||||
private onConfigChangedForConfiguredProject;
|
||||
|
||||
+53
-38
@@ -536,6 +536,7 @@ declare namespace ts {
|
||||
name?: Identifier | StringLiteral | NumericLiteral;
|
||||
}
|
||||
interface ComputedPropertyName extends Node {
|
||||
parent: Declaration;
|
||||
kind: SyntaxKind.ComputedPropertyName;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -632,6 +633,7 @@ declare namespace ts {
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
objectAssignmentInitializer?: Expression;
|
||||
}
|
||||
@@ -668,6 +670,7 @@ declare namespace ts {
|
||||
_functionLikeDeclarationBrand: any;
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
exclamationToken?: ExclamationToken;
|
||||
body?: Block | Expression;
|
||||
}
|
||||
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
|
||||
@@ -2060,28 +2063,28 @@ declare namespace ts {
|
||||
ModuleExports = 134217728,
|
||||
Enum = 384,
|
||||
Variable = 3,
|
||||
Value = 67216319,
|
||||
Type = 67901928,
|
||||
Value = 67220415,
|
||||
Type = 67897832,
|
||||
Namespace = 1920,
|
||||
Module = 1536,
|
||||
Accessor = 98304,
|
||||
FunctionScopedVariableExcludes = 67216318,
|
||||
BlockScopedVariableExcludes = 67216319,
|
||||
ParameterExcludes = 67216319,
|
||||
FunctionScopedVariableExcludes = 67220414,
|
||||
BlockScopedVariableExcludes = 67220415,
|
||||
ParameterExcludes = 67220415,
|
||||
PropertyExcludes = 0,
|
||||
EnumMemberExcludes = 68008959,
|
||||
FunctionExcludes = 67215791,
|
||||
FunctionExcludes = 67219887,
|
||||
ClassExcludes = 68008383,
|
||||
InterfaceExcludes = 67901832,
|
||||
InterfaceExcludes = 67897736,
|
||||
RegularEnumExcludes = 68008191,
|
||||
ConstEnumExcludes = 68008831,
|
||||
ValueModuleExcludes = 67215503,
|
||||
ValueModuleExcludes = 110735,
|
||||
NamespaceModuleExcludes = 0,
|
||||
MethodExcludes = 67208127,
|
||||
GetAccessorExcludes = 67150783,
|
||||
SetAccessorExcludes = 67183551,
|
||||
TypeParameterExcludes = 67639784,
|
||||
TypeAliasExcludes = 67901928,
|
||||
MethodExcludes = 67212223,
|
||||
GetAccessorExcludes = 67154879,
|
||||
SetAccessorExcludes = 67187647,
|
||||
TypeParameterExcludes = 67635688,
|
||||
TypeAliasExcludes = 67897832,
|
||||
AliasExcludes = 2097152,
|
||||
ModuleMember = 2623475,
|
||||
ExportHasLocal = 944,
|
||||
@@ -2690,9 +2693,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -2993,6 +2993,16 @@ declare namespace ts {
|
||||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
@@ -3202,17 +3212,27 @@ declare namespace ts {
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* @remarks Returns any JSDoc param tag whose name matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
* For binding patterns, parameter tags are matched by position.
|
||||
*/
|
||||
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag>;
|
||||
/**
|
||||
* Gets the JSDoc type parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc template tag whose names match the provided
|
||||
* parameter, whether a template tag on a containing function
|
||||
* expression, or a template tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the template
|
||||
* tag on the containing function expression would be first.
|
||||
*/
|
||||
function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag>;
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
@@ -4313,15 +4333,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4354,14 +4385,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
@@ -4637,14 +4660,6 @@ declare namespace ts {
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
//// [arrayFlatMap.ts]
|
||||
const array: number[] = [];
|
||||
const readonlyArray: ReadonlyArray<number> = [];
|
||||
array.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
readonlyArray.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
|
||||
|
||||
//// [arrayFlatMap.js]
|
||||
var array = [];
|
||||
var readonlyArray = [];
|
||||
array.flatMap(function () { return []; }); // ok
|
||||
readonlyArray.flatMap(function () { return []; }); // ok
|
||||
@@ -0,0 +1,20 @@
|
||||
=== tests/cases/compiler/arrayFlatMap.ts ===
|
||||
const array: number[] = [];
|
||||
>array : Symbol(array, Decl(arrayFlatMap.ts, 0, 5))
|
||||
|
||||
const readonlyArray: ReadonlyArray<number> = [];
|
||||
>readonlyArray : Symbol(readonlyArray, Decl(arrayFlatMap.ts, 1, 5))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
|
||||
|
||||
array.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
>array.flatMap : Symbol(Array.flatMap, Decl(lib.esnext.array.d.ts, --, --))
|
||||
>array : Symbol(array, Decl(arrayFlatMap.ts, 0, 5))
|
||||
>flatMap : Symbol(Array.flatMap, Decl(lib.esnext.array.d.ts, --, --))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
|
||||
|
||||
readonlyArray.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
>readonlyArray.flatMap : Symbol(ReadonlyArray.flatMap, Decl(lib.esnext.array.d.ts, --, --))
|
||||
>readonlyArray : Symbol(readonlyArray, Decl(arrayFlatMap.ts, 1, 5))
|
||||
>flatMap : Symbol(ReadonlyArray.flatMap, Decl(lib.esnext.array.d.ts, --, --))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
=== tests/cases/compiler/arrayFlatMap.ts ===
|
||||
const array: number[] = [];
|
||||
>array : number[]
|
||||
>[] : undefined[]
|
||||
|
||||
const readonlyArray: ReadonlyArray<number> = [];
|
||||
>readonlyArray : ReadonlyArray<number>
|
||||
>[] : undefined[]
|
||||
|
||||
array.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
>array.flatMap((): ReadonlyArray<number> => []) : number[]
|
||||
>array.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | ReadonlyArray<U>, thisArg?: This) => U[]
|
||||
>array : number[]
|
||||
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | ReadonlyArray<U>, thisArg?: This) => U[]
|
||||
>(): ReadonlyArray<number> => [] : () => ReadonlyArray<number>
|
||||
>[] : undefined[]
|
||||
|
||||
readonlyArray.flatMap((): ReadonlyArray<number> => []); // ok
|
||||
>readonlyArray.flatMap((): ReadonlyArray<number> => []) : number[]
|
||||
>readonlyArray.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | ReadonlyArray<U>, thisArg?: This) => U[]
|
||||
>readonlyArray : ReadonlyArray<number>
|
||||
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | ReadonlyArray<U>, thisArg?: This) => U[]
|
||||
>(): ReadonlyArray<number> => [] : () => ReadonlyArray<number>
|
||||
>[] : undefined[]
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
tests/cases/compiler/arrayIndexWithArrayFails.ts(3,16): error TS2538: Type 'string[]' cannot be used as an index type.
|
||||
|
||||
|
||||
==== tests/cases/compiler/arrayIndexWithArrayFails.ts (1 errors) ====
|
||||
declare const arr1: (string | string[])[];
|
||||
declare const arr2: number[];
|
||||
const j = arr2[arr1[0]]; // should error
|
||||
~~~~~~~
|
||||
!!! error TS2538: Type 'string[]' cannot be used as an index type.
|
||||
@@ -0,0 +1,7 @@
|
||||
//// [arrayIndexWithArrayFails.ts]
|
||||
declare const arr1: (string | string[])[];
|
||||
declare const arr2: number[];
|
||||
const j = arr2[arr1[0]]; // should error
|
||||
|
||||
//// [arrayIndexWithArrayFails.js]
|
||||
var j = arr2[arr1[0]]; // should error
|
||||
@@ -0,0 +1,12 @@
|
||||
=== tests/cases/compiler/arrayIndexWithArrayFails.ts ===
|
||||
declare const arr1: (string | string[])[];
|
||||
>arr1 : Symbol(arr1, Decl(arrayIndexWithArrayFails.ts, 0, 13))
|
||||
|
||||
declare const arr2: number[];
|
||||
>arr2 : Symbol(arr2, Decl(arrayIndexWithArrayFails.ts, 1, 13))
|
||||
|
||||
const j = arr2[arr1[0]]; // should error
|
||||
>j : Symbol(j, Decl(arrayIndexWithArrayFails.ts, 2, 5))
|
||||
>arr2 : Symbol(arr2, Decl(arrayIndexWithArrayFails.ts, 1, 13))
|
||||
>arr1 : Symbol(arr1, Decl(arrayIndexWithArrayFails.ts, 0, 13))
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
=== tests/cases/compiler/arrayIndexWithArrayFails.ts ===
|
||||
declare const arr1: (string | string[])[];
|
||||
>arr1 : (string | string[])[]
|
||||
|
||||
declare const arr2: number[];
|
||||
>arr2 : number[]
|
||||
|
||||
const j = arr2[arr1[0]]; // should error
|
||||
>j : any
|
||||
>arr2[arr1[0]] : any
|
||||
>arr2 : number[]
|
||||
>arr1[0] : string | string[]
|
||||
>arr1 : (string | string[])[]
|
||||
>0 : 0
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(13,1): error TS2322: Type 'A[]' is not assignable to type 'ReadonlyArray<B>'.
|
||||
Types of property 'concat' are incompatible.
|
||||
Type '{ (...items: ConcatArray<A>[]): A[]; (...items: (A | ConcatArray<A>)[]): A[]; }' is not assignable to type '{ (...items: ConcatArray<B>[]): B[]; (...items: (B | ConcatArray<B>)[]): B[]; }'.
|
||||
Type 'A[]' is not assignable to type 'B[]'.
|
||||
Type 'A' is not assignable to type 'B'.
|
||||
Property 'b' is missing in type 'A'.
|
||||
Type 'A' is not assignable to type 'B'.
|
||||
Property 'b' is missing in type 'A'.
|
||||
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is not assignable to type 'ReadonlyArray<B>'.
|
||||
Types of property 'concat' are incompatible.
|
||||
Type '{ (...items: ConcatArray<A>[]): A[]; (...items: (A | ConcatArray<A>)[]): A[]; }' is not assignable to type '{ (...items: ConcatArray<B>[]): B[]; (...items: (B | ConcatArray<B>)[]): B[]; }'.
|
||||
Type 'A[]' is not assignable to type 'B[]'.
|
||||
Type 'A' is not assignable to type 'B'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts (2 errors) ====
|
||||
@@ -26,11 +24,8 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
|
||||
rrb = ara; // error: 'A' is not assignable to 'B'
|
||||
~~~
|
||||
!!! error TS2322: Type 'A[]' is not assignable to type 'ReadonlyArray<B>'.
|
||||
!!! error TS2322: Types of property 'concat' are incompatible.
|
||||
!!! error TS2322: Type '{ (...items: ConcatArray<A>[]): A[]; (...items: (A | ConcatArray<A>)[]): A[]; }' is not assignable to type '{ (...items: ConcatArray<B>[]): B[]; (...items: (B | ConcatArray<B>)[]): B[]; }'.
|
||||
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
|
||||
!!! error TS2322: Type 'A' is not assignable to type 'B'.
|
||||
!!! error TS2322: Property 'b' is missing in type 'A'.
|
||||
!!! error TS2322: Type 'A' is not assignable to type 'B'.
|
||||
!!! error TS2322: Property 'b' is missing in type 'A'.
|
||||
|
||||
rra = cra;
|
||||
rra = crb; // OK, C<B> is assignable to ReadonlyArray<A>
|
||||
@@ -41,4 +36,5 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
|
||||
!!! error TS2322: Types of property 'concat' are incompatible.
|
||||
!!! error TS2322: Type '{ (...items: ConcatArray<A>[]): A[]; (...items: (A | ConcatArray<A>)[]): A[]; }' is not assignable to type '{ (...items: ConcatArray<B>[]): B[]; (...items: (B | ConcatArray<B>)[]): B[]; }'.
|
||||
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
|
||||
!!! error TS2322: Type 'A' is not assignable to type 'B'.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatBetweenTupleAndArray.ts(17,1): error TS2322: Type '[number, string]' is not assignable to type 'number[]'.
|
||||
Types of property 'pop' are incompatible.
|
||||
Type '() => string | number' is not assignable to type '() => number'.
|
||||
Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatBetweenTupleAndArray.ts(18,1): error TS2322: Type '{}[]' is not assignable to type '[{}]'.
|
||||
Property '0' is missing in type '{}[]'.
|
||||
|
||||
@@ -27,10 +25,8 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
numArray = numStrTuple;
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '[number, string]' is not assignable to type 'number[]'.
|
||||
!!! error TS2322: Types of property 'pop' are incompatible.
|
||||
!!! error TS2322: Type '() => string | number' is not assignable to type '() => number'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
emptyObjTuple = emptyObjArray;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{}[]' is not assignable to type '[{}]'.
|
||||
|
||||
@@ -23,7 +23,7 @@ function foo() {
|
||||
|
||||
var x: TokenType = list['one'];
|
||||
>x : TokenType
|
||||
>list['one'] : any
|
||||
>list['one'] : error
|
||||
>list : {}
|
||||
>'one' : "one"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(4,5): error TS2345: Argument of type '{ id: number; name: boolean; }' is not assignable to parameter of type '{ id: number; name?: string; }'.
|
||||
Types of property 'name' are incompatible.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(4,17): error TS2322: Type 'false' is not assignable to type 'string'.
|
||||
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(5,5): error TS2345: Argument of type '{ name: string; }' is not assignable to parameter of type '{ id: number; name?: string; }'.
|
||||
Property 'id' is missing in type '{ name: string; }'.
|
||||
|
||||
@@ -13,10 +11,9 @@ tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(5,5): error TS
|
||||
foo({ id: 1234 }); // Ok
|
||||
foo({ id: 1234, name: "hello" }); // Ok
|
||||
foo({ id: 1234, name: false }); // Error, name of wrong type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ id: number; name: boolean; }' is not assignable to parameter of type '{ id: number; name?: string; }'.
|
||||
!!! error TS2345: Types of property 'name' are incompatible.
|
||||
!!! error TS2345: Type 'boolean' is not assignable to type 'string'.
|
||||
~~~~
|
||||
!!! error TS2322: Type 'false' is not assignable to type 'string'.
|
||||
!!! related TS6500 tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts:1:31: The expected type comes from property 'name' which is declared here on type '{ id: number; name?: string; }'
|
||||
foo({ name: "hello" }); // Error, id required but missing
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ name: string; }' is not assignable to parameter of type '{ id: number; name?: string; }'.
|
||||
|
||||
@@ -45,6 +45,11 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Property 'baz' is missing in type 'Base'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(83,1): error TS2322: Type '(x: Base[], y: Derived[]) => Derived[]' is not assignable to type '<T extends Derived[]>(x: Base[], y: T) => T'.
|
||||
Type 'Derived[]' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(85,1): error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => Object'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: string; b: number; }) => Object' is not assignable to type '<T>(x: { a: T; b: T; }) => T'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
|
||||
@@ -52,7 +57,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'T' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts (14 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts (15 errors) ====
|
||||
// these are all permitted with the current rules, since we do not do contextual signature instantiation
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -198,6 +203,12 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
!!! error TS2322: Type 'Derived[]' is not assignable to type 'T'.
|
||||
var b14: <T>(x: { a: T; b: T }) => T;
|
||||
a14 = b14; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => Object'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
b14 = a14; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type '(x: { a: string; b: number; }) => Object' is not assignable to type '<T>(x: { a: T; b: T; }) => T'.
|
||||
|
||||
@@ -22,8 +22,10 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(66,9): error TS2322: Type '(x: Base[], y: Derived2[]) => Derived[]' is not assignable to type '<T extends Derived2[]>(x: Base[], y: Base[]) => T'.
|
||||
Type 'Derived[]' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(69,9): error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => number'.
|
||||
Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(70,9): error TS2322: Type '(x: { a: string; b: number; }) => number' is not assignable to type '<T>(x: { a: T; b: T; }) => T'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
|
||||
@@ -156,8 +158,10 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
a15 = b15;
|
||||
~~~
|
||||
!!! error TS2322: Type '<T>(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => number'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
b15 = a15;
|
||||
~~~
|
||||
!!! error TS2322: Type '(x: { a: string; b: number; }) => number' is not assignable to type '<T>(x: { a: T; b: T; }) => T'.
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts(40,1): error TS2322: Type '<T>(x: T) => void' is not assignable to type '<T>(x: T) => T'.
|
||||
Type 'void' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts(52,1): error TS2322: Type '<T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type '<T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'U' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts(55,1): error TS2322: Type '<T>(x: { a: T; b: T; }) => T[]' is not assignable to type '<U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
Type '(U | V)[]' is not assignable to type 'U[]'.
|
||||
Type 'U | V' is not assignable to type 'U'.
|
||||
Type 'V' is not assignable to type 'U'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: U; b: V; }' is not assignable to type '{ a: U; b: U; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'V' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts(58,1): error TS2322: Type '<T extends Base>(x: { a: T; b: T; }) => T[]' is not assignable to type '<U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: U; b: V; }' is not assignable to type '{ a: Base; b: Base; }'.
|
||||
@@ -11,7 +17,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'U' is not assignable to type 'Base'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts (3 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts (4 errors) ====
|
||||
// checking assignment compat for function types. No errors in this file
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -67,14 +73,21 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
var b11: <T, U>(x: { foo: T }, y: { foo: U; bar: U }) => Base;
|
||||
a11 = b11; // ok
|
||||
b11 = a11; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type '<T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type '<T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
|
||||
!!! error TS2322: Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
!!! error TS2322: Types of property 'foo' are incompatible.
|
||||
!!! error TS2322: Type 'U' is not assignable to type 'T'.
|
||||
var b15: <U, V>(x: { a: U; b: V; }) => U[];
|
||||
a15 = b15; // ok, T = U, T = V
|
||||
b15 = a15; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type '<T>(x: { a: T; b: T; }) => T[]' is not assignable to type '<U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
!!! error TS2322: Type '(U | V)[]' is not assignable to type 'U[]'.
|
||||
!!! error TS2322: Type 'U | V' is not assignable to type 'U'.
|
||||
!!! error TS2322: Type 'V' is not assignable to type 'U'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: U; b: V; }' is not assignable to type '{ a: U; b: U; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'V' is not assignable to type 'U'.
|
||||
var b16: <T>(x: { a: T; b: T }) => T[];
|
||||
a15 = b16; // ok
|
||||
b15 = a16; // ok
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts(30,1): error TS2322: Type '<T>(x: T) => void' is not assignable to type '<T>(x: T) => T'.
|
||||
Type 'void' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts(39,1): error TS2322: Type '<T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type '<T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'U' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts(42,1): error TS2322: Type '<T extends Base>(x: { a: T; b: T; }) => T[]' is not assignable to type '<T>(x: { a: T; b: T; }) => T[]'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: Base; b: Base; }'.
|
||||
@@ -7,7 +12,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'T' is not assignable to type 'Base'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts (2 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts (3 errors) ====
|
||||
// checking assignment compatibility relations for function types. All valid
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -50,6 +55,12 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
var b11: <T, U>(x: { foo: T }, y: { foo: U; bar: U }) => Base;
|
||||
x.a11 = b11;
|
||||
b11 = x.a11;
|
||||
~~~
|
||||
!!! error TS2322: Type '<T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type '<T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
|
||||
!!! error TS2322: Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
!!! error TS2322: Types of property 'foo' are incompatible.
|
||||
!!! error TS2322: Type 'U' is not assignable to type 'T'.
|
||||
var b16: <T>(x: { a: T; b: T }) => T[];
|
||||
x.a16 = b16;
|
||||
b16 = x.a16;
|
||||
|
||||
@@ -45,6 +45,11 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Property 'baz' is missing in type 'Base'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts(83,1): error TS2322: Type 'new (x: Base[], y: Derived[]) => Derived[]' is not assignable to type 'new <T extends Derived[]>(x: Base[], y: T) => T'.
|
||||
Type 'Derived[]' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts(85,1): error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => Object'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts(86,1): error TS2322: Type 'new (x: { a: string; b: number; }) => Object' is not assignable to type 'new <T>(x: { a: T; b: T; }) => T'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
|
||||
@@ -52,7 +57,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'T' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts (14 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts (15 errors) ====
|
||||
// checking assignment compatibility relations for function types. All of these are valid.
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -198,6 +203,12 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
!!! error TS2322: Type 'Derived[]' is not assignable to type 'T'.
|
||||
var b14: new <T>(x: { a: T; b: T }) => T;
|
||||
a14 = b14; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => Object'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
b14 = a14; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new (x: { a: string; b: number; }) => Object' is not assignable to type 'new <T>(x: { a: T; b: T; }) => T'.
|
||||
|
||||
@@ -22,8 +22,10 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts(66,9): error TS2322: Type 'new (x: Base[], y: Derived2[]) => Derived[]' is not assignable to type 'new <T extends Derived2[]>(x: Base[], y: Base[]) => T'.
|
||||
Type 'Derived[]' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts(69,9): error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => number'.
|
||||
Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts(70,9): error TS2322: Type 'new (x: { a: string; b: number; }) => number' is not assignable to type 'new <T>(x: { a: T; b: T; }) => T'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
|
||||
@@ -172,8 +174,10 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
a15 = b15; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => number'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
b15 = a15; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new (x: { a: string; b: number; }) => number' is not assignable to type 'new <T>(x: { a: T; b: T; }) => T'.
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts(40,1): error TS2322: Type 'new <T>(x: T) => void' is not assignable to type 'new <T>(x: T) => T'.
|
||||
Type 'void' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts(52,1): error TS2322: Type 'new <T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type 'new <T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'U' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts(55,1): error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T[]' is not assignable to type 'new <U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
Type '(U | V)[]' is not assignable to type 'U[]'.
|
||||
Type 'U | V' is not assignable to type 'U'.
|
||||
Type 'V' is not assignable to type 'U'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: U; b: V; }' is not assignable to type '{ a: U; b: U; }'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'V' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts(58,1): error TS2322: Type 'new <T extends Base>(x: { a: T; b: T; }) => T[]' is not assignable to type 'new <U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: U; b: V; }' is not assignable to type '{ a: Base; b: Base; }'.
|
||||
@@ -11,7 +17,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'U' is not assignable to type 'Base'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts (3 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures5.ts (4 errors) ====
|
||||
// checking assignment compat for function types. All valid
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -67,14 +73,21 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
var b11: new <T, U>(x: { foo: T }, y: { foo: U; bar: U }) => Base;
|
||||
a11 = b11; // ok
|
||||
b11 = a11; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new <T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type 'new <T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
|
||||
!!! error TS2322: Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
!!! error TS2322: Types of property 'foo' are incompatible.
|
||||
!!! error TS2322: Type 'U' is not assignable to type 'T'.
|
||||
var b15: new <U, V>(x: { a: U; b: V; }) => U[];
|
||||
a15 = b15; // ok
|
||||
b15 = a15; // ok
|
||||
~~~
|
||||
!!! error TS2322: Type 'new <T>(x: { a: T; b: T; }) => T[]' is not assignable to type 'new <U, V>(x: { a: U; b: V; }) => U[]'.
|
||||
!!! error TS2322: Type '(U | V)[]' is not assignable to type 'U[]'.
|
||||
!!! error TS2322: Type 'U | V' is not assignable to type 'U'.
|
||||
!!! error TS2322: Type 'V' is not assignable to type 'U'.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type '{ a: U; b: V; }' is not assignable to type '{ a: U; b: U; }'.
|
||||
!!! error TS2322: Types of property 'b' are incompatible.
|
||||
!!! error TS2322: Type 'V' is not assignable to type 'U'.
|
||||
var b16: new <T>(x: { a: T; b: T }) => T[];
|
||||
a15 = b16; // ok
|
||||
b15 = a16; // ok
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures6.ts(30,1): error TS2322: Type 'new <T>(x: T) => void' is not assignable to type 'new <T>(x: T) => T'.
|
||||
Type 'void' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures6.ts(39,1): error TS2322: Type 'new <T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type 'new <T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'U' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures6.ts(42,1): error TS2322: Type 'new <T extends Base>(x: { a: T; b: T; }) => T[]' is not assignable to type 'new <T>(x: { a: T; b: T; }) => T[]'.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type '{ a: T; b: T; }' is not assignable to type '{ a: Base; b: Base; }'.
|
||||
@@ -7,7 +12,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
Type 'T' is not assignable to type 'Base'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures6.ts (2 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures6.ts (3 errors) ====
|
||||
// checking assignment compatibility relations for function types. All valid.
|
||||
|
||||
class Base { foo: string; }
|
||||
@@ -50,6 +55,12 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
var b11: new <T, U>(x: { foo: T }, y: { foo: U; bar: U }) => Base;
|
||||
x.a11 = b11;
|
||||
b11 = x.a11;
|
||||
~~~
|
||||
!!! error TS2322: Type 'new <T>(x: { foo: T; }, y: { foo: T; bar: T; }) => Base' is not assignable to type 'new <T, U>(x: { foo: T; }, y: { foo: U; bar: U; }) => Base'.
|
||||
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
|
||||
!!! error TS2322: Type '{ foo: U; bar: U; }' is not assignable to type '{ foo: T; bar: T; }'.
|
||||
!!! error TS2322: Types of property 'foo' are incompatible.
|
||||
!!! error TS2322: Type 'U' is not assignable to type 'T'.
|
||||
var b16: new <T>(x: { a: T; b: T }) => T[];
|
||||
x.a16 = b16;
|
||||
b16 = x.a16;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithGenericCallSignatures2.ts(15,1): error TS2322: Type 'B' is not assignable to type 'A'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type 'T[]' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithGenericCallSignatures2.ts(16,1): error TS2322: Type 'A' is not assignable to type 'B'.
|
||||
Types of parameters 'y' and 'y' are incompatible.
|
||||
Type 'S' is not assignable to type 'S[]'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithGenericCallSignatures2.ts (1 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithGenericCallSignatures2.ts (2 errors) ====
|
||||
// some complex cases of assignment compat of generic signatures. No contextual signature instantiation
|
||||
|
||||
interface A {
|
||||
@@ -17,8 +20,12 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
|
||||
var a: A;
|
||||
var b: B;
|
||||
|
||||
// Both ok
|
||||
// Both errors
|
||||
a = b;
|
||||
~
|
||||
!!! error TS2322: Type 'B' is not assignable to type 'A'.
|
||||
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
|
||||
!!! error TS2322: Type 'T[]' is not assignable to type 'T'.
|
||||
b = a;
|
||||
~
|
||||
!!! error TS2322: Type 'A' is not assignable to type 'B'.
|
||||
|
||||
@@ -12,7 +12,7 @@ interface B {
|
||||
var a: A;
|
||||
var b: B;
|
||||
|
||||
// Both ok
|
||||
// Both errors
|
||||
a = b;
|
||||
b = a;
|
||||
|
||||
@@ -21,6 +21,6 @@ b = a;
|
||||
// some complex cases of assignment compat of generic signatures. No contextual signature instantiation
|
||||
var a;
|
||||
var b;
|
||||
// Both ok
|
||||
// Both errors
|
||||
a = b;
|
||||
b = a;
|
||||
|
||||
@@ -31,7 +31,7 @@ var b: B;
|
||||
>b : Symbol(b, Decl(assignmentCompatWithGenericCallSignatures2.ts, 11, 3))
|
||||
>B : Symbol(B, Decl(assignmentCompatWithGenericCallSignatures2.ts, 4, 1))
|
||||
|
||||
// Both ok
|
||||
// Both errors
|
||||
a = b;
|
||||
>a : Symbol(a, Decl(assignmentCompatWithGenericCallSignatures2.ts, 10, 3))
|
||||
>b : Symbol(b, Decl(assignmentCompatWithGenericCallSignatures2.ts, 11, 3))
|
||||
|
||||
@@ -19,7 +19,7 @@ var a: A;
|
||||
var b: B;
|
||||
>b : B
|
||||
|
||||
// Both ok
|
||||
// Both errors
|
||||
a = b;
|
||||
>a = b : B
|
||||
>a : A
|
||||
|
||||
@@ -16,14 +16,14 @@ interface Function {
|
||||
}
|
||||
|
||||
var a = {}[0]; // Should be Foo
|
||||
>a : any
|
||||
>{}[0] : any
|
||||
>a : error
|
||||
>{}[0] : error
|
||||
>{} : {}
|
||||
>0 : 0
|
||||
|
||||
var b = (() => { })[0]; // Should be Bar
|
||||
>b : any
|
||||
>(() => { })[0] : any
|
||||
>b : error
|
||||
>(() => { })[0] : error
|
||||
>(() => { }) : () => void
|
||||
>() => { } : () => void
|
||||
>0 : 0
|
||||
|
||||
@@ -22,8 +22,8 @@ var r1 = o['data']; // Should be number
|
||||
>'data' : "data"
|
||||
|
||||
var r2 = o['functionData']; // Should be any (no property found)
|
||||
>r2 : any
|
||||
>o['functionData'] : any
|
||||
>r2 : error
|
||||
>o['functionData'] : error
|
||||
>o : {}
|
||||
>'functionData' : "functionData"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user